xref: /titanic_44/usr/src/cmd/modload/drvsubr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
33*7c478bd9Sstevel@tonic-gate #include <libintl.h>
34*7c478bd9Sstevel@tonic-gate #include <wait.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate #include <errno.h>
37*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
38*7c478bd9Sstevel@tonic-gate #include <signal.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
41*7c478bd9Sstevel@tonic-gate #include <grp.h>
42*7c478bd9Sstevel@tonic-gate #include "addrem.h"
43*7c478bd9Sstevel@tonic-gate #include "errmsg.h"
44*7c478bd9Sstevel@tonic-gate #include "plcysubr.h"
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate static char *add_rem_lock;	/* lock file */
47*7c478bd9Sstevel@tonic-gate static char *tmphold;		/* temperary file for updating */
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate static int get_cached_n_to_m_file(char *filename, char ***cache);
50*7c478bd9Sstevel@tonic-gate static int get_name_to_major_entry(int *major_no, char *driver_name,
51*7c478bd9Sstevel@tonic-gate     char *file_name);
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
54*7c478bd9Sstevel@tonic-gate void
55*7c478bd9Sstevel@tonic-gate log_minorperm_error(minorperm_err_t err, int key)
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	switch (err) {
58*7c478bd9Sstevel@tonic-gate 	case MP_FOPEN_ERR:
59*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
60*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
61*7c478bd9Sstevel@tonic-gate 		break;
62*7c478bd9Sstevel@tonic-gate 	case MP_FCLOSE_ERR:
63*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
64*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
65*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
66*7c478bd9Sstevel@tonic-gate 		break;
67*7c478bd9Sstevel@tonic-gate 	case MP_IGNORING_LINE_ERR:
68*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
69*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
70*7c478bd9Sstevel@tonic-gate 		break;
71*7c478bd9Sstevel@tonic-gate 	case MP_ALLOC_ERR:
72*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
73*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
74*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
75*7c478bd9Sstevel@tonic-gate 		break;
76*7c478bd9Sstevel@tonic-gate 	case MP_NVLIST_ERR:
77*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
78*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
79*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
80*7c478bd9Sstevel@tonic-gate 		break;
81*7c478bd9Sstevel@tonic-gate 	case MP_CANT_FIND_USER_ERR:
82*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
83*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
84*7c478bd9Sstevel@tonic-gate 		break;
85*7c478bd9Sstevel@tonic-gate 	case MP_CANT_FIND_GROUP_ERR:
86*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
87*7c478bd9Sstevel@tonic-gate 			MINOR_PERM_FILE);
88*7c478bd9Sstevel@tonic-gate 		break;
89*7c478bd9Sstevel@tonic-gate 	}
90*7c478bd9Sstevel@tonic-gate }
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate /*
93*7c478bd9Sstevel@tonic-gate  *  open file
94*7c478bd9Sstevel@tonic-gate  * for each entry in list
95*7c478bd9Sstevel@tonic-gate  *	where list entries are separated by <list_separator>
96*7c478bd9Sstevel@tonic-gate  * 	append entry : driver_name <entry_separator> entry
97*7c478bd9Sstevel@tonic-gate  * close file
98*7c478bd9Sstevel@tonic-gate  * return error/noerr
99*7c478bd9Sstevel@tonic-gate  */
100*7c478bd9Sstevel@tonic-gate int
101*7c478bd9Sstevel@tonic-gate append_to_file(
102*7c478bd9Sstevel@tonic-gate 	char *driver_name,
103*7c478bd9Sstevel@tonic-gate 	char *entry_list,
104*7c478bd9Sstevel@tonic-gate 	char *filename,
105*7c478bd9Sstevel@tonic-gate 	char list_separator,
106*7c478bd9Sstevel@tonic-gate 	char *entry_separator)
107*7c478bd9Sstevel@tonic-gate {
108*7c478bd9Sstevel@tonic-gate 	int	i, len;
109*7c478bd9Sstevel@tonic-gate 	int	fpint;
110*7c478bd9Sstevel@tonic-gate 	char	*current_head, *previous_head;
111*7c478bd9Sstevel@tonic-gate 	char	*line, *one_entry;
112*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(filename, "a")) == NULL) {
115*7c478bd9Sstevel@tonic-gate 		perror(NULL);
116*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
117*7c478bd9Sstevel@tonic-gate 		    filename);
118*7c478bd9Sstevel@tonic-gate 		return (ERROR);
119*7c478bd9Sstevel@tonic-gate 	}
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	len = strlen(entry_list);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	one_entry = calloc(len + 1, 1);
124*7c478bd9Sstevel@tonic-gate 	if (one_entry == NULL) {
125*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename);
126*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
127*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
128*7c478bd9Sstevel@tonic-gate 		return (ERROR);
129*7c478bd9Sstevel@tonic-gate 	}
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	previous_head = entry_list;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	line = calloc(strlen(driver_name) + len + 4, 1);
134*7c478bd9Sstevel@tonic-gate 	if (line == NULL) {
135*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
136*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
137*7c478bd9Sstevel@tonic-gate 		err_exit();
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	/*
141*7c478bd9Sstevel@tonic-gate 	 * get one entry at a time from list and append to <filename> file
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	do {
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= len; i++)
147*7c478bd9Sstevel@tonic-gate 			one_entry[i] = 0;
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= (int)strlen(line); i++)
150*7c478bd9Sstevel@tonic-gate 			line[i] = 0;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 		current_head = get_entry(previous_head, one_entry,
153*7c478bd9Sstevel@tonic-gate 		    list_separator);
154*7c478bd9Sstevel@tonic-gate 		previous_head = current_head;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 		(void) strcpy(line, driver_name);
157*7c478bd9Sstevel@tonic-gate 		(void) strcat(line, entry_separator);
158*7c478bd9Sstevel@tonic-gate 		(void) strcat(line, one_entry);
159*7c478bd9Sstevel@tonic-gate 		(void) strcat(line, "\n");
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 		if ((fputs(line, fp)) == EOF) {
162*7c478bd9Sstevel@tonic-gate 			perror(NULL);
163*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
164*7c478bd9Sstevel@tonic-gate 			    filename);
165*7c478bd9Sstevel@tonic-gate 		}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	} while (*current_head != '\0');
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	(void) fflush(fp);
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	fpint = fileno(fp);
173*7c478bd9Sstevel@tonic-gate 	(void) fsync(fpint);
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	free(one_entry);
178*7c478bd9Sstevel@tonic-gate 	free(line);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	return (NOERR);
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate /*
185*7c478bd9Sstevel@tonic-gate  *  open file
186*7c478bd9Sstevel@tonic-gate  * read thru file, deleting all entries if first
187*7c478bd9Sstevel@tonic-gate  *    entry = driver_name
188*7c478bd9Sstevel@tonic-gate  * close
189*7c478bd9Sstevel@tonic-gate  * if error, leave original file intact with message
190*7c478bd9Sstevel@tonic-gate  * assumption : drvconfig has been modified to work with clone
191*7c478bd9Sstevel@tonic-gate  *  entries in /etc/minor_perm as driver:mummble NOT
192*7c478bd9Sstevel@tonic-gate  *  clone:driver mummble
193*7c478bd9Sstevel@tonic-gate  * this implementation will NOT find clone entries
194*7c478bd9Sstevel@tonic-gate  * clone:driver mummble
195*7c478bd9Sstevel@tonic-gate  * match:
196*7c478bd9Sstevel@tonic-gate  *	delete just the matching entry
197*7c478bd9Sstevel@tonic-gate  *
198*7c478bd9Sstevel@tonic-gate  */
199*7c478bd9Sstevel@tonic-gate int
200*7c478bd9Sstevel@tonic-gate delete_entry(
201*7c478bd9Sstevel@tonic-gate 	char *oldfile,
202*7c478bd9Sstevel@tonic-gate 	char *driver_name,
203*7c478bd9Sstevel@tonic-gate 	char *marker,
204*7c478bd9Sstevel@tonic-gate 	char *match)
205*7c478bd9Sstevel@tonic-gate {
206*7c478bd9Sstevel@tonic-gate 	int		rv, i;
207*7c478bd9Sstevel@tonic-gate 	int		status = NOERR;
208*7c478bd9Sstevel@tonic-gate 	int		drvr_found = 0;
209*7c478bd9Sstevel@tonic-gate 	boolean_t 	nomatch = B_TRUE;
210*7c478bd9Sstevel@tonic-gate 	char		*newfile, *tptr;
211*7c478bd9Sstevel@tonic-gate 	char		line[MAX_DBFILE_ENTRY], drv[FILENAME_MAX + 1];
212*7c478bd9Sstevel@tonic-gate 	FILE		*fp, *newfp;
213*7c478bd9Sstevel@tonic-gate 	struct group	*sysgrp;
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	/*
216*7c478bd9Sstevel@tonic-gate 	 * check if match is specified and if it equals " "
217*7c478bd9Sstevel@tonic-gate 	 * this is a special case handling as we do a strstr(3STRING)
218*7c478bd9Sstevel@tonic-gate 	 * to match an entry. By default all entries are space separated
219*7c478bd9Sstevel@tonic-gate 	 * and without this check all entries of the file could get deleted.
220*7c478bd9Sstevel@tonic-gate 	 */
221*7c478bd9Sstevel@tonic-gate 	if (match && (*match == ' ' && strlen(match) == 1)) {
222*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_INT_UPDATE), oldfile);
223*7c478bd9Sstevel@tonic-gate 		return (ERROR);
224*7c478bd9Sstevel@tonic-gate 	}
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(oldfile, "r")) == NULL) {
227*7c478bd9Sstevel@tonic-gate 		perror(NULL);
228*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile);
229*7c478bd9Sstevel@tonic-gate 		return (ERROR);
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	/*
233*7c478bd9Sstevel@tonic-gate 	 * Build filename for temporary file
234*7c478bd9Sstevel@tonic-gate 	 */
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	if ((tptr = calloc(strlen(oldfile) + strlen(XEND) + 1, 1)) == NULL) {
237*7c478bd9Sstevel@tonic-gate 		perror(NULL);
238*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	(void) strcpy(tptr, oldfile);
242*7c478bd9Sstevel@tonic-gate 	(void) strcat(tptr, XEND);
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	/*
245*7c478bd9Sstevel@tonic-gate 	 * Set gid so we preserve group attribute.  Ideally we wouldn't
246*7c478bd9Sstevel@tonic-gate 	 * assume a gid of "sys" but we can't undo the damage on already
247*7c478bd9Sstevel@tonic-gate 	 * installed systems unless we force the issue.
248*7c478bd9Sstevel@tonic-gate 	 */
249*7c478bd9Sstevel@tonic-gate 	if ((sysgrp = getgrnam("sys")) != NULL) {
250*7c478bd9Sstevel@tonic-gate 		(void) setgid(sysgrp->gr_gid);
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	newfile = mktemp(tptr);
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	if ((newfp = fopen(newfile, "w")) == NULL) {
256*7c478bd9Sstevel@tonic-gate 		perror(NULL);
257*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
258*7c478bd9Sstevel@tonic-gate 		    newfile);
259*7c478bd9Sstevel@tonic-gate 		return (ERROR);
260*7c478bd9Sstevel@tonic-gate 	}
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) {
263*7c478bd9Sstevel@tonic-gate 		if (*line == '#' || *line == '\n') {
264*7c478bd9Sstevel@tonic-gate 			if ((fputs(line, newfp)) == EOF) {
265*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
266*7c478bd9Sstevel@tonic-gate 				    oldfile);
267*7c478bd9Sstevel@tonic-gate 				status = ERROR;
268*7c478bd9Sstevel@tonic-gate 			}
269*7c478bd9Sstevel@tonic-gate 			continue;
270*7c478bd9Sstevel@tonic-gate 		}
271*7c478bd9Sstevel@tonic-gate 		if (sscanf(line, "%s", drv) != 1) {
272*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
273*7c478bd9Sstevel@tonic-gate 			    oldfile, line);
274*7c478bd9Sstevel@tonic-gate 			status = ERROR;
275*7c478bd9Sstevel@tonic-gate 		}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 		for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) {
279*7c478bd9Sstevel@tonic-gate 			drv[i] =  '\0';
280*7c478bd9Sstevel@tonic-gate 		}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 		if (strcmp(driver_name, drv) != 0) {
283*7c478bd9Sstevel@tonic-gate 			if ((fputs(line, newfp)) == EOF) {
284*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
285*7c478bd9Sstevel@tonic-gate 				    oldfile);
286*7c478bd9Sstevel@tonic-gate 				status = ERROR;
287*7c478bd9Sstevel@tonic-gate 			}
288*7c478bd9Sstevel@tonic-gate 		} else {
289*7c478bd9Sstevel@tonic-gate 			drvr_found++;
290*7c478bd9Sstevel@tonic-gate 			if (match) {	/* Just delete one entry */
291*7c478bd9Sstevel@tonic-gate 				/* for now delete just minor_perm and aliases */
292*7c478bd9Sstevel@tonic-gate 				if ((strcmp(oldfile, minor_perm) == 0) ||
293*7c478bd9Sstevel@tonic-gate 				    (strcmp(oldfile, extra_privs) == 0) ||
294*7c478bd9Sstevel@tonic-gate 				    (strcmp(oldfile, driver_aliases) == 0)) {
295*7c478bd9Sstevel@tonic-gate 					if (strstr(line, match)) {
296*7c478bd9Sstevel@tonic-gate 						nomatch = B_FALSE;
297*7c478bd9Sstevel@tonic-gate 					} else {
298*7c478bd9Sstevel@tonic-gate 						if ((fputs(line, newfp)) ==
299*7c478bd9Sstevel@tonic-gate 						    EOF) {
300*7c478bd9Sstevel@tonic-gate 							(void) fprintf(stderr,
301*7c478bd9Sstevel@tonic-gate 							    gettext(ERR_UPDATE),
302*7c478bd9Sstevel@tonic-gate 							    oldfile);
303*7c478bd9Sstevel@tonic-gate 							status = ERROR;
304*7c478bd9Sstevel@tonic-gate 						}
305*7c478bd9Sstevel@tonic-gate 						if (nomatch != B_FALSE)
306*7c478bd9Sstevel@tonic-gate 							nomatch = B_TRUE;
307*7c478bd9Sstevel@tonic-gate 					}
308*7c478bd9Sstevel@tonic-gate 				}
309*7c478bd9Sstevel@tonic-gate 			}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 		} /* end of else */
312*7c478bd9Sstevel@tonic-gate 	} /* end of while */
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	/* Make sure that the file is on disk */
317*7c478bd9Sstevel@tonic-gate 	if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0)
318*7c478bd9Sstevel@tonic-gate 		status = ERROR;
319*7c478bd9Sstevel@tonic-gate 	else
320*7c478bd9Sstevel@tonic-gate 		rv = NOERR;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	(void) fclose(newfp);
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	/* no matching driver found */
325*7c478bd9Sstevel@tonic-gate 	rv = NOERR;
326*7c478bd9Sstevel@tonic-gate 	if (!drvr_found ||
327*7c478bd9Sstevel@tonic-gate 	    (nomatch == B_TRUE)) {
328*7c478bd9Sstevel@tonic-gate 		rv = NONE_FOUND;
329*7c478bd9Sstevel@tonic-gate 	}
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	/*
332*7c478bd9Sstevel@tonic-gate 	 * if error, leave original file, delete new file
333*7c478bd9Sstevel@tonic-gate 	 * if noerr, replace original file with new file
334*7c478bd9Sstevel@tonic-gate 	 */
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	if (status == NOERR) {
337*7c478bd9Sstevel@tonic-gate 		if (rename(oldfile, tmphold) == -1) {
338*7c478bd9Sstevel@tonic-gate 			perror(NULL);
339*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
340*7c478bd9Sstevel@tonic-gate 			(void) unlink(newfile);
341*7c478bd9Sstevel@tonic-gate 			return (ERROR);
342*7c478bd9Sstevel@tonic-gate 		} else if (rename(newfile, oldfile) == -1) {
343*7c478bd9Sstevel@tonic-gate 			perror(NULL);
344*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
345*7c478bd9Sstevel@tonic-gate 			(void) unlink(oldfile);
346*7c478bd9Sstevel@tonic-gate 			(void) unlink(newfile);
347*7c478bd9Sstevel@tonic-gate 			if (link(tmphold, oldfile) == -1) {
348*7c478bd9Sstevel@tonic-gate 				perror(NULL);
349*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINK),
350*7c478bd9Sstevel@tonic-gate 				    oldfile, tmphold);
351*7c478bd9Sstevel@tonic-gate 			}
352*7c478bd9Sstevel@tonic-gate 			return (ERROR);
353*7c478bd9Sstevel@tonic-gate 		}
354*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmphold);
355*7c478bd9Sstevel@tonic-gate 	} else {
356*7c478bd9Sstevel@tonic-gate 		/*
357*7c478bd9Sstevel@tonic-gate 		 * since there's an error, leave file alone; remove
358*7c478bd9Sstevel@tonic-gate 		 * new file
359*7c478bd9Sstevel@tonic-gate 		 */
360*7c478bd9Sstevel@tonic-gate 		if (unlink(newfile) == -1) {
361*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_RM), newfile);
362*7c478bd9Sstevel@tonic-gate 		}
363*7c478bd9Sstevel@tonic-gate 		return (ERROR);
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	return (rv);
367*7c478bd9Sstevel@tonic-gate }
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate /*
371*7c478bd9Sstevel@tonic-gate  * wrapper for call to get_name_to_major_entry(): given driver name,
372*7c478bd9Sstevel@tonic-gate  * retrieve major number.
373*7c478bd9Sstevel@tonic-gate  */
374*7c478bd9Sstevel@tonic-gate int
375*7c478bd9Sstevel@tonic-gate get_major_no(char *driver_name, char *file_name)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	int major = UNIQUE;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	if (get_name_to_major_entry(&major, driver_name, file_name) == ERROR)
380*7c478bd9Sstevel@tonic-gate 		return (ERROR);
381*7c478bd9Sstevel@tonic-gate 	else
382*7c478bd9Sstevel@tonic-gate 		return (major);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*
386*7c478bd9Sstevel@tonic-gate  * wrapper for call to get_name_to_major_entry(): given major number,
387*7c478bd9Sstevel@tonic-gate  * retrieve driver name.
388*7c478bd9Sstevel@tonic-gate  */
389*7c478bd9Sstevel@tonic-gate int
390*7c478bd9Sstevel@tonic-gate get_driver_name(int major, char *file_name, char *buf)
391*7c478bd9Sstevel@tonic-gate {
392*7c478bd9Sstevel@tonic-gate 	if (major < 0)
393*7c478bd9Sstevel@tonic-gate 		return (ERROR);
394*7c478bd9Sstevel@tonic-gate 	return (get_name_to_major_entry(&major, buf, file_name));
395*7c478bd9Sstevel@tonic-gate }
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate /*
399*7c478bd9Sstevel@tonic-gate  * return pointer to cached name_to_major file - reads file into
400*7c478bd9Sstevel@tonic-gate  * cache if this has not already been done.  Since there may be
401*7c478bd9Sstevel@tonic-gate  * requests for multiple name_to_major files (rem_name_to_major,
402*7c478bd9Sstevel@tonic-gate  * name_to_major), this routine keeps a list of cached files.
403*7c478bd9Sstevel@tonic-gate  */
404*7c478bd9Sstevel@tonic-gate static int
405*7c478bd9Sstevel@tonic-gate get_cached_n_to_m_file(char *filename, char ***cache)
406*7c478bd9Sstevel@tonic-gate {
407*7c478bd9Sstevel@tonic-gate 	struct n_to_m_cache {
408*7c478bd9Sstevel@tonic-gate 		char *file;
409*7c478bd9Sstevel@tonic-gate 		char **cached_file;
410*7c478bd9Sstevel@tonic-gate 		int size;
411*7c478bd9Sstevel@tonic-gate 		struct n_to_m_cache *next;
412*7c478bd9Sstevel@tonic-gate 	};
413*7c478bd9Sstevel@tonic-gate 	static struct n_to_m_cache *head = NULL;
414*7c478bd9Sstevel@tonic-gate 	struct n_to_m_cache *ptr;
415*7c478bd9Sstevel@tonic-gate 	FILE *fp;
416*7c478bd9Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
417*7c478bd9Sstevel@tonic-gate 	char entry[FILENAME_MAX + 1];
418*7c478bd9Sstevel@tonic-gate 	char line[MAX_N2M_ALIAS_LINE];
419*7c478bd9Sstevel@tonic-gate 	int maj;
420*7c478bd9Sstevel@tonic-gate 	int size = 0;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	/*
424*7c478bd9Sstevel@tonic-gate 	 * see if the file is already cached - either
425*7c478bd9Sstevel@tonic-gate 	 * rem_name_to_major or name_to_major
426*7c478bd9Sstevel@tonic-gate 	 */
427*7c478bd9Sstevel@tonic-gate 	ptr = head;
428*7c478bd9Sstevel@tonic-gate 	while (ptr != NULL) {
429*7c478bd9Sstevel@tonic-gate 		if (strcmp(ptr->file, filename) == 0)
430*7c478bd9Sstevel@tonic-gate 			break;
431*7c478bd9Sstevel@tonic-gate 		ptr = ptr->next;
432*7c478bd9Sstevel@tonic-gate 	}
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	if (ptr == NULL) {	/* we need to cache the contents */
435*7c478bd9Sstevel@tonic-gate 		if ((fp = fopen(filename, "r")) == NULL) {
436*7c478bd9Sstevel@tonic-gate 			perror(NULL);
437*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_OPEN),
438*7c478bd9Sstevel@tonic-gate 			    filename);
439*7c478bd9Sstevel@tonic-gate 			return (ERROR);
440*7c478bd9Sstevel@tonic-gate 		}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 		while (fgets(line, sizeof (line), fp) != NULL) {
443*7c478bd9Sstevel@tonic-gate 			if (sscanf(line, "%s%s", drv, entry) != 2) {
444*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
445*7c478bd9Sstevel@tonic-gate 				    filename, line);
446*7c478bd9Sstevel@tonic-gate 				continue;
447*7c478bd9Sstevel@tonic-gate 			}
448*7c478bd9Sstevel@tonic-gate 			maj = atoi(entry);
449*7c478bd9Sstevel@tonic-gate 			if (maj > size)
450*7c478bd9Sstevel@tonic-gate 				size = maj;
451*7c478bd9Sstevel@tonic-gate 		}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		/* allocate struct to cache the file */
454*7c478bd9Sstevel@tonic-gate 		ptr = (struct n_to_m_cache *)calloc(1,
455*7c478bd9Sstevel@tonic-gate 		    sizeof (struct n_to_m_cache));
456*7c478bd9Sstevel@tonic-gate 		if (ptr == NULL) {
457*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
458*7c478bd9Sstevel@tonic-gate 			return (ERROR);
459*7c478bd9Sstevel@tonic-gate 		}
460*7c478bd9Sstevel@tonic-gate 		ptr->size = size + 1;
461*7c478bd9Sstevel@tonic-gate 		/* allocate space to cache contents of file */
462*7c478bd9Sstevel@tonic-gate 		ptr->cached_file = (char **)calloc(ptr->size, sizeof (char *));
463*7c478bd9Sstevel@tonic-gate 		if (ptr->cached_file == NULL) {
464*7c478bd9Sstevel@tonic-gate 			free(ptr);
465*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
466*7c478bd9Sstevel@tonic-gate 			return (ERROR);
467*7c478bd9Sstevel@tonic-gate 		}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 		rewind(fp);
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 		/*
472*7c478bd9Sstevel@tonic-gate 		 * now fill the cache
473*7c478bd9Sstevel@tonic-gate 		 * the cache is an array of char pointers indexed by major
474*7c478bd9Sstevel@tonic-gate 		 * number
475*7c478bd9Sstevel@tonic-gate 		 */
476*7c478bd9Sstevel@tonic-gate 		while (fgets(line, sizeof (line), fp) != NULL) {
477*7c478bd9Sstevel@tonic-gate 			if (sscanf(line, "%s%s", drv, entry) != 2) {
478*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
479*7c478bd9Sstevel@tonic-gate 				    filename, line);
480*7c478bd9Sstevel@tonic-gate 				continue;
481*7c478bd9Sstevel@tonic-gate 			}
482*7c478bd9Sstevel@tonic-gate 			maj = atoi(entry);
483*7c478bd9Sstevel@tonic-gate 			if ((ptr->cached_file[maj] = strdup(drv)) == NULL) {
484*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
485*7c478bd9Sstevel@tonic-gate 				free(ptr->cached_file);
486*7c478bd9Sstevel@tonic-gate 				free(ptr);
487*7c478bd9Sstevel@tonic-gate 				return (ERROR);
488*7c478bd9Sstevel@tonic-gate 			}
489*7c478bd9Sstevel@tonic-gate 			(void) strcpy(ptr->cached_file[maj], drv);
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
492*7c478bd9Sstevel@tonic-gate 		/* link the cache struct into the list of cached files */
493*7c478bd9Sstevel@tonic-gate 		ptr->file = strdup(filename);
494*7c478bd9Sstevel@tonic-gate 		if (ptr->file == NULL) {
495*7c478bd9Sstevel@tonic-gate 			for (maj = 0; maj <= ptr->size; maj++)
496*7c478bd9Sstevel@tonic-gate 				free(ptr->cached_file[maj]);
497*7c478bd9Sstevel@tonic-gate 			free(ptr->cached_file);
498*7c478bd9Sstevel@tonic-gate 			free(ptr);
499*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
500*7c478bd9Sstevel@tonic-gate 			return (ERROR);
501*7c478bd9Sstevel@tonic-gate 		}
502*7c478bd9Sstevel@tonic-gate 		ptr->next = head;
503*7c478bd9Sstevel@tonic-gate 		head = ptr;
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 	/* return value pointer to contents of file */
506*7c478bd9Sstevel@tonic-gate 	*cache = ptr->cached_file;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	/* return size */
509*7c478bd9Sstevel@tonic-gate 	return (ptr->size);
510*7c478bd9Sstevel@tonic-gate }
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate /*
514*7c478bd9Sstevel@tonic-gate  * Using get_cached_n_to_m_file(), retrieve maximum major number
515*7c478bd9Sstevel@tonic-gate  * found in the specificed file (name_to_major/rem_name_to_major).
516*7c478bd9Sstevel@tonic-gate  *
517*7c478bd9Sstevel@tonic-gate  * The return value is actually the size of the internal cache including 0.
518*7c478bd9Sstevel@tonic-gate  */
519*7c478bd9Sstevel@tonic-gate int
520*7c478bd9Sstevel@tonic-gate get_max_major(char *file_name)
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	char **n_to_m_cache = NULL;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	return (get_cached_n_to_m_file(file_name, &n_to_m_cache));
525*7c478bd9Sstevel@tonic-gate }
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate /*
529*7c478bd9Sstevel@tonic-gate  * searching name_to_major: if major_no == UNIQUE then the caller wants to
530*7c478bd9Sstevel@tonic-gate  * use the driver name as the key.  Otherwise, the caller wants to use
531*7c478bd9Sstevel@tonic-gate  * the major number as a key.
532*7c478bd9Sstevel@tonic-gate  *
533*7c478bd9Sstevel@tonic-gate  * This routine caches the contents of the name_to_major file on
534*7c478bd9Sstevel@tonic-gate  * first call.  And it could be generalized to deal with other
535*7c478bd9Sstevel@tonic-gate  * config files if necessary.
536*7c478bd9Sstevel@tonic-gate  */
537*7c478bd9Sstevel@tonic-gate static int
538*7c478bd9Sstevel@tonic-gate get_name_to_major_entry(int *major_no, char *driver_name, char *file_name)
539*7c478bd9Sstevel@tonic-gate {
540*7c478bd9Sstevel@tonic-gate 	int maj;
541*7c478bd9Sstevel@tonic-gate 	char **n_to_m_cache = NULL;
542*7c478bd9Sstevel@tonic-gate 	int size = 0;
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	int ret = NOT_UNIQUE;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	/*
547*7c478bd9Sstevel@tonic-gate 	 * read the file in - we cache it in case caller wants to
548*7c478bd9Sstevel@tonic-gate 	 * do multiple lookups
549*7c478bd9Sstevel@tonic-gate 	 */
550*7c478bd9Sstevel@tonic-gate 	size = get_cached_n_to_m_file(file_name, &n_to_m_cache);
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	if (size == ERROR)
553*7c478bd9Sstevel@tonic-gate 		return (ERROR);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	/* search with driver name as key */
556*7c478bd9Sstevel@tonic-gate 	if (*major_no == UNIQUE) {
557*7c478bd9Sstevel@tonic-gate 		for (maj = 0; maj < size; maj++) {
558*7c478bd9Sstevel@tonic-gate 			if ((n_to_m_cache[maj] != NULL) &&
559*7c478bd9Sstevel@tonic-gate 			    (strcmp(driver_name, n_to_m_cache[maj]) == 0)) {
560*7c478bd9Sstevel@tonic-gate 				*major_no = maj;
561*7c478bd9Sstevel@tonic-gate 				break;
562*7c478bd9Sstevel@tonic-gate 			}
563*7c478bd9Sstevel@tonic-gate 		}
564*7c478bd9Sstevel@tonic-gate 		if (maj >= size)
565*7c478bd9Sstevel@tonic-gate 			ret = UNIQUE;
566*7c478bd9Sstevel@tonic-gate 	/* search with major number as key */
567*7c478bd9Sstevel@tonic-gate 	} else {
568*7c478bd9Sstevel@tonic-gate 		/*
569*7c478bd9Sstevel@tonic-gate 		 * Bugid 1254588, drvconfig dump core after loading driver
570*7c478bd9Sstevel@tonic-gate 		 * with major number bigger than entries defined in
571*7c478bd9Sstevel@tonic-gate 		 * /etc/name_to_major.
572*7c478bd9Sstevel@tonic-gate 		 */
573*7c478bd9Sstevel@tonic-gate 		if (*major_no >= size)
574*7c478bd9Sstevel@tonic-gate 			return (UNIQUE);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 		if (n_to_m_cache[*major_no] != NULL) {
577*7c478bd9Sstevel@tonic-gate 			(void) strcpy(driver_name, n_to_m_cache[*major_no]);
578*7c478bd9Sstevel@tonic-gate 		} else
579*7c478bd9Sstevel@tonic-gate 			ret = UNIQUE;
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 	return (ret);
582*7c478bd9Sstevel@tonic-gate }
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate /*
586*7c478bd9Sstevel@tonic-gate  * given pointer to member n in space separated list, return pointer
587*7c478bd9Sstevel@tonic-gate  * to member n+1, return member n
588*7c478bd9Sstevel@tonic-gate  */
589*7c478bd9Sstevel@tonic-gate char *
590*7c478bd9Sstevel@tonic-gate get_entry(
591*7c478bd9Sstevel@tonic-gate 	char *prev_member,
592*7c478bd9Sstevel@tonic-gate 	char *current_entry,
593*7c478bd9Sstevel@tonic-gate 	char separator)
594*7c478bd9Sstevel@tonic-gate {
595*7c478bd9Sstevel@tonic-gate 	char *ptr;
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	ptr = prev_member;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	/* skip white space */
600*7c478bd9Sstevel@tonic-gate 	while (*ptr == '\t' || *ptr == ' ')
601*7c478bd9Sstevel@tonic-gate 		ptr++;
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	/* read thru the current entry */
604*7c478bd9Sstevel@tonic-gate 	while (*ptr != separator && *ptr != '\0') {
605*7c478bd9Sstevel@tonic-gate 		*current_entry++ = *ptr++;
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate 	*current_entry = '\0';
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	if ((separator == ',') && (*ptr == separator))
610*7c478bd9Sstevel@tonic-gate 		ptr++;	/* skip over comma */
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	/* skip white space */
613*7c478bd9Sstevel@tonic-gate 	while (*ptr == '\t' || *ptr == ' ') {
614*7c478bd9Sstevel@tonic-gate 		ptr++;
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	return (ptr);
618*7c478bd9Sstevel@tonic-gate }
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
621*7c478bd9Sstevel@tonic-gate static void
622*7c478bd9Sstevel@tonic-gate signal_rtn(int sig)
623*7c478bd9Sstevel@tonic-gate {
624*7c478bd9Sstevel@tonic-gate 	exit_unlock();
625*7c478bd9Sstevel@tonic-gate }
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate void
628*7c478bd9Sstevel@tonic-gate enter_lock(void)
629*7c478bd9Sstevel@tonic-gate {
630*7c478bd9Sstevel@tonic-gate 	int fd;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	/*
633*7c478bd9Sstevel@tonic-gate 	 * Setup handler to clean lock file in case user terminates
634*7c478bd9Sstevel@tonic-gate 	 * the command.
635*7c478bd9Sstevel@tonic-gate 	 */
636*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, signal_rtn);
637*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGHUP, signal_rtn);
638*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, signal_rtn);
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	/*
641*7c478bd9Sstevel@tonic-gate 	 * attempt to create the lock file
642*7c478bd9Sstevel@tonic-gate 	 */
643*7c478bd9Sstevel@tonic-gate 	if ((fd = open(add_rem_lock, O_CREAT | O_EXCL | O_WRONLY,
644*7c478bd9Sstevel@tonic-gate 	    S_IRUSR | S_IWUSR)) == -1) {
645*7c478bd9Sstevel@tonic-gate 		if (errno == EEXIST) {
646*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_PROG_IN_USE));
647*7c478bd9Sstevel@tonic-gate 		} else {
648*7c478bd9Sstevel@tonic-gate 			perror(gettext(ERR_LOCKFILE));
649*7c478bd9Sstevel@tonic-gate 		}
650*7c478bd9Sstevel@tonic-gate 		exit(1);
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
653*7c478bd9Sstevel@tonic-gate }
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate void
656*7c478bd9Sstevel@tonic-gate err_exit(void)
657*7c478bd9Sstevel@tonic-gate {
658*7c478bd9Sstevel@tonic-gate 	/* release memory allocated for moddir */
659*7c478bd9Sstevel@tonic-gate 	cleanup_moddir();
660*7c478bd9Sstevel@tonic-gate 	/* remove add_drv/rem_drv lock */
661*7c478bd9Sstevel@tonic-gate 	exit_unlock();
662*7c478bd9Sstevel@tonic-gate 	exit(1);
663*7c478bd9Sstevel@tonic-gate }
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate void
666*7c478bd9Sstevel@tonic-gate cleanup_moddir(void)
667*7c478bd9Sstevel@tonic-gate {
668*7c478bd9Sstevel@tonic-gate 	struct drvmod_dir *walk_ptr;
669*7c478bd9Sstevel@tonic-gate 	struct drvmod_dir *free_ptr = moddir;
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	while (free_ptr != NULL) {
672*7c478bd9Sstevel@tonic-gate 		walk_ptr = free_ptr->next;
673*7c478bd9Sstevel@tonic-gate 		free(free_ptr);
674*7c478bd9Sstevel@tonic-gate 		free_ptr = walk_ptr;
675*7c478bd9Sstevel@tonic-gate 	}
676*7c478bd9Sstevel@tonic-gate }
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate void
679*7c478bd9Sstevel@tonic-gate exit_unlock(void)
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	struct stat buf;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	if (stat(add_rem_lock, &buf) == NOERR) {
684*7c478bd9Sstevel@tonic-gate 		if (unlink(add_rem_lock) == -1) {
685*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_REM_LOCK),
686*7c478bd9Sstevel@tonic-gate 			    add_rem_lock);
687*7c478bd9Sstevel@tonic-gate 		}
688*7c478bd9Sstevel@tonic-gate 	}
689*7c478bd9Sstevel@tonic-gate }
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate /*
692*7c478bd9Sstevel@tonic-gate  * error adding driver; need to back out any changes to files.
693*7c478bd9Sstevel@tonic-gate  * check flag to see which files need entries removed
694*7c478bd9Sstevel@tonic-gate  * entry removal based on driver name
695*7c478bd9Sstevel@tonic-gate  */
696*7c478bd9Sstevel@tonic-gate void
697*7c478bd9Sstevel@tonic-gate remove_entry(
698*7c478bd9Sstevel@tonic-gate 	int c_flag,
699*7c478bd9Sstevel@tonic-gate 	char *driver_name)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 	if (c_flag & CLEAN_NAM_MAJ) {
703*7c478bd9Sstevel@tonic-gate 		if (delete_entry(name_to_major, driver_name, " ",
704*7c478bd9Sstevel@tonic-gate 		    NULL) == ERROR) {
705*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_CLEAN),
706*7c478bd9Sstevel@tonic-gate 			    name_to_major, driver_name);
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	if (c_flag & CLEAN_DRV_ALIAS) {
711*7c478bd9Sstevel@tonic-gate 		if (delete_entry(driver_aliases, driver_name, " ",
712*7c478bd9Sstevel@tonic-gate 		    NULL) == ERROR) {
713*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
714*7c478bd9Sstevel@tonic-gate 			    driver_name, driver_aliases);
715*7c478bd9Sstevel@tonic-gate 		}
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	if (c_flag & CLEAN_DRV_CLASSES) {
719*7c478bd9Sstevel@tonic-gate 		if (delete_entry(driver_classes, driver_name, "\t", NULL) ==
720*7c478bd9Sstevel@tonic-gate 		    ERROR) {
721*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
722*7c478bd9Sstevel@tonic-gate 			    driver_name, driver_classes);
723*7c478bd9Sstevel@tonic-gate 		}
724*7c478bd9Sstevel@tonic-gate 	}
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if (c_flag & CLEAN_MINOR_PERM) {
727*7c478bd9Sstevel@tonic-gate 		if (delete_entry(minor_perm, driver_name, ":", NULL) == ERROR) {
728*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
729*7c478bd9Sstevel@tonic-gate 			    driver_name, minor_perm);
730*7c478bd9Sstevel@tonic-gate 		}
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 	/*
733*7c478bd9Sstevel@tonic-gate 	 * There's no point in removing entries from files that don't
734*7c478bd9Sstevel@tonic-gate 	 * exist.  Prevent error messages by checking for file existence
735*7c478bd9Sstevel@tonic-gate 	 * first.
736*7c478bd9Sstevel@tonic-gate 	 */
737*7c478bd9Sstevel@tonic-gate 	if ((c_flag & CLEAN_DEV_POLICY) != 0 &&
738*7c478bd9Sstevel@tonic-gate 	    access(device_policy, F_OK) == 0) {
739*7c478bd9Sstevel@tonic-gate 		if (delete_plcy_entry(device_policy, driver_name) == ERROR) {
740*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
741*7c478bd9Sstevel@tonic-gate 				driver_name, device_policy);
742*7c478bd9Sstevel@tonic-gate 		}
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 	if ((c_flag & CLEAN_DRV_PRIV) != 0 &&
745*7c478bd9Sstevel@tonic-gate 	    access(extra_privs, F_OK) == 0) {
746*7c478bd9Sstevel@tonic-gate 		if (delete_entry(extra_privs, driver_name, ":", NULL) ==
747*7c478bd9Sstevel@tonic-gate 		    ERROR) {
748*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
749*7c478bd9Sstevel@tonic-gate 				driver_name, extra_privs);
750*7c478bd9Sstevel@tonic-gate 		}
751*7c478bd9Sstevel@tonic-gate 	}
752*7c478bd9Sstevel@tonic-gate }
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate int
755*7c478bd9Sstevel@tonic-gate check_perms_aliases(
756*7c478bd9Sstevel@tonic-gate 	int m_flag,
757*7c478bd9Sstevel@tonic-gate 	int i_flag)
758*7c478bd9Sstevel@tonic-gate {
759*7c478bd9Sstevel@tonic-gate 	/*
760*7c478bd9Sstevel@tonic-gate 	 * If neither i_flag nor m_flag are specified no need to check the
761*7c478bd9Sstevel@tonic-gate 	 * files for access permissions
762*7c478bd9Sstevel@tonic-gate 	 */
763*7c478bd9Sstevel@tonic-gate 	if (!m_flag && !i_flag)
764*7c478bd9Sstevel@tonic-gate 		return (NOERR);
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 	/* check minor_perm file : exits and is writable */
767*7c478bd9Sstevel@tonic-gate 	if (m_flag) {
768*7c478bd9Sstevel@tonic-gate 		if (access(minor_perm, R_OK | W_OK)) {
769*7c478bd9Sstevel@tonic-gate 			perror(NULL);
770*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
771*7c478bd9Sstevel@tonic-gate 			    minor_perm);
772*7c478bd9Sstevel@tonic-gate 			return (ERROR);
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	/* check driver_aliases file : exits and is writable */
777*7c478bd9Sstevel@tonic-gate 	if (i_flag) {
778*7c478bd9Sstevel@tonic-gate 		if (access(driver_aliases, R_OK | W_OK)) {
779*7c478bd9Sstevel@tonic-gate 			perror(NULL);
780*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
781*7c478bd9Sstevel@tonic-gate 			    driver_aliases);
782*7c478bd9Sstevel@tonic-gate 			return (ERROR);
783*7c478bd9Sstevel@tonic-gate 		}
784*7c478bd9Sstevel@tonic-gate 	}
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	return (NOERR);
787*7c478bd9Sstevel@tonic-gate }
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate int
791*7c478bd9Sstevel@tonic-gate check_name_to_major(int mode)
792*7c478bd9Sstevel@tonic-gate {
793*7c478bd9Sstevel@tonic-gate 	/* check name_to_major file : exists and is writable */
794*7c478bd9Sstevel@tonic-gate 	if (access(name_to_major, mode)) {
795*7c478bd9Sstevel@tonic-gate 		perror(NULL);
796*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
797*7c478bd9Sstevel@tonic-gate 		    name_to_major);
798*7c478bd9Sstevel@tonic-gate 		return (ERROR);
799*7c478bd9Sstevel@tonic-gate 	}
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	return (NOERR);
802*7c478bd9Sstevel@tonic-gate }
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate /*
806*7c478bd9Sstevel@tonic-gate  * All this stuff is to support a server installing
807*7c478bd9Sstevel@tonic-gate  * drivers on diskless clients.  When on the server
808*7c478bd9Sstevel@tonic-gate  * need to prepend the basedir
809*7c478bd9Sstevel@tonic-gate  */
810*7c478bd9Sstevel@tonic-gate int
811*7c478bd9Sstevel@tonic-gate build_filenames(char *basedir)
812*7c478bd9Sstevel@tonic-gate {
813*7c478bd9Sstevel@tonic-gate 	int len;
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	if (basedir == NULL) {
816*7c478bd9Sstevel@tonic-gate 		driver_aliases = DRIVER_ALIAS;
817*7c478bd9Sstevel@tonic-gate 		driver_classes = DRIVER_CLASSES;
818*7c478bd9Sstevel@tonic-gate 		minor_perm = MINOR_PERM;
819*7c478bd9Sstevel@tonic-gate 		name_to_major = NAM_TO_MAJ;
820*7c478bd9Sstevel@tonic-gate 		rem_name_to_major = REM_NAM_TO_MAJ;
821*7c478bd9Sstevel@tonic-gate 		add_rem_lock = ADD_REM_LOCK;
822*7c478bd9Sstevel@tonic-gate 		tmphold = TMPHOLD;
823*7c478bd9Sstevel@tonic-gate 		devfs_root = DEVFS_ROOT;
824*7c478bd9Sstevel@tonic-gate 		device_policy = DEV_POLICY;
825*7c478bd9Sstevel@tonic-gate 		extra_privs = EXTRA_PRIVS;
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	} else {
828*7c478bd9Sstevel@tonic-gate 		len = strlen(basedir);
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 		driver_aliases = malloc(len + sizeof (DRIVER_ALIAS));
831*7c478bd9Sstevel@tonic-gate 		driver_classes = malloc(len + sizeof (DRIVER_CLASSES));
832*7c478bd9Sstevel@tonic-gate 		minor_perm = malloc(len + sizeof (MINOR_PERM));
833*7c478bd9Sstevel@tonic-gate 		name_to_major = malloc(len + sizeof (NAM_TO_MAJ));
834*7c478bd9Sstevel@tonic-gate 		rem_name_to_major = malloc(len + sizeof (REM_NAM_TO_MAJ));
835*7c478bd9Sstevel@tonic-gate 		add_rem_lock = malloc(len + sizeof (ADD_REM_LOCK));
836*7c478bd9Sstevel@tonic-gate 		tmphold = malloc(len + sizeof (TMPHOLD));
837*7c478bd9Sstevel@tonic-gate 		devfs_root = malloc(len + sizeof (DEVFS_ROOT));
838*7c478bd9Sstevel@tonic-gate 		device_policy = malloc(len + sizeof (DEV_POLICY));
839*7c478bd9Sstevel@tonic-gate 		extra_privs = malloc(len + sizeof (EXTRA_PRIVS));
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 		if ((driver_aliases == NULL) ||
843*7c478bd9Sstevel@tonic-gate 		    (driver_classes == NULL) ||
844*7c478bd9Sstevel@tonic-gate 		    (minor_perm == NULL) ||
845*7c478bd9Sstevel@tonic-gate 		    (name_to_major == NULL) ||
846*7c478bd9Sstevel@tonic-gate 		    (rem_name_to_major == NULL) ||
847*7c478bd9Sstevel@tonic-gate 		    (add_rem_lock == NULL) ||
848*7c478bd9Sstevel@tonic-gate 		    (tmphold == NULL) ||
849*7c478bd9Sstevel@tonic-gate 		    (devfs_root == NULL) ||
850*7c478bd9Sstevel@tonic-gate 		    (device_policy == NULL) ||
851*7c478bd9Sstevel@tonic-gate 		    (extra_privs == NULL)) {
852*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
853*7c478bd9Sstevel@tonic-gate 			return (ERROR);
854*7c478bd9Sstevel@tonic-gate 		}
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 		(void) sprintf(driver_aliases, "%s%s", basedir, DRIVER_ALIAS);
857*7c478bd9Sstevel@tonic-gate 		(void) sprintf(driver_classes, "%s%s", basedir, DRIVER_CLASSES);
858*7c478bd9Sstevel@tonic-gate 		(void) sprintf(minor_perm, "%s%s", basedir, MINOR_PERM);
859*7c478bd9Sstevel@tonic-gate 		(void) sprintf(name_to_major, "%s%s", basedir, NAM_TO_MAJ);
860*7c478bd9Sstevel@tonic-gate 		(void) sprintf(rem_name_to_major, "%s%s", basedir,
861*7c478bd9Sstevel@tonic-gate 				REM_NAM_TO_MAJ);
862*7c478bd9Sstevel@tonic-gate 		(void) sprintf(add_rem_lock, "%s%s", basedir, ADD_REM_LOCK);
863*7c478bd9Sstevel@tonic-gate 		(void) sprintf(tmphold, "%s%s", basedir, TMPHOLD);
864*7c478bd9Sstevel@tonic-gate 		(void) sprintf(devfs_root, "%s%s", basedir, DEVFS_ROOT);
865*7c478bd9Sstevel@tonic-gate 		(void) sprintf(device_policy, "%s%s", basedir, DEV_POLICY);
866*7c478bd9Sstevel@tonic-gate 		(void) sprintf(extra_privs, "%s%s", basedir, EXTRA_PRIVS);
867*7c478bd9Sstevel@tonic-gate 	}
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	return (NOERR);
870*7c478bd9Sstevel@tonic-gate }
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate static int
873*7c478bd9Sstevel@tonic-gate exec_command(char *path, char *cmdline[MAX_CMD_LINE])
874*7c478bd9Sstevel@tonic-gate {
875*7c478bd9Sstevel@tonic-gate 	pid_t pid;
876*7c478bd9Sstevel@tonic-gate 	uint_t stat_loc;
877*7c478bd9Sstevel@tonic-gate 	int waitstat;
878*7c478bd9Sstevel@tonic-gate 	int exit_status;
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	/* child */
881*7c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == 0) {
882*7c478bd9Sstevel@tonic-gate 		(void) execv(path, cmdline);
883*7c478bd9Sstevel@tonic-gate 		perror(NULL);
884*7c478bd9Sstevel@tonic-gate 		return (ERROR);
885*7c478bd9Sstevel@tonic-gate 	} else if (pid == -1) {
886*7c478bd9Sstevel@tonic-gate 		/* fork failed */
887*7c478bd9Sstevel@tonic-gate 		perror(NULL);
888*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_FORK_FAIL), cmdline);
889*7c478bd9Sstevel@tonic-gate 		return (ERROR);
890*7c478bd9Sstevel@tonic-gate 	} else {
891*7c478bd9Sstevel@tonic-gate 		/* parent */
892*7c478bd9Sstevel@tonic-gate 		do {
893*7c478bd9Sstevel@tonic-gate 			waitstat = waitpid(pid, (int *)&stat_loc, 0);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 		} while ((!WIFEXITED(stat_loc) &&
896*7c478bd9Sstevel@tonic-gate 			!WIFSIGNALED(stat_loc)) || (waitstat == 0));
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 		exit_status = WEXITSTATUS(stat_loc);
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 		return (exit_status);
901*7c478bd9Sstevel@tonic-gate 	}
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate /*
905*7c478bd9Sstevel@tonic-gate  * check that major_num doesn't exceed maximum on this machine
906*7c478bd9Sstevel@tonic-gate  * do this here to support add_drv on server for diskless clients
907*7c478bd9Sstevel@tonic-gate  */
908*7c478bd9Sstevel@tonic-gate int
909*7c478bd9Sstevel@tonic-gate config_driver(
910*7c478bd9Sstevel@tonic-gate 	char *driver_name,
911*7c478bd9Sstevel@tonic-gate 	major_t major_num,
912*7c478bd9Sstevel@tonic-gate 	char *aliases,
913*7c478bd9Sstevel@tonic-gate 	char *classes,
914*7c478bd9Sstevel@tonic-gate 	int cleanup_flag,
915*7c478bd9Sstevel@tonic-gate 	int verbose_flag)
916*7c478bd9Sstevel@tonic-gate {
917*7c478bd9Sstevel@tonic-gate 	int max_dev;
918*7c478bd9Sstevel@tonic-gate 	int n = 0;
919*7c478bd9Sstevel@tonic-gate 	char *cmdline[MAX_CMD_LINE];
920*7c478bd9Sstevel@tonic-gate 	char maj_num[128];
921*7c478bd9Sstevel@tonic-gate 	char *previous;
922*7c478bd9Sstevel@tonic-gate 	char *current;
923*7c478bd9Sstevel@tonic-gate 	int exec_status;
924*7c478bd9Sstevel@tonic-gate 	int len;
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	if (modctl(MODRESERVED, NULL, &max_dev) < 0) {
927*7c478bd9Sstevel@tonic-gate 		perror(NULL);
928*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_MAX_MAJOR));
929*7c478bd9Sstevel@tonic-gate 		return (ERROR);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	if (major_num >= max_dev) {
933*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_MAX_EXCEEDS),
934*7c478bd9Sstevel@tonic-gate 		    major_num, max_dev);
935*7c478bd9Sstevel@tonic-gate 		return (ERROR);
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	/* bind major number and driver name */
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	/* build command line */
941*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = DRVCONFIG;
942*7c478bd9Sstevel@tonic-gate 	if (verbose_flag) {
943*7c478bd9Sstevel@tonic-gate 		cmdline[n++] = "-v";
944*7c478bd9Sstevel@tonic-gate 	}
945*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = "-b";
946*7c478bd9Sstevel@tonic-gate 	if (classes) {
947*7c478bd9Sstevel@tonic-gate 		cmdline[n++] = "-c";
948*7c478bd9Sstevel@tonic-gate 		cmdline[n++] = classes;
949*7c478bd9Sstevel@tonic-gate 	}
950*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = "-i";
951*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = driver_name;
952*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = "-m";
953*7c478bd9Sstevel@tonic-gate 	(void) sprintf(maj_num, "%lu", major_num);
954*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = maj_num;
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	if (aliases != NULL) {
957*7c478bd9Sstevel@tonic-gate 		len = strlen(aliases);
958*7c478bd9Sstevel@tonic-gate 		previous = aliases;
959*7c478bd9Sstevel@tonic-gate 		do {
960*7c478bd9Sstevel@tonic-gate 			cmdline[n++] = "-a";
961*7c478bd9Sstevel@tonic-gate 			cmdline[n] = calloc(len + 1, 1);
962*7c478bd9Sstevel@tonic-gate 			if (cmdline[n] == NULL) {
963*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
964*7c478bd9Sstevel@tonic-gate 				    gettext(ERR_NO_MEM));
965*7c478bd9Sstevel@tonic-gate 				return (ERROR);
966*7c478bd9Sstevel@tonic-gate 			}
967*7c478bd9Sstevel@tonic-gate 			current = get_entry(previous,
968*7c478bd9Sstevel@tonic-gate 			    cmdline[n++], ' ');
969*7c478bd9Sstevel@tonic-gate 			previous = current;
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate 		} while (*current != '\0');
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	}
974*7c478bd9Sstevel@tonic-gate 	cmdline[n] = (char *)0;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	exec_status = exec_command(DRVCONFIG_PATH, cmdline);
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	if (exec_status == NOERR)
979*7c478bd9Sstevel@tonic-gate 		return (NOERR);
980*7c478bd9Sstevel@tonic-gate 	perror(NULL);
981*7c478bd9Sstevel@tonic-gate 	remove_entry(cleanup_flag, driver_name);
982*7c478bd9Sstevel@tonic-gate 	return (ERROR);
983*7c478bd9Sstevel@tonic-gate }
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate void
986*7c478bd9Sstevel@tonic-gate load_driver(char *driver_name, int verbose_flag)
987*7c478bd9Sstevel@tonic-gate {
988*7c478bd9Sstevel@tonic-gate 	int n = 0;
989*7c478bd9Sstevel@tonic-gate 	char *cmdline[MAX_CMD_LINE];
990*7c478bd9Sstevel@tonic-gate 	int exec_status;
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	/* build command line */
993*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = DEVFSADM;
994*7c478bd9Sstevel@tonic-gate 	if (verbose_flag) {
995*7c478bd9Sstevel@tonic-gate 		cmdline[n++] = "-v";
996*7c478bd9Sstevel@tonic-gate 	}
997*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = "-i";
998*7c478bd9Sstevel@tonic-gate 	cmdline[n++] = driver_name;
999*7c478bd9Sstevel@tonic-gate 	cmdline[n] = (char *)0;
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	exec_status = exec_command(DEVFSADM_PATH, cmdline);
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	if (exec_status != NOERR) {
1004*7c478bd9Sstevel@tonic-gate 		/* no clean : name and major number are bound */
1005*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CONFIG),
1006*7c478bd9Sstevel@tonic-gate 			driver_name);
1007*7c478bd9Sstevel@tonic-gate 	}
1008*7c478bd9Sstevel@tonic-gate }
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate void
1011*7c478bd9Sstevel@tonic-gate get_modid(char *driver_name, int *mod)
1012*7c478bd9Sstevel@tonic-gate {
1013*7c478bd9Sstevel@tonic-gate 	struct modinfo	modinfo;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	modinfo.mi_id = -1;
1016*7c478bd9Sstevel@tonic-gate 	modinfo.mi_info = MI_INFO_ALL;
1017*7c478bd9Sstevel@tonic-gate 	do {
1018*7c478bd9Sstevel@tonic-gate 		/*
1019*7c478bd9Sstevel@tonic-gate 		 * If we are at the end of the list of loaded modules
1020*7c478bd9Sstevel@tonic-gate 		 * then set *mod = -1 and return
1021*7c478bd9Sstevel@tonic-gate 		 */
1022*7c478bd9Sstevel@tonic-gate 		if (modctl(MODINFO, 0, &modinfo) < 0) {
1023*7c478bd9Sstevel@tonic-gate 			*mod = -1;
1024*7c478bd9Sstevel@tonic-gate 			return;
1025*7c478bd9Sstevel@tonic-gate 		}
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 		*mod = modinfo.mi_id;
1028*7c478bd9Sstevel@tonic-gate 	} while (strcmp(driver_name, modinfo.mi_name) != 0);
1029*7c478bd9Sstevel@tonic-gate }
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate int
1032*7c478bd9Sstevel@tonic-gate create_reconfig(char *basedir)
1033*7c478bd9Sstevel@tonic-gate {
1034*7c478bd9Sstevel@tonic-gate 	char reconfig_file[MAXPATHLEN + FILENAME_MAX + 1];
1035*7c478bd9Sstevel@tonic-gate 	FILE *reconfig_fp;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	if (basedir != NULL) {
1038*7c478bd9Sstevel@tonic-gate 		(void) strcpy(reconfig_file, basedir);
1039*7c478bd9Sstevel@tonic-gate 		(void) strcat(reconfig_file, RECONFIGURE);
1040*7c478bd9Sstevel@tonic-gate 	} else {
1041*7c478bd9Sstevel@tonic-gate 		(void) strcpy(reconfig_file, RECONFIGURE);
1042*7c478bd9Sstevel@tonic-gate 	}
1043*7c478bd9Sstevel@tonic-gate 	if ((reconfig_fp = fopen(reconfig_file, "a")) == NULL)
1044*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	(void) fclose(reconfig_fp);
1047*7c478bd9Sstevel@tonic-gate 	return (NOERR);
1048*7c478bd9Sstevel@tonic-gate }
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate /*
1052*7c478bd9Sstevel@tonic-gate  * update_minor_entry:
1053*7c478bd9Sstevel@tonic-gate  *	open file
1054*7c478bd9Sstevel@tonic-gate  *	for each entry in list
1055*7c478bd9Sstevel@tonic-gate  *		where list entries are separated by <list_separator>
1056*7c478bd9Sstevel@tonic-gate  * 		modify entry : driver_name <entry_separator> entry
1057*7c478bd9Sstevel@tonic-gate  *	close file
1058*7c478bd9Sstevel@tonic-gate  *
1059*7c478bd9Sstevel@tonic-gate  *	return error/noerr
1060*7c478bd9Sstevel@tonic-gate  */
1061*7c478bd9Sstevel@tonic-gate int
1062*7c478bd9Sstevel@tonic-gate update_minor_entry(char *driver_name, char *perm_list)
1063*7c478bd9Sstevel@tonic-gate {
1064*7c478bd9Sstevel@tonic-gate 	FILE *fp;
1065*7c478bd9Sstevel@tonic-gate 	FILE *newfp;
1066*7c478bd9Sstevel@tonic-gate 	struct group *sysgrp;
1067*7c478bd9Sstevel@tonic-gate 	int match = 0;
1068*7c478bd9Sstevel@tonic-gate 	char line[MAX_DBFILE_ENTRY];
1069*7c478bd9Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
1070*7c478bd9Sstevel@tonic-gate 	char *drv_minor, new_minor[FILENAME_MAX + 1];
1071*7c478bd9Sstevel@tonic-gate 	char minor[FILENAME_MAX + 1], perm[OPT_LEN + 1];
1072*7c478bd9Sstevel@tonic-gate 	char own[OPT_LEN + 1], grp[OPT_LEN + 1];
1073*7c478bd9Sstevel@tonic-gate 	int status = NOERR, i;
1074*7c478bd9Sstevel@tonic-gate 	char *newfile, *tptr;
1075*7c478bd9Sstevel@tonic-gate 	extern void bzero();
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(minor_perm, "r")) == NULL) {
1078*7c478bd9Sstevel@tonic-gate 		perror(NULL);
1079*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
1080*7c478bd9Sstevel@tonic-gate 		    minor_perm);
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1083*7c478bd9Sstevel@tonic-gate 	}
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	/*
1086*7c478bd9Sstevel@tonic-gate 	 * Build filename for temporary file
1087*7c478bd9Sstevel@tonic-gate 	 */
1088*7c478bd9Sstevel@tonic-gate 	if ((tptr = calloc(strlen(minor_perm) + strlen(XEND) + 1, 1)) == NULL) {
1089*7c478bd9Sstevel@tonic-gate 		perror(NULL);
1090*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1091*7c478bd9Sstevel@tonic-gate 	}
1092*7c478bd9Sstevel@tonic-gate 	(void) strcpy(tptr, minor_perm);
1093*7c478bd9Sstevel@tonic-gate 	(void) strcat(tptr, XEND);
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	/*
1096*7c478bd9Sstevel@tonic-gate 	 * Set gid so we preserve group attribute.  Ideally we wouldn't
1097*7c478bd9Sstevel@tonic-gate 	 * assume a gid of "sys" but we can't undo the damage on already
1098*7c478bd9Sstevel@tonic-gate 	 * installed systems unless we force the issue.
1099*7c478bd9Sstevel@tonic-gate 	 */
1100*7c478bd9Sstevel@tonic-gate 	if ((sysgrp = getgrnam("sys")) != NULL) {
1101*7c478bd9Sstevel@tonic-gate 		(void) setgid(sysgrp->gr_gid);
1102*7c478bd9Sstevel@tonic-gate 	}
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	newfile = mktemp(tptr);
1105*7c478bd9Sstevel@tonic-gate 	if ((newfp = fopen(newfile, "w")) == NULL) {
1106*7c478bd9Sstevel@tonic-gate 		perror(NULL);
1107*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
1108*7c478bd9Sstevel@tonic-gate 		    newfile);
1109*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	if (sscanf(perm_list, "%s%s%s%s", minor, perm, own, grp) != 4) {
1113*7c478bd9Sstevel@tonic-gate 		status = ERROR;
1114*7c478bd9Sstevel@tonic-gate 	}
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	(void) sscanf(perm_list, "%s%s%s%s", minor, perm, own, grp);
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) {
1119*7c478bd9Sstevel@tonic-gate 		if (*line == '#' || *line == '\n') {
1120*7c478bd9Sstevel@tonic-gate 			if ((fputs(line, newfp)) == EOF) {
1121*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
1122*7c478bd9Sstevel@tonic-gate 				    minor_perm);
1123*7c478bd9Sstevel@tonic-gate 				status = ERROR;
1124*7c478bd9Sstevel@tonic-gate 			}
1125*7c478bd9Sstevel@tonic-gate 			continue;
1126*7c478bd9Sstevel@tonic-gate 		}
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 		if (sscanf(line, "%s", drv) != 1) {
1129*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
1130*7c478bd9Sstevel@tonic-gate 			    minor_perm, line);
1131*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1132*7c478bd9Sstevel@tonic-gate 		}
1133*7c478bd9Sstevel@tonic-gate 		for (i = strcspn(drv, ":"); i < FILENAME_MAX; i++) {
1134*7c478bd9Sstevel@tonic-gate 			drv[i] =  '\0';
1135*7c478bd9Sstevel@tonic-gate 		}
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 		if (sscanf(line, "%s", new_minor) != 1) {
1138*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
1139*7c478bd9Sstevel@tonic-gate 			    minor_perm, line);
1140*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1141*7c478bd9Sstevel@tonic-gate 		}
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate 		drv_minor = &new_minor[strlen(drv) + 1];
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 		/* replace it */
1146*7c478bd9Sstevel@tonic-gate 		if ((strcmp(drv, driver_name) == 0) &&
1147*7c478bd9Sstevel@tonic-gate 		    (strcmp(minor, drv_minor) == 0)) {
1148*7c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%s:%s %s %s %s\n",
1149*7c478bd9Sstevel@tonic-gate 			    drv, minor, perm, own, grp);
1150*7c478bd9Sstevel@tonic-gate 			match = 1;
1151*7c478bd9Sstevel@tonic-gate 		}
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 		if ((fputs(line, newfp)) == EOF) {
1154*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE),
1155*7c478bd9Sstevel@tonic-gate 			    minor_perm);
1156*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1157*7c478bd9Sstevel@tonic-gate 		}
1158*7c478bd9Sstevel@tonic-gate 	}
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	if (!match) {
1161*7c478bd9Sstevel@tonic-gate 		(void) bzero(line, sizeof (&line[0]));
1162*7c478bd9Sstevel@tonic-gate 		(void) sprintf(line, "%s:%s %s %s %s\n",
1163*7c478bd9Sstevel@tonic-gate 		    driver_name, minor, perm, own, grp);
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 		/* add the new entry */
1166*7c478bd9Sstevel@tonic-gate 		if ((fputs(line, newfp)) == EOF) {
1167*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm);
1168*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1169*7c478bd9Sstevel@tonic-gate 		}
1170*7c478bd9Sstevel@tonic-gate 	}
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0)
1175*7c478bd9Sstevel@tonic-gate 		status = ERROR;
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 	(void) fclose(newfp);
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 	/*
1180*7c478bd9Sstevel@tonic-gate 	 * if error, leave original file, delete new file
1181*7c478bd9Sstevel@tonic-gate 	 * if noerr, replace original file with new file
1182*7c478bd9Sstevel@tonic-gate 	 */
1183*7c478bd9Sstevel@tonic-gate 	if (status == NOERR) {
1184*7c478bd9Sstevel@tonic-gate 		if (rename(minor_perm, tmphold) == -1) {
1185*7c478bd9Sstevel@tonic-gate 			perror(NULL);
1186*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm);
1187*7c478bd9Sstevel@tonic-gate 			(void) unlink(newfile);
1188*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1189*7c478bd9Sstevel@tonic-gate 		} else if (rename(newfile, minor_perm) == -1) {
1190*7c478bd9Sstevel@tonic-gate 			perror(NULL);
1191*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm);
1192*7c478bd9Sstevel@tonic-gate 			(void) unlink(minor_perm);
1193*7c478bd9Sstevel@tonic-gate 			(void) unlink(newfile);
1194*7c478bd9Sstevel@tonic-gate 			if (link(tmphold, minor_perm) == -1) {
1195*7c478bd9Sstevel@tonic-gate 				perror(NULL);
1196*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINK),
1197*7c478bd9Sstevel@tonic-gate 				    minor_perm, tmphold);
1198*7c478bd9Sstevel@tonic-gate 			}
1199*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1200*7c478bd9Sstevel@tonic-gate 		}
1201*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmphold);
1202*7c478bd9Sstevel@tonic-gate 	} else {
1203*7c478bd9Sstevel@tonic-gate 		/*
1204*7c478bd9Sstevel@tonic-gate 		 * since there's an error, leave file alone; remove
1205*7c478bd9Sstevel@tonic-gate 		 * new file
1206*7c478bd9Sstevel@tonic-gate 		 */
1207*7c478bd9Sstevel@tonic-gate 		if (unlink(newfile) == -1) {
1208*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_RM), newfile);
1209*7c478bd9Sstevel@tonic-gate 		}
1210*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1211*7c478bd9Sstevel@tonic-gate 	}
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 	return (NOERR);
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate }
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate /*
1219*7c478bd9Sstevel@tonic-gate  * list_entry:
1220*7c478bd9Sstevel@tonic-gate  *	open file
1221*7c478bd9Sstevel@tonic-gate  *	read thru file, listing all entries if first entry = driver_name
1222*7c478bd9Sstevel@tonic-gate  *	close
1223*7c478bd9Sstevel@tonic-gate  */
1224*7c478bd9Sstevel@tonic-gate void
1225*7c478bd9Sstevel@tonic-gate list_entry(
1226*7c478bd9Sstevel@tonic-gate 	char *oldfile,
1227*7c478bd9Sstevel@tonic-gate 	char *driver_name,
1228*7c478bd9Sstevel@tonic-gate 	char *marker)
1229*7c478bd9Sstevel@tonic-gate {
1230*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
1231*7c478bd9Sstevel@tonic-gate 	int	i;
1232*7c478bd9Sstevel@tonic-gate 	char	line[MAX_DBFILE_ENTRY];
1233*7c478bd9Sstevel@tonic-gate 	char	drv[FILENAME_MAX + 1];
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(oldfile, "r")) == NULL) {
1236*7c478bd9Sstevel@tonic-gate 		perror(NULL);
1237*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile);
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate 		return;
1240*7c478bd9Sstevel@tonic-gate 	}
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != NULL) {
1243*7c478bd9Sstevel@tonic-gate 		if (*line == '#' || *line == '\n') {
1244*7c478bd9Sstevel@tonic-gate 			continue;
1245*7c478bd9Sstevel@tonic-gate 		}
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 		if (sscanf(line, "%s", drv) != 1) {
1248*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
1249*7c478bd9Sstevel@tonic-gate 			    oldfile, line);
1250*7c478bd9Sstevel@tonic-gate 		}
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 		for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) {
1253*7c478bd9Sstevel@tonic-gate 			drv[i] =  '\0';
1254*7c478bd9Sstevel@tonic-gate 		}
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 		if (strcmp(driver_name, drv) == 0) {
1257*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "%s", line);
1258*7c478bd9Sstevel@tonic-gate 		}
1259*7c478bd9Sstevel@tonic-gate 	}
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
1262*7c478bd9Sstevel@tonic-gate }
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate /*
1266*7c478bd9Sstevel@tonic-gate  * check each entry in perm_list for:
1267*7c478bd9Sstevel@tonic-gate  *	4 arguments
1268*7c478bd9Sstevel@tonic-gate  *	permission arg is in valid range
1269*7c478bd9Sstevel@tonic-gate  * permlist entries separated by comma
1270*7c478bd9Sstevel@tonic-gate  * return ERROR/NOERR
1271*7c478bd9Sstevel@tonic-gate  */
1272*7c478bd9Sstevel@tonic-gate int
1273*7c478bd9Sstevel@tonic-gate check_perm_opts(char *perm_list)
1274*7c478bd9Sstevel@tonic-gate {
1275*7c478bd9Sstevel@tonic-gate 	char *current_head;
1276*7c478bd9Sstevel@tonic-gate 	char *previous_head;
1277*7c478bd9Sstevel@tonic-gate 	char *one_entry;
1278*7c478bd9Sstevel@tonic-gate 	int i, len, scan_stat;
1279*7c478bd9Sstevel@tonic-gate 	char minor[FILENAME_MAX + 1];
1280*7c478bd9Sstevel@tonic-gate 	char perm[OPT_LEN + 1];
1281*7c478bd9Sstevel@tonic-gate 	char own[OPT_LEN + 1];
1282*7c478bd9Sstevel@tonic-gate 	char grp[OPT_LEN + 1];
1283*7c478bd9Sstevel@tonic-gate 	char dumb[OPT_LEN + 1];
1284*7c478bd9Sstevel@tonic-gate 	int status = NOERR;
1285*7c478bd9Sstevel@tonic-gate 	int intperm;
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 	len = strlen(perm_list);
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 	if (len == 0) {
1290*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1291*7c478bd9Sstevel@tonic-gate 	}
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 	one_entry = calloc(len + 1, 1);
1294*7c478bd9Sstevel@tonic-gate 	if (one_entry == NULL) {
1295*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1296*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	previous_head = perm_list;
1300*7c478bd9Sstevel@tonic-gate 	current_head = perm_list;
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 	while (*current_head != '\0') {
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= len; i++)
1305*7c478bd9Sstevel@tonic-gate 			one_entry[i] = 0;
1306*7c478bd9Sstevel@tonic-gate 
1307*7c478bd9Sstevel@tonic-gate 		current_head = get_entry(previous_head, one_entry, ',');
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate 		previous_head = current_head;
1310*7c478bd9Sstevel@tonic-gate 		scan_stat = sscanf(one_entry, "%s%s%s%s%s", minor, perm, own,
1311*7c478bd9Sstevel@tonic-gate 		    grp, dumb);
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 		if (scan_stat < 4) {
1314*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MIS_TOK),
1315*7c478bd9Sstevel@tonic-gate 			    "-m", one_entry);
1316*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1317*7c478bd9Sstevel@tonic-gate 		}
1318*7c478bd9Sstevel@tonic-gate 		if (scan_stat > 4) {
1319*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_TOO_MANY_ARGS),
1320*7c478bd9Sstevel@tonic-gate 			    "-m", one_entry);
1321*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1322*7c478bd9Sstevel@tonic-gate 		}
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 		intperm = atoi(perm);
1325*7c478bd9Sstevel@tonic-gate 		if (intperm < 0000 || intperm > 4777) {
1326*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_MODE), perm);
1327*7c478bd9Sstevel@tonic-gate 			status = ERROR;
1328*7c478bd9Sstevel@tonic-gate 		}
1329*7c478bd9Sstevel@tonic-gate 
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	free(one_entry);
1333*7c478bd9Sstevel@tonic-gate 	return (status);
1334*7c478bd9Sstevel@tonic-gate }
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate /*
1338*7c478bd9Sstevel@tonic-gate  * check each alias :
1339*7c478bd9Sstevel@tonic-gate  *	alias list members separated by white space
1340*7c478bd9Sstevel@tonic-gate  *	cannot exist as driver name in /etc/name_to_major
1341*7c478bd9Sstevel@tonic-gate  *	cannot exist as driver or alias name in /etc/driver_aliases
1342*7c478bd9Sstevel@tonic-gate  */
1343*7c478bd9Sstevel@tonic-gate int
1344*7c478bd9Sstevel@tonic-gate aliases_unique(char *aliases)
1345*7c478bd9Sstevel@tonic-gate {
1346*7c478bd9Sstevel@tonic-gate 	char *current_head;
1347*7c478bd9Sstevel@tonic-gate 	char *previous_head;
1348*7c478bd9Sstevel@tonic-gate 	char *one_entry;
1349*7c478bd9Sstevel@tonic-gate 	int i, len;
1350*7c478bd9Sstevel@tonic-gate 	int is_unique;
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 	len = strlen(aliases);
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate 	one_entry = calloc(len + 1, 1);
1355*7c478bd9Sstevel@tonic-gate 	if (one_entry == NULL) {
1356*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1357*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1358*7c478bd9Sstevel@tonic-gate 	}
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	previous_head = aliases;
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	do {
1363*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= len; i++)
1364*7c478bd9Sstevel@tonic-gate 			one_entry[i] = 0;
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate 		current_head = get_entry(previous_head, one_entry, ' ');
1367*7c478bd9Sstevel@tonic-gate 		previous_head = current_head;
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate 		if ((unique_driver_name(one_entry, name_to_major,
1370*7c478bd9Sstevel@tonic-gate 		    &is_unique)) == ERROR) {
1371*7c478bd9Sstevel@tonic-gate 			free(one_entry);
1372*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1373*7c478bd9Sstevel@tonic-gate 		}
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 		if (is_unique != UNIQUE) {
1376*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_ALIAS_IN_NAM_MAJ),
1377*7c478bd9Sstevel@tonic-gate 			    one_entry);
1378*7c478bd9Sstevel@tonic-gate 			free(one_entry);
1379*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1380*7c478bd9Sstevel@tonic-gate 		}
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 		if (unique_drv_alias(one_entry) != NOERR) {
1383*7c478bd9Sstevel@tonic-gate 			free(one_entry);
1384*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1385*7c478bd9Sstevel@tonic-gate 		}
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	} while (*current_head != '\0');
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	free(one_entry);
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	return (NOERR);
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate }
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate int
1397*7c478bd9Sstevel@tonic-gate update_driver_aliases(
1398*7c478bd9Sstevel@tonic-gate 	char *driver_name,
1399*7c478bd9Sstevel@tonic-gate 	char *aliases)
1400*7c478bd9Sstevel@tonic-gate {
1401*7c478bd9Sstevel@tonic-gate 	/* make call to update the aliases file */
1402*7c478bd9Sstevel@tonic-gate 	return (append_to_file(driver_name, aliases, driver_aliases, ' ', " "));
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate }
1405*7c478bd9Sstevel@tonic-gate 
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate int
1408*7c478bd9Sstevel@tonic-gate unique_drv_alias(char *drv_alias)
1409*7c478bd9Sstevel@tonic-gate {
1410*7c478bd9Sstevel@tonic-gate 	FILE *fp;
1411*7c478bd9Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
1412*7c478bd9Sstevel@tonic-gate 	char line[MAX_N2M_ALIAS_LINE + 1];
1413*7c478bd9Sstevel@tonic-gate 	char alias[FILENAME_MAX + 1];
1414*7c478bd9Sstevel@tonic-gate 	int status = NOERR;
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	fp = fopen(driver_aliases, "r");
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 	if (fp != NULL) {
1419*7c478bd9Sstevel@tonic-gate 		while ((fgets(line, sizeof (line), fp) != 0) &&
1420*7c478bd9Sstevel@tonic-gate 		    status != ERROR) {
1421*7c478bd9Sstevel@tonic-gate 			if (sscanf(line, "%s %s", drv, alias) != 2)
1422*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
1423*7c478bd9Sstevel@tonic-gate 				    driver_aliases, line);
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate 			if ((strcmp(drv_alias, drv) == 0) ||
1426*7c478bd9Sstevel@tonic-gate 			    (strcmp(drv_alias, alias) == 0)) {
1427*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1428*7c478bd9Sstevel@tonic-gate 				    gettext(ERR_ALIAS_IN_USE),
1429*7c478bd9Sstevel@tonic-gate 				    drv_alias);
1430*7c478bd9Sstevel@tonic-gate 				status = ERROR;
1431*7c478bd9Sstevel@tonic-gate 			}
1432*7c478bd9Sstevel@tonic-gate 		}
1433*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
1434*7c478bd9Sstevel@tonic-gate 		return (status);
1435*7c478bd9Sstevel@tonic-gate 	} else {
1436*7c478bd9Sstevel@tonic-gate 		perror(NULL);
1437*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_OPEN), driver_aliases);
1438*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1439*7c478bd9Sstevel@tonic-gate 	}
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate }
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate /*
1445*7c478bd9Sstevel@tonic-gate  * search for driver_name in first field of file file_name
1446*7c478bd9Sstevel@tonic-gate  * searching name_to_major and driver_aliases: name separated from rest of
1447*7c478bd9Sstevel@tonic-gate  * line by blank
1448*7c478bd9Sstevel@tonic-gate  * if there return
1449*7c478bd9Sstevel@tonic-gate  * else return
1450*7c478bd9Sstevel@tonic-gate  */
1451*7c478bd9Sstevel@tonic-gate int
1452*7c478bd9Sstevel@tonic-gate unique_driver_name(char *driver_name, char *file_name,
1453*7c478bd9Sstevel@tonic-gate 	int *is_unique)
1454*7c478bd9Sstevel@tonic-gate {
1455*7c478bd9Sstevel@tonic-gate 	int ret;
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate 	if ((ret = get_major_no(driver_name, file_name)) == ERROR) {
1458*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
1459*7c478bd9Sstevel@tonic-gate 		    file_name);
1460*7c478bd9Sstevel@tonic-gate 	} else {
1461*7c478bd9Sstevel@tonic-gate 		/* XXX */
1462*7c478bd9Sstevel@tonic-gate 		/* check alias file for name collision */
1463*7c478bd9Sstevel@tonic-gate 		if (unique_drv_alias(driver_name) == ERROR) {
1464*7c478bd9Sstevel@tonic-gate 			ret = ERROR;
1465*7c478bd9Sstevel@tonic-gate 		} else {
1466*7c478bd9Sstevel@tonic-gate 			if (ret != UNIQUE)
1467*7c478bd9Sstevel@tonic-gate 				*is_unique = NOT_UNIQUE;
1468*7c478bd9Sstevel@tonic-gate 			else
1469*7c478bd9Sstevel@tonic-gate 				*is_unique = ret;
1470*7c478bd9Sstevel@tonic-gate 			ret = NOERR;
1471*7c478bd9Sstevel@tonic-gate 		}
1472*7c478bd9Sstevel@tonic-gate 	}
1473*7c478bd9Sstevel@tonic-gate 	return (ret);
1474*7c478bd9Sstevel@tonic-gate }
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate int
1478*7c478bd9Sstevel@tonic-gate check_space_within_quote(char *str)
1479*7c478bd9Sstevel@tonic-gate {
1480*7c478bd9Sstevel@tonic-gate 	register int i;
1481*7c478bd9Sstevel@tonic-gate 	register int len;
1482*7c478bd9Sstevel@tonic-gate 	int quoted = 0;
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate 	len = strlen(str);
1485*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++, str++) {
1486*7c478bd9Sstevel@tonic-gate 		if (*str == '"') {
1487*7c478bd9Sstevel@tonic-gate 			if (quoted == 0)
1488*7c478bd9Sstevel@tonic-gate 				quoted++;
1489*7c478bd9Sstevel@tonic-gate 			else
1490*7c478bd9Sstevel@tonic-gate 				quoted--;
1491*7c478bd9Sstevel@tonic-gate 		} else if (*str == ' ' && quoted)
1492*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1493*7c478bd9Sstevel@tonic-gate 	}
1494*7c478bd9Sstevel@tonic-gate 
1495*7c478bd9Sstevel@tonic-gate 	return (0);
1496*7c478bd9Sstevel@tonic-gate }
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate /*
1500*7c478bd9Sstevel@tonic-gate  * get major number
1501*7c478bd9Sstevel@tonic-gate  * write driver_name major_num to name_to_major file
1502*7c478bd9Sstevel@tonic-gate  * major_num returned in major_num
1503*7c478bd9Sstevel@tonic-gate  * return success/failure
1504*7c478bd9Sstevel@tonic-gate  */
1505*7c478bd9Sstevel@tonic-gate int
1506*7c478bd9Sstevel@tonic-gate update_name_to_major(char *driver_name, major_t *major_num, int server)
1507*7c478bd9Sstevel@tonic-gate {
1508*7c478bd9Sstevel@tonic-gate 	char major[MAX_STR_MAJOR + 1];
1509*7c478bd9Sstevel@tonic-gate 	struct stat buf;
1510*7c478bd9Sstevel@tonic-gate 	char *num_list;
1511*7c478bd9Sstevel@tonic-gate 	char drv_majnum_str[MAX_STR_MAJOR + 1];
1512*7c478bd9Sstevel@tonic-gate 	int new_maj = -1;
1513*7c478bd9Sstevel@tonic-gate 	int i, tmp = 0, is_unique, have_rem_n2m = 0;
1514*7c478bd9Sstevel@tonic-gate 	int max_dev = 0;
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 	/*
1517*7c478bd9Sstevel@tonic-gate 	 * if driver_name already in rem_name_to_major
1518*7c478bd9Sstevel@tonic-gate 	 * 	delete entry from rem_nam_to_major
1519*7c478bd9Sstevel@tonic-gate 	 *	put entry into name_to_major
1520*7c478bd9Sstevel@tonic-gate 	 */
1521*7c478bd9Sstevel@tonic-gate 
1522*7c478bd9Sstevel@tonic-gate 	if (stat(rem_name_to_major, &buf) == 0) {
1523*7c478bd9Sstevel@tonic-gate 		have_rem_n2m = 1;
1524*7c478bd9Sstevel@tonic-gate 	}
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	if (have_rem_n2m) {
1527*7c478bd9Sstevel@tonic-gate 		if ((is_unique = get_major_no(driver_name, rem_name_to_major))
1528*7c478bd9Sstevel@tonic-gate 		    == ERROR)
1529*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 		/*
1532*7c478bd9Sstevel@tonic-gate 		 * found a match in rem_name_to_major
1533*7c478bd9Sstevel@tonic-gate 		 */
1534*7c478bd9Sstevel@tonic-gate 		if (is_unique != UNIQUE) {
1535*7c478bd9Sstevel@tonic-gate 			char scratch[FILENAME_MAX];
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate 			/*
1538*7c478bd9Sstevel@tonic-gate 			 * If there is a match in /etc/rem_name_to_major then
1539*7c478bd9Sstevel@tonic-gate 			 * be paranoid: is that major number already in
1540*7c478bd9Sstevel@tonic-gate 			 * /etc/name_to_major (potentially under another name)?
1541*7c478bd9Sstevel@tonic-gate 			 */
1542*7c478bd9Sstevel@tonic-gate 			if (get_driver_name(is_unique, name_to_major,
1543*7c478bd9Sstevel@tonic-gate 			    scratch) != UNIQUE) {
1544*7c478bd9Sstevel@tonic-gate 				/*
1545*7c478bd9Sstevel@tonic-gate 				 * nuke the rem_name_to_major entry-- it
1546*7c478bd9Sstevel@tonic-gate 				 * isn't helpful.
1547*7c478bd9Sstevel@tonic-gate 				 */
1548*7c478bd9Sstevel@tonic-gate 				(void) delete_entry(rem_name_to_major,
1549*7c478bd9Sstevel@tonic-gate 				    driver_name, " ", NULL);
1550*7c478bd9Sstevel@tonic-gate 			} else {
1551*7c478bd9Sstevel@tonic-gate 				(void) snprintf(major, sizeof (major),
1552*7c478bd9Sstevel@tonic-gate 				    "%d", is_unique);
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 				if (append_to_file(driver_name, major,
1555*7c478bd9Sstevel@tonic-gate 				    name_to_major, ' ', " ") == ERROR) {
1556*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
1557*7c478bd9Sstevel@tonic-gate 					    gettext(ERR_NO_UPDATE),
1558*7c478bd9Sstevel@tonic-gate 					    name_to_major);
1559*7c478bd9Sstevel@tonic-gate 					return (ERROR);
1560*7c478bd9Sstevel@tonic-gate 				}
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 				if (delete_entry(rem_name_to_major,
1563*7c478bd9Sstevel@tonic-gate 				    driver_name, " ", NULL) == ERROR) {
1564*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
1565*7c478bd9Sstevel@tonic-gate 					    gettext(ERR_DEL_ENTRY), driver_name,
1566*7c478bd9Sstevel@tonic-gate 					    rem_name_to_major);
1567*7c478bd9Sstevel@tonic-gate 					return (ERROR);
1568*7c478bd9Sstevel@tonic-gate 				}
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 				/* found matching entry : no errors */
1571*7c478bd9Sstevel@tonic-gate 				*major_num = is_unique;
1572*7c478bd9Sstevel@tonic-gate 				return (NOERR);
1573*7c478bd9Sstevel@tonic-gate 			}
1574*7c478bd9Sstevel@tonic-gate 		}
1575*7c478bd9Sstevel@tonic-gate 	}
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate 	/*
1578*7c478bd9Sstevel@tonic-gate 	 * Bugid: 1264079
1579*7c478bd9Sstevel@tonic-gate 	 * In a server case (with -b option), we can't use modctl() to find
1580*7c478bd9Sstevel@tonic-gate 	 *    the maximum major number, we need to dig thru client's
1581*7c478bd9Sstevel@tonic-gate 	 *    /etc/name_to_major and /etc/rem_name_to_major for the max_dev.
1582*7c478bd9Sstevel@tonic-gate 	 *
1583*7c478bd9Sstevel@tonic-gate 	 * if (server)
1584*7c478bd9Sstevel@tonic-gate 	 *    get maximum major number thru (rem_)name_to_major file on client
1585*7c478bd9Sstevel@tonic-gate 	 * else
1586*7c478bd9Sstevel@tonic-gate 	 *    get maximum major number allowable on current system using modctl
1587*7c478bd9Sstevel@tonic-gate 	 */
1588*7c478bd9Sstevel@tonic-gate 	if (server) {
1589*7c478bd9Sstevel@tonic-gate 		max_dev = 0;
1590*7c478bd9Sstevel@tonic-gate 		tmp = 0;
1591*7c478bd9Sstevel@tonic-gate 
1592*7c478bd9Sstevel@tonic-gate 		max_dev = get_max_major(name_to_major);
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 		/* If rem_name_to_major exists, we need to check it too */
1595*7c478bd9Sstevel@tonic-gate 		if (have_rem_n2m) {
1596*7c478bd9Sstevel@tonic-gate 			tmp = get_max_major(rem_name_to_major);
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate 			/*
1599*7c478bd9Sstevel@tonic-gate 			 * If name_to_major is missing, we can get max_dev from
1600*7c478bd9Sstevel@tonic-gate 			 * /etc/rem_name_to_major.  If both missing, bail out!
1601*7c478bd9Sstevel@tonic-gate 			 */
1602*7c478bd9Sstevel@tonic-gate 			if ((max_dev == ERROR) && (tmp == ERROR)) {
1603*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1604*7c478bd9Sstevel@tonic-gate 					gettext(ERR_CANT_ACCESS_FILE),
1605*7c478bd9Sstevel@tonic-gate 					name_to_major);
1606*7c478bd9Sstevel@tonic-gate 				return (ERROR);
1607*7c478bd9Sstevel@tonic-gate 			}
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate 			/* guard against bigger maj_num in rem_name_to_major */
1610*7c478bd9Sstevel@tonic-gate 			if (tmp > max_dev)
1611*7c478bd9Sstevel@tonic-gate 				max_dev = tmp;
1612*7c478bd9Sstevel@tonic-gate 		} else {
1613*7c478bd9Sstevel@tonic-gate 			/*
1614*7c478bd9Sstevel@tonic-gate 			 * If we can't get major from name_to_major file
1615*7c478bd9Sstevel@tonic-gate 			 * and there is no /etc/rem_name_to_major file,
1616*7c478bd9Sstevel@tonic-gate 			 * then we don't have a max_dev, bail out quick!
1617*7c478bd9Sstevel@tonic-gate 			 */
1618*7c478bd9Sstevel@tonic-gate 			if (max_dev == ERROR)
1619*7c478bd9Sstevel@tonic-gate 				return (ERROR);
1620*7c478bd9Sstevel@tonic-gate 		}
1621*7c478bd9Sstevel@tonic-gate 
1622*7c478bd9Sstevel@tonic-gate 		/*
1623*7c478bd9Sstevel@tonic-gate 		 * In case there is no more slack in current name_to_major
1624*7c478bd9Sstevel@tonic-gate 		 * table, provide at least 1 extra entry so the add_drv can
1625*7c478bd9Sstevel@tonic-gate 		 * succeed.  Since only one add_drv process is allowed at one
1626*7c478bd9Sstevel@tonic-gate 		 * time, and hence max_dev will be re-calculated each time
1627*7c478bd9Sstevel@tonic-gate 		 * add_drv is ran, we don't need to worry about adding more
1628*7c478bd9Sstevel@tonic-gate 		 * than 1 extra slot for max_dev.
1629*7c478bd9Sstevel@tonic-gate 		 */
1630*7c478bd9Sstevel@tonic-gate 		max_dev++;
1631*7c478bd9Sstevel@tonic-gate 
1632*7c478bd9Sstevel@tonic-gate 	} else {
1633*7c478bd9Sstevel@tonic-gate 		if (modctl(MODRESERVED, NULL, &max_dev) < 0) {
1634*7c478bd9Sstevel@tonic-gate 			perror(NULL);
1635*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MAX_MAJOR));
1636*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1637*7c478bd9Sstevel@tonic-gate 		}
1638*7c478bd9Sstevel@tonic-gate 	}
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 	/*
1641*7c478bd9Sstevel@tonic-gate 	 * max_dev is really how many slots the kernel has allocated for
1642*7c478bd9Sstevel@tonic-gate 	 * devices... [0 , maxdev-1], not the largest available device num.
1643*7c478bd9Sstevel@tonic-gate 	 */
1644*7c478bd9Sstevel@tonic-gate 	if ((num_list = calloc(max_dev, 1)) == NULL) {
1645*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1646*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1647*7c478bd9Sstevel@tonic-gate 	}
1648*7c478bd9Sstevel@tonic-gate 
1649*7c478bd9Sstevel@tonic-gate 	/*
1650*7c478bd9Sstevel@tonic-gate 	 * Populate the num_list array
1651*7c478bd9Sstevel@tonic-gate 	 */
1652*7c478bd9Sstevel@tonic-gate 	if (fill_n2m_array(name_to_major, &num_list, &max_dev) != 0) {
1653*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1654*7c478bd9Sstevel@tonic-gate 	}
1655*7c478bd9Sstevel@tonic-gate 	if (have_rem_n2m) {
1656*7c478bd9Sstevel@tonic-gate 		if (fill_n2m_array(rem_name_to_major, &num_list, &max_dev) != 0)
1657*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1658*7c478bd9Sstevel@tonic-gate 	}
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate 	/* find first free major number */
1661*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < max_dev; i++) {
1662*7c478bd9Sstevel@tonic-gate 		if (num_list[i] != 1) {
1663*7c478bd9Sstevel@tonic-gate 			new_maj = i;
1664*7c478bd9Sstevel@tonic-gate 			break;
1665*7c478bd9Sstevel@tonic-gate 		}
1666*7c478bd9Sstevel@tonic-gate 	}
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 	if (new_maj == -1) {
1669*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_FREE_MAJOR));
1670*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1671*7c478bd9Sstevel@tonic-gate 	}
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate 	(void) sprintf(drv_majnum_str, "%d", new_maj);
1674*7c478bd9Sstevel@tonic-gate 	if (do_the_update(driver_name, drv_majnum_str) == ERROR) {
1675*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1676*7c478bd9Sstevel@tonic-gate 	}
1677*7c478bd9Sstevel@tonic-gate 
1678*7c478bd9Sstevel@tonic-gate 	*major_num = new_maj;
1679*7c478bd9Sstevel@tonic-gate 	return (NOERR);
1680*7c478bd9Sstevel@tonic-gate }
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 
1683*7c478bd9Sstevel@tonic-gate int
1684*7c478bd9Sstevel@tonic-gate fill_n2m_array(char *filename, char **array, int *nelems)
1685*7c478bd9Sstevel@tonic-gate {
1686*7c478bd9Sstevel@tonic-gate 	FILE *fp;
1687*7c478bd9Sstevel@tonic-gate 	char line[MAX_N2M_ALIAS_LINE + 1];
1688*7c478bd9Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
1689*7c478bd9Sstevel@tonic-gate 	u_longlong_t dnum;
1690*7c478bd9Sstevel@tonic-gate 	major_t drv_majnum;
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 	/*
1693*7c478bd9Sstevel@tonic-gate 	 * Read through the file, marking each major number found
1694*7c478bd9Sstevel@tonic-gate 	 * order is not relevant
1695*7c478bd9Sstevel@tonic-gate 	 */
1696*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(filename, "r")) == NULL) {
1697*7c478bd9Sstevel@tonic-gate 		perror(NULL);
1698*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), filename);
1699*7c478bd9Sstevel@tonic-gate 		return (ERROR);
1700*7c478bd9Sstevel@tonic-gate 	}
1701*7c478bd9Sstevel@tonic-gate 
1702*7c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != 0) {
1703*7c478bd9Sstevel@tonic-gate 
1704*7c478bd9Sstevel@tonic-gate 		if (sscanf(line, "%s %llu", drv, &dnum) != 2) {
1705*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
1706*7c478bd9Sstevel@tonic-gate 			    filename, line);
1707*7c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
1708*7c478bd9Sstevel@tonic-gate 			return (ERROR);
1709*7c478bd9Sstevel@tonic-gate 		}
1710*7c478bd9Sstevel@tonic-gate 
1711*7c478bd9Sstevel@tonic-gate 		if (dnum > L_MAXMAJ32) {
1712*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MAJ_TOOBIG), drv,
1713*7c478bd9Sstevel@tonic-gate 			    dnum, filename, L_MAXMAJ32);
1714*7c478bd9Sstevel@tonic-gate 			continue;
1715*7c478bd9Sstevel@tonic-gate 		}
1716*7c478bd9Sstevel@tonic-gate 		/*
1717*7c478bd9Sstevel@tonic-gate 		 * cast down to a major_t; we can be sure this is safe because
1718*7c478bd9Sstevel@tonic-gate 		 * of the above range-check.
1719*7c478bd9Sstevel@tonic-gate 		 */
1720*7c478bd9Sstevel@tonic-gate 		drv_majnum = (major_t)dnum;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 		if (drv_majnum >= *nelems) {
1723*7c478bd9Sstevel@tonic-gate 			/*
1724*7c478bd9Sstevel@tonic-gate 			 * Allocate some more space, up to drv_majnum + 1 so
1725*7c478bd9Sstevel@tonic-gate 			 * we can accomodate 0 through drv_majnum.
1726*7c478bd9Sstevel@tonic-gate 			 *
1727*7c478bd9Sstevel@tonic-gate 			 * Note that in the failure case, we leak all of the
1728*7c478bd9Sstevel@tonic-gate 			 * old contents of array.  It's ok, since we just
1729*7c478bd9Sstevel@tonic-gate 			 * wind up exiting immediately anyway.
1730*7c478bd9Sstevel@tonic-gate 			 */
1731*7c478bd9Sstevel@tonic-gate 			*nelems = drv_majnum + 1;
1732*7c478bd9Sstevel@tonic-gate 			*array = realloc(*array, *nelems);
1733*7c478bd9Sstevel@tonic-gate 			if (*array == NULL) {
1734*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
1735*7c478bd9Sstevel@tonic-gate 				return (ERROR);
1736*7c478bd9Sstevel@tonic-gate 			}
1737*7c478bd9Sstevel@tonic-gate 		}
1738*7c478bd9Sstevel@tonic-gate 		(*array)[drv_majnum] = 1;
1739*7c478bd9Sstevel@tonic-gate 	}
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
1742*7c478bd9Sstevel@tonic-gate 	return (0);
1743*7c478bd9Sstevel@tonic-gate }
1744*7c478bd9Sstevel@tonic-gate 
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate int
1747*7c478bd9Sstevel@tonic-gate do_the_update(char *driver_name, char *major_number)
1748*7c478bd9Sstevel@tonic-gate {
1749*7c478bd9Sstevel@tonic-gate 	return (append_to_file(driver_name, major_number, name_to_major,
1750*7c478bd9Sstevel@tonic-gate 	    ' ', " "));
1751*7c478bd9Sstevel@tonic-gate }
1752