Home | History | Annotate | Download | only in devfsadm
      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