xref: /onnv-gate/usr/src/cmd/modload/drvsubr.c (revision 10842:e5e88c478ff5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52805Seota  * Common Development and Distribution License (the "License").
62805Seota  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
228831SJerry.Gilliam@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <stdlib.h>
282805Seota #include <ctype.h>
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <wait.h>
330Sstevel@tonic-gate #include <string.h>
348331SJerry.Gilliam@Sun.COM #include <strings.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <fcntl.h>
370Sstevel@tonic-gate #include <signal.h>
380Sstevel@tonic-gate #include <sys/buf.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <grp.h>
410Sstevel@tonic-gate #include "addrem.h"
420Sstevel@tonic-gate #include "errmsg.h"
430Sstevel@tonic-gate #include "plcysubr.h"
440Sstevel@tonic-gate 
4510599SJerry.Gilliam@Sun.COM /*
4610599SJerry.Gilliam@Sun.COM  * Macros to produce a quoted string containing the value of a
4710599SJerry.Gilliam@Sun.COM  * preprocessor macro. For example, if SIZE is defined to be 256,
4810599SJerry.Gilliam@Sun.COM  * VAL2STR(SIZE) is "256". This is used to construct format
4910599SJerry.Gilliam@Sun.COM  * strings for scanf-family functions below.
5010599SJerry.Gilliam@Sun.COM  * Note: For format string use, the argument to VAL2STR() must
5110599SJerry.Gilliam@Sun.COM  * be a numeric constant that is one less than the size of the
5210599SJerry.Gilliam@Sun.COM  * corresponding data buffer.
5310599SJerry.Gilliam@Sun.COM  */
5410599SJerry.Gilliam@Sun.COM #define	VAL2STR_QUOTE(x)	#x
5510599SJerry.Gilliam@Sun.COM #define	VAL2STR(x)		VAL2STR_QUOTE(x)
5610599SJerry.Gilliam@Sun.COM 
5710599SJerry.Gilliam@Sun.COM /*
5810599SJerry.Gilliam@Sun.COM  * Convenience macro to determine if a character is a quote
5910599SJerry.Gilliam@Sun.COM  */
6010599SJerry.Gilliam@Sun.COM #define	isquote(c)	(((c) == '"') || ((c) == '\''))
6110599SJerry.Gilliam@Sun.COM 
6210599SJerry.Gilliam@Sun.COM 
630Sstevel@tonic-gate static char *add_rem_lock;	/* lock file */
6410599SJerry.Gilliam@Sun.COM static char *tmphold;		/* temporary file for updating */
653442Svikram static int  add_rem_lock_fd = -1;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static int get_cached_n_to_m_file(char *filename, char ***cache);
680Sstevel@tonic-gate static int get_name_to_major_entry(int *major_no, char *driver_name,
690Sstevel@tonic-gate     char *file_name);
700Sstevel@tonic-gate 
712805Seota static int is_blank(char *);
722805Seota 
730Sstevel@tonic-gate /*ARGSUSED*/
740Sstevel@tonic-gate void
log_minorperm_error(minorperm_err_t err,int key)750Sstevel@tonic-gate log_minorperm_error(minorperm_err_t err, int key)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	switch (err) {
780Sstevel@tonic-gate 	case MP_FOPEN_ERR:
790Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
808331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
810Sstevel@tonic-gate 		break;
820Sstevel@tonic-gate 	case MP_FCLOSE_ERR:
830Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
848331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
850Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
860Sstevel@tonic-gate 		break;
870Sstevel@tonic-gate 	case MP_IGNORING_LINE_ERR:
880Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
898331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
900Sstevel@tonic-gate 		break;
910Sstevel@tonic-gate 	case MP_ALLOC_ERR:
920Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
938331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
940Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
950Sstevel@tonic-gate 		break;
960Sstevel@tonic-gate 	case MP_NVLIST_ERR:
970Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
988331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
990Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1000Sstevel@tonic-gate 		break;
1010Sstevel@tonic-gate 	case MP_CANT_FIND_USER_ERR:
1020Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1038331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
1040Sstevel@tonic-gate 		break;
1050Sstevel@tonic-gate 	case MP_CANT_FIND_GROUP_ERR:
1060Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1078331SJerry.Gilliam@Sun.COM 		    MINOR_PERM_FILE);
1080Sstevel@tonic-gate 		break;
1090Sstevel@tonic-gate 	}
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  *  open file
1140Sstevel@tonic-gate  * for each entry in list
1150Sstevel@tonic-gate  *	where list entries are separated by <list_separator>
1160Sstevel@tonic-gate  * 	append entry : driver_name <entry_separator> entry
1170Sstevel@tonic-gate  * close file
1180Sstevel@tonic-gate  * return error/noerr
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate int
append_to_file(char * driver_name,char * entry_list,char * filename,char list_separator,char * entry_separator,int quoted)1210Sstevel@tonic-gate append_to_file(
1220Sstevel@tonic-gate 	char *driver_name,
1230Sstevel@tonic-gate 	char *entry_list,
1240Sstevel@tonic-gate 	char *filename,
1250Sstevel@tonic-gate 	char list_separator,
1264145Scth 	char *entry_separator,
1274145Scth 	int quoted)
1280Sstevel@tonic-gate {
12910599SJerry.Gilliam@Sun.COM 	int	len, line_len;
1300Sstevel@tonic-gate 	int	fpint;
1310Sstevel@tonic-gate 	char	*current_head, *previous_head;
1320Sstevel@tonic-gate 	char	*line, *one_entry;
1330Sstevel@tonic-gate 	FILE	*fp;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	if ((fp = fopen(filename, "a")) == NULL) {
1360Sstevel@tonic-gate 		perror(NULL);
1370Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
1380Sstevel@tonic-gate 		    filename);
1390Sstevel@tonic-gate 		return (ERROR);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	len = strlen(entry_list);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	one_entry = calloc(len + 1, 1);
1450Sstevel@tonic-gate 	if (one_entry == NULL) {
1460Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename);
1470Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1480Sstevel@tonic-gate 		(void) fclose(fp);
1490Sstevel@tonic-gate 		return (ERROR);
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	previous_head = entry_list;
1530Sstevel@tonic-gate 
15410354SEdward.Pilatowicz@Sun.COM 	line_len = strlen(driver_name) + len + 4;
15510354SEdward.Pilatowicz@Sun.COM 	if (quoted)
15610354SEdward.Pilatowicz@Sun.COM 		line_len += 2;
15710354SEdward.Pilatowicz@Sun.COM 
15810354SEdward.Pilatowicz@Sun.COM 	line = calloc(line_len, 1);
1590Sstevel@tonic-gate 	if (line == NULL) {
1600Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1610Sstevel@tonic-gate 		(void) fclose(fp);
1620Sstevel@tonic-gate 		err_exit();
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	/*
1660Sstevel@tonic-gate 	 * get one entry at a time from list and append to <filename> file
1670Sstevel@tonic-gate 	 */
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	do {
17010599SJerry.Gilliam@Sun.COM 		bzero(one_entry, len + 1);
17110354SEdward.Pilatowicz@Sun.COM 		bzero(line, line_len);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 		current_head = get_entry(previous_head, one_entry,
1744145Scth 		    list_separator, quoted);
1750Sstevel@tonic-gate 		previous_head = current_head;
1760Sstevel@tonic-gate 
17710599SJerry.Gilliam@Sun.COM 		(void) snprintf(line, line_len,
17810599SJerry.Gilliam@Sun.COM 		    quoted ? "%s%s\"%s\"\n" : "%s%s%s\n",
17910599SJerry.Gilliam@Sun.COM 		    driver_name, entry_separator, one_entry);
18010599SJerry.Gilliam@Sun.COM 
18110599SJerry.Gilliam@Sun.COM 		if ((fputs(line, fp)) == EOF) {
18210599SJerry.Gilliam@Sun.COM 			perror(NULL);
18310599SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
18410599SJerry.Gilliam@Sun.COM 			    filename);
18510599SJerry.Gilliam@Sun.COM 		}
18610599SJerry.Gilliam@Sun.COM 
18710599SJerry.Gilliam@Sun.COM 	} while (*current_head != '\0');
18810599SJerry.Gilliam@Sun.COM 
18910599SJerry.Gilliam@Sun.COM 
19010599SJerry.Gilliam@Sun.COM 	(void) fflush(fp);
19110599SJerry.Gilliam@Sun.COM 
19210599SJerry.Gilliam@Sun.COM 	fpint = fileno(fp);
19310599SJerry.Gilliam@Sun.COM 	(void) fsync(fpint);
19410599SJerry.Gilliam@Sun.COM 
19510599SJerry.Gilliam@Sun.COM 	(void) fclose(fp);
19610599SJerry.Gilliam@Sun.COM 
19710599SJerry.Gilliam@Sun.COM 	free(one_entry);
19810599SJerry.Gilliam@Sun.COM 	free(line);
19910599SJerry.Gilliam@Sun.COM 
20010599SJerry.Gilliam@Sun.COM 	return (NOERR);
20110599SJerry.Gilliam@Sun.COM }
20210599SJerry.Gilliam@Sun.COM 
20310599SJerry.Gilliam@Sun.COM /*
20410599SJerry.Gilliam@Sun.COM  *  open file
20510599SJerry.Gilliam@Sun.COM  * for each entry in list
20610599SJerry.Gilliam@Sun.COM  *	where list entries are separated by <list_separator>
20710599SJerry.Gilliam@Sun.COM  * 	append entry : driver_name <entry_separator> entry
20810599SJerry.Gilliam@Sun.COM  * close file
20910599SJerry.Gilliam@Sun.COM  * return error/noerr
21010599SJerry.Gilliam@Sun.COM  */
21110599SJerry.Gilliam@Sun.COM int
append_to_minor_perm(char * driver_name,char * entry_list,char * filename)21210599SJerry.Gilliam@Sun.COM append_to_minor_perm(
21310599SJerry.Gilliam@Sun.COM 	char *driver_name,
21410599SJerry.Gilliam@Sun.COM 	char *entry_list,
21510599SJerry.Gilliam@Sun.COM 	char *filename)
21610599SJerry.Gilliam@Sun.COM {
21710599SJerry.Gilliam@Sun.COM 	int	len, line_len;
21810599SJerry.Gilliam@Sun.COM 	int	fpint;
21910599SJerry.Gilliam@Sun.COM 	char	*current_head, *previous_head;
22010599SJerry.Gilliam@Sun.COM 	char	*line, *one_entry;
22110599SJerry.Gilliam@Sun.COM 	FILE	*fp;
22210599SJerry.Gilliam@Sun.COM 
22310599SJerry.Gilliam@Sun.COM 	if ((fp = fopen(filename, "a")) == NULL) {
22410599SJerry.Gilliam@Sun.COM 		perror(NULL);
22510599SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
22610599SJerry.Gilliam@Sun.COM 		    filename);
22710599SJerry.Gilliam@Sun.COM 		return (ERROR);
22810599SJerry.Gilliam@Sun.COM 	}
22910599SJerry.Gilliam@Sun.COM 
23010599SJerry.Gilliam@Sun.COM 	len = strlen(entry_list);
23110599SJerry.Gilliam@Sun.COM 
23210599SJerry.Gilliam@Sun.COM 	one_entry = calloc(len + 1, 1);
23310599SJerry.Gilliam@Sun.COM 	if (one_entry == NULL) {
23410599SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename);
23510599SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
23610599SJerry.Gilliam@Sun.COM 		(void) fclose(fp);
23710599SJerry.Gilliam@Sun.COM 		return (ERROR);
23810599SJerry.Gilliam@Sun.COM 	}
23910599SJerry.Gilliam@Sun.COM 
24010599SJerry.Gilliam@Sun.COM 	previous_head = entry_list;
24110599SJerry.Gilliam@Sun.COM 
24210599SJerry.Gilliam@Sun.COM 	line_len = strlen(driver_name) + len + 4;
24310599SJerry.Gilliam@Sun.COM 	line = calloc(line_len, 1);
24410599SJerry.Gilliam@Sun.COM 	if (line == NULL) {
24510599SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
24610599SJerry.Gilliam@Sun.COM 		(void) fclose(fp);
24710599SJerry.Gilliam@Sun.COM 		err_exit();
24810599SJerry.Gilliam@Sun.COM 	}
24910599SJerry.Gilliam@Sun.COM 
25010599SJerry.Gilliam@Sun.COM 	/*
25110599SJerry.Gilliam@Sun.COM 	 * get one entry at a time from list and append to <filename> file
25210599SJerry.Gilliam@Sun.COM 	 */
25310599SJerry.Gilliam@Sun.COM 	do {
25410599SJerry.Gilliam@Sun.COM 		bzero(one_entry, len + 1);
25510599SJerry.Gilliam@Sun.COM 		bzero(line, line_len);
25610599SJerry.Gilliam@Sun.COM 
25710599SJerry.Gilliam@Sun.COM 		current_head = get_perm_entry(previous_head, one_entry);
25810599SJerry.Gilliam@Sun.COM 		previous_head = current_head;
25910599SJerry.Gilliam@Sun.COM 
26010599SJerry.Gilliam@Sun.COM 		(void) snprintf(line, line_len, "%s:%s\n",
26110599SJerry.Gilliam@Sun.COM 		    driver_name, one_entry);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		if ((fputs(line, fp)) == EOF) {
2640Sstevel@tonic-gate 			perror(NULL);
2650Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
2660Sstevel@tonic-gate 			    filename);
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	} while (*current_head != '\0');
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	(void) fflush(fp);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	fpint = fileno(fp);
2750Sstevel@tonic-gate 	(void) fsync(fpint);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	(void) fclose(fp);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	free(one_entry);
2800Sstevel@tonic-gate 	free(line);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	return (NOERR);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2858456SJerry.Gilliam@Sun.COM /*
2868456SJerry.Gilliam@Sun.COM  * Require exact match to delete a driver alias/permission entry.
2878456SJerry.Gilliam@Sun.COM  * Note line argument does not remain unchanged.  Return 1 if matched.
2888456SJerry.Gilliam@Sun.COM  */
2898456SJerry.Gilliam@Sun.COM static int
match_entry(char * line,char * match)2908456SJerry.Gilliam@Sun.COM match_entry(char *line, char *match)
2918456SJerry.Gilliam@Sun.COM {
2928456SJerry.Gilliam@Sun.COM 	char	*token, *p;
2938456SJerry.Gilliam@Sun.COM 	int	n;
2948456SJerry.Gilliam@Sun.COM 
2958456SJerry.Gilliam@Sun.COM 	/* skip any leading white space */
29610599SJerry.Gilliam@Sun.COM 	while (*line && isspace(*line))
2978456SJerry.Gilliam@Sun.COM 		line++;
2988456SJerry.Gilliam@Sun.COM 	/*
2998456SJerry.Gilliam@Sun.COM 	 * Find separator for driver name, either space or colon
3008456SJerry.Gilliam@Sun.COM 	 *	minor_perm: <driver>:<perm>
3018456SJerry.Gilliam@Sun.COM 	 *	driver_aliases: <driver> <alias>
3028456SJerry.Gilliam@Sun.COM 	 *	extra_privs: <driver>:<priv>
3038456SJerry.Gilliam@Sun.COM 	 */
3048456SJerry.Gilliam@Sun.COM 	if ((token = strpbrk(line, " :\t")) == NULL)
3058456SJerry.Gilliam@Sun.COM 		return (0);
3068456SJerry.Gilliam@Sun.COM 	token++;
3078456SJerry.Gilliam@Sun.COM 	/* skip leading white space and quotes */
30810599SJerry.Gilliam@Sun.COM 	while (*token && (isspace(*token) || isquote(*token)))
3098456SJerry.Gilliam@Sun.COM 		token++;
3108456SJerry.Gilliam@Sun.COM 	/* strip trailing newline, white space and quotes */
3118456SJerry.Gilliam@Sun.COM 	n = strlen(token);
3128456SJerry.Gilliam@Sun.COM 	p = token + n-1;
31310599SJerry.Gilliam@Sun.COM 	while (n > 0 && (*p == '\n' || isspace(*p) || isquote(*p))) {
3148456SJerry.Gilliam@Sun.COM 		*p-- = 0;
3158456SJerry.Gilliam@Sun.COM 		n--;
3168456SJerry.Gilliam@Sun.COM 	}
3178456SJerry.Gilliam@Sun.COM 	if (n == 0)
3188456SJerry.Gilliam@Sun.COM 		return (0);
3198456SJerry.Gilliam@Sun.COM 	return (strcmp(token, match) == 0);
3208456SJerry.Gilliam@Sun.COM }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate  *  open file
3240Sstevel@tonic-gate  * read thru file, deleting all entries if first
3250Sstevel@tonic-gate  *    entry = driver_name
3260Sstevel@tonic-gate  * close
3270Sstevel@tonic-gate  * if error, leave original file intact with message
3280Sstevel@tonic-gate  * assumption : drvconfig has been modified to work with clone
3290Sstevel@tonic-gate  *  entries in /etc/minor_perm as driver:mummble NOT
3300Sstevel@tonic-gate  *  clone:driver mummble
3310Sstevel@tonic-gate  * this implementation will NOT find clone entries
3320Sstevel@tonic-gate  * clone:driver mummble
3330Sstevel@tonic-gate  * match:
3340Sstevel@tonic-gate  *	delete just the matching entry
3350Sstevel@tonic-gate  *
3360Sstevel@tonic-gate  */
3370Sstevel@tonic-gate int
delete_entry(char * oldfile,char * driver_name,char * marker,char * match)3380Sstevel@tonic-gate delete_entry(
3390Sstevel@tonic-gate 	char *oldfile,
3400Sstevel@tonic-gate 	char *driver_name,
3410Sstevel@tonic-gate 	char *marker,
3420Sstevel@tonic-gate 	char *match)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	int		rv, i;
3450Sstevel@tonic-gate 	int		status = NOERR;
3460Sstevel@tonic-gate 	int		drvr_found = 0;
3470Sstevel@tonic-gate 	boolean_t 	nomatch = B_TRUE;
3488456SJerry.Gilliam@Sun.COM 	char		*newfile, *tptr, *cp;
34910599SJerry.Gilliam@Sun.COM 	char		line[MAX_DBFILE_ENTRY];
35010599SJerry.Gilliam@Sun.COM 	char		drv[FILENAME_MAX + 1];
3510Sstevel@tonic-gate 	FILE		*fp, *newfp;
3520Sstevel@tonic-gate 	struct group	*sysgrp;
3538456SJerry.Gilliam@Sun.COM 	char		*copy;		/* same size as line */
3549268SJerry.Gilliam@Sun.COM 	char		*match2 = NULL;	/* match with quotes cleaned up */
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/*
3579268SJerry.Gilliam@Sun.COM 	 * if match is specified, sanity check it and clean it
3589268SJerry.Gilliam@Sun.COM 	 * up by removing surrounding quotes as we require
3599268SJerry.Gilliam@Sun.COM 	 * an exact match.
3600Sstevel@tonic-gate 	 */
3619268SJerry.Gilliam@Sun.COM 	if (match) {
3629268SJerry.Gilliam@Sun.COM 		cp = match;
36310599SJerry.Gilliam@Sun.COM 		while (*cp && (isspace(*cp)))
3649268SJerry.Gilliam@Sun.COM 			cp++;
3659268SJerry.Gilliam@Sun.COM 		i = strlen(cp);
3669268SJerry.Gilliam@Sun.COM 		if (i > 0) {
3679268SJerry.Gilliam@Sun.COM 			if ((match2 = strdup(cp)) == NULL) {
3689268SJerry.Gilliam@Sun.COM 				perror(NULL);
3699268SJerry.Gilliam@Sun.COM 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
3709268SJerry.Gilliam@Sun.COM 				return (ERROR);
3719268SJerry.Gilliam@Sun.COM 			}
37210599SJerry.Gilliam@Sun.COM 			i = strlen(match2) - 1;
37310599SJerry.Gilliam@Sun.COM 			while (i >= 0 && (isspace(match2[i]))) {
37410599SJerry.Gilliam@Sun.COM 				match2[i] = 0;
37510599SJerry.Gilliam@Sun.COM 				i--;
37610599SJerry.Gilliam@Sun.COM 			}
3779268SJerry.Gilliam@Sun.COM 		}
3789268SJerry.Gilliam@Sun.COM 		if (match2 == NULL || (strlen(match2) == 0)) {
3799268SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr,
3809268SJerry.Gilliam@Sun.COM 			    gettext(ERR_INT_UPDATE), oldfile);
3819268SJerry.Gilliam@Sun.COM 			return (ERROR);
3829268SJerry.Gilliam@Sun.COM 		}
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if ((fp = fopen(oldfile, "r")) == NULL) {
3860Sstevel@tonic-gate 		perror(NULL);
3870Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile);
3880Sstevel@tonic-gate 		return (ERROR);
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3918456SJerry.Gilliam@Sun.COM 	/* Space for defensive copy of input line */
3928456SJerry.Gilliam@Sun.COM 	copy = calloc(sizeof (line), 1);
3930Sstevel@tonic-gate 
3948456SJerry.Gilliam@Sun.COM 	/* Build filename for temporary file */
3958456SJerry.Gilliam@Sun.COM 	tptr = calloc(strlen(oldfile) + strlen(XEND) + 1, 1);
3968456SJerry.Gilliam@Sun.COM 	if (tptr == NULL || copy == NULL) {
3970Sstevel@tonic-gate 		perror(NULL);
3980Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
3998456SJerry.Gilliam@Sun.COM 		return (ERROR);
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	(void) strcpy(tptr, oldfile);
4030Sstevel@tonic-gate 	(void) strcat(tptr, XEND);
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * Set gid so we preserve group attribute.  Ideally we wouldn't
4070Sstevel@tonic-gate 	 * assume a gid of "sys" but we can't undo the damage on already
4080Sstevel@tonic-gate 	 * installed systems unless we force the issue.
4090Sstevel@tonic-gate 	 */
4100Sstevel@tonic-gate 	if ((sysgrp = getgrnam("sys")) != NULL) {
4110Sstevel@tonic-gate 		(void) setgid(sysgrp->gr_gid);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	newfile = mktemp(tptr);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	if ((newfp = fopen(newfile, "w")) == NULL) {
4170Sstevel@tonic-gate 		perror(NULL);
4180Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
4190Sstevel@tonic-gate 		    newfile);
4200Sstevel@tonic-gate 		return (ERROR);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) {
4248456SJerry.Gilliam@Sun.COM 		/* copy the whole line */
4258456SJerry.Gilliam@Sun.COM 		if (strlcpy(copy, line, sizeof (line)) >= sizeof (line)) {
4268456SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
4272805Seota 			status = ERROR;
4282805Seota 			break;
4292805Seota 		}
4302805Seota 		/* cut off comments starting with '#' */
4318456SJerry.Gilliam@Sun.COM 		if ((cp = strchr(copy, '#')) != NULL)
4322805Seota 			*cp = '\0';
4332805Seota 		/* ignore comment or blank lines */
4348456SJerry.Gilliam@Sun.COM 		if (is_blank(copy)) {
4352805Seota 			if (fputs(line, newfp) == EOF) {
4360Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
4370Sstevel@tonic-gate 				    oldfile);
4380Sstevel@tonic-gate 				status = ERROR;
4390Sstevel@tonic-gate 			}
4400Sstevel@tonic-gate 			continue;
4410Sstevel@tonic-gate 		}
4422805Seota 
4432805Seota 		/* get the driver name */
44410599SJerry.Gilliam@Sun.COM 		if (sscanf(copy, "%" VAL2STR(FILENAME_MAX) "s", drv) != 1) {
4450Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
4460Sstevel@tonic-gate 			    oldfile, line);
4470Sstevel@tonic-gate 			status = ERROR;
4482805Seota 			break;
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) {
4520Sstevel@tonic-gate 			drv[i] =  '\0';
4530Sstevel@tonic-gate 		}
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		if (strcmp(driver_name, drv) != 0) {
4560Sstevel@tonic-gate 			if ((fputs(line, newfp)) == EOF) {
4570Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
4580Sstevel@tonic-gate 				    oldfile);
4590Sstevel@tonic-gate 				status = ERROR;
4600Sstevel@tonic-gate 			}
4610Sstevel@tonic-gate 		} else {
4620Sstevel@tonic-gate 			drvr_found++;
4639268SJerry.Gilliam@Sun.COM 			if (match2) {	/* Just delete one entry */
4640Sstevel@tonic-gate 				/* for now delete just minor_perm and aliases */
4650Sstevel@tonic-gate 				if ((strcmp(oldfile, minor_perm) == 0) ||
4660Sstevel@tonic-gate 				    (strcmp(oldfile, extra_privs) == 0) ||
4670Sstevel@tonic-gate 				    (strcmp(oldfile, driver_aliases) == 0)) {
4688456SJerry.Gilliam@Sun.COM 
4698456SJerry.Gilliam@Sun.COM 					/* make defensive copy */
4708456SJerry.Gilliam@Sun.COM 					if (strlcpy(copy, line, sizeof (line))
4718456SJerry.Gilliam@Sun.COM 					    >= sizeof (line)) {
4728456SJerry.Gilliam@Sun.COM 						(void) fprintf(stderr,
4738456SJerry.Gilliam@Sun.COM 						    gettext(ERR_UPDATE),
4748456SJerry.Gilliam@Sun.COM 						    oldfile);
4758456SJerry.Gilliam@Sun.COM 						status = ERROR;
4768456SJerry.Gilliam@Sun.COM 						break;
4778456SJerry.Gilliam@Sun.COM 					}
4789268SJerry.Gilliam@Sun.COM 					if (match_entry(copy, match2)) {
4790Sstevel@tonic-gate 						nomatch = B_FALSE;
4800Sstevel@tonic-gate 					} else {
4810Sstevel@tonic-gate 						if ((fputs(line, newfp)) ==
4820Sstevel@tonic-gate 						    EOF) {
4830Sstevel@tonic-gate 							(void) fprintf(stderr,
4840Sstevel@tonic-gate 							    gettext(ERR_UPDATE),
4850Sstevel@tonic-gate 							    oldfile);
4860Sstevel@tonic-gate 							status = ERROR;
4870Sstevel@tonic-gate 						}
4880Sstevel@tonic-gate 						if (nomatch != B_FALSE)
4890Sstevel@tonic-gate 							nomatch = B_TRUE;
4900Sstevel@tonic-gate 					}
4910Sstevel@tonic-gate 				}
4920Sstevel@tonic-gate 			}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		} /* end of else */
4950Sstevel@tonic-gate 	} /* end of while */
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	(void) fclose(fp);
4988456SJerry.Gilliam@Sun.COM 	free(tptr);
4998456SJerry.Gilliam@Sun.COM 	free(copy);
5009268SJerry.Gilliam@Sun.COM 	if (match2)
5019268SJerry.Gilliam@Sun.COM 		free(match2);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	/* Make sure that the file is on disk */
5040Sstevel@tonic-gate 	if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0)
5050Sstevel@tonic-gate 		status = ERROR;
5060Sstevel@tonic-gate 	else
5070Sstevel@tonic-gate 		rv = NOERR;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	(void) fclose(newfp);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/* no matching driver found */
5120Sstevel@tonic-gate 	rv = NOERR;
5130Sstevel@tonic-gate 	if (!drvr_found ||
5140Sstevel@tonic-gate 	    (nomatch == B_TRUE)) {
5150Sstevel@tonic-gate 		rv = NONE_FOUND;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*
5190Sstevel@tonic-gate 	 * if error, leave original file, delete new file
5200Sstevel@tonic-gate 	 * if noerr, replace original file with new file
5210Sstevel@tonic-gate 	 */
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (status == NOERR) {
5240Sstevel@tonic-gate 		if (rename(oldfile, tmphold) == -1) {
5250Sstevel@tonic-gate 			perror(NULL);
5260Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
5270Sstevel@tonic-gate 			(void) unlink(newfile);
5280Sstevel@tonic-gate 			return (ERROR);
5290Sstevel@tonic-gate 		} else if (rename(newfile, oldfile) == -1) {
5300Sstevel@tonic-gate 			perror(NULL);
5310Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
5320Sstevel@tonic-gate 			(void) unlink(oldfile);
5330Sstevel@tonic-gate 			(void) unlink(newfile);
5340Sstevel@tonic-gate 			if (link(tmphold, oldfile) == -1) {
5350Sstevel@tonic-gate 				perror(NULL);
5360Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINK),
5370Sstevel@tonic-gate 				    oldfile, tmphold);
5380Sstevel@tonic-gate 			}
5390Sstevel@tonic-gate 			return (ERROR);
5400Sstevel@tonic-gate 		}
5410Sstevel@tonic-gate 		(void) unlink(tmphold);
5420Sstevel@tonic-gate 	} else {
5430Sstevel@tonic-gate 		/*
5440Sstevel@tonic-gate 		 * since there's an error, leave file alone; remove
5450Sstevel@tonic-gate 		 * new file
5460Sstevel@tonic-gate 		 */
5470Sstevel@tonic-gate 		if (unlink(newfile) == -1) {
5480Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_RM), newfile);
5490Sstevel@tonic-gate 		}
5500Sstevel@tonic-gate 		return (ERROR);
5510Sstevel@tonic-gate 	}
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	return (rv);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate  * wrapper for call to get_name_to_major_entry(): given driver name,
5590Sstevel@tonic-gate  * retrieve major number.
5600Sstevel@tonic-gate  */
5610Sstevel@tonic-gate int
get_major_no(char * driver_name,char * file_name)5620Sstevel@tonic-gate get_major_no(char *driver_name, char *file_name)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 	int major = UNIQUE;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if (get_name_to_major_entry(&major, driver_name, file_name) == ERROR)
5670Sstevel@tonic-gate 		return (ERROR);
5680Sstevel@tonic-gate 	else
5690Sstevel@tonic-gate 		return (major);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate  * wrapper for call to get_name_to_major_entry(): given major number,
5740Sstevel@tonic-gate  * retrieve driver name.
5750Sstevel@tonic-gate  */
5760Sstevel@tonic-gate int
get_driver_name(int major,char * file_name,char * buf)5770Sstevel@tonic-gate get_driver_name(int major, char *file_name, char *buf)
5780Sstevel@tonic-gate {
5790Sstevel@tonic-gate 	if (major < 0)
5800Sstevel@tonic-gate 		return (ERROR);
5810Sstevel@tonic-gate 	return (get_name_to_major_entry(&major, buf, file_name));
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate /*
5860Sstevel@tonic-gate  * return pointer to cached name_to_major file - reads file into
5870Sstevel@tonic-gate  * cache if this has not already been done.  Since there may be
5880Sstevel@tonic-gate  * requests for multiple name_to_major files (rem_name_to_major,
5890Sstevel@tonic-gate  * name_to_major), this routine keeps a list of cached files.
5900Sstevel@tonic-gate  */
5910Sstevel@tonic-gate static int
get_cached_n_to_m_file(char * filename,char *** cache)5920Sstevel@tonic-gate get_cached_n_to_m_file(char *filename, char ***cache)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate 	struct n_to_m_cache {
5950Sstevel@tonic-gate 		char *file;
5960Sstevel@tonic-gate 		char **cached_file;
5970Sstevel@tonic-gate 		int size;
5980Sstevel@tonic-gate 		struct n_to_m_cache *next;
5990Sstevel@tonic-gate 	};
6000Sstevel@tonic-gate 	static struct n_to_m_cache *head = NULL;
6010Sstevel@tonic-gate 	struct n_to_m_cache *ptr;
6020Sstevel@tonic-gate 	FILE *fp;
6030Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
6040Sstevel@tonic-gate 	char entry[FILENAME_MAX + 1];
6052805Seota 	char line[MAX_N2M_ALIAS_LINE], *cp;
6060Sstevel@tonic-gate 	int maj;
6070Sstevel@tonic-gate 	int size = 0;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	/*
6110Sstevel@tonic-gate 	 * see if the file is already cached - either
6120Sstevel@tonic-gate 	 * rem_name_to_major or name_to_major
6130Sstevel@tonic-gate 	 */
6140Sstevel@tonic-gate 	ptr = head;
6150Sstevel@tonic-gate 	while (ptr != NULL) {
6160Sstevel@tonic-gate 		if (strcmp(ptr->file, filename) == 0)
6170Sstevel@tonic-gate 			break;
6180Sstevel@tonic-gate 		ptr = ptr->next;
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (ptr == NULL) {	/* we need to cache the contents */
6220Sstevel@tonic-gate 		if ((fp = fopen(filename, "r")) == NULL) {
6230Sstevel@tonic-gate 			perror(NULL);
6240Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_OPEN),
6250Sstevel@tonic-gate 			    filename);
6260Sstevel@tonic-gate 			return (ERROR);
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		while (fgets(line, sizeof (line), fp) != NULL) {
6302805Seota 			/* cut off comments starting with '#' */
6312805Seota 			if ((cp = strchr(line, '#')) != NULL)
6322805Seota 				*cp = '\0';
6332805Seota 			/* ignore comment or blank lines */
6342805Seota 			if (is_blank(line))
6352805Seota 				continue;
6362805Seota 			/* sanity-check */
63710599SJerry.Gilliam@Sun.COM 			if (sscanf(line,
63810599SJerry.Gilliam@Sun.COM 			    "%" VAL2STR(FILENAME_MAX) "s"	/* drv */
63910599SJerry.Gilliam@Sun.COM 			    "%" VAL2STR(FILENAME_MAX) "s",	/* entry */
64010599SJerry.Gilliam@Sun.COM 			    drv, entry) != 2) {
6410Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
6420Sstevel@tonic-gate 				    filename, line);
6430Sstevel@tonic-gate 				continue;
6440Sstevel@tonic-gate 			}
6450Sstevel@tonic-gate 			maj = atoi(entry);
6460Sstevel@tonic-gate 			if (maj > size)
6470Sstevel@tonic-gate 				size = maj;
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		/* allocate struct to cache the file */
6510Sstevel@tonic-gate 		ptr = (struct n_to_m_cache *)calloc(1,
6520Sstevel@tonic-gate 		    sizeof (struct n_to_m_cache));
6530Sstevel@tonic-gate 		if (ptr == NULL) {
6540Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
6550Sstevel@tonic-gate 			return (ERROR);
6560Sstevel@tonic-gate 		}
6570Sstevel@tonic-gate 		ptr->size = size + 1;
6580Sstevel@tonic-gate 		/* allocate space to cache contents of file */
6590Sstevel@tonic-gate 		ptr->cached_file = (char **)calloc(ptr->size, sizeof (char *));
6600Sstevel@tonic-gate 		if (ptr->cached_file == NULL) {
6610Sstevel@tonic-gate 			free(ptr);
6620Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
6630Sstevel@tonic-gate 			return (ERROR);
6640Sstevel@tonic-gate 		}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 		rewind(fp);
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 		/*
6690Sstevel@tonic-gate 		 * now fill the cache
6700Sstevel@tonic-gate 		 * the cache is an array of char pointers indexed by major
6710Sstevel@tonic-gate 		 * number
6720Sstevel@tonic-gate 		 */
6730Sstevel@tonic-gate 		while (fgets(line, sizeof (line), fp) != NULL) {
6742805Seota 			/* cut off comments starting with '#' */
6752805Seota 			if ((cp = strchr(line, '#')) != NULL)
6762805Seota 				*cp = '\0';
6772805Seota 			/* ignore comment or blank lines */
6782805Seota 			if (is_blank(line))
6792805Seota 				continue;
6802805Seota 			/* sanity-check */
68110599SJerry.Gilliam@Sun.COM 			if (sscanf(line,
68210599SJerry.Gilliam@Sun.COM 			    "%" VAL2STR(FILENAME_MAX) "s"	/* drv */
68310599SJerry.Gilliam@Sun.COM 			    "%" VAL2STR(FILENAME_MAX) "s",	/* entry */
68410599SJerry.Gilliam@Sun.COM 			    drv, entry) != 2) {
6850Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
6860Sstevel@tonic-gate 				    filename, line);
6870Sstevel@tonic-gate 				continue;
6880Sstevel@tonic-gate 			}
6890Sstevel@tonic-gate 			maj = atoi(entry);
6900Sstevel@tonic-gate 			if ((ptr->cached_file[maj] = strdup(drv)) == NULL) {
6910Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
6920Sstevel@tonic-gate 				free(ptr->cached_file);
6930Sstevel@tonic-gate 				free(ptr);
6940Sstevel@tonic-gate 				return (ERROR);
6950Sstevel@tonic-gate 			}
6960Sstevel@tonic-gate 			(void) strcpy(ptr->cached_file[maj], drv);
6970Sstevel@tonic-gate 		}
6980Sstevel@tonic-gate 		(void) fclose(fp);
6990Sstevel@tonic-gate 		/* link the cache struct into the list of cached files */
7000Sstevel@tonic-gate 		ptr->file = strdup(filename);
7010Sstevel@tonic-gate 		if (ptr->file == NULL) {
7020Sstevel@tonic-gate 			for (maj = 0; maj <= ptr->size; maj++)
7030Sstevel@tonic-gate 				free(ptr->cached_file[maj]);
7040Sstevel@tonic-gate 			free(ptr->cached_file);
7050Sstevel@tonic-gate 			free(ptr);
7060Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
7070Sstevel@tonic-gate 			return (ERROR);
7080Sstevel@tonic-gate 		}
7090Sstevel@tonic-gate 		ptr->next = head;
7100Sstevel@tonic-gate 		head = ptr;
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 	/* return value pointer to contents of file */
7130Sstevel@tonic-gate 	*cache = ptr->cached_file;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/* return size */
7160Sstevel@tonic-gate 	return (ptr->size);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate  * Using get_cached_n_to_m_file(), retrieve maximum major number
7220Sstevel@tonic-gate  * found in the specificed file (name_to_major/rem_name_to_major).
7230Sstevel@tonic-gate  *
7240Sstevel@tonic-gate  * The return value is actually the size of the internal cache including 0.
7250Sstevel@tonic-gate  */
7260Sstevel@tonic-gate int
get_max_major(char * file_name)7270Sstevel@tonic-gate get_max_major(char *file_name)
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	char **n_to_m_cache = NULL;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	return (get_cached_n_to_m_file(file_name, &n_to_m_cache));
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * searching name_to_major: if major_no == UNIQUE then the caller wants to
7370Sstevel@tonic-gate  * use the driver name as the key.  Otherwise, the caller wants to use
7380Sstevel@tonic-gate  * the major number as a key.
7390Sstevel@tonic-gate  *
7400Sstevel@tonic-gate  * This routine caches the contents of the name_to_major file on
7410Sstevel@tonic-gate  * first call.  And it could be generalized to deal with other
7420Sstevel@tonic-gate  * config files if necessary.
7430Sstevel@tonic-gate  */
7440Sstevel@tonic-gate static int
get_name_to_major_entry(int * major_no,char * driver_name,char * file_name)7450Sstevel@tonic-gate get_name_to_major_entry(int *major_no, char *driver_name, char *file_name)
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	int maj;
7480Sstevel@tonic-gate 	char **n_to_m_cache = NULL;
7490Sstevel@tonic-gate 	int size = 0;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	int ret = NOT_UNIQUE;
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	/*
7540Sstevel@tonic-gate 	 * read the file in - we cache it in case caller wants to
7550Sstevel@tonic-gate 	 * do multiple lookups
7560Sstevel@tonic-gate 	 */
7570Sstevel@tonic-gate 	size = get_cached_n_to_m_file(file_name, &n_to_m_cache);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	if (size == ERROR)
7600Sstevel@tonic-gate 		return (ERROR);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	/* search with driver name as key */
7630Sstevel@tonic-gate 	if (*major_no == UNIQUE) {
7640Sstevel@tonic-gate 		for (maj = 0; maj < size; maj++) {
7650Sstevel@tonic-gate 			if ((n_to_m_cache[maj] != NULL) &&
7660Sstevel@tonic-gate 			    (strcmp(driver_name, n_to_m_cache[maj]) == 0)) {
7670Sstevel@tonic-gate 				*major_no = maj;
7680Sstevel@tonic-gate 				break;
7690Sstevel@tonic-gate 			}
7700Sstevel@tonic-gate 		}
7710Sstevel@tonic-gate 		if (maj >= size)
7720Sstevel@tonic-gate 			ret = UNIQUE;
7730Sstevel@tonic-gate 	/* search with major number as key */
7740Sstevel@tonic-gate 	} else {
7750Sstevel@tonic-gate 		/*
7760Sstevel@tonic-gate 		 * Bugid 1254588, drvconfig dump core after loading driver
7770Sstevel@tonic-gate 		 * with major number bigger than entries defined in
7780Sstevel@tonic-gate 		 * /etc/name_to_major.
7790Sstevel@tonic-gate 		 */
7800Sstevel@tonic-gate 		if (*major_no >= size)
7810Sstevel@tonic-gate 			return (UNIQUE);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 		if (n_to_m_cache[*major_no] != NULL) {
7840Sstevel@tonic-gate 			(void) strcpy(driver_name, n_to_m_cache[*major_no]);
7850Sstevel@tonic-gate 		} else
7860Sstevel@tonic-gate 			ret = UNIQUE;
7870Sstevel@tonic-gate 	}
7880Sstevel@tonic-gate 	return (ret);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /*
7924145Scth  * Given pointer to begining of member 'n' in a space (or separator)
7934145Scth  * separated list, return pointer to member 'n+1', and establish member 'n'
7944145Scth  * in *current_entry.  If unquote, then we skip a leading quote and treat
7954145Scth  * the trailing quote as a separator (and skip).
7960Sstevel@tonic-gate  */
7970Sstevel@tonic-gate char *
get_entry(char * prev_member,char * current_entry,char separator,int unquote)7980Sstevel@tonic-gate get_entry(
7990Sstevel@tonic-gate 	char *prev_member,
8000Sstevel@tonic-gate 	char *current_entry,
8014145Scth 	char separator,
8024145Scth 	int  unquote)
8030Sstevel@tonic-gate {
8044145Scth 	char	*ptr;
8054145Scth 	int	quoted = 0;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	ptr = prev_member;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/* skip white space */
81010599SJerry.Gilliam@Sun.COM 	while (isspace(*ptr))
8110Sstevel@tonic-gate 		ptr++;
8120Sstevel@tonic-gate 
8134145Scth 	/* if unquote skip leading quote */
8144145Scth 	if (unquote && *ptr == '"') {
8154145Scth 		quoted++;
8164145Scth 		ptr++;
8174145Scth 	}
8184145Scth 
8194145Scth 	/* read thru the current entry looking for end, separator, or unquote */
8204145Scth 	while (*ptr &&
82110599SJerry.Gilliam@Sun.COM 	    (*ptr != separator) && (!isspace(*ptr)) &&
8224145Scth 	    (!quoted || (*ptr != '"'))) {
8230Sstevel@tonic-gate 		*current_entry++ = *ptr++;
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate 	*current_entry = '\0';
8260Sstevel@tonic-gate 
8274145Scth 	if (separator && (*ptr == separator))
8284145Scth 		ptr++;	/* skip over separator */
8294145Scth 	if (quoted && (*ptr == '"'))
8304145Scth 		ptr++;	/* skip over trailing quote */
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	/* skip white space */
83310599SJerry.Gilliam@Sun.COM 	while (isspace(*ptr))
8340Sstevel@tonic-gate 		ptr++;
83510599SJerry.Gilliam@Sun.COM 
83610599SJerry.Gilliam@Sun.COM 	return (ptr);
83710599SJerry.Gilliam@Sun.COM }
83810599SJerry.Gilliam@Sun.COM 
83910599SJerry.Gilliam@Sun.COM /*
84010599SJerry.Gilliam@Sun.COM  * A parser specific to the add_drv "-m permission" syntax:
84110599SJerry.Gilliam@Sun.COM  *
84210599SJerry.Gilliam@Sun.COM  *	-m '<minor-name> <permissions> <owner> <group>', ...
84310599SJerry.Gilliam@Sun.COM  *
84410599SJerry.Gilliam@Sun.COM  * One entry is parsed starting at prev_member and returned
84510599SJerry.Gilliam@Sun.COM  * in the string pointed at by current_entry.  A pointer
84610599SJerry.Gilliam@Sun.COM  * to the entry following is returned.
84710599SJerry.Gilliam@Sun.COM  */
84810599SJerry.Gilliam@Sun.COM char *
get_perm_entry(char * prev_member,char * current_entry)84910599SJerry.Gilliam@Sun.COM get_perm_entry(
85010599SJerry.Gilliam@Sun.COM 	char *prev_member,
85110599SJerry.Gilliam@Sun.COM 	char *current_entry)
85210599SJerry.Gilliam@Sun.COM {
85310599SJerry.Gilliam@Sun.COM 	char	*ptr;
85410599SJerry.Gilliam@Sun.COM 	int	nfields = 0;
85510599SJerry.Gilliam@Sun.COM 	int	maxfields = 4;		/* fields in a permissions format */
85610599SJerry.Gilliam@Sun.COM 
85710599SJerry.Gilliam@Sun.COM 	ptr = prev_member;
85810599SJerry.Gilliam@Sun.COM 	while (isspace(*ptr))
85910599SJerry.Gilliam@Sun.COM 		ptr++;
86010599SJerry.Gilliam@Sun.COM 
86110599SJerry.Gilliam@Sun.COM 	while (*ptr) {
86210599SJerry.Gilliam@Sun.COM 		/* comma allowed in minor name token only */
86310599SJerry.Gilliam@Sun.COM 		if (*ptr == ',' && nfields > 0) {
86410599SJerry.Gilliam@Sun.COM 			break;
86510599SJerry.Gilliam@Sun.COM 		} else if (isspace(*ptr)) {
86610599SJerry.Gilliam@Sun.COM 			*current_entry++ = *ptr++;
86710599SJerry.Gilliam@Sun.COM 			while (isspace(*ptr))
86810599SJerry.Gilliam@Sun.COM 				ptr++;
86910599SJerry.Gilliam@Sun.COM 			if (++nfields == maxfields)
87010599SJerry.Gilliam@Sun.COM 				break;
87110599SJerry.Gilliam@Sun.COM 		} else
87210599SJerry.Gilliam@Sun.COM 			*current_entry++ = *ptr++;
8730Sstevel@tonic-gate 	}
87410599SJerry.Gilliam@Sun.COM 	*current_entry = '\0';
87510599SJerry.Gilliam@Sun.COM 
87610599SJerry.Gilliam@Sun.COM 	while (isspace(*ptr))
87710599SJerry.Gilliam@Sun.COM 		ptr++;
87810599SJerry.Gilliam@Sun.COM 	if (*ptr == ',') {
87910599SJerry.Gilliam@Sun.COM 		ptr++;	/* skip over optional trailing comma */
88010599SJerry.Gilliam@Sun.COM 	}
88110599SJerry.Gilliam@Sun.COM 	while (isspace(*ptr))
88210599SJerry.Gilliam@Sun.COM 		ptr++;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	return (ptr);
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate void
enter_lock(void)8880Sstevel@tonic-gate enter_lock(void)
8890Sstevel@tonic-gate {
8903442Svikram 	struct flock lock;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	/*
89310599SJerry.Gilliam@Sun.COM 	 * Attempt to create the lock file.  Open the file itself,
89410599SJerry.Gilliam@Sun.COM 	 * and not a symlink to some other file.
8950Sstevel@tonic-gate 	 */
89610599SJerry.Gilliam@Sun.COM 	add_rem_lock_fd = open(add_rem_lock,
89710599SJerry.Gilliam@Sun.COM 	    O_CREAT|O_RDWR|O_NOFOLLOW|O_NOLINKS, S_IRUSR|S_IWUSR);
8983442Svikram 	if (add_rem_lock_fd < 0) {
8993442Svikram 		(void) fprintf(stderr, gettext(ERR_CREAT_LOCK),
9003442Svikram 		    add_rem_lock, strerror(errno));
9013442Svikram 		exit(1);
9023442Svikram 	}
9033442Svikram 
9043442Svikram 	lock.l_type = F_WRLCK;
9053442Svikram 	lock.l_whence = SEEK_SET;
9063442Svikram 	lock.l_start = 0;
9073442Svikram 	lock.l_len = 0;
9083442Svikram 
9093442Svikram 	/* Try for the lock but don't wait. */
9103442Svikram 	if (fcntl(add_rem_lock_fd, F_SETLK, &lock) == -1) {
9113442Svikram 		if (errno == EACCES || errno == EAGAIN) {
9120Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_PROG_IN_USE));
9130Sstevel@tonic-gate 		} else {
9143442Svikram 			(void) fprintf(stderr, gettext(ERR_LOCK),
9153442Svikram 			    add_rem_lock, strerror(errno));
9160Sstevel@tonic-gate 		}
9170Sstevel@tonic-gate 		exit(1);
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate void
err_exit(void)9220Sstevel@tonic-gate err_exit(void)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	/* release memory allocated for moddir */
9250Sstevel@tonic-gate 	cleanup_moddir();
9260Sstevel@tonic-gate 	/* remove add_drv/rem_drv lock */
9270Sstevel@tonic-gate 	exit_unlock();
9280Sstevel@tonic-gate 	exit(1);
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate void
cleanup_moddir(void)9320Sstevel@tonic-gate cleanup_moddir(void)
9330Sstevel@tonic-gate {
9340Sstevel@tonic-gate 	struct drvmod_dir *walk_ptr;
9350Sstevel@tonic-gate 	struct drvmod_dir *free_ptr = moddir;
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	while (free_ptr != NULL) {
9380Sstevel@tonic-gate 		walk_ptr = free_ptr->next;
9390Sstevel@tonic-gate 		free(free_ptr);
9400Sstevel@tonic-gate 		free_ptr = walk_ptr;
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate void
exit_unlock(void)9450Sstevel@tonic-gate exit_unlock(void)
9460Sstevel@tonic-gate {
9473442Svikram 	struct flock unlock;
9483442Svikram 
9493442Svikram 	if (add_rem_lock_fd < 0)
9503442Svikram 		return;
9510Sstevel@tonic-gate 
9523442Svikram 	unlock.l_type = F_UNLCK;
9533442Svikram 	unlock.l_whence = SEEK_SET;
9543442Svikram 	unlock.l_start = 0;
9553442Svikram 	unlock.l_len = 0;
9563442Svikram 
9573442Svikram 	if (fcntl(add_rem_lock_fd, F_SETLK, &unlock) == -1) {
9583442Svikram 		(void) fprintf(stderr, gettext(ERR_UNLOCK),
9593442Svikram 		    add_rem_lock, strerror(errno));
9603442Svikram 	} else {
9613442Svikram 		(void) close(add_rem_lock_fd);
9623442Svikram 		add_rem_lock_fd = -1;
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate /*
9670Sstevel@tonic-gate  * error adding driver; need to back out any changes to files.
9680Sstevel@tonic-gate  * check flag to see which files need entries removed
9690Sstevel@tonic-gate  * entry removal based on driver name
9700Sstevel@tonic-gate  */
9710Sstevel@tonic-gate void
remove_entry(int c_flag,char * driver_name)9720Sstevel@tonic-gate remove_entry(
9730Sstevel@tonic-gate 	int c_flag,
9740Sstevel@tonic-gate 	char *driver_name)
9750Sstevel@tonic-gate {
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	if (c_flag & CLEAN_NAM_MAJ) {
9780Sstevel@tonic-gate 		if (delete_entry(name_to_major, driver_name, " ",
9790Sstevel@tonic-gate 		    NULL) == ERROR) {
9800Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_CLEAN),
9810Sstevel@tonic-gate 			    name_to_major, driver_name);
9820Sstevel@tonic-gate 		}
9830Sstevel@tonic-gate 	}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	if (c_flag & CLEAN_DRV_ALIAS) {
9860Sstevel@tonic-gate 		if (delete_entry(driver_aliases, driver_name, " ",
9870Sstevel@tonic-gate 		    NULL) == ERROR) {
9880Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
9890Sstevel@tonic-gate 			    driver_name, driver_aliases);
9900Sstevel@tonic-gate 		}
9910Sstevel@tonic-gate 	}
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	if (c_flag & CLEAN_DRV_CLASSES) {
9940Sstevel@tonic-gate 		if (delete_entry(driver_classes, driver_name, "\t", NULL) ==
9950Sstevel@tonic-gate 		    ERROR) {
9960Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
9970Sstevel@tonic-gate 			    driver_name, driver_classes);
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 	}
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	if (c_flag & CLEAN_MINOR_PERM) {
10020Sstevel@tonic-gate 		if (delete_entry(minor_perm, driver_name, ":", NULL) == ERROR) {
10030Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
10040Sstevel@tonic-gate 			    driver_name, minor_perm);
10050Sstevel@tonic-gate 		}
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	/*
10080Sstevel@tonic-gate 	 * There's no point in removing entries from files that don't
10090Sstevel@tonic-gate 	 * exist.  Prevent error messages by checking for file existence
10100Sstevel@tonic-gate 	 * first.
10110Sstevel@tonic-gate 	 */
10120Sstevel@tonic-gate 	if ((c_flag & CLEAN_DEV_POLICY) != 0 &&
10130Sstevel@tonic-gate 	    access(device_policy, F_OK) == 0) {
10140Sstevel@tonic-gate 		if (delete_plcy_entry(device_policy, driver_name) == ERROR) {
10150Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
10168331SJerry.Gilliam@Sun.COM 			    driver_name, device_policy);
10170Sstevel@tonic-gate 		}
10180Sstevel@tonic-gate 	}
10190Sstevel@tonic-gate 	if ((c_flag & CLEAN_DRV_PRIV) != 0 &&
10200Sstevel@tonic-gate 	    access(extra_privs, F_OK) == 0) {
10210Sstevel@tonic-gate 		if (delete_entry(extra_privs, driver_name, ":", NULL) ==
10220Sstevel@tonic-gate 		    ERROR) {
10230Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
10248331SJerry.Gilliam@Sun.COM 			    driver_name, extra_privs);
10250Sstevel@tonic-gate 		}
10260Sstevel@tonic-gate 	}
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate int
check_perms_aliases(int m_flag,int i_flag)10300Sstevel@tonic-gate check_perms_aliases(
10310Sstevel@tonic-gate 	int m_flag,
10320Sstevel@tonic-gate 	int i_flag)
10330Sstevel@tonic-gate {
10340Sstevel@tonic-gate 	/*
10350Sstevel@tonic-gate 	 * If neither i_flag nor m_flag are specified no need to check the
10360Sstevel@tonic-gate 	 * files for access permissions
10370Sstevel@tonic-gate 	 */
10380Sstevel@tonic-gate 	if (!m_flag && !i_flag)
10390Sstevel@tonic-gate 		return (NOERR);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/* check minor_perm file : exits and is writable */
10420Sstevel@tonic-gate 	if (m_flag) {
10430Sstevel@tonic-gate 		if (access(minor_perm, R_OK | W_OK)) {
10440Sstevel@tonic-gate 			perror(NULL);
10450Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
10460Sstevel@tonic-gate 			    minor_perm);
10470Sstevel@tonic-gate 			return (ERROR);
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/* check driver_aliases file : exits and is writable */
10520Sstevel@tonic-gate 	if (i_flag) {
10530Sstevel@tonic-gate 		if (access(driver_aliases, R_OK | W_OK)) {
10540Sstevel@tonic-gate 			perror(NULL);
10550Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
10560Sstevel@tonic-gate 			    driver_aliases);
10570Sstevel@tonic-gate 			return (ERROR);
10580Sstevel@tonic-gate 		}
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	return (NOERR);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate int
check_name_to_major(int mode)10660Sstevel@tonic-gate check_name_to_major(int mode)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate 	/* check name_to_major file : exists and is writable */
10690Sstevel@tonic-gate 	if (access(name_to_major, mode)) {
10700Sstevel@tonic-gate 		perror(NULL);
10710Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
10720Sstevel@tonic-gate 		    name_to_major);
10730Sstevel@tonic-gate 		return (ERROR);
10740Sstevel@tonic-gate 	}
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	return (NOERR);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate /*
10810Sstevel@tonic-gate  * All this stuff is to support a server installing
10820Sstevel@tonic-gate  * drivers on diskless clients.  When on the server
10830Sstevel@tonic-gate  * need to prepend the basedir
10840Sstevel@tonic-gate  */
10850Sstevel@tonic-gate int
build_filenames(char * basedir)10860Sstevel@tonic-gate build_filenames(char *basedir)
10870Sstevel@tonic-gate {
10889268SJerry.Gilliam@Sun.COM 	int	len;
10899268SJerry.Gilliam@Sun.COM 	int	driver_aliases_len;
10909268SJerry.Gilliam@Sun.COM 	int	driver_classes_len;
10919268SJerry.Gilliam@Sun.COM 	int	minor_perm_len;
10929268SJerry.Gilliam@Sun.COM 	int	name_to_major_len;
10939268SJerry.Gilliam@Sun.COM 	int	rem_name_to_major_len;
10949268SJerry.Gilliam@Sun.COM 	int	add_rem_lock_len;
10959268SJerry.Gilliam@Sun.COM 	int	tmphold_len;
10969268SJerry.Gilliam@Sun.COM 	int	devfs_root_len;
10979268SJerry.Gilliam@Sun.COM 	int	device_policy_len;
10989268SJerry.Gilliam@Sun.COM 	int	extra_privs_len;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (basedir == NULL) {
11010Sstevel@tonic-gate 		driver_aliases = DRIVER_ALIAS;
11020Sstevel@tonic-gate 		driver_classes = DRIVER_CLASSES;
11030Sstevel@tonic-gate 		minor_perm = MINOR_PERM;
11040Sstevel@tonic-gate 		name_to_major = NAM_TO_MAJ;
11050Sstevel@tonic-gate 		rem_name_to_major = REM_NAM_TO_MAJ;
11060Sstevel@tonic-gate 		add_rem_lock = ADD_REM_LOCK;
11070Sstevel@tonic-gate 		tmphold = TMPHOLD;
11080Sstevel@tonic-gate 		devfs_root = DEVFS_ROOT;
11090Sstevel@tonic-gate 		device_policy = DEV_POLICY;
11100Sstevel@tonic-gate 		extra_privs = EXTRA_PRIVS;
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	} else {
11139268SJerry.Gilliam@Sun.COM 		len = strlen(basedir) + 1;
11140Sstevel@tonic-gate 
11159268SJerry.Gilliam@Sun.COM 		driver_aliases_len = len + sizeof (DRIVER_ALIAS);
11169268SJerry.Gilliam@Sun.COM 		driver_classes_len = len + sizeof (DRIVER_CLASSES);
11179268SJerry.Gilliam@Sun.COM 		minor_perm_len = len + sizeof (MINOR_PERM);
11189268SJerry.Gilliam@Sun.COM 		name_to_major_len = len + sizeof (NAM_TO_MAJ);
11199268SJerry.Gilliam@Sun.COM 		rem_name_to_major_len = len + sizeof (REM_NAM_TO_MAJ);
11209268SJerry.Gilliam@Sun.COM 		add_rem_lock_len = len + sizeof (ADD_REM_LOCK);
11219268SJerry.Gilliam@Sun.COM 		tmphold_len = len + sizeof (TMPHOLD);
11229268SJerry.Gilliam@Sun.COM 		devfs_root_len = len + sizeof (DEVFS_ROOT);
11239268SJerry.Gilliam@Sun.COM 		device_policy_len = len + sizeof (DEV_POLICY);
11249268SJerry.Gilliam@Sun.COM 		extra_privs_len = len + sizeof (EXTRA_PRIVS);
11250Sstevel@tonic-gate 
11269268SJerry.Gilliam@Sun.COM 		driver_aliases = malloc(driver_aliases_len);
11279268SJerry.Gilliam@Sun.COM 		driver_classes = malloc(driver_classes_len);
11289268SJerry.Gilliam@Sun.COM 		minor_perm = malloc(minor_perm_len);
11299268SJerry.Gilliam@Sun.COM 		name_to_major = malloc(name_to_major_len);
11309268SJerry.Gilliam@Sun.COM 		rem_name_to_major = malloc(rem_name_to_major_len);
11319268SJerry.Gilliam@Sun.COM 		add_rem_lock = malloc(add_rem_lock_len);
11329268SJerry.Gilliam@Sun.COM 		tmphold = malloc(tmphold_len);
11339268SJerry.Gilliam@Sun.COM 		devfs_root = malloc(devfs_root_len);
11349268SJerry.Gilliam@Sun.COM 		device_policy = malloc(device_policy_len);
11359268SJerry.Gilliam@Sun.COM 		extra_privs = malloc(extra_privs_len);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		if ((driver_aliases == NULL) ||
11380Sstevel@tonic-gate 		    (driver_classes == NULL) ||
11390Sstevel@tonic-gate 		    (minor_perm == NULL) ||
11400Sstevel@tonic-gate 		    (name_to_major == NULL) ||
11410Sstevel@tonic-gate 		    (rem_name_to_major == NULL) ||
11420Sstevel@tonic-gate 		    (add_rem_lock == NULL) ||
11430Sstevel@tonic-gate 		    (tmphold == NULL) ||
11440Sstevel@tonic-gate 		    (devfs_root == NULL) ||
11450Sstevel@tonic-gate 		    (device_policy == NULL) ||
11460Sstevel@tonic-gate 		    (extra_privs == NULL)) {
11470Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
11480Sstevel@tonic-gate 			return (ERROR);
11490Sstevel@tonic-gate 		}
11500Sstevel@tonic-gate 
11519268SJerry.Gilliam@Sun.COM 		(void) snprintf(driver_aliases, driver_aliases_len,
11529268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, DRIVER_ALIAS);
11539268SJerry.Gilliam@Sun.COM 		(void) snprintf(driver_classes, driver_classes_len,
11549268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, DRIVER_CLASSES);
11559268SJerry.Gilliam@Sun.COM 		(void) snprintf(minor_perm, minor_perm_len,
11569268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, MINOR_PERM);
11579268SJerry.Gilliam@Sun.COM 		(void) snprintf(name_to_major, name_to_major_len,
11589268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, NAM_TO_MAJ);
11599268SJerry.Gilliam@Sun.COM 		(void) snprintf(rem_name_to_major, rem_name_to_major_len,
11609268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, REM_NAM_TO_MAJ);
11619268SJerry.Gilliam@Sun.COM 		(void) snprintf(add_rem_lock, add_rem_lock_len,
11629268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, ADD_REM_LOCK);
11639268SJerry.Gilliam@Sun.COM 		(void) snprintf(tmphold, tmphold_len,
11649268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, TMPHOLD);
11659268SJerry.Gilliam@Sun.COM 		(void) snprintf(devfs_root, devfs_root_len,
11669268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, DEVFS_ROOT);
11679268SJerry.Gilliam@Sun.COM 		(void) snprintf(device_policy, device_policy_len,
11689268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, DEV_POLICY);
11699268SJerry.Gilliam@Sun.COM 		(void) snprintf(extra_privs, extra_privs_len,
11709268SJerry.Gilliam@Sun.COM 		    "%s%s", basedir, EXTRA_PRIVS);
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	return (NOERR);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate static int
exec_command(char * path,char * cmdline[MAX_CMD_LINE])11770Sstevel@tonic-gate exec_command(char *path, char *cmdline[MAX_CMD_LINE])
11780Sstevel@tonic-gate {
11790Sstevel@tonic-gate 	pid_t pid;
11800Sstevel@tonic-gate 	uint_t stat_loc;
11810Sstevel@tonic-gate 	int waitstat;
11820Sstevel@tonic-gate 	int exit_status;
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	/* child */
11850Sstevel@tonic-gate 	if ((pid = fork()) == 0) {
11860Sstevel@tonic-gate 		(void) execv(path, cmdline);
11870Sstevel@tonic-gate 		perror(NULL);
11880Sstevel@tonic-gate 		return (ERROR);
11890Sstevel@tonic-gate 	} else if (pid == -1) {
11900Sstevel@tonic-gate 		/* fork failed */
11910Sstevel@tonic-gate 		perror(NULL);
11920Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_FORK_FAIL), cmdline);
11930Sstevel@tonic-gate 		return (ERROR);
11940Sstevel@tonic-gate 	} else {
11950Sstevel@tonic-gate 		/* parent */
11960Sstevel@tonic-gate 		do {
11970Sstevel@tonic-gate 			waitstat = waitpid(pid, (int *)&stat_loc, 0);
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 		} while ((!WIFEXITED(stat_loc) &&
12008331SJerry.Gilliam@Sun.COM 		    !WIFSIGNALED(stat_loc)) || (waitstat == 0));
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		exit_status = WEXITSTATUS(stat_loc);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		return (exit_status);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /*
12098831SJerry.Gilliam@Sun.COM  * Exec devfsadm to perform driver config/unconfig operation,
12108831SJerry.Gilliam@Sun.COM  * adding or removing aliases.
12110Sstevel@tonic-gate  */
12128831SJerry.Gilliam@Sun.COM static int
exec_devfsadm(boolean_t config,char * driver_name,major_t major_num,char * aliases,char * classes,int config_flags)12138831SJerry.Gilliam@Sun.COM exec_devfsadm(
12148831SJerry.Gilliam@Sun.COM 	boolean_t config,
12150Sstevel@tonic-gate 	char *driver_name,
12160Sstevel@tonic-gate 	major_t major_num,
12170Sstevel@tonic-gate 	char *aliases,
12180Sstevel@tonic-gate 	char *classes,
1219*10842SJerry.Gilliam@Sun.COM 	int config_flags)
12200Sstevel@tonic-gate {
12210Sstevel@tonic-gate 	int n = 0;
12220Sstevel@tonic-gate 	char *cmdline[MAX_CMD_LINE];
12230Sstevel@tonic-gate 	char maj_num[128];
12240Sstevel@tonic-gate 	char *previous;
12250Sstevel@tonic-gate 	char *current;
12260Sstevel@tonic-gate 	int len;
12278831SJerry.Gilliam@Sun.COM 	int rv;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	/* build command line */
12300Sstevel@tonic-gate 	cmdline[n++] = DRVCONFIG;
12318831SJerry.Gilliam@Sun.COM 	if (config == B_FALSE) {
12328831SJerry.Gilliam@Sun.COM 		cmdline[n++] = "-u";		/* unconfigure */
1233*10842SJerry.Gilliam@Sun.COM 		if (config_flags & CONFIG_DRV_FORCE)
12348831SJerry.Gilliam@Sun.COM 			cmdline[n++] = "-f";	/* force if currently in use */
12358831SJerry.Gilliam@Sun.COM 	}
1236*10842SJerry.Gilliam@Sun.COM 	if (config_flags & CONFIG_DRV_VERBOSE) {
12370Sstevel@tonic-gate 		cmdline[n++] = "-v";
12380Sstevel@tonic-gate 	}
12390Sstevel@tonic-gate 	cmdline[n++] = "-b";
12400Sstevel@tonic-gate 	if (classes) {
12410Sstevel@tonic-gate 		cmdline[n++] = "-c";
12420Sstevel@tonic-gate 		cmdline[n++] = classes;
12430Sstevel@tonic-gate 	}
12440Sstevel@tonic-gate 	cmdline[n++] = "-i";
12450Sstevel@tonic-gate 	cmdline[n++] = driver_name;
12460Sstevel@tonic-gate 	cmdline[n++] = "-m";
12479268SJerry.Gilliam@Sun.COM 	(void) snprintf(maj_num, sizeof (maj_num), "%lu", major_num);
12480Sstevel@tonic-gate 	cmdline[n++] = maj_num;
1249*10842SJerry.Gilliam@Sun.COM 	if (config_flags & CONFIG_DRV_UPDATE_ONLY)
1250*10842SJerry.Gilliam@Sun.COM 		cmdline[n++] = "-x";
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	if (aliases != NULL) {
12530Sstevel@tonic-gate 		len = strlen(aliases);
12540Sstevel@tonic-gate 		previous = aliases;
12550Sstevel@tonic-gate 		do {
12560Sstevel@tonic-gate 			cmdline[n++] = "-a";
12570Sstevel@tonic-gate 			cmdline[n] = calloc(len + 1, 1);
12580Sstevel@tonic-gate 			if (cmdline[n] == NULL) {
12590Sstevel@tonic-gate 				(void) fprintf(stderr,
12600Sstevel@tonic-gate 				    gettext(ERR_NO_MEM));
12610Sstevel@tonic-gate 				return (ERROR);
12620Sstevel@tonic-gate 			}
12630Sstevel@tonic-gate 			current = get_entry(previous,
12644145Scth 			    cmdline[n++], ' ', 0);
12650Sstevel@tonic-gate 			previous = current;
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 		} while (*current != '\0');
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	}
12700Sstevel@tonic-gate 	cmdline[n] = (char *)0;
12710Sstevel@tonic-gate 
12728831SJerry.Gilliam@Sun.COM 	rv = exec_command(DRVCONFIG_PATH, cmdline);
12738831SJerry.Gilliam@Sun.COM 	if (rv == NOERR)
12748831SJerry.Gilliam@Sun.COM 		return (NOERR);
12758831SJerry.Gilliam@Sun.COM 	return (ERROR);
12768831SJerry.Gilliam@Sun.COM }
12778831SJerry.Gilliam@Sun.COM 
12788831SJerry.Gilliam@Sun.COM int
unconfig_driver(char * driver_name,major_t major_num,char * aliases,int config_flags)12798831SJerry.Gilliam@Sun.COM unconfig_driver(
12808831SJerry.Gilliam@Sun.COM 	char *driver_name,
12818831SJerry.Gilliam@Sun.COM 	major_t major_num,
12828831SJerry.Gilliam@Sun.COM 	char *aliases,
1283*10842SJerry.Gilliam@Sun.COM 	int config_flags)
12848831SJerry.Gilliam@Sun.COM {
12858831SJerry.Gilliam@Sun.COM 	return (exec_devfsadm(B_FALSE, driver_name, major_num,
1286*10842SJerry.Gilliam@Sun.COM 	    aliases, NULL, config_flags));
12878831SJerry.Gilliam@Sun.COM }
12880Sstevel@tonic-gate 
12898831SJerry.Gilliam@Sun.COM /*
12908831SJerry.Gilliam@Sun.COM  * check that major_num doesn't exceed maximum on this machine
12918831SJerry.Gilliam@Sun.COM  * do this here to support add_drv on server for diskless clients
12928831SJerry.Gilliam@Sun.COM  */
12938831SJerry.Gilliam@Sun.COM int
config_driver(char * driver_name,major_t major_num,char * aliases,char * classes,int cleanup_flag,int config_flags)12948831SJerry.Gilliam@Sun.COM config_driver(
12958831SJerry.Gilliam@Sun.COM 	char *driver_name,
12968831SJerry.Gilliam@Sun.COM 	major_t major_num,
12978831SJerry.Gilliam@Sun.COM 	char *aliases,
12988831SJerry.Gilliam@Sun.COM 	char *classes,
12998831SJerry.Gilliam@Sun.COM 	int cleanup_flag,
1300*10842SJerry.Gilliam@Sun.COM 	int config_flags)
13018831SJerry.Gilliam@Sun.COM {
13028831SJerry.Gilliam@Sun.COM 	int	max_dev;
13038831SJerry.Gilliam@Sun.COM 	int	rv;
13048831SJerry.Gilliam@Sun.COM 
13058831SJerry.Gilliam@Sun.COM 	if (modctl(MODRESERVED, NULL, &max_dev) < 0) {
13068831SJerry.Gilliam@Sun.COM 		perror(NULL);
13078831SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_MAX_MAJOR));
13088831SJerry.Gilliam@Sun.COM 		return (ERROR);
13098831SJerry.Gilliam@Sun.COM 	}
13108831SJerry.Gilliam@Sun.COM 
13118831SJerry.Gilliam@Sun.COM 	if (major_num >= max_dev) {
13128831SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_MAX_EXCEEDS),
13138831SJerry.Gilliam@Sun.COM 		    major_num, max_dev);
13148831SJerry.Gilliam@Sun.COM 		return (ERROR);
13158831SJerry.Gilliam@Sun.COM 	}
13168831SJerry.Gilliam@Sun.COM 
13178831SJerry.Gilliam@Sun.COM 	/* bind major number and driver name */
13188831SJerry.Gilliam@Sun.COM 	rv = exec_devfsadm(B_TRUE, driver_name, major_num,
1319*10842SJerry.Gilliam@Sun.COM 	    aliases, classes, config_flags);
13208831SJerry.Gilliam@Sun.COM 
13218831SJerry.Gilliam@Sun.COM 	if (rv == NOERR)
13220Sstevel@tonic-gate 		return (NOERR);
13230Sstevel@tonic-gate 	perror(NULL);
13240Sstevel@tonic-gate 	remove_entry(cleanup_flag, driver_name);
13250Sstevel@tonic-gate 	return (ERROR);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate void
load_driver(char * driver_name,int verbose_flag)13290Sstevel@tonic-gate load_driver(char *driver_name, int verbose_flag)
13300Sstevel@tonic-gate {
13310Sstevel@tonic-gate 	int n = 0;
13320Sstevel@tonic-gate 	char *cmdline[MAX_CMD_LINE];
13330Sstevel@tonic-gate 	int exec_status;
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	/* build command line */
13360Sstevel@tonic-gate 	cmdline[n++] = DEVFSADM;
13370Sstevel@tonic-gate 	if (verbose_flag) {
13380Sstevel@tonic-gate 		cmdline[n++] = "-v";
13390Sstevel@tonic-gate 	}
13400Sstevel@tonic-gate 	cmdline[n++] = "-i";
13410Sstevel@tonic-gate 	cmdline[n++] = driver_name;
13420Sstevel@tonic-gate 	cmdline[n] = (char *)0;
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	exec_status = exec_command(DEVFSADM_PATH, cmdline);
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	if (exec_status != NOERR) {
13470Sstevel@tonic-gate 		/* no clean : name and major number are bound */
13488456SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_CONFIG), driver_name);
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate void
get_modid(char * driver_name,int * mod)13530Sstevel@tonic-gate get_modid(char *driver_name, int *mod)
13540Sstevel@tonic-gate {
13550Sstevel@tonic-gate 	struct modinfo	modinfo;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	modinfo.mi_id = -1;
13580Sstevel@tonic-gate 	modinfo.mi_info = MI_INFO_ALL;
13590Sstevel@tonic-gate 	do {
13600Sstevel@tonic-gate 		/*
13610Sstevel@tonic-gate 		 * If we are at the end of the list of loaded modules
13620Sstevel@tonic-gate 		 * then set *mod = -1 and return
13630Sstevel@tonic-gate 		 */
13640Sstevel@tonic-gate 		if (modctl(MODINFO, 0, &modinfo) < 0) {
13650Sstevel@tonic-gate 			*mod = -1;
13660Sstevel@tonic-gate 			return;
13670Sstevel@tonic-gate 		}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 		*mod = modinfo.mi_id;
13700Sstevel@tonic-gate 	} while (strcmp(driver_name, modinfo.mi_name) != 0);
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate int
create_reconfig(char * basedir)13740Sstevel@tonic-gate create_reconfig(char *basedir)
13750Sstevel@tonic-gate {
13760Sstevel@tonic-gate 	char reconfig_file[MAXPATHLEN + FILENAME_MAX + 1];
13770Sstevel@tonic-gate 	FILE *reconfig_fp;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	if (basedir != NULL) {
13800Sstevel@tonic-gate 		(void) strcpy(reconfig_file, basedir);
13810Sstevel@tonic-gate 		(void) strcat(reconfig_file, RECONFIGURE);
13820Sstevel@tonic-gate 	} else {
13830Sstevel@tonic-gate 		(void) strcpy(reconfig_file, RECONFIGURE);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 	if ((reconfig_fp = fopen(reconfig_file, "a")) == NULL)
13860Sstevel@tonic-gate 		return (ERROR);
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	(void) fclose(reconfig_fp);
13890Sstevel@tonic-gate 	return (NOERR);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate /*
13940Sstevel@tonic-gate  * update_minor_entry:
13950Sstevel@tonic-gate  *	open file
13960Sstevel@tonic-gate  *	for each entry in list
13970Sstevel@tonic-gate  *		where list entries are separated by <list_separator>
13980Sstevel@tonic-gate  * 		modify entry : driver_name <entry_separator> entry
13990Sstevel@tonic-gate  *	close file
14000Sstevel@tonic-gate  *
14010Sstevel@tonic-gate  *	return error/noerr
14020Sstevel@tonic-gate  */
14030Sstevel@tonic-gate int
update_minor_entry(char * driver_name,char * perm_list)14040Sstevel@tonic-gate update_minor_entry(char *driver_name, char *perm_list)
14050Sstevel@tonic-gate {
140610599SJerry.Gilliam@Sun.COM 	FILE	*fp;
140710599SJerry.Gilliam@Sun.COM 	FILE	*newfp;
140810599SJerry.Gilliam@Sun.COM 	int	match = 0;
140910599SJerry.Gilliam@Sun.COM 	char	line[MAX_DBFILE_ENTRY];
141010599SJerry.Gilliam@Sun.COM 	char	drv[FILENAME_MAX + 1];
141110599SJerry.Gilliam@Sun.COM 	char	minor[FILENAME_MAX + 1];
141210599SJerry.Gilliam@Sun.COM 	char	perm[OPT_LEN + 1];
141310599SJerry.Gilliam@Sun.COM 	char	own[OPT_LEN + 1];
141410599SJerry.Gilliam@Sun.COM 	char	grp[OPT_LEN + 1];
141510599SJerry.Gilliam@Sun.COM 	int	status = NOERR, i;
141610599SJerry.Gilliam@Sun.COM 	char	*newfile, *tptr;
141710599SJerry.Gilliam@Sun.COM 	char	*cp, *dup, *drv_minor;
14180Sstevel@tonic-gate 	struct group *sysgrp;
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	if ((fp = fopen(minor_perm, "r")) == NULL) {
14210Sstevel@tonic-gate 		perror(NULL);
14220Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
14230Sstevel@tonic-gate 		    minor_perm);
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 		return (ERROR);
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	/*
14290Sstevel@tonic-gate 	 * Build filename for temporary file
14300Sstevel@tonic-gate 	 */
14310Sstevel@tonic-gate 	if ((tptr = calloc(strlen(minor_perm) + strlen(XEND) + 1, 1)) == NULL) {
14320Sstevel@tonic-gate 		perror(NULL);
14330Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
14340Sstevel@tonic-gate 	}
14350Sstevel@tonic-gate 	(void) strcpy(tptr, minor_perm);
14360Sstevel@tonic-gate 	(void) strcat(tptr, XEND);
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	/*
14390Sstevel@tonic-gate 	 * Set gid so we preserve group attribute.  Ideally we wouldn't
14400Sstevel@tonic-gate 	 * assume a gid of "sys" but we can't undo the damage on already
14410Sstevel@tonic-gate 	 * installed systems unless we force the issue.
14420Sstevel@tonic-gate 	 */
14430Sstevel@tonic-gate 	if ((sysgrp = getgrnam("sys")) != NULL) {
14440Sstevel@tonic-gate 		(void) setgid(sysgrp->gr_gid);
14450Sstevel@tonic-gate 	}
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	newfile = mktemp(tptr);
14480Sstevel@tonic-gate 	if ((newfp = fopen(newfile, "w")) == NULL) {
14490Sstevel@tonic-gate 		perror(NULL);
14500Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
14510Sstevel@tonic-gate 		    newfile);
14520Sstevel@tonic-gate 		return (ERROR);
14530Sstevel@tonic-gate 	}
14540Sstevel@tonic-gate 
145510599SJerry.Gilliam@Sun.COM 	if (sscanf(perm_list,
145610599SJerry.Gilliam@Sun.COM 	    "%" VAL2STR(FILENAME_MAX) "s"	/* minor */
145710599SJerry.Gilliam@Sun.COM 	    "%" VAL2STR(OPT_LEN) "s"		/* perm */
145810599SJerry.Gilliam@Sun.COM 	    "%" VAL2STR(OPT_LEN) "s"		/* own */
145910599SJerry.Gilliam@Sun.COM 	    "%" VAL2STR(OPT_LEN) "s",		/* grp */
146010599SJerry.Gilliam@Sun.COM 	    minor, perm, own, grp) != 4) {
14610Sstevel@tonic-gate 		status = ERROR;
14620Sstevel@tonic-gate 	}
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) {
14652805Seota 		/* copy the whole line into dup */
14662805Seota 		if ((dup = strdup(line)) == NULL) {
14672805Seota 			perror(NULL);
14682805Seota 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
14692805Seota 			status = ERROR;
14702805Seota 			break;
14712805Seota 		}
14722805Seota 		/* cut off comments starting with '#' */
14732805Seota 		if ((cp = strchr(dup, '#')) != NULL)
14742805Seota 			*cp = '\0';
14752805Seota 		/* ignore comment or blank lines */
14762805Seota 		if (is_blank(dup)) {
14772805Seota 			if (fputs(line, newfp) == EOF) {
14780Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
14790Sstevel@tonic-gate 				    minor_perm);
14800Sstevel@tonic-gate 				status = ERROR;
14810Sstevel@tonic-gate 			}
14822805Seota 			free(dup);
14830Sstevel@tonic-gate 			continue;
14840Sstevel@tonic-gate 		}
14850Sstevel@tonic-gate 
14862805Seota 		/* get the driver name */
148710599SJerry.Gilliam@Sun.COM 		if (sscanf(dup, "%" VAL2STR(FILENAME_MAX) "s", drv) != 1) {
14882805Seota 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
14892805Seota 			    minor_perm, line);
14902805Seota 			status = ERROR;
14912805Seota 			free(dup);
14922805Seota 			break;
14932805Seota 		}
14942805Seota 
14952805Seota 		/*
14962805Seota 		 * get the minor name; place the NULL character at the
14972805Seota 		 * end of the driver name, then make the drv_minor
14982805Seota 		 * point to the first character of the minor name.
14992805Seota 		 * the line missing ':' must be treated as a broken one.
15002805Seota 		 */
15012805Seota 		i = strcspn(drv, ":");
15022805Seota 		if (i == strlen(drv)) {
15030Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
15040Sstevel@tonic-gate 			    minor_perm, line);
15050Sstevel@tonic-gate 			status = ERROR;
15062805Seota 			free(dup);
15072805Seota 			break;
15080Sstevel@tonic-gate 		}
15092805Seota 		drv[i] =  '\0';
15102805Seota 		drv_minor = &drv[strlen(drv) + 1];
15110Sstevel@tonic-gate 
15122805Seota 		/*
15132805Seota 		 * compare both of the driver name and the minor name.
15142805Seota 		 * then the new line should be written to the file if
15152805Seota 		 * both of them match
15162805Seota 		 */
15170Sstevel@tonic-gate 		if ((strcmp(drv, driver_name) == 0) &&
15180Sstevel@tonic-gate 		    (strcmp(minor, drv_minor) == 0)) {
15192805Seota 			/* if it has a comment, keep it */
15202805Seota 			if (cp != NULL) {
15212805Seota 				cp++; /* skip a terminator */
15229268SJerry.Gilliam@Sun.COM 				(void) snprintf(line, sizeof (line),
15239268SJerry.Gilliam@Sun.COM 				    "%s:%s %s %s %s #%s\n",
15242805Seota 				    drv, minor, perm, own, grp, cp);
15252805Seota 			} else {
15269268SJerry.Gilliam@Sun.COM 				(void) snprintf(line, sizeof (line),
15279268SJerry.Gilliam@Sun.COM 				    "%s:%s %s %s %s\n",
15282805Seota 				    drv, minor, perm, own, grp);
15292805Seota 			}
15300Sstevel@tonic-gate 			match = 1;
15310Sstevel@tonic-gate 		}
15322805Seota 		free(dup);
15330Sstevel@tonic-gate 
15342805Seota 		/* update the file */
15350Sstevel@tonic-gate 		if ((fputs(line, newfp)) == EOF) {
15360Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE),
15370Sstevel@tonic-gate 			    minor_perm);
15380Sstevel@tonic-gate 			status = ERROR;
15390Sstevel@tonic-gate 		}
15400Sstevel@tonic-gate 	}
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	if (!match) {
15430Sstevel@tonic-gate 		(void) bzero(line, sizeof (&line[0]));
15449268SJerry.Gilliam@Sun.COM 		(void) snprintf(line, sizeof (line),
15459268SJerry.Gilliam@Sun.COM 		    "%s:%s %s %s %s\n",
15460Sstevel@tonic-gate 		    driver_name, minor, perm, own, grp);
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 		/* add the new entry */
15490Sstevel@tonic-gate 		if ((fputs(line, newfp)) == EOF) {
15500Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm);
15510Sstevel@tonic-gate 			status = ERROR;
15520Sstevel@tonic-gate 		}
15530Sstevel@tonic-gate 	}
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	(void) fclose(fp);
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0)
15580Sstevel@tonic-gate 		status = ERROR;
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	(void) fclose(newfp);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	/*
15630Sstevel@tonic-gate 	 * if error, leave original file, delete new file
15640Sstevel@tonic-gate 	 * if noerr, replace original file with new file
15650Sstevel@tonic-gate 	 */
15660Sstevel@tonic-gate 	if (status == NOERR) {
15670Sstevel@tonic-gate 		if (rename(minor_perm, tmphold) == -1) {
15680Sstevel@tonic-gate 			perror(NULL);
15690Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm);
15700Sstevel@tonic-gate 			(void) unlink(newfile);
15710Sstevel@tonic-gate 			return (ERROR);
15720Sstevel@tonic-gate 		} else if (rename(newfile, minor_perm) == -1) {
15730Sstevel@tonic-gate 			perror(NULL);
15740Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm);
15750Sstevel@tonic-gate 			(void) unlink(minor_perm);
15760Sstevel@tonic-gate 			(void) unlink(newfile);
15770Sstevel@tonic-gate 			if (link(tmphold, minor_perm) == -1) {
15780Sstevel@tonic-gate 				perror(NULL);
15790Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINK),
15800Sstevel@tonic-gate 				    minor_perm, tmphold);
15810Sstevel@tonic-gate 			}
15820Sstevel@tonic-gate 			return (ERROR);
15830Sstevel@tonic-gate 		}
15840Sstevel@tonic-gate 		(void) unlink(tmphold);
15850Sstevel@tonic-gate 	} else {
15860Sstevel@tonic-gate 		/*
15870Sstevel@tonic-gate 		 * since there's an error, leave file alone; remove
15880Sstevel@tonic-gate 		 * new file
15890Sstevel@tonic-gate 		 */
15900Sstevel@tonic-gate 		if (unlink(newfile) == -1) {
15910Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_RM), newfile);
15920Sstevel@tonic-gate 		}
15930Sstevel@tonic-gate 		return (ERROR);
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	return (NOERR);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate }
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate /*
16020Sstevel@tonic-gate  * list_entry:
16030Sstevel@tonic-gate  *	open file
16040Sstevel@tonic-gate  *	read thru file, listing all entries if first entry = driver_name
16050Sstevel@tonic-gate  *	close
16060Sstevel@tonic-gate  */
16070Sstevel@tonic-gate void
list_entry(char * oldfile,char * driver_name,char * marker)16080Sstevel@tonic-gate list_entry(
16090Sstevel@tonic-gate 	char *oldfile,
16100Sstevel@tonic-gate 	char *driver_name,
16110Sstevel@tonic-gate 	char *marker)
16120Sstevel@tonic-gate {
16130Sstevel@tonic-gate 	FILE	*fp;
16140Sstevel@tonic-gate 	int	i;
16152805Seota 	char	line[MAX_DBFILE_ENTRY], *cp;
16160Sstevel@tonic-gate 	char	drv[FILENAME_MAX + 1];
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 	if ((fp = fopen(oldfile, "r")) == NULL) {
16190Sstevel@tonic-gate 		perror(NULL);
16200Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile);
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 		return;
16230Sstevel@tonic-gate 	}
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != NULL) {
16262805Seota 		/* cut off comments starting with '#' */
16272805Seota 		if ((cp = strchr(line, '#')) != NULL)
16282805Seota 			*cp = '\0';
16292805Seota 		/* ignore comment or blank lines */
16302805Seota 		if (is_blank(line))
16310Sstevel@tonic-gate 			continue;
16322805Seota 		/* sanity-check */
163310599SJerry.Gilliam@Sun.COM 		if (sscanf(line, "%" VAL2STR(FILENAME_MAX) "s", drv) != 1) {
16340Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
16350Sstevel@tonic-gate 			    oldfile, line);
16360Sstevel@tonic-gate 		}
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 		for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) {
16390Sstevel@tonic-gate 			drv[i] =  '\0';
16400Sstevel@tonic-gate 		}
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 		if (strcmp(driver_name, drv) == 0) {
16430Sstevel@tonic-gate 			(void) fprintf(stdout, "%s", line);
16440Sstevel@tonic-gate 		}
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	(void) fclose(fp);
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate 
16502805Seota static boolean_t
is_token(char * tok)16512805Seota is_token(char *tok)
16522805Seota {
16532805Seota 	/*
16542805Seota 	 * Check the token here. According to IEEE1275 Open Firmware Boot
16552805Seota 	 * Standard, the name is composed of 1 to 31 letters,
16562805Seota 	 * digits and punctuation characters from the set ",._+-", and
16572805Seota 	 * uppercase and lowercase characters are considered distinct.
16582805Seota 	 * (ie. token := [a-zA-Z0-9,._+-]+, length(token) <= 31)
16592805Seota 	 * However, since either the definition of driver or aliase names is
16602805Seota 	 * not known well, only '#' is avoided explicitly. (the kernel lexical
16612805Seota 	 * analyzer treats it as a start of a comment)
16622805Seota 	 */
16632805Seota 	for (/* nothing */; *tok != '\0'; tok++)
16642805Seota 		if (*tok == '#' || iscntrl(*tok))
16652805Seota 			return (B_FALSE);
16662805Seota 
16672805Seota 	return (B_TRUE);
16682805Seota }
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate /*
16710Sstevel@tonic-gate  * check each entry in perm_list for:
16720Sstevel@tonic-gate  *	4 arguments
16730Sstevel@tonic-gate  *	permission arg is in valid range
16740Sstevel@tonic-gate  * permlist entries separated by comma
16750Sstevel@tonic-gate  * return ERROR/NOERR
16760Sstevel@tonic-gate  */
16770Sstevel@tonic-gate int
check_perm_opts(char * perm_list)16780Sstevel@tonic-gate check_perm_opts(char *perm_list)
16790Sstevel@tonic-gate {
16800Sstevel@tonic-gate 	char *current_head;
16810Sstevel@tonic-gate 	char *previous_head;
16820Sstevel@tonic-gate 	char *one_entry;
168310599SJerry.Gilliam@Sun.COM 	int len, scan_stat;
16840Sstevel@tonic-gate 	char minor[FILENAME_MAX + 1];
16850Sstevel@tonic-gate 	char perm[OPT_LEN + 1];
16860Sstevel@tonic-gate 	char own[OPT_LEN + 1];
16870Sstevel@tonic-gate 	char grp[OPT_LEN + 1];
16880Sstevel@tonic-gate 	char dumb[OPT_LEN + 1];
16890Sstevel@tonic-gate 	int status = NOERR;
16900Sstevel@tonic-gate 	int intperm;
16910Sstevel@tonic-gate 
169210599SJerry.Gilliam@Sun.COM 	if ((len = strlen(perm_list)) == 0)
16930Sstevel@tonic-gate 		return (ERROR);
16940Sstevel@tonic-gate 
169510599SJerry.Gilliam@Sun.COM 	if ((one_entry = calloc(len + 1, 1)) == NULL) {
16960Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
16970Sstevel@tonic-gate 		return (ERROR);
16980Sstevel@tonic-gate 	}
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	previous_head = perm_list;
17010Sstevel@tonic-gate 	current_head = perm_list;
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 	while (*current_head != '\0') {
170410599SJerry.Gilliam@Sun.COM 		bzero(one_entry, len + 1);
170510599SJerry.Gilliam@Sun.COM 		current_head = get_perm_entry(previous_head, one_entry);
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 		previous_head = current_head;
170810599SJerry.Gilliam@Sun.COM 		scan_stat = sscanf(one_entry,
170910599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(FILENAME_MAX) "s"	/* minor */
171010599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(OPT_LEN) "s"		/* perm */
171110599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(OPT_LEN) "s"		/* own */
171210599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(OPT_LEN) "s"		/* grp */
171310599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(OPT_LEN) "s",		/* dumb */
171410599SJerry.Gilliam@Sun.COM 		    minor, perm, own, grp, dumb);
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 		if (scan_stat < 4) {
17170Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MIS_TOK),
17180Sstevel@tonic-gate 			    "-m", one_entry);
17190Sstevel@tonic-gate 			status = ERROR;
17200Sstevel@tonic-gate 		}
17210Sstevel@tonic-gate 		if (scan_stat > 4) {
17220Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_TOO_MANY_ARGS),
17230Sstevel@tonic-gate 			    "-m", one_entry);
17240Sstevel@tonic-gate 			status = ERROR;
17250Sstevel@tonic-gate 		}
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 		intperm = atoi(perm);
17280Sstevel@tonic-gate 		if (intperm < 0000 || intperm > 4777) {
17290Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_MODE), perm);
17300Sstevel@tonic-gate 			status = ERROR;
17310Sstevel@tonic-gate 		}
17320Sstevel@tonic-gate 	}
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	free(one_entry);
17350Sstevel@tonic-gate 	return (status);
17360Sstevel@tonic-gate }
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate /*
17400Sstevel@tonic-gate  * check each alias :
17410Sstevel@tonic-gate  *	alias list members separated by white space
17420Sstevel@tonic-gate  *	cannot exist as driver name in /etc/name_to_major
17430Sstevel@tonic-gate  *	cannot exist as driver or alias name in /etc/driver_aliases
17440Sstevel@tonic-gate  */
17450Sstevel@tonic-gate int
aliases_unique(char * aliases)17460Sstevel@tonic-gate aliases_unique(char *aliases)
17470Sstevel@tonic-gate {
17480Sstevel@tonic-gate 	char *current_head;
17490Sstevel@tonic-gate 	char *previous_head;
17500Sstevel@tonic-gate 	char *one_entry;
17518831SJerry.Gilliam@Sun.COM 	int len;
17520Sstevel@tonic-gate 	int is_unique;
17538831SJerry.Gilliam@Sun.COM 	int err;
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	len = strlen(aliases);
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	one_entry = calloc(len + 1, 1);
17580Sstevel@tonic-gate 	if (one_entry == NULL) {
17590Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
17600Sstevel@tonic-gate 		return (ERROR);
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	previous_head = aliases;
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 	do {
17668831SJerry.Gilliam@Sun.COM 		bzero(one_entry, len+1);
17674145Scth 		current_head = get_entry(previous_head, one_entry, ' ', 1);
17680Sstevel@tonic-gate 		previous_head = current_head;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 		if ((unique_driver_name(one_entry, name_to_major,
17718831SJerry.Gilliam@Sun.COM 		    &is_unique)) == ERROR)
17728831SJerry.Gilliam@Sun.COM 			goto err_out;
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 		if (is_unique != UNIQUE) {
17750Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_ALIAS_IN_NAM_MAJ),
17760Sstevel@tonic-gate 			    one_entry);
17778831SJerry.Gilliam@Sun.COM 			goto err_out;
17780Sstevel@tonic-gate 		}
17790Sstevel@tonic-gate 
17808831SJerry.Gilliam@Sun.COM 		if ((err = unique_drv_alias(one_entry)) != UNIQUE) {
17818831SJerry.Gilliam@Sun.COM 			if (err == NOT_UNIQUE) {
17828831SJerry.Gilliam@Sun.COM 				(void) fprintf(stderr,
17838831SJerry.Gilliam@Sun.COM 				    gettext(ERR_ALIAS_IN_USE), one_entry);
17848831SJerry.Gilliam@Sun.COM 			}
17858831SJerry.Gilliam@Sun.COM 			goto err_out;
17860Sstevel@tonic-gate 		}
17870Sstevel@tonic-gate 
17882805Seota 		if (!is_token(one_entry)) {
17892805Seota 			(void) fprintf(stderr, gettext(ERR_BAD_TOK),
17902805Seota 			    "-i", one_entry);
17918831SJerry.Gilliam@Sun.COM 			goto err_out;
17922805Seota 		}
17932805Seota 
17940Sstevel@tonic-gate 	} while (*current_head != '\0');
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	free(one_entry);
17970Sstevel@tonic-gate 	return (NOERR);
17980Sstevel@tonic-gate 
17998831SJerry.Gilliam@Sun.COM err_out:
18008831SJerry.Gilliam@Sun.COM 	free(one_entry);
18018831SJerry.Gilliam@Sun.COM 	return (ERROR);
18028831SJerry.Gilliam@Sun.COM }
18038831SJerry.Gilliam@Sun.COM 
18048831SJerry.Gilliam@Sun.COM /*
18058831SJerry.Gilliam@Sun.COM  * verify each alias :
18068831SJerry.Gilliam@Sun.COM  *	alias list members separated by white space and quoted
18078831SJerry.Gilliam@Sun.COM  *	exist as alias name in /etc/driver_aliases
18088831SJerry.Gilliam@Sun.COM  */
18098831SJerry.Gilliam@Sun.COM int
aliases_exist(char * aliases)18109268SJerry.Gilliam@Sun.COM aliases_exist(char *aliases)
18118831SJerry.Gilliam@Sun.COM {
18128831SJerry.Gilliam@Sun.COM 	char *current_head;
18138831SJerry.Gilliam@Sun.COM 	char *previous_head;
18148831SJerry.Gilliam@Sun.COM 	char *one_entry;
18158831SJerry.Gilliam@Sun.COM 	int len;
18168831SJerry.Gilliam@Sun.COM 
18178831SJerry.Gilliam@Sun.COM 	len = strlen(aliases);
18188831SJerry.Gilliam@Sun.COM 
18198831SJerry.Gilliam@Sun.COM 	one_entry = calloc(len + 1, 1);
18208831SJerry.Gilliam@Sun.COM 	if (one_entry == NULL) {
18218831SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
18228831SJerry.Gilliam@Sun.COM 		return (ERROR);
18238831SJerry.Gilliam@Sun.COM 	}
18248831SJerry.Gilliam@Sun.COM 
18258831SJerry.Gilliam@Sun.COM 	previous_head = aliases;
18268831SJerry.Gilliam@Sun.COM 
18278831SJerry.Gilliam@Sun.COM 	do {
18288831SJerry.Gilliam@Sun.COM 		bzero(one_entry, len+1);
18298831SJerry.Gilliam@Sun.COM 		current_head = get_entry(previous_head, one_entry, ' ', 1);
18308831SJerry.Gilliam@Sun.COM 		previous_head = current_head;
18318831SJerry.Gilliam@Sun.COM 
18329268SJerry.Gilliam@Sun.COM 		if (unique_drv_alias(one_entry) != NOT_UNIQUE)
18338831SJerry.Gilliam@Sun.COM 			goto err_out;
18348831SJerry.Gilliam@Sun.COM 
18358831SJerry.Gilliam@Sun.COM 		if (!is_token(one_entry)) {
18368831SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr, gettext(ERR_BAD_TOK),
18378831SJerry.Gilliam@Sun.COM 			    "-i", one_entry);
18388831SJerry.Gilliam@Sun.COM 			goto err_out;
18398831SJerry.Gilliam@Sun.COM 		}
18408831SJerry.Gilliam@Sun.COM 
18418831SJerry.Gilliam@Sun.COM 	} while (*current_head != '\0');
18428831SJerry.Gilliam@Sun.COM 
18438831SJerry.Gilliam@Sun.COM 	free(one_entry);
18448831SJerry.Gilliam@Sun.COM 	return (NOERR);
18458831SJerry.Gilliam@Sun.COM 
18468831SJerry.Gilliam@Sun.COM err_out:
18478831SJerry.Gilliam@Sun.COM 	free(one_entry);
18488831SJerry.Gilliam@Sun.COM 	return (ERROR);
18490Sstevel@tonic-gate }
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 
18524145Scth /*
18534145Scth  * check each alias :
18544145Scth  *	if path-oriented alias, path exists
18554145Scth  */
18564145Scth int
aliases_paths_exist(char * aliases)18574145Scth aliases_paths_exist(char *aliases)
18584145Scth {
18594145Scth 	char *current_head;
18604145Scth 	char *previous_head;
18614145Scth 	char *one_entry;
18624145Scth 	int i, len;
18634145Scth 	char path[MAXPATHLEN];
18644145Scth 	struct stat buf;
18654145Scth 
18664145Scth 	len = strlen(aliases);
18674145Scth 
18684145Scth 	one_entry = calloc(len + 1, 1);
18694145Scth 	if (one_entry == NULL) {
18704145Scth 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
18714145Scth 		return (ERROR);
18724145Scth 	}
18734145Scth 
18744145Scth 	previous_head = aliases;
18754145Scth 
18764145Scth 	do {
18774145Scth 		for (i = 0; i <= len; i++)
18784145Scth 			one_entry[i] = 0;
18794145Scth 
18804145Scth 		current_head = get_entry(previous_head, one_entry, ' ', 1);
18814145Scth 		previous_head = current_head;
18824145Scth 
18834145Scth 		/* if the alias is a path, ensure that the path exists */
18844145Scth 		if (*one_entry != '/')
18854145Scth 			continue;
18864145Scth 		(void) snprintf(path, sizeof (path), "/devices/%s", one_entry);
18874145Scth 		if (stat(path, &buf) == 0)
18884145Scth 			continue;
18894145Scth 
18904145Scth 		/* no device at specified path-oriented alias path */
18914145Scth 		(void) fprintf(stderr, gettext(ERR_PATH_ORIENTED_ALIAS),
18924145Scth 		    one_entry);
18934145Scth 		free(one_entry);
18944145Scth 		return (ERROR);
18954145Scth 
18964145Scth 	} while (*current_head != '\0');
18974145Scth 
18984145Scth 	free(one_entry);
18994145Scth 
19004145Scth 	return (NOERR);
19014145Scth }
19024145Scth 
19034145Scth 
19040Sstevel@tonic-gate int
update_driver_aliases(char * driver_name,char * aliases)19050Sstevel@tonic-gate update_driver_aliases(
19060Sstevel@tonic-gate 	char *driver_name,
19070Sstevel@tonic-gate 	char *aliases)
19080Sstevel@tonic-gate {
19090Sstevel@tonic-gate 	/* make call to update the aliases file */
19104145Scth 	return (append_to_file(driver_name, aliases, driver_aliases,
19114145Scth 	    ' ', " ", 1));
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate 
19158831SJerry.Gilliam@Sun.COM /*
19168831SJerry.Gilliam@Sun.COM  * Return:
19178831SJerry.Gilliam@Sun.COM  *	ERROR in case of memory or read error
19188831SJerry.Gilliam@Sun.COM  *	UNIQUE if there is no existing match to the supplied alias
19198831SJerry.Gilliam@Sun.COM  *	NOT_UNIQUE if there is a match
19208831SJerry.Gilliam@Sun.COM  * An error message is emitted in the case of ERROR,
19218831SJerry.Gilliam@Sun.COM  * up to the caller otherwise.
19228831SJerry.Gilliam@Sun.COM  */
19230Sstevel@tonic-gate int
unique_drv_alias(char * drv_alias)19240Sstevel@tonic-gate unique_drv_alias(char *drv_alias)
19250Sstevel@tonic-gate {
19260Sstevel@tonic-gate 	FILE *fp;
19270Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
19282805Seota 	char line[MAX_N2M_ALIAS_LINE + 1], *cp;
19290Sstevel@tonic-gate 	char alias[FILENAME_MAX + 1];
19304145Scth 	char *a;
19318831SJerry.Gilliam@Sun.COM 	int status = UNIQUE;
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	fp = fopen(driver_aliases, "r");
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	if (fp != NULL) {
19360Sstevel@tonic-gate 		while ((fgets(line, sizeof (line), fp) != 0) &&
19378831SJerry.Gilliam@Sun.COM 		    status == UNIQUE) {
19382805Seota 			/* cut off comments starting with '#' */
19392805Seota 			if ((cp = strchr(line, '#')) != NULL)
19402805Seota 				*cp = '\0';
19412805Seota 			/* ignore comment or blank lines */
19422805Seota 			if (is_blank(line))
19432805Seota 				continue;
19442805Seota 			/* sanity-check */
194510599SJerry.Gilliam@Sun.COM 			if (sscanf(line,
194610599SJerry.Gilliam@Sun.COM 			    "%" VAL2STR(FILENAME_MAX) "s" 	/* drv */
194710599SJerry.Gilliam@Sun.COM 			    "%" VAL2STR(FILENAME_MAX) "s",	/* alias */
194810599SJerry.Gilliam@Sun.COM 			    drv, alias) != 2)
19490Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
19500Sstevel@tonic-gate 				    driver_aliases, line);
19510Sstevel@tonic-gate 
19524145Scth 			/* unquote for compare */
19534145Scth 			if ((*alias == '"') &&
19544145Scth 			    (*(alias + strlen(alias) - 1) == '"')) {
19554145Scth 				a = &alias[1];
19564145Scth 				alias[strlen(alias) - 1] = '\0';
19574145Scth 			} else
19584145Scth 				a = alias;
19594145Scth 
19600Sstevel@tonic-gate 			if ((strcmp(drv_alias, drv) == 0) ||
19614145Scth 			    (strcmp(drv_alias, a) == 0)) {
19628831SJerry.Gilliam@Sun.COM 				status = NOT_UNIQUE;
19638831SJerry.Gilliam@Sun.COM 				break;
19640Sstevel@tonic-gate 			}
19650Sstevel@tonic-gate 		}
19660Sstevel@tonic-gate 		(void) fclose(fp);
19670Sstevel@tonic-gate 		return (status);
19680Sstevel@tonic-gate 	} else {
19690Sstevel@tonic-gate 		perror(NULL);
19700Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_OPEN), driver_aliases);
19710Sstevel@tonic-gate 		return (ERROR);
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate }
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate /*
19770Sstevel@tonic-gate  * search for driver_name in first field of file file_name
19788831SJerry.Gilliam@Sun.COM  * searching name_to_major and driver_aliases: name separated
19798831SJerry.Gilliam@Sun.COM  * from the remainder of the line by white space.
19800Sstevel@tonic-gate  */
19810Sstevel@tonic-gate int
unique_driver_name(char * driver_name,char * file_name,int * is_unique)19820Sstevel@tonic-gate unique_driver_name(char *driver_name, char *file_name,
19830Sstevel@tonic-gate 	int *is_unique)
19840Sstevel@tonic-gate {
19858831SJerry.Gilliam@Sun.COM 	int ret, err;
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	if ((ret = get_major_no(driver_name, file_name)) == ERROR) {
19880Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
19890Sstevel@tonic-gate 		    file_name);
19900Sstevel@tonic-gate 	} else {
19910Sstevel@tonic-gate 		/* check alias file for name collision */
19928831SJerry.Gilliam@Sun.COM 		if ((err = unique_drv_alias(driver_name)) != UNIQUE) {
19938831SJerry.Gilliam@Sun.COM 			if (err == NOT_UNIQUE) {
19948831SJerry.Gilliam@Sun.COM 				(void) fprintf(stderr,
19958831SJerry.Gilliam@Sun.COM 				    gettext(ERR_ALIAS_IN_USE),
19968831SJerry.Gilliam@Sun.COM 				    driver_name);
19978831SJerry.Gilliam@Sun.COM 			}
19980Sstevel@tonic-gate 			ret = ERROR;
19990Sstevel@tonic-gate 		} else {
20000Sstevel@tonic-gate 			if (ret != UNIQUE)
20010Sstevel@tonic-gate 				*is_unique = NOT_UNIQUE;
20020Sstevel@tonic-gate 			else
20030Sstevel@tonic-gate 				*is_unique = ret;
20040Sstevel@tonic-gate 			ret = NOERR;
20050Sstevel@tonic-gate 		}
20060Sstevel@tonic-gate 	}
20070Sstevel@tonic-gate 	return (ret);
20080Sstevel@tonic-gate }
20090Sstevel@tonic-gate 
20108331SJerry.Gilliam@Sun.COM /*
20118331SJerry.Gilliam@Sun.COM  * returns:
20128331SJerry.Gilliam@Sun.COM  *	SUCCESS - not an existing driver alias
20138331SJerry.Gilliam@Sun.COM  *	NOT_UNIQUE - matching driver alias exists
20148331SJerry.Gilliam@Sun.COM  *	ERROR - an error occurred
20158331SJerry.Gilliam@Sun.COM  */
20168331SJerry.Gilliam@Sun.COM int
check_duplicate_driver_alias(char * driver_name,char * drv_alias)20178331SJerry.Gilliam@Sun.COM check_duplicate_driver_alias(char *driver_name, char *drv_alias)
20188331SJerry.Gilliam@Sun.COM {
20198331SJerry.Gilliam@Sun.COM 	FILE *fp;
20208331SJerry.Gilliam@Sun.COM 	char drv[FILENAME_MAX + 1];
20218331SJerry.Gilliam@Sun.COM 	char line[MAX_N2M_ALIAS_LINE + 1], *cp;
20228331SJerry.Gilliam@Sun.COM 	char alias[FILENAME_MAX + 1];
20238331SJerry.Gilliam@Sun.COM 	char *a;
20248331SJerry.Gilliam@Sun.COM 	int status = SUCCESS;
20258331SJerry.Gilliam@Sun.COM 
20268331SJerry.Gilliam@Sun.COM 	if ((fp = fopen(driver_aliases, "r")) == NULL) {
20278331SJerry.Gilliam@Sun.COM 		perror(NULL);
20288331SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_CANT_OPEN), driver_aliases);
20298331SJerry.Gilliam@Sun.COM 		return (ERROR);
20308331SJerry.Gilliam@Sun.COM 	}
20318331SJerry.Gilliam@Sun.COM 
20328331SJerry.Gilliam@Sun.COM 	while (fgets(line, sizeof (line), fp) != 0) {
20338331SJerry.Gilliam@Sun.COM 		/* cut off comments starting with '#' */
20348331SJerry.Gilliam@Sun.COM 		if ((cp = strchr(line, '#')) != NULL)
20358331SJerry.Gilliam@Sun.COM 			*cp = '\0';
20368331SJerry.Gilliam@Sun.COM 		/* ignore comment or blank lines */
20378331SJerry.Gilliam@Sun.COM 		if (is_blank(line))
20388331SJerry.Gilliam@Sun.COM 			continue;
20398331SJerry.Gilliam@Sun.COM 		/* sanity-check */
204010599SJerry.Gilliam@Sun.COM 		if (sscanf(line,
204110599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(FILENAME_MAX) "s"	/* drv */
204210599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(FILENAME_MAX) "s",	/* alias */
204310599SJerry.Gilliam@Sun.COM 		    drv, alias) != 2)
20448331SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
20458331SJerry.Gilliam@Sun.COM 			    driver_aliases, line);
20468331SJerry.Gilliam@Sun.COM 
20478331SJerry.Gilliam@Sun.COM 		/* unquote for compare */
20488331SJerry.Gilliam@Sun.COM 		if ((*alias == '"') &&
20498331SJerry.Gilliam@Sun.COM 		    (*(alias + strlen(alias) - 1) == '"')) {
20508331SJerry.Gilliam@Sun.COM 			a = &alias[1];
20518331SJerry.Gilliam@Sun.COM 			alias[strlen(alias) - 1] = '\0';
20528331SJerry.Gilliam@Sun.COM 		} else
20538331SJerry.Gilliam@Sun.COM 			a = alias;
20548331SJerry.Gilliam@Sun.COM 
20558331SJerry.Gilliam@Sun.COM 		if ((strcmp(drv_alias, a) == 0) &&
20568331SJerry.Gilliam@Sun.COM 		    (strcmp(drv, driver_name) == 0)) {
20578331SJerry.Gilliam@Sun.COM 			status = NOT_UNIQUE;
20588331SJerry.Gilliam@Sun.COM 		}
20598331SJerry.Gilliam@Sun.COM 
20608331SJerry.Gilliam@Sun.COM 		if ((strcmp(drv_alias, drv) == 0) ||
20618331SJerry.Gilliam@Sun.COM 		    ((strcmp(drv_alias, a) == 0) &&
20628331SJerry.Gilliam@Sun.COM 		    (strcmp(drv, driver_name) != 0))) {
20638331SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr,
20648331SJerry.Gilliam@Sun.COM 			    gettext(ERR_ALIAS_IN_USE),
20658331SJerry.Gilliam@Sun.COM 			    drv_alias);
20668331SJerry.Gilliam@Sun.COM 			status = ERROR;
20678331SJerry.Gilliam@Sun.COM 			goto done;
20688331SJerry.Gilliam@Sun.COM 		}
20698331SJerry.Gilliam@Sun.COM 	}
20708331SJerry.Gilliam@Sun.COM 
20718331SJerry.Gilliam@Sun.COM done:
20728331SJerry.Gilliam@Sun.COM 	(void) fclose(fp);
20738331SJerry.Gilliam@Sun.COM 	return (status);
20748331SJerry.Gilliam@Sun.COM }
20758331SJerry.Gilliam@Sun.COM 
20768331SJerry.Gilliam@Sun.COM int
trim_duplicate_aliases(char * driver_name,char * aliases,char ** aliases2p)20778331SJerry.Gilliam@Sun.COM trim_duplicate_aliases(char *driver_name, char *aliases, char **aliases2p)
20788331SJerry.Gilliam@Sun.COM {
20798331SJerry.Gilliam@Sun.COM 	char *current_head;
20808331SJerry.Gilliam@Sun.COM 	char *previous_head;
20818331SJerry.Gilliam@Sun.COM 	char *one_entry;
20828331SJerry.Gilliam@Sun.COM 	char *aliases2;
20838331SJerry.Gilliam@Sun.COM 	int rv, len;
20848331SJerry.Gilliam@Sun.COM 	int n = 0;
20858331SJerry.Gilliam@Sun.COM 
20868331SJerry.Gilliam@Sun.COM 	*aliases2p = NULL;
20878331SJerry.Gilliam@Sun.COM 	len = strlen(aliases) + 1;
20888331SJerry.Gilliam@Sun.COM 
20898331SJerry.Gilliam@Sun.COM 	one_entry = calloc(len, 1);
20908331SJerry.Gilliam@Sun.COM 	aliases2 = calloc(len, 1);
20918331SJerry.Gilliam@Sun.COM 	if (one_entry == NULL || aliases2 == NULL) {
20928331SJerry.Gilliam@Sun.COM 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
20938331SJerry.Gilliam@Sun.COM 		return (ERROR);
20948331SJerry.Gilliam@Sun.COM 	}
20958331SJerry.Gilliam@Sun.COM 
20968331SJerry.Gilliam@Sun.COM 	previous_head = aliases;
20978331SJerry.Gilliam@Sun.COM 
20988331SJerry.Gilliam@Sun.COM 	do {
20998331SJerry.Gilliam@Sun.COM 		(void) bzero(one_entry, len);
21008331SJerry.Gilliam@Sun.COM 		current_head = get_entry(previous_head, one_entry, ' ', 1);
21018331SJerry.Gilliam@Sun.COM 		previous_head = current_head;
21028331SJerry.Gilliam@Sun.COM 
21038331SJerry.Gilliam@Sun.COM 		rv = check_duplicate_driver_alias(driver_name, one_entry);
21048331SJerry.Gilliam@Sun.COM 		switch (rv) {
21058331SJerry.Gilliam@Sun.COM 		case SUCCESS:
21068331SJerry.Gilliam@Sun.COM 			/* not an existing driver alias: add it */
21078331SJerry.Gilliam@Sun.COM 			if (n > 0) {
21088331SJerry.Gilliam@Sun.COM 				if (strlcat(aliases2, " ", len) >= len)
21098331SJerry.Gilliam@Sun.COM 					goto err;
21108331SJerry.Gilliam@Sun.COM 			}
21118331SJerry.Gilliam@Sun.COM 			if (strlcat(aliases2, one_entry, len) >= len)
21128331SJerry.Gilliam@Sun.COM 				goto err;
21138331SJerry.Gilliam@Sun.COM 			n++;
21148331SJerry.Gilliam@Sun.COM 			break;
21158331SJerry.Gilliam@Sun.COM 		case NOT_UNIQUE:
21168331SJerry.Gilliam@Sun.COM 			/* matching driver alias exists: do not add it */
21178331SJerry.Gilliam@Sun.COM 			break;
21188331SJerry.Gilliam@Sun.COM 		case ERROR:
21198331SJerry.Gilliam@Sun.COM 			/* error reading the alias file */
21208331SJerry.Gilliam@Sun.COM 			goto err;
21218331SJerry.Gilliam@Sun.COM 		default:
21228331SJerry.Gilliam@Sun.COM 			goto err;
21238331SJerry.Gilliam@Sun.COM 		}
21248331SJerry.Gilliam@Sun.COM 
21258331SJerry.Gilliam@Sun.COM 		if (!is_token(one_entry)) {
21268331SJerry.Gilliam@Sun.COM 			(void) fprintf(stderr, gettext(ERR_BAD_TOK),
21278331SJerry.Gilliam@Sun.COM 			    "-i", one_entry);
21288331SJerry.Gilliam@Sun.COM 			goto err;
21298331SJerry.Gilliam@Sun.COM 		}
21308331SJerry.Gilliam@Sun.COM 	} while (*current_head != '\0');
21318331SJerry.Gilliam@Sun.COM 
21328331SJerry.Gilliam@Sun.COM 	/*
21338331SJerry.Gilliam@Sun.COM 	 * If all the aliases listed are already
21348331SJerry.Gilliam@Sun.COM 	 * present we actually have none to do.
21358331SJerry.Gilliam@Sun.COM 	 */
21368331SJerry.Gilliam@Sun.COM 	if (n == 0) {
21378331SJerry.Gilliam@Sun.COM 		free(aliases2);
21388331SJerry.Gilliam@Sun.COM 	} else {
21398331SJerry.Gilliam@Sun.COM 		*aliases2p = aliases2;
21408331SJerry.Gilliam@Sun.COM 	}
21418331SJerry.Gilliam@Sun.COM 	free(one_entry);
21428331SJerry.Gilliam@Sun.COM 	return (NOERR);
21438331SJerry.Gilliam@Sun.COM 
21448331SJerry.Gilliam@Sun.COM err:
21458331SJerry.Gilliam@Sun.COM 	free(aliases2);
21468331SJerry.Gilliam@Sun.COM 	free(one_entry);
21478331SJerry.Gilliam@Sun.COM 	return (ERROR);
21488331SJerry.Gilliam@Sun.COM }
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate int
check_space_within_quote(char * str)21510Sstevel@tonic-gate check_space_within_quote(char *str)
21520Sstevel@tonic-gate {
21530Sstevel@tonic-gate 	register int i;
21540Sstevel@tonic-gate 	register int len;
21550Sstevel@tonic-gate 	int quoted = 0;
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 	len = strlen(str);
21580Sstevel@tonic-gate 	for (i = 0; i < len; i++, str++) {
21590Sstevel@tonic-gate 		if (*str == '"') {
21600Sstevel@tonic-gate 			if (quoted == 0)
21610Sstevel@tonic-gate 				quoted++;
21620Sstevel@tonic-gate 			else
21630Sstevel@tonic-gate 				quoted--;
21640Sstevel@tonic-gate 		} else if (*str == ' ' && quoted)
21650Sstevel@tonic-gate 			return (ERROR);
21660Sstevel@tonic-gate 	}
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	return (0);
21690Sstevel@tonic-gate }
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate /*
21730Sstevel@tonic-gate  * get major number
21740Sstevel@tonic-gate  * write driver_name major_num to name_to_major file
21750Sstevel@tonic-gate  * major_num returned in major_num
21760Sstevel@tonic-gate  * return success/failure
21770Sstevel@tonic-gate  */
21780Sstevel@tonic-gate int
update_name_to_major(char * driver_name,major_t * major_num,int server)21790Sstevel@tonic-gate update_name_to_major(char *driver_name, major_t *major_num, int server)
21800Sstevel@tonic-gate {
21810Sstevel@tonic-gate 	char major[MAX_STR_MAJOR + 1];
21820Sstevel@tonic-gate 	struct stat buf;
21830Sstevel@tonic-gate 	char *num_list;
21840Sstevel@tonic-gate 	char drv_majnum_str[MAX_STR_MAJOR + 1];
21850Sstevel@tonic-gate 	int new_maj = -1;
21860Sstevel@tonic-gate 	int i, tmp = 0, is_unique, have_rem_n2m = 0;
21870Sstevel@tonic-gate 	int max_dev = 0;
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	/*
21900Sstevel@tonic-gate 	 * if driver_name already in rem_name_to_major
21910Sstevel@tonic-gate 	 * 	delete entry from rem_nam_to_major
21920Sstevel@tonic-gate 	 *	put entry into name_to_major
21930Sstevel@tonic-gate 	 */
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	if (stat(rem_name_to_major, &buf) == 0) {
21960Sstevel@tonic-gate 		have_rem_n2m = 1;
21970Sstevel@tonic-gate 	}
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 	if (have_rem_n2m) {
22000Sstevel@tonic-gate 		if ((is_unique = get_major_no(driver_name, rem_name_to_major))
22010Sstevel@tonic-gate 		    == ERROR)
22020Sstevel@tonic-gate 			return (ERROR);
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 		/*
22050Sstevel@tonic-gate 		 * found a match in rem_name_to_major
22060Sstevel@tonic-gate 		 */
22070Sstevel@tonic-gate 		if (is_unique != UNIQUE) {
22080Sstevel@tonic-gate 			char scratch[FILENAME_MAX];
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 			/*
22110Sstevel@tonic-gate 			 * If there is a match in /etc/rem_name_to_major then
22120Sstevel@tonic-gate 			 * be paranoid: is that major number already in
22130Sstevel@tonic-gate 			 * /etc/name_to_major (potentially under another name)?
22140Sstevel@tonic-gate 			 */
22150Sstevel@tonic-gate 			if (get_driver_name(is_unique, name_to_major,
22160Sstevel@tonic-gate 			    scratch) != UNIQUE) {
22170Sstevel@tonic-gate 				/*
22180Sstevel@tonic-gate 				 * nuke the rem_name_to_major entry-- it
22190Sstevel@tonic-gate 				 * isn't helpful.
22200Sstevel@tonic-gate 				 */
22210Sstevel@tonic-gate 				(void) delete_entry(rem_name_to_major,
22220Sstevel@tonic-gate 				    driver_name, " ", NULL);
22230Sstevel@tonic-gate 			} else {
22240Sstevel@tonic-gate 				(void) snprintf(major, sizeof (major),
22250Sstevel@tonic-gate 				    "%d", is_unique);
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 				if (append_to_file(driver_name, major,
22284145Scth 				    name_to_major, ' ', " ", 0) == ERROR) {
22290Sstevel@tonic-gate 					(void) fprintf(stderr,
22300Sstevel@tonic-gate 					    gettext(ERR_NO_UPDATE),
22310Sstevel@tonic-gate 					    name_to_major);
22320Sstevel@tonic-gate 					return (ERROR);
22330Sstevel@tonic-gate 				}
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate 				if (delete_entry(rem_name_to_major,
22360Sstevel@tonic-gate 				    driver_name, " ", NULL) == ERROR) {
22370Sstevel@tonic-gate 					(void) fprintf(stderr,
22380Sstevel@tonic-gate 					    gettext(ERR_DEL_ENTRY), driver_name,
22390Sstevel@tonic-gate 					    rem_name_to_major);
22400Sstevel@tonic-gate 					return (ERROR);
22410Sstevel@tonic-gate 				}
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 				/* found matching entry : no errors */
22440Sstevel@tonic-gate 				*major_num = is_unique;
22450Sstevel@tonic-gate 				return (NOERR);
22460Sstevel@tonic-gate 			}
22470Sstevel@tonic-gate 		}
22480Sstevel@tonic-gate 	}
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 	/*
22510Sstevel@tonic-gate 	 * Bugid: 1264079
22520Sstevel@tonic-gate 	 * In a server case (with -b option), we can't use modctl() to find
22530Sstevel@tonic-gate 	 *    the maximum major number, we need to dig thru client's
22540Sstevel@tonic-gate 	 *    /etc/name_to_major and /etc/rem_name_to_major for the max_dev.
22550Sstevel@tonic-gate 	 *
22560Sstevel@tonic-gate 	 * if (server)
22570Sstevel@tonic-gate 	 *    get maximum major number thru (rem_)name_to_major file on client
22580Sstevel@tonic-gate 	 * else
22590Sstevel@tonic-gate 	 *    get maximum major number allowable on current system using modctl
22600Sstevel@tonic-gate 	 */
22610Sstevel@tonic-gate 	if (server) {
22620Sstevel@tonic-gate 		max_dev = 0;
22630Sstevel@tonic-gate 		tmp = 0;
22640Sstevel@tonic-gate 
22650Sstevel@tonic-gate 		max_dev = get_max_major(name_to_major);
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 		/* If rem_name_to_major exists, we need to check it too */
22680Sstevel@tonic-gate 		if (have_rem_n2m) {
22690Sstevel@tonic-gate 			tmp = get_max_major(rem_name_to_major);
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate 			/*
22720Sstevel@tonic-gate 			 * If name_to_major is missing, we can get max_dev from
22730Sstevel@tonic-gate 			 * /etc/rem_name_to_major.  If both missing, bail out!
22740Sstevel@tonic-gate 			 */
22750Sstevel@tonic-gate 			if ((max_dev == ERROR) && (tmp == ERROR)) {
22760Sstevel@tonic-gate 				(void) fprintf(stderr,
22778331SJerry.Gilliam@Sun.COM 				    gettext(ERR_CANT_ACCESS_FILE),
22788331SJerry.Gilliam@Sun.COM 				    name_to_major);
22790Sstevel@tonic-gate 				return (ERROR);
22800Sstevel@tonic-gate 			}
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 			/* guard against bigger maj_num in rem_name_to_major */
22830Sstevel@tonic-gate 			if (tmp > max_dev)
22840Sstevel@tonic-gate 				max_dev = tmp;
22850Sstevel@tonic-gate 		} else {
22860Sstevel@tonic-gate 			/*
22870Sstevel@tonic-gate 			 * If we can't get major from name_to_major file
22880Sstevel@tonic-gate 			 * and there is no /etc/rem_name_to_major file,
22890Sstevel@tonic-gate 			 * then we don't have a max_dev, bail out quick!
22900Sstevel@tonic-gate 			 */
22910Sstevel@tonic-gate 			if (max_dev == ERROR)
22920Sstevel@tonic-gate 				return (ERROR);
22930Sstevel@tonic-gate 		}
22940Sstevel@tonic-gate 
22950Sstevel@tonic-gate 		/*
22960Sstevel@tonic-gate 		 * In case there is no more slack in current name_to_major
22970Sstevel@tonic-gate 		 * table, provide at least 1 extra entry so the add_drv can
22980Sstevel@tonic-gate 		 * succeed.  Since only one add_drv process is allowed at one
22990Sstevel@tonic-gate 		 * time, and hence max_dev will be re-calculated each time
23000Sstevel@tonic-gate 		 * add_drv is ran, we don't need to worry about adding more
23010Sstevel@tonic-gate 		 * than 1 extra slot for max_dev.
23020Sstevel@tonic-gate 		 */
23030Sstevel@tonic-gate 		max_dev++;
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	} else {
23060Sstevel@tonic-gate 		if (modctl(MODRESERVED, NULL, &max_dev) < 0) {
23070Sstevel@tonic-gate 			perror(NULL);
23080Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MAX_MAJOR));
23090Sstevel@tonic-gate 			return (ERROR);
23100Sstevel@tonic-gate 		}
23110Sstevel@tonic-gate 	}
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 	/*
23140Sstevel@tonic-gate 	 * max_dev is really how many slots the kernel has allocated for
23150Sstevel@tonic-gate 	 * devices... [0 , maxdev-1], not the largest available device num.
23160Sstevel@tonic-gate 	 */
23170Sstevel@tonic-gate 	if ((num_list = calloc(max_dev, 1)) == NULL) {
23180Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
23190Sstevel@tonic-gate 		return (ERROR);
23200Sstevel@tonic-gate 	}
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	/*
23230Sstevel@tonic-gate 	 * Populate the num_list array
23240Sstevel@tonic-gate 	 */
23250Sstevel@tonic-gate 	if (fill_n2m_array(name_to_major, &num_list, &max_dev) != 0) {
23260Sstevel@tonic-gate 		return (ERROR);
23270Sstevel@tonic-gate 	}
23280Sstevel@tonic-gate 	if (have_rem_n2m) {
23290Sstevel@tonic-gate 		if (fill_n2m_array(rem_name_to_major, &num_list, &max_dev) != 0)
23300Sstevel@tonic-gate 			return (ERROR);
23310Sstevel@tonic-gate 	}
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	/* find first free major number */
23340Sstevel@tonic-gate 	for (i = 0; i < max_dev; i++) {
23350Sstevel@tonic-gate 		if (num_list[i] != 1) {
23360Sstevel@tonic-gate 			new_maj = i;
23370Sstevel@tonic-gate 			break;
23380Sstevel@tonic-gate 		}
23390Sstevel@tonic-gate 	}
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	if (new_maj == -1) {
23420Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_FREE_MAJOR));
23430Sstevel@tonic-gate 		return (ERROR);
23440Sstevel@tonic-gate 	}
23450Sstevel@tonic-gate 
23469268SJerry.Gilliam@Sun.COM 	(void) snprintf(drv_majnum_str, sizeof (drv_majnum_str),
23479268SJerry.Gilliam@Sun.COM 	    "%d", new_maj);
23480Sstevel@tonic-gate 	if (do_the_update(driver_name, drv_majnum_str) == ERROR) {
23490Sstevel@tonic-gate 		return (ERROR);
23500Sstevel@tonic-gate 	}
23510Sstevel@tonic-gate 
23520Sstevel@tonic-gate 	*major_num = new_maj;
23530Sstevel@tonic-gate 	return (NOERR);
23540Sstevel@tonic-gate }
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate int
fill_n2m_array(char * filename,char ** array,int * nelems)23580Sstevel@tonic-gate fill_n2m_array(char *filename, char **array, int *nelems)
23590Sstevel@tonic-gate {
23600Sstevel@tonic-gate 	FILE *fp;
23612805Seota 	char line[MAX_N2M_ALIAS_LINE + 1], *cp;
23620Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
23630Sstevel@tonic-gate 	u_longlong_t dnum;
23640Sstevel@tonic-gate 	major_t drv_majnum;
23650Sstevel@tonic-gate 
23660Sstevel@tonic-gate 	/*
23670Sstevel@tonic-gate 	 * Read through the file, marking each major number found
23680Sstevel@tonic-gate 	 * order is not relevant
23690Sstevel@tonic-gate 	 */
23700Sstevel@tonic-gate 	if ((fp = fopen(filename, "r")) == NULL) {
23710Sstevel@tonic-gate 		perror(NULL);
23720Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), filename);
23730Sstevel@tonic-gate 		return (ERROR);
23740Sstevel@tonic-gate 	}
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != 0) {
23772805Seota 		/* cut off comments starting with '#' */
23782805Seota 		if ((cp = strchr(line, '#')) != NULL)
23792805Seota 			*cp = '\0';
23802805Seota 		/* ignore comment or blank lines */
23812805Seota 		if (is_blank(line))
23822805Seota 			continue;
23832805Seota 		/* sanity-check */
238410599SJerry.Gilliam@Sun.COM 		if (sscanf(line,
238510599SJerry.Gilliam@Sun.COM 		    "%" VAL2STR(FILENAME_MAX) "s %llu", drv, &dnum) != 2) {
23860Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
23870Sstevel@tonic-gate 			    filename, line);
23880Sstevel@tonic-gate 			(void) fclose(fp);
23890Sstevel@tonic-gate 			return (ERROR);
23900Sstevel@tonic-gate 		}
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 		if (dnum > L_MAXMAJ32) {
23930Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MAJ_TOOBIG), drv,
23940Sstevel@tonic-gate 			    dnum, filename, L_MAXMAJ32);
23950Sstevel@tonic-gate 			continue;
23960Sstevel@tonic-gate 		}
23970Sstevel@tonic-gate 		/*
23980Sstevel@tonic-gate 		 * cast down to a major_t; we can be sure this is safe because
23990Sstevel@tonic-gate 		 * of the above range-check.
24000Sstevel@tonic-gate 		 */
24010Sstevel@tonic-gate 		drv_majnum = (major_t)dnum;
24020Sstevel@tonic-gate 
24030Sstevel@tonic-gate 		if (drv_majnum >= *nelems) {
24040Sstevel@tonic-gate 			/*
24050Sstevel@tonic-gate 			 * Allocate some more space, up to drv_majnum + 1 so
24060Sstevel@tonic-gate 			 * we can accomodate 0 through drv_majnum.
24070Sstevel@tonic-gate 			 *
24080Sstevel@tonic-gate 			 * Note that in the failure case, we leak all of the
24090Sstevel@tonic-gate 			 * old contents of array.  It's ok, since we just
24100Sstevel@tonic-gate 			 * wind up exiting immediately anyway.
24110Sstevel@tonic-gate 			 */
24120Sstevel@tonic-gate 			*nelems = drv_majnum + 1;
24130Sstevel@tonic-gate 			*array = realloc(*array, *nelems);
24140Sstevel@tonic-gate 			if (*array == NULL) {
24150Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
24160Sstevel@tonic-gate 				return (ERROR);
24170Sstevel@tonic-gate 			}
24180Sstevel@tonic-gate 		}
24190Sstevel@tonic-gate 		(*array)[drv_majnum] = 1;
24200Sstevel@tonic-gate 	}
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 	(void) fclose(fp);
24230Sstevel@tonic-gate 	return (0);
24240Sstevel@tonic-gate }
24250Sstevel@tonic-gate 
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate int
do_the_update(char * driver_name,char * major_number)24280Sstevel@tonic-gate do_the_update(char *driver_name, char *major_number)
24290Sstevel@tonic-gate {
24300Sstevel@tonic-gate 	return (append_to_file(driver_name, major_number, name_to_major,
24314145Scth 	    ' ', " ", 0));
24320Sstevel@tonic-gate }
24332805Seota 
24342805Seota /*
24352805Seota  * is_blank() returns 1 (true) if a line specified is composed of
24362805Seota  * whitespace characters only. otherwise, it returns 0 (false).
24372805Seota  *
24382805Seota  * Note. the argument (line) must be null-terminated.
24392805Seota  */
24402805Seota static int
is_blank(char * line)24412805Seota is_blank(char *line)
24422805Seota {
24432805Seota 	for (/* nothing */; *line != '\0'; line++)
24442805Seota 		if (!isspace(*line))
24452805Seota 			return (0);
24462805Seota 	return (1);
24472805Seota }
2448