1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <regex.h> 29 #include <devfsadm.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <limits.h> 33 #include <stdio.h> 34 #include <bsm/devalloc.h> 35 36 #define MAX_AUDIO_LINK 100 37 #define RE_SIZE 64 38 39 extern int system_labeled; 40 41 static void check_audio_link(char *secondary_link, 42 const char *primary_link_format); 43 static int audio_process(di_minor_t minor, di_node_t node); 44 45 static devfsadm_create_t audio_cbt[] = { 46 { "audio", "ddi_audio", NULL, 47 TYPE_EXACT, ILEVEL_0, audio_process 48 } 49 }; 50 51 DEVFSADM_CREATE_INIT_V0(audio_cbt); 52 53 /* 54 * the following can't be one big RE with a bunch of alterations "|" 55 * because recurse_dev_re() would not work. 56 */ 57 static devfsadm_remove_t audio_remove_cbt[] = { 58 { "audio", 59 "^audio(ctl)?$", 60 RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 61 }, 62 { "audio", 63 "^sound/[0-9]+.*$", 64 RM_PRE|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 65 }, 66 { "audio", 67 "^isdn/[0-9]+/mgt$", 68 RM_PRE, ILEVEL_0, devfsadm_rm_all 69 }, 70 { "audio", 71 "^isdn/[0-9]+/aux/0(ctl)?$", 72 RM_PRE, ILEVEL_0, devfsadm_rm_all 73 }, 74 { "audio", 75 "^isdn/[0-9]+/(nt)|(te)/((dtrace)|(mgt)|(b1)|(b2)|(d))$", 76 RM_PRE, ILEVEL_0, devfsadm_rm_all 77 } 78 }; 79 80 DEVFSADM_REMOVE_INIT_V0(audio_remove_cbt); 81 82 static regex_t isdn_re; 83 84 #define ISDN_RE "((nt)|(te)|(aux))\\,((0)|(0ctl)|(d)|(b1)|(b2)|(mgt)|(dtrace))" 85 #define F 1 86 #define S 5 87 88 int 89 minor_init(void) 90 { 91 if (0 != regcomp(&isdn_re, ISDN_RE, REG_EXTENDED)) { 92 devfsadm_errprint("SUNW_audio_link: minor_init: regular " 93 "expression bad: '%s'\n", ISDN_RE); 94 return (DEVFSADM_FAILURE); 95 } else { 96 return (DEVFSADM_SUCCESS); 97 } 98 } 99 100 int 101 minor_fini(void) 102 { 103 regfree(&isdn_re); 104 check_audio_link("audio", "sound/%d"); 105 check_audio_link("audioctl", "sound/%dctl"); 106 return (DEVFSADM_SUCCESS); 107 } 108 109 110 #define COPYSUB(to, from, pm, pos) (void) strncpy(to, &from[pm[pos].rm_so], \ 111 pm[pos].rm_eo - pm[pos].rm_so); \ 112 to[pm[pos].rm_eo - pm[pos].rm_so] = 0; 113 114 /* 115 * This function is called for every audio node. 116 * Calls enumerate to assign a logical unit id, and then 117 * devfsadm_mklink to make the link. 118 */ 119 static int 120 audio_process(di_minor_t minor, di_node_t node) 121 { 122 int flags = 0; 123 char path[PATH_MAX + 1]; 124 char *buf; 125 char *mn; 126 char m1[10]; 127 char m2[10]; 128 char *devfspath; 129 char re_string[RE_SIZE+1]; 130 devfsadm_enumerate_t rules[1] = {NULL}; 131 regmatch_t pmatch[12]; 132 char *au_mn; 133 134 135 mn = di_minor_name(minor); 136 137 if ((devfspath = di_devfs_path(node)) == NULL) { 138 return (DEVFSADM_CONTINUE); 139 } 140 (void) strcpy(path, devfspath); 141 (void) strcat(path, ":"); 142 (void) strcat(path, mn); 143 di_devfs_path_free(devfspath); 144 145 if (strstr(mn, "sound,") != NULL) { 146 (void) snprintf(re_string, RE_SIZE, "%s", "^sound$/^([0-9]+)"); 147 } else { 148 (void) strcpy(re_string, "isdn/([0-9]+)"); 149 } 150 151 /* 152 * We want a match against the physical path 153 * without the minor name component. 154 */ 155 rules[0].re = re_string; 156 rules[0].subexp = 1; 157 rules[0].flags = MATCH_ADDR; 158 159 /* 160 * enumerate finds the logical audio id, and stuffs 161 * it in buf 162 */ 163 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 164 return (DEVFSADM_CONTINUE); 165 } 166 167 path[0] = '\0'; 168 169 if (strstr(mn, "sound,") != NULL) { 170 (void) strcpy(path, "sound/"); 171 (void) strcat(path, buf); 172 173 /* if this is a minor node, tack on the correct suffix */ 174 au_mn = strchr(mn, ','); 175 if (strcmp(++au_mn, "audio") != 0) { 176 177 /* 178 * audioctl is a special case. It is handled 179 * by stripping off the audio from the node name 180 */ 181 if (strcmp(au_mn, "audioctl") == 0) 182 au_mn = strstr(au_mn, "ctl"); 183 (void) strcat(path, au_mn); 184 } 185 } 186 187 if (regexec(&isdn_re, mn, sizeof (pmatch) / sizeof (pmatch[0]), 188 pmatch, 0) == 0) { 189 COPYSUB(m1, mn, pmatch, F); 190 COPYSUB(m2, mn, pmatch, S); 191 (void) strcpy(path, "isdn/"); 192 (void) strcat(path, buf); 193 (void) strcat(path, "/"); 194 (void) strcat(path, m1); 195 (void) strcat(path, "/"); 196 (void) strcat(path, m2); 197 } 198 199 if (strstr("mgt,mgt", mn) != NULL) { 200 (void) strcpy(path, "isdn/"); 201 (void) strcat(path, buf); 202 (void) strcat(path, "/mgt"); 203 } 204 205 free(buf); 206 207 if (path[0] == '\0') { 208 devfsadm_errprint("SUNW_audio_link: audio_process: can't find" 209 " match for'%s'\n", mn); 210 return (DEVFSADM_CONTINUE); 211 } 212 213 if (system_labeled) 214 flags = DA_ADD|DA_AUDIO; 215 216 (void) devfsadm_mklink(path, node, minor, flags); 217 return (DEVFSADM_CONTINUE); 218 } 219 220 221 static void 222 check_audio_link(char *secondary_link, const char *primary_link_format) 223 { 224 char primary_link[PATH_MAX + 1]; 225 int i; 226 int flags = 0; 227 228 /* if link is present, return */ 229 if (devfsadm_link_valid(secondary_link) == DEVFSADM_TRUE) { 230 return; 231 } 232 233 if (system_labeled) 234 flags = DA_ADD|DA_AUDIO; 235 236 for (i = 0; i < MAX_AUDIO_LINK; i++) { 237 (void) sprintf(primary_link, primary_link_format, i); 238 if (devfsadm_link_valid(primary_link) == DEVFSADM_TRUE) { 239 (void) devfsadm_secondary_link(secondary_link, 240 primary_link, flags); 241 break; 242 } 243 } 244 } 245