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 2006 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 strcmp(au_mn, "sbpro") != 0) { 177 178 /* 179 * audioctl/sbproctl are special cases. They are handled 180 * by stripping off the audio/sbpro from the node name 181 */ 182 if (strcmp(au_mn, "audioctl") == 0 || 183 strcmp(au_mn, "sbproctl") == 0) 184 au_mn = strstr(au_mn, "ctl"); 185 (void) strcat(path, au_mn); 186 } 187 } 188 189 if (regexec(&isdn_re, mn, sizeof (pmatch) / sizeof (pmatch[0]), 190 pmatch, 0) == 0) { 191 COPYSUB(m1, mn, pmatch, F); 192 COPYSUB(m2, mn, pmatch, S); 193 (void) strcpy(path, "isdn/"); 194 (void) strcat(path, buf); 195 (void) strcat(path, "/"); 196 (void) strcat(path, m1); 197 (void) strcat(path, "/"); 198 (void) strcat(path, m2); 199 } 200 201 if (strstr("mgt,mgt", mn) != NULL) { 202 (void) strcpy(path, "isdn/"); 203 (void) strcat(path, buf); 204 (void) strcat(path, "/mgt"); 205 } 206 207 free(buf); 208 209 if (path[0] == '\0') { 210 devfsadm_errprint("SUNW_audio_link: audio_process: can't find" 211 " match for'%s'\n", mn); 212 return (DEVFSADM_CONTINUE); 213 } 214 215 if (system_labeled) 216 flags = DA_ADD|DA_AUDIO; 217 218 (void) devfsadm_mklink(path, node, minor, flags); 219 return (DEVFSADM_CONTINUE); 220 } 221 222 223 static void 224 check_audio_link(char *secondary_link, const char *primary_link_format) 225 { 226 char primary_link[PATH_MAX + 1]; 227 int i; 228 int flags = 0; 229 230 /* if link is present, return */ 231 if (devfsadm_link_valid(secondary_link) == DEVFSADM_TRUE) { 232 return; 233 } 234 235 if (system_labeled) 236 flags = DA_ADD|DA_AUDIO; 237 238 for (i = 0; i < MAX_AUDIO_LINK; i++) { 239 (void) sprintf(primary_link, primary_link_format, i); 240 if (devfsadm_link_valid(primary_link) == DEVFSADM_TRUE) { 241 (void) devfsadm_secondary_link(secondary_link, 242 primary_link, flags); 243 break; 244 } 245 } 246 } 247