xref: /illumos-gate/usr/src/cmd/devfsadm/audio_link.c (revision ba2be53024c0b999e74ba9adcd7d80fec5df8c57)
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