xref: /illumos-gate/usr/src/cmd/modload/drvsubr.c (revision b2d74f53)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51ca93273Seota  * Common Development and Distribution License (the "License").
61ca93273Seota  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2188181e00SAlexander Eremin /*
2288181e00SAlexander Eremin  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
2388181e00SAlexander Eremin  * Use is subject to license terms.
2488181e00SAlexander Eremin  */
257c478bd9Sstevel@tonic-gate /*
266532b960SJerry Gilliam  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate  */
29e4a991ebSAndy Fiddaman /*
30e4a991ebSAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
31e4a991ebSAndy Fiddaman  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
351ca93273Seota #include <ctype.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <libintl.h>
397c478bd9Sstevel@tonic-gate #include <wait.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
410013e2d3SJerry Gilliam #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <errno.h>
437c478bd9Sstevel@tonic-gate #include <fcntl.h>
447c478bd9Sstevel@tonic-gate #include <signal.h>
457c478bd9Sstevel@tonic-gate #include <sys/buf.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <grp.h>
487c478bd9Sstevel@tonic-gate #include "addrem.h"
497c478bd9Sstevel@tonic-gate #include "errmsg.h"
507c478bd9Sstevel@tonic-gate #include "plcysubr.h"
517c478bd9Sstevel@tonic-gate 
523c0ea289SJerry Gilliam /*
533c0ea289SJerry Gilliam  * Macros to produce a quoted string containing the value of a
543c0ea289SJerry Gilliam  * preprocessor macro. For example, if SIZE is defined to be 256,
553c0ea289SJerry Gilliam  * VAL2STR(SIZE) is "256". This is used to construct format
563c0ea289SJerry Gilliam  * strings for scanf-family functions below.
573c0ea289SJerry Gilliam  * Note: For format string use, the argument to VAL2STR() must
583c0ea289SJerry Gilliam  * be a numeric constant that is one less than the size of the
593c0ea289SJerry Gilliam  * corresponding data buffer.
603c0ea289SJerry Gilliam  */
613c0ea289SJerry Gilliam #define	VAL2STR_QUOTE(x)	#x
623c0ea289SJerry Gilliam #define	VAL2STR(x)		VAL2STR_QUOTE(x)
633c0ea289SJerry Gilliam 
643c0ea289SJerry Gilliam /*
653c0ea289SJerry Gilliam  * Convenience macro to determine if a character is a quote
663c0ea289SJerry Gilliam  */
673c0ea289SJerry Gilliam #define	isquote(c)	(((c) == '"') || ((c) == '\''))
683c0ea289SJerry Gilliam 
69*b2d74f53SToomas Soome char *driver_aliases;
70*b2d74f53SToomas Soome char *driver_classes;
71*b2d74f53SToomas Soome char *device_policy;
72*b2d74f53SToomas Soome char *extra_privs;
73*b2d74f53SToomas Soome char *devfs_root;
74*b2d74f53SToomas Soome char *minor_perm;
75*b2d74f53SToomas Soome struct drvmod_dir *moddir;
76*b2d74f53SToomas Soome char *name_to_major;
77*b2d74f53SToomas Soome char *rem_name_to_major;
783c0ea289SJerry Gilliam 
797c478bd9Sstevel@tonic-gate static char *add_rem_lock;	/* lock file */
8049e92448Svikram static int  add_rem_lock_fd = -1;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static int get_cached_n_to_m_file(char *filename, char ***cache);
837c478bd9Sstevel@tonic-gate static int get_name_to_major_entry(int *major_no, char *driver_name,
847c478bd9Sstevel@tonic-gate     char *file_name);
857c478bd9Sstevel@tonic-gate 
861ca93273Seota static int is_blank(char *);
871ca93273Seota 
887c478bd9Sstevel@tonic-gate /*ARGSUSED*/
897c478bd9Sstevel@tonic-gate void
log_minorperm_error(minorperm_err_t err,int key)907c478bd9Sstevel@tonic-gate log_minorperm_error(minorperm_err_t err, int key)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	switch (err) {
937c478bd9Sstevel@tonic-gate 	case MP_FOPEN_ERR:
947c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
950013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
967c478bd9Sstevel@tonic-gate 		break;
977c478bd9Sstevel@tonic-gate 	case MP_FCLOSE_ERR:
987c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
990013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
1007c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1017c478bd9Sstevel@tonic-gate 		break;
1027c478bd9Sstevel@tonic-gate 	case MP_IGNORING_LINE_ERR:
1037c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1040013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
1057c478bd9Sstevel@tonic-gate 		break;
1067c478bd9Sstevel@tonic-gate 	case MP_ALLOC_ERR:
1077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1080013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
1097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1107c478bd9Sstevel@tonic-gate 		break;
1117c478bd9Sstevel@tonic-gate 	case MP_NVLIST_ERR:
1127c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1130013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
1147c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1157c478bd9Sstevel@tonic-gate 		break;
1167c478bd9Sstevel@tonic-gate 	case MP_CANT_FIND_USER_ERR:
1177c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1180013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
1197c478bd9Sstevel@tonic-gate 		break;
1207c478bd9Sstevel@tonic-gate 	case MP_CANT_FIND_GROUP_ERR:
1217c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1220013e2d3SJerry Gilliam 		    MINOR_PERM_FILE);
1237c478bd9Sstevel@tonic-gate 		break;
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  *  open file
1297c478bd9Sstevel@tonic-gate  * for each entry in list
1307c478bd9Sstevel@tonic-gate  *	where list entries are separated by <list_separator>
131e4a991ebSAndy Fiddaman  *	append entry : driver_name <entry_separator> entry
1327c478bd9Sstevel@tonic-gate  * close file
1337c478bd9Sstevel@tonic-gate  * return error/noerr
1347c478bd9Sstevel@tonic-gate  */
1357c478bd9Sstevel@tonic-gate int
append_to_file(char * driver_name,char * entry_list,char * filename,char list_separator,char * entry_separator,int quoted)1367c478bd9Sstevel@tonic-gate append_to_file(
1377c478bd9Sstevel@tonic-gate 	char *driver_name,
1387c478bd9Sstevel@tonic-gate 	char *entry_list,
1397c478bd9Sstevel@tonic-gate 	char *filename,
1407c478bd9Sstevel@tonic-gate 	char list_separator,
141f4da9be0Scth 	char *entry_separator,
142f4da9be0Scth 	int quoted)
1437c478bd9Sstevel@tonic-gate {
1443c0ea289SJerry Gilliam 	int	len, line_len;
1457c478bd9Sstevel@tonic-gate 	int	fpint;
1467c478bd9Sstevel@tonic-gate 	char	*current_head, *previous_head;
1477c478bd9Sstevel@tonic-gate 	char	*line, *one_entry;
1487c478bd9Sstevel@tonic-gate 	FILE	*fp;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	if ((fp = fopen(filename, "a")) == NULL) {
1517c478bd9Sstevel@tonic-gate 		perror(NULL);
1527c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
1537c478bd9Sstevel@tonic-gate 		    filename);
1547c478bd9Sstevel@tonic-gate 		return (ERROR);
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	len = strlen(entry_list);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	one_entry = calloc(len + 1, 1);
1607c478bd9Sstevel@tonic-gate 	if (one_entry == NULL) {
1617c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename);
1627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1637c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
1647c478bd9Sstevel@tonic-gate 		return (ERROR);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	previous_head = entry_list;
1687c478bd9Sstevel@tonic-gate 
169f8cb811fSEdward Pilatowicz 	line_len = strlen(driver_name) + len + 4;
170f8cb811fSEdward Pilatowicz 	if (quoted)
171f8cb811fSEdward Pilatowicz 		line_len += 2;
172f8cb811fSEdward Pilatowicz 
173f8cb811fSEdward Pilatowicz 	line = calloc(line_len, 1);
1747c478bd9Sstevel@tonic-gate 	if (line == NULL) {
1757c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
1767c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
1777c478bd9Sstevel@tonic-gate 		err_exit();
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * get one entry at a time from list and append to <filename> file
1827c478bd9Sstevel@tonic-gate 	 */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	do {
1853c0ea289SJerry Gilliam 		bzero(one_entry, len + 1);
186f8cb811fSEdward Pilatowicz 		bzero(line, line_len);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		current_head = get_entry(previous_head, one_entry,
189f4da9be0Scth 		    list_separator, quoted);
1907c478bd9Sstevel@tonic-gate 		previous_head = current_head;
1917c478bd9Sstevel@tonic-gate 
1923c0ea289SJerry Gilliam 		(void) snprintf(line, line_len,
1933c0ea289SJerry Gilliam 		    quoted ? "%s%s\"%s\"\n" : "%s%s%s\n",
1943c0ea289SJerry Gilliam 		    driver_name, entry_separator, one_entry);
1953c0ea289SJerry Gilliam 
1963c0ea289SJerry Gilliam 		if ((fputs(line, fp)) == EOF) {
1973c0ea289SJerry Gilliam 			perror(NULL);
1983c0ea289SJerry Gilliam 			(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
1993c0ea289SJerry Gilliam 			    filename);
2003c0ea289SJerry Gilliam 		}
2013c0ea289SJerry Gilliam 
2023c0ea289SJerry Gilliam 	} while (*current_head != '\0');
2033c0ea289SJerry Gilliam 
2043c0ea289SJerry Gilliam 
2053c0ea289SJerry Gilliam 	(void) fflush(fp);
2063c0ea289SJerry Gilliam 
2073c0ea289SJerry Gilliam 	fpint = fileno(fp);
2083c0ea289SJerry Gilliam 	(void) fsync(fpint);
2093c0ea289SJerry Gilliam 
2103c0ea289SJerry Gilliam 	(void) fclose(fp);
2113c0ea289SJerry Gilliam 
2123c0ea289SJerry Gilliam 	free(one_entry);
2133c0ea289SJerry Gilliam 	free(line);
2143c0ea289SJerry Gilliam 
2153c0ea289SJerry Gilliam 	return (NOERR);
2163c0ea289SJerry Gilliam }
2173c0ea289SJerry Gilliam 
2183c0ea289SJerry Gilliam /*
2193c0ea289SJerry Gilliam  *  open file
2203c0ea289SJerry Gilliam  * for each entry in list
2213c0ea289SJerry Gilliam  *	where list entries are separated by <list_separator>
222e4a991ebSAndy Fiddaman  *	append entry : driver_name <entry_separator> entry
2233c0ea289SJerry Gilliam  * close file
2243c0ea289SJerry Gilliam  * return error/noerr
2253c0ea289SJerry Gilliam  */
2263c0ea289SJerry Gilliam int
append_to_minor_perm(char * driver_name,char * entry_list,char * filename)2273c0ea289SJerry Gilliam append_to_minor_perm(
2283c0ea289SJerry Gilliam 	char *driver_name,
2293c0ea289SJerry Gilliam 	char *entry_list,
2303c0ea289SJerry Gilliam 	char *filename)
2313c0ea289SJerry Gilliam {
2323c0ea289SJerry Gilliam 	int	len, line_len;
2333c0ea289SJerry Gilliam 	int	fpint;
2343c0ea289SJerry Gilliam 	char	*current_head, *previous_head;
2353c0ea289SJerry Gilliam 	char	*line, *one_entry;
2363c0ea289SJerry Gilliam 	FILE	*fp;
2373c0ea289SJerry Gilliam 
2383c0ea289SJerry Gilliam 	if ((fp = fopen(filename, "a")) == NULL) {
2393c0ea289SJerry Gilliam 		perror(NULL);
2403c0ea289SJerry Gilliam 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
2413c0ea289SJerry Gilliam 		    filename);
2423c0ea289SJerry Gilliam 		return (ERROR);
2433c0ea289SJerry Gilliam 	}
2443c0ea289SJerry Gilliam 
2453c0ea289SJerry Gilliam 	len = strlen(entry_list);
2463c0ea289SJerry Gilliam 
2473c0ea289SJerry Gilliam 	one_entry = calloc(len + 1, 1);
2483c0ea289SJerry Gilliam 	if (one_entry == NULL) {
2493c0ea289SJerry Gilliam 		(void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename);
2503c0ea289SJerry Gilliam 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
2513c0ea289SJerry Gilliam 		(void) fclose(fp);
2523c0ea289SJerry Gilliam 		return (ERROR);
2533c0ea289SJerry Gilliam 	}
2543c0ea289SJerry Gilliam 
2553c0ea289SJerry Gilliam 	previous_head = entry_list;
2563c0ea289SJerry Gilliam 
2573c0ea289SJerry Gilliam 	line_len = strlen(driver_name) + len + 4;
2583c0ea289SJerry Gilliam 	line = calloc(line_len, 1);
2593c0ea289SJerry Gilliam 	if (line == NULL) {
2603c0ea289SJerry Gilliam 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
2613c0ea289SJerry Gilliam 		(void) fclose(fp);
2623c0ea289SJerry Gilliam 		err_exit();
2633c0ea289SJerry Gilliam 	}
2643c0ea289SJerry Gilliam 
2653c0ea289SJerry Gilliam 	/*
2663c0ea289SJerry Gilliam 	 * get one entry at a time from list and append to <filename> file
2673c0ea289SJerry Gilliam 	 */
2683c0ea289SJerry Gilliam 	do {
2693c0ea289SJerry Gilliam 		bzero(one_entry, len + 1);
2703c0ea289SJerry Gilliam 		bzero(line, line_len);
2713c0ea289SJerry Gilliam 
2723c0ea289SJerry Gilliam 		current_head = get_perm_entry(previous_head, one_entry);
2733c0ea289SJerry Gilliam 		previous_head = current_head;
2743c0ea289SJerry Gilliam 
2753c0ea289SJerry Gilliam 		(void) snprintf(line, line_len, "%s:%s\n",
2763c0ea289SJerry Gilliam 		    driver_name, one_entry);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 		if ((fputs(line, fp)) == EOF) {
2797c478bd9Sstevel@tonic-gate 			perror(NULL);
2807c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
2817c478bd9Sstevel@tonic-gate 			    filename);
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	} while (*current_head != '\0');
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	(void) fflush(fp);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	fpint = fileno(fp);
2907c478bd9Sstevel@tonic-gate 	(void) fsync(fpint);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	free(one_entry);
2957c478bd9Sstevel@tonic-gate 	free(line);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	return (NOERR);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate 
30011ebc2d0SJerry Gilliam /*
30111ebc2d0SJerry Gilliam  * Require exact match to delete a driver alias/permission entry.
30211ebc2d0SJerry Gilliam  * Note line argument does not remain unchanged.  Return 1 if matched.
30311ebc2d0SJerry Gilliam  */
30411ebc2d0SJerry Gilliam static int
match_entry(char * line,char * match)30511ebc2d0SJerry Gilliam match_entry(char *line, char *match)
30611ebc2d0SJerry Gilliam {
30711ebc2d0SJerry Gilliam 	char	*token, *p;
30811ebc2d0SJerry Gilliam 	int	n;
30911ebc2d0SJerry Gilliam 
31011ebc2d0SJerry Gilliam 	/* skip any leading white space */
3113c0ea289SJerry Gilliam 	while (*line && isspace(*line))
31211ebc2d0SJerry Gilliam 		line++;
31311ebc2d0SJerry Gilliam 	/*
31411ebc2d0SJerry Gilliam 	 * Find separator for driver name, either space or colon
31511ebc2d0SJerry Gilliam 	 *	minor_perm: <driver>:<perm>
31611ebc2d0SJerry Gilliam 	 *	driver_aliases: <driver> <alias>
31711ebc2d0SJerry Gilliam 	 *	extra_privs: <driver>:<priv>
31811ebc2d0SJerry Gilliam 	 */
31911ebc2d0SJerry Gilliam 	if ((token = strpbrk(line, " :\t")) == NULL)
32011ebc2d0SJerry Gilliam 		return (0);
32111ebc2d0SJerry Gilliam 	token++;
32211ebc2d0SJerry Gilliam 	/* skip leading white space and quotes */
3233c0ea289SJerry Gilliam 	while (*token && (isspace(*token) || isquote(*token)))
32411ebc2d0SJerry Gilliam 		token++;
32511ebc2d0SJerry Gilliam 	/* strip trailing newline, white space and quotes */
32611ebc2d0SJerry Gilliam 	n = strlen(token);
32711ebc2d0SJerry Gilliam 	p = token + n-1;
3283c0ea289SJerry Gilliam 	while (n > 0 && (*p == '\n' || isspace(*p) || isquote(*p))) {
32911ebc2d0SJerry Gilliam 		*p-- = 0;
33011ebc2d0SJerry Gilliam 		n--;
33111ebc2d0SJerry Gilliam 	}
33211ebc2d0SJerry Gilliam 	if (n == 0)
33311ebc2d0SJerry Gilliam 		return (0);
33411ebc2d0SJerry Gilliam 	return (strcmp(token, match) == 0);
33511ebc2d0SJerry Gilliam }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  *  open file
3397c478bd9Sstevel@tonic-gate  * read thru file, deleting all entries if first
3407c478bd9Sstevel@tonic-gate  *    entry = driver_name
3417c478bd9Sstevel@tonic-gate  * close
3427c478bd9Sstevel@tonic-gate  * if error, leave original file intact with message
3437c478bd9Sstevel@tonic-gate  * assumption : drvconfig has been modified to work with clone
3447c478bd9Sstevel@tonic-gate  *  entries in /etc/minor_perm as driver:mummble NOT
3457c478bd9Sstevel@tonic-gate  *  clone:driver mummble
3467c478bd9Sstevel@tonic-gate  * this implementation will NOT find clone entries
3477c478bd9Sstevel@tonic-gate  * clone:driver mummble
3487c478bd9Sstevel@tonic-gate  * match:
3497c478bd9Sstevel@tonic-gate  *	delete just the matching entry
3507c478bd9Sstevel@tonic-gate  *
3517c478bd9Sstevel@tonic-gate  */
3527c478bd9Sstevel@tonic-gate int
delete_entry(char * oldfile,char * driver_name,char * marker,char * match)3537c478bd9Sstevel@tonic-gate delete_entry(
3547c478bd9Sstevel@tonic-gate 	char *oldfile,
3557c478bd9Sstevel@tonic-gate 	char *driver_name,
3567c478bd9Sstevel@tonic-gate 	char *marker,
3577c478bd9Sstevel@tonic-gate 	char *match)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	int		rv, i;
3607c478bd9Sstevel@tonic-gate 	int		status = NOERR;
3617c478bd9Sstevel@tonic-gate 	int		drvr_found = 0;
362e4a991ebSAndy Fiddaman 	boolean_t	nomatch = B_TRUE;
36388181e00SAlexander Eremin 	char		newfile[MAXPATHLEN];
36488181e00SAlexander Eremin 	char		*cp;
3653c0ea289SJerry Gilliam 	char		line[MAX_DBFILE_ENTRY];
3663c0ea289SJerry Gilliam 	char		drv[FILENAME_MAX + 1];
3677c478bd9Sstevel@tonic-gate 	FILE		*fp, *newfp;
3687c478bd9Sstevel@tonic-gate 	struct group	*sysgrp;
36988181e00SAlexander Eremin 	int		newfd;
37011ebc2d0SJerry Gilliam 	char		*copy;		/* same size as line */
3712e107de7SJerry Gilliam 	char		*match2 = NULL;	/* match with quotes cleaned up */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	/*
3742e107de7SJerry Gilliam 	 * if match is specified, sanity check it and clean it
3752e107de7SJerry Gilliam 	 * up by removing surrounding quotes as we require
3762e107de7SJerry Gilliam 	 * an exact match.
3777c478bd9Sstevel@tonic-gate 	 */
3782e107de7SJerry Gilliam 	if (match) {
3792e107de7SJerry Gilliam 		cp = match;
3803c0ea289SJerry Gilliam 		while (*cp && (isspace(*cp)))
3812e107de7SJerry Gilliam 			cp++;
3822e107de7SJerry Gilliam 		i = strlen(cp);
3832e107de7SJerry Gilliam 		if (i > 0) {
3842e107de7SJerry Gilliam 			if ((match2 = strdup(cp)) == NULL) {
3852e107de7SJerry Gilliam 				perror(NULL);
3862e107de7SJerry Gilliam 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
3872e107de7SJerry Gilliam 				return (ERROR);
3882e107de7SJerry Gilliam 			}
3893c0ea289SJerry Gilliam 			i = strlen(match2) - 1;
3903c0ea289SJerry Gilliam 			while (i >= 0 && (isspace(match2[i]))) {
3913c0ea289SJerry Gilliam 				match2[i] = 0;
3923c0ea289SJerry Gilliam 				i--;
3933c0ea289SJerry Gilliam 			}
3942e107de7SJerry Gilliam 		}
3952e107de7SJerry Gilliam 		if (match2 == NULL || (strlen(match2) == 0)) {
3962e107de7SJerry Gilliam 			(void) fprintf(stderr,
3972e107de7SJerry Gilliam 			    gettext(ERR_INT_UPDATE), oldfile);
3982e107de7SJerry Gilliam 			return (ERROR);
3992e107de7SJerry Gilliam 		}
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	if ((fp = fopen(oldfile, "r")) == NULL) {
4037c478bd9Sstevel@tonic-gate 		perror(NULL);
4047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile);
4057c478bd9Sstevel@tonic-gate 		return (ERROR);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
40811ebc2d0SJerry Gilliam 	/* Space for defensive copy of input line */
40988181e00SAlexander Eremin 	if ((copy = calloc(sizeof (line), 1)) == NULL) {
4107c478bd9Sstevel@tonic-gate 		perror(NULL);
4117c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
41211ebc2d0SJerry Gilliam 		return (ERROR);
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
41588181e00SAlexander Eremin 	/* Build filename for temporary file */
41688181e00SAlexander Eremin 	(void) snprintf(newfile, sizeof (newfile), "%s%s", oldfile, ".hold");
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/*
4197c478bd9Sstevel@tonic-gate 	 * Set gid so we preserve group attribute.  Ideally we wouldn't
4207c478bd9Sstevel@tonic-gate 	 * assume a gid of "sys" but we can't undo the damage on already
4217c478bd9Sstevel@tonic-gate 	 * installed systems unless we force the issue.
4227c478bd9Sstevel@tonic-gate 	 */
4237c478bd9Sstevel@tonic-gate 	if ((sysgrp = getgrnam("sys")) != NULL) {
4247c478bd9Sstevel@tonic-gate 		(void) setgid(sysgrp->gr_gid);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
42788181e00SAlexander Eremin 	if ((newfd = open(newfile, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) {
42888181e00SAlexander Eremin 		if (errno == EEXIST) {
42988181e00SAlexander Eremin 			(void) fprintf(stderr, gettext(ERR_FILE_EXISTS),
43088181e00SAlexander Eremin 			    newfile);
43188181e00SAlexander Eremin 			return (ERROR);
43288181e00SAlexander Eremin 		} else {
43388181e00SAlexander Eremin 			(void) fprintf(stderr, gettext(ERR_CREAT_LOCK),
43488181e00SAlexander Eremin 			    newfile);
43588181e00SAlexander Eremin 			return (ERROR);
43688181e00SAlexander Eremin 		}
43788181e00SAlexander Eremin 	}
4387c478bd9Sstevel@tonic-gate 
43988181e00SAlexander Eremin 	if ((newfp = fdopen(newfd, "w")) == NULL) {
4407c478bd9Sstevel@tonic-gate 		perror(NULL);
4417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE),
4427c478bd9Sstevel@tonic-gate 		    newfile);
44388181e00SAlexander Eremin 		(void) close(newfd);
4447c478bd9Sstevel@tonic-gate 		return (ERROR);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) {
44811ebc2d0SJerry Gilliam 		/* copy the whole line */
44911ebc2d0SJerry Gilliam 		if (strlcpy(copy, line, sizeof (line)) >= sizeof (line)) {
45011ebc2d0SJerry Gilliam 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
4511ca93273Seota 			status = ERROR;
4521ca93273Seota 			break;
4531ca93273Seota 		}
4541ca93273Seota 		/* cut off comments starting with '#' */
45511ebc2d0SJerry Gilliam 		if ((cp = strchr(copy, '#')) != NULL)
4561ca93273Seota 			*cp = '\0';
4571ca93273Seota 		/* ignore comment or blank lines */
45811ebc2d0SJerry Gilliam 		if (is_blank(copy)) {
4591ca93273Seota 			if (fputs(line, newfp) == EOF) {
4607c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
4617c478bd9Sstevel@tonic-gate 				    oldfile);
4627c478bd9Sstevel@tonic-gate 				status = ERROR;
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 			continue;
4657c478bd9Sstevel@tonic-gate 		}
4661ca93273Seota 
4671ca93273Seota 		/* get the driver name */
4683c0ea289SJerry Gilliam 		if (sscanf(copy, "%" VAL2STR(FILENAME_MAX) "s", drv) != 1) {
4697c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_LINE),
4707c478bd9Sstevel@tonic-gate 			    oldfile, line);
4717c478bd9Sstevel@tonic-gate 			status = ERROR;
4721ca93273Seota 			break;
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) {
4767c478bd9Sstevel@tonic-gate 			drv[i] =  '\0';
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 		if (strcmp(driver_name, drv) != 0) {
4807c478bd9Sstevel@tonic-gate 			if ((fputs(line, newfp)) == EOF) {
4817c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_UPDATE),
4827c478bd9Sstevel@tonic-gate 				    oldfile);
4837c478bd9Sstevel@tonic-gate 				status = ERROR;
4847c478bd9Sstevel@tonic-gate 			}
4857c478bd9Sstevel@tonic-gate 		} else {
4867c478bd9Sstevel@tonic-gate 			drvr_found++;
4872e107de7SJerry Gilliam 			if (match2) {	/* Just delete one entry */
4887c478bd9Sstevel@tonic-gate 				/* for now delete just minor_perm and aliases */
4897c478bd9Sstevel@tonic-gate 				if ((strcmp(oldfile, minor_perm) == 0) ||
4907c478bd9Sstevel@tonic-gate 				    (strcmp(oldfile, extra_privs) == 0) ||
4917c478bd9Sstevel@tonic-gate 				    (strcmp(oldfile, driver_aliases) == 0)) {
49211ebc2d0SJerry Gilliam 
49311ebc2d0SJerry Gilliam 					/* make defensive copy */
49411ebc2d0SJerry Gilliam 					if (strlcpy(copy, line, sizeof (line))
49511ebc2d0SJerry Gilliam 					    >= sizeof (line)) {
49611ebc2d0SJerry Gilliam 						(void) fprintf(stderr,
49711ebc2d0SJerry Gilliam 						    gettext(ERR_UPDATE),
49811ebc2d0SJerry Gilliam 						    oldfile);
49911ebc2d0SJerry Gilliam 						status = ERROR;
50011ebc2d0SJerry Gilliam 						break;
50111ebc2d0SJerry Gilliam 					}
5022e107de7SJerry Gilliam 					if (match_entry(copy, match2)) {
5037c478bd9Sstevel@tonic-gate 						nomatch = B_FALSE;
5047c478bd9Sstevel@tonic-gate 					} else {
5057c478bd9Sstevel@tonic-gate 						if ((fputs(line, newfp)) ==
5067c478bd9Sstevel@tonic-gate 						    EOF) {
5077c478bd9Sstevel@tonic-gate 							(void) fprintf(stderr,
5087c478bd9Sstevel@tonic-gate 							    gettext(ERR_UPDATE),
5097c478bd9Sstevel@tonic-gate 							    oldfile);
5107c478bd9Sstevel@tonic-gate 							status = ERROR;
5117c478bd9Sstevel@tonic-gate 						}
5127c478bd9Sstevel@tonic-gate 						if (nomatch != B_FALSE)
5137c478bd9Sstevel@tonic-gate 							nomatch = B_TRUE;
5147c478bd9Sstevel@tonic-gate 					}
5157c478bd9Sstevel@tonic-gate 				}
5167c478bd9Sstevel@tonic-gate 			}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		} /* end of else */
5197c478bd9Sstevel@tonic-gate 	} /* end of while */
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
52211ebc2d0SJerry Gilliam 	free(copy);
5232e107de7SJerry Gilliam 	if (match2)
5242e107de7SJerry Gilliam 		free(match2);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/* Make sure that the file is on disk */
5277c478bd9Sstevel@tonic-gate 	if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0)
5287c478bd9Sstevel@tonic-gate 		status = ERROR;
5297c478bd9Sstevel@tonic-gate 	else
5307c478bd9Sstevel@tonic-gate 		rv = NOERR;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	(void) fclose(newfp);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/* no matching driver found */
5357c478bd9Sstevel@tonic-gate 	rv = NOERR;
5367c478bd9Sstevel@tonic-gate 	if (!drvr_found ||
5377c478bd9Sstevel@tonic-gate 	    (nomatch == B_TRUE)) {
5387c478bd9Sstevel@tonic-gate 		rv = NONE_FOUND;
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/*
5427c478bd9Sstevel@tonic-gate 	 * if error, leave original file, delete new file
5437c478bd9Sstevel@tonic-gate 	 * if noerr, replace original file with new file
5447c478bd9Sstevel@tonic-gate 	 */
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (status == NOERR) {
54788181e00SAlexander Eremin 		if (rename(newfile, oldfile) == -1) {
5487c478bd9Sstevel@tonic-gate 			perror(NULL);
5497c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), oldfile);
5507c478bd9Sstevel@tonic-gate 			(void) unlink(newfile);
5517c478bd9Sstevel@tonic-gate 			return (ERROR);
5527c478bd9Sstevel@tonic-gate 		}
5537c478bd9Sstevel@tonic-gate 	} else {
5547c478bd9Sstevel@tonic-gate 		/*
5557c478bd9Sstevel@tonic-gate 		 * since there's an error, leave file alone; remove
5567c478bd9Sstevel@tonic-gate 		 * new file
5577c478bd9Sstevel@tonic-gate 		 */
5587c478bd9Sstevel@tonic-gate 		if (unlink(newfile) == -1) {
5597c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_RM), newfile);
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 		return (ERROR);
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	return (rv);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate /*
5697c478bd9Sstevel@tonic-gate  * wrapper for call to get_name_to_major_entry(): given driver name,
5707c478bd9Sstevel@tonic-gate  * retrieve major number.
5717c478bd9Sstevel@tonic-gate  */
5727c478bd9Sstevel@tonic-gate int
get_major_no(char * driver_name,char * file_name)5737c478bd9Sstevel@tonic-gate get_major_no(char *driver_name, char *file_name)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 	int major = UNIQUE;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (get_name_to_major_entry(&major, driver_name, file_name) == ERROR)
5787c478bd9Sstevel@tonic-gate 		return (ERROR);
5797c478bd9Sstevel@tonic-gate 	else
5807c478bd9Sstevel@tonic-gate 		return (major);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate  * wrapper for call to get_name_to_major_entry(): given major number,
5857c478bd9Sstevel@tonic-gate  * retrieve driver name.
5867c478bd9Sstevel@tonic-gate  */
5877c478bd9Sstevel@tonic-gate int
get_driver_name(int major,char * file_name,char * buf)5887c478bd9Sstevel@tonic-gate get_driver_name(int major, char *file_name, char *buf)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	if (major < 0)
5917c478bd9Sstevel@tonic-gate 		return (ERROR);
5927c478bd9Sstevel@tonic-gate 	return (get_name_to_major_entry(&major, buf, file_name));
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate  * return pointer to cached name_to_major file - reads file into
5987c478bd9Sstevel@tonic-gate  * cache if this has not already been done.  Since there may be
5997c478bd9Sstevel@tonic-gate  * requests for multiple name_to_major files (rem_name_to_major,
6007c478bd9Sstevel@tonic-gate  * name_to_major), this routine keeps a list of cached files.
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate static int
get_cached_n_to_m_file(char * filename,char *** cache)6037c478bd9Sstevel@tonic-gate get_cached_n_to_m_file(char *filename, char ***cache)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	struct n_to_m_cache {
6067c478bd9Sstevel@tonic-gate 		char *file;
6077c478bd9Sstevel@tonic-gate 		char **cached_file;
6087c478bd9Sstevel@tonic-gate 		int size;
6097c478bd9Sstevel@tonic-gate 		struct n_to_m_cache *next;
6107c478bd9Sstevel@tonic-gate 	};
6117c478bd9Sstevel@tonic-gate 	static struct n_to_m_cache *head = NULL;
6127c478bd9Sstevel@tonic-gate 	struct n_to_m_cache *ptr;
6137c478bd9Sstevel@tonic-gate 	FILE *fp;
6147c478bd9Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
6157c478bd9Sstevel@tonic-gate 	char entry[FILENAME_MAX + 1];
6161ca93273Seota 	char line[MAX_N2M_ALIAS_LINE], *cp;
6177c478bd9Sstevel@tonic-gate 	int maj;
6187c478bd9Sstevel@tonic-gate 	int size = 0;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/*
6227c478bd9Sstevel@tonic-gate 	 * see if the file is already cached - either
6237c478bd9Sstevel@tonic-gate 	 * rem_name_to_major or name_to_major
6247c478bd9Sstevel@tonic-gate 	 */
6257c478bd9Sstevel@tonic-gate 	ptr = head;
6267c478bd9Sstevel@tonic-gate 	while (ptr != NULL) {
6277c478bd9Sstevel@tonic-gate 		if (strcmp(ptr->file, filename) == 0)
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		ptr = ptr->next;
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if (ptr == NULL) {	/* we need to cache the contents */
6337c478bd9Sstevel@tonic-gate 		if ((fp = fopen(filename, "r")) == NULL) {
6347c478bd9Sstevel@tonic-gate 			perror(NULL);
6357c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_CANT_OPEN),
6367c478bd9Sstevel@tonic-gate 			    filename);
6377c478bd9Sstevel@tonic-gate 			return (ERROR);
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		while (fgets(line, sizeof (line), fp) != NULL) {
6411ca93273Seota 			/* cut off comments starting with '#' */
6421ca93273Seota 			if ((cp = strchr(line, '#')) != NULL)
6431ca93273Seota 				*cp = '\0';
6441ca93273Seota 			/* ignore comment or blank lines */
6451ca93273Seota 			if (is_blank(line))
6461ca93273Seota 				continue;
6471ca93273Seota 			/* sanity-check */
6483c0ea289SJerry Gilliam 			if (sscanf(line,
6493c0ea289SJerry Gilliam 			    "%" VAL2STR(FILENAME_MAX) "s"	/* drv */
6503c0ea289SJerry Gilliam 			    "%" VAL2STR(FILENAME_MAX) "s",	/* entry */
6513c0ea289SJerry Gilliam 			    drv, entry) != 2) {
6527c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
6537c478bd9Sstevel@tonic-gate 				    filename, line);
6547c478bd9Sstevel@tonic-gate 				continue;
6557c478bd9Sstevel@tonic-gate 			}
6567c478bd9Sstevel@tonic-gate 			maj = atoi(entry);
6577c478bd9Sstevel@tonic-gate 			if (maj > size)
6587c478bd9Sstevel@tonic-gate 				size = maj;
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		/* allocate struct to cache the file */
6627c478bd9Sstevel@tonic-gate 		ptr = (struct n_to_m_cache *)calloc(1,
6637c478bd9Sstevel@tonic-gate 		    sizeof (struct n_to_m_cache));
6647c478bd9Sstevel@tonic-gate 		if (ptr == NULL) {
6657c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
6667c478bd9Sstevel@tonic-gate 			return (ERROR);
6677c478bd9Sstevel@tonic-gate 		}
6687c478bd9Sstevel@tonic-gate 		ptr->size = size + 1;
6697c478bd9Sstevel@tonic-gate 		/* allocate space to cache contents of file */
6707c478bd9Sstevel@tonic-gate 		ptr->cached_file = (char **)calloc(ptr->size, sizeof (char *));
6717c478bd9Sstevel@tonic-gate 		if (ptr->cached_file == NULL) {
6727c478bd9Sstevel@tonic-gate 			free(ptr);
6737c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
6747c478bd9Sstevel@tonic-gate 			return (ERROR);
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		rewind(fp);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 		/*
6807c478bd9Sstevel@tonic-gate 		 * now fill the cache
6817c478bd9Sstevel@tonic-gate 		 * the cache is an array of char pointers indexed by major
6827c478bd9Sstevel@tonic-gate 		 * number
6837c478bd9Sstevel@tonic-gate 		 */
6847c478bd9Sstevel@tonic-gate 		while (fgets(line, sizeof (line), fp) != NULL) {
6851ca93273Seota 			/* cut off comments starting with '#' */
6861ca93273Seota 			if ((cp = strchr(line, '#')) != NULL)
6871ca93273Seota 				*cp = '\0';
6881ca93273Seota 			/* ignore comment or blank lines */
6891ca93273Seota 			if (is_blank(line))
6901ca93273Seota 				continue;
6911ca93273Seota 			/* sanity-check */
6923c0ea289SJerry Gilliam 			if (sscanf(line,
6933c0ea289SJerry Gilliam 			    "%" VAL2STR(FILENAME_MAX) "s"	/* drv */
6943c0ea289SJerry Gilliam 			    "%" VAL2STR(FILENAME_MAX) "s",	/* entry */
6953c0ea289SJerry Gilliam 			    drv, entry) != 2) {
6967c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_LINE),
6977c478bd9Sstevel@tonic-gate 				    filename, line);
6987c478bd9Sstevel@tonic-gate 				continue;
6997c478bd9Sstevel@tonic-gate 			}
7007c478bd9Sstevel@tonic-gate 			maj = atoi(entry);
7017c478bd9Sstevel@tonic-gate 			if ((ptr->cached_file[maj] = strdup(drv)) == NULL) {
7027c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_MEM));
7037c478bd9Sstevel@tonic-gate 				free(ptr->cached_file);
7047c478bd9Sstevel@tonic-gate 				free(ptr);
7057c478bd9Sstevel@tonic-gate 				return (ERROR);
7067c478bd9Sstevel@tonic-gate 			}
7077c478bd9Sstevel@tonic-gate 			(void) strcpy(ptr->cached_file[maj], drv);
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
7107c478bd9Sstevel@tonic-gate 		/* link the cache struct into the list of cached files */
7117c478bd9Sstevel@tonic-gate 		ptr->file = strdup(filename);
7127c478bd9Sstevel@tonic-gate 		if (ptr->file == NULL) {
7137c478bd9Sstevel@tonic-gate 			for (maj = 0; maj <= ptr->size; maj++)
7147c478bd9Sstevel@tonic-gate 				free(ptr->cached_file[maj]);
7157c478bd9Sstevel@tonic-gate 			free(ptr->cached_file);
7167c478bd9Sstevel@tonic-gate 			free(ptr);
7177c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
7187c478bd9Sstevel@tonic-gate 			return (ERROR);
7197c478bd9Sstevel@tonic-gate 		}
7207c478bd9Sstevel@tonic-gate 		ptr->next = head;
7217c478bd9Sstevel@tonic-gate 		head = ptr;
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 	/* return value pointer to contents of file */
7247c478bd9Sstevel@tonic-gate 	*cache = ptr->cached_file;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	/* return size */
7277c478bd9Sstevel@tonic-gate 	return (ptr->size);
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate /*
7327c478bd9Sstevel@tonic-gate  * Using get_cached_n_to_m_file(), retrieve maximum major number
7337c478bd9Sstevel@tonic-gate  * found in the specificed file (name_to_major/rem_name_to_major).
7347c478bd9Sstevel@tonic-gate  *
7357c478bd9Sstevel@tonic-gate  * The return value is actually the size of the internal cache including 0.
7367c478bd9Sstevel@tonic-gate  */
7377c478bd9Sstevel@tonic-gate int
get_max_major(char * file_name)7387c478bd9Sstevel@tonic-gate get_max_major(char *file_name)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate 	char **n_to_m_cache = NULL;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	return (get_cached_n_to_m_file(file_name, &n_to_m_cache));
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate /*
7477c478bd9Sstevel@tonic-gate  * searching name_to_major: if major_no == UNIQUE then the caller wants to
7487c478bd9Sstevel@tonic-gate  * use the driver name as the key.  Otherwise, the caller wants to use
7497c478bd9Sstevel@tonic-gate  * the major number as a key.
7507c478bd9Sstevel@tonic-gate  *
7517c478bd9Sstevel@tonic-gate  * This routine caches the contents of the name_to_major file on
7527c478bd9Sstevel@tonic-gate  * first call.  And it could be generalized to deal with other
7537c478bd9Sstevel@tonic-gate  * config files if necessary.
7547c478bd9Sstevel@tonic-gate  */
7557c478bd9Sstevel@tonic-gate static int
get_name_to_major_entry(int * major_no,char * driver_name,char * file_name)7567c478bd9Sstevel@tonic-gate get_name_to_major_entry(int *major_no, char *driver_name, char *file_name)
7577c478bd9Sstevel@tonic-gate {
7587c478bd9Sstevel@tonic-gate 	int maj;
7597c478bd9Sstevel@tonic-gate 	char **n_to_m_cache = NULL;
7607c478bd9Sstevel@tonic-gate 	int size = 0;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	int ret = NOT_UNIQUE;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/*
7657c478bd9Sstevel@tonic-gate 	 * read the file in - we cache it in case caller wants to
7667c478bd9Sstevel@tonic-gate 	 * do multiple lookups
7677c478bd9Sstevel@tonic-gate 	 */
7687c478bd9Sstevel@tonic-gate 	size = get_cached_n_to_m_file(file_name, &n_to_m_cache);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	if (size == ERROR)
7717c478bd9Sstevel@tonic-gate 		return (ERROR);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/* search with driver name as key */
7747c478bd9Sstevel@tonic-gate 	if (*major_no == UNIQUE) {
7757c478bd9Sstevel@tonic-gate 		for (maj = 0; maj < size; maj++) {
7767c478bd9Sstevel@tonic-gate 			if ((n_to_m_cache[maj] != NULL) &&
7777c478bd9Sstevel@tonic-gate 			    (strcmp(driver_name, n_to_m_cache[maj]) == 0)) {
7787c478bd9Sstevel@tonic-gate 				*major_no = maj;
7797c478bd9Sstevel@tonic-gate 				break;
7807c478bd9Sstevel@tonic-gate 			}
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 		if (maj >= size)
7837c478bd9Sstevel@tonic-gate 			ret = UNIQUE;
7847c478bd9Sstevel@tonic-gate 	/* search with major number as key */
7857c478bd9Sstevel@tonic-gate 	} else {
7867c478bd9Sstevel@tonic-gate 		/*
7877c478bd9Sstevel@tonic-gate 		 * Bugid 1254588, drvconfig dump core after loading driver
7887c478bd9Sstevel@tonic-gate 		 * with major number bigger than entries defined in
7897c478bd9Sstevel@tonic-gate 		 * /etc/name_to_major.
7907c478bd9Sstevel@tonic-gate 		 */
7917c478bd9Sstevel@tonic-gate 		if (*major_no >= size)
7927c478bd9Sstevel@tonic-gate 			return (UNIQUE);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		if (n_to_m_cache[*major_no] != NULL) {
7957c478bd9Sstevel@tonic-gate 			(void) strcpy(driver_name, n_to_m_cache[*major_no]);
7967c478bd9Sstevel@tonic-gate 		} else
7977c478bd9Sstevel@tonic-gate 			ret = UNIQUE;
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 	return (ret);
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate /*
803f4da9be0Scth  * Given pointer to begining of member 'n' in a space (or separator)
804f4da9be0Scth  * separated list, return pointer to member 'n+1', and establish member 'n'
805f4da9be0Scth  * in *current_entry.  If unquote, then we skip a leading quote and treat
806f4da9be0Scth  * the trailing quote as a separator (and skip).
8077c478bd9Sstevel@tonic-gate  */
8087c478bd9Sstevel@tonic-gate char *
get_entry(char * prev_member,char * current_entry,char separator,int unquote)8097c478bd9Sstevel@tonic-gate get_entry(
8107c478bd9Sstevel@tonic-gate 	char *prev_member,
8117c478bd9Sstevel@tonic-gate 	char *current_entry,
812f4da9be0Scth 	char separator,
813f4da9be0Scth 	int  unquote)
8147c478bd9Sstevel@tonic-gate {
815f4da9be0Scth 	char	*ptr;
816f4da9be0Scth 	int	quoted = 0;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	ptr = prev_member;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	/* skip white space */
8213c0ea289SJerry Gilliam 	while (isspace(*ptr))
8227c478bd9Sstevel@tonic-gate 		ptr++;
8237c478bd9Sstevel@tonic-gate 
824f4da9be0Scth 	/* if unquote skip leading quote */
825f4da9be0Scth 	if (unquote && *ptr == '"') {
826f4da9be0Scth 		quoted++;
827f4da9be0Scth 		ptr++;
828f4da9be0Scth 	}
829f4da9be0Scth 
830f4da9be0Scth 	/* read thru the current entry looking for end, separator, or unquote */
831f4da9be0Scth 	while (*ptr &&
8323c0ea289SJerry Gilliam 	    (*ptr != separator) && (!isspace(*ptr)) &&
833f4da9be0Scth 	    (!quoted || (*ptr != '"'))) {
8347c478bd9Sstevel@tonic-gate 		*current_entry++ = *ptr++;
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 	*current_entry = '\0';
8377c478bd9Sstevel@tonic-gate 
838f4da9be0Scth 	if (separator && (*ptr == separator))
839f4da9be0Scth 		ptr++;	/* skip over separator */
840f4da9be0Scth 	if (quoted && (*ptr == '"'))
841f4da9be0Scth 		ptr++;	/* skip over trailing quote */
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	/* skip white space */
8443c0ea289SJerry Gilliam 	while (isspace(*ptr))
8457c478bd9Sstevel@tonic-gate 		ptr++;
8463c0ea289SJerry Gilliam 
8473c0ea289SJerry Gilliam 	return (ptr);
8483c0ea289SJerry Gilliam }
8493c0ea289SJerry Gilliam 
8503c0ea289SJerry Gilliam /*
8513c0ea289SJerry Gilliam  * A parser specific to the add_drv "-m permission" syntax:
8523c0ea289SJerry Gilliam  *
8533c0ea289SJerry Gilliam  *	-m '<minor-name> <permissions> <owner> <group>', ...
8543c0ea289SJerry Gilliam  *
8553c0ea289SJerry Gilliam  * One entry is parsed starting at prev_member and returned
8563c0ea289SJerry Gilliam  * in the string pointed at by current_entry.  A pointer
8573c0ea289SJerry Gilliam  * to the entry following is returned.
8583c0ea289SJerry Gilliam  */
8593c0ea289SJerry Gilliam char *
get_perm_entry(char * prev_member,char * current_entry)8603c0ea289SJerry Gilliam get_perm_entry(
8613c0ea289SJerry Gilliam 	char *prev_member,
8623c0ea289SJerry Gilliam 	char *current_entry)
8633c0ea289SJerry Gilliam {
8643c0ea289SJerry Gilliam 	char	*ptr;
8653c0ea289SJerry Gilliam 	int	nfields = 0;
8663c0ea289SJerry Gilliam 	int	maxfields = 4;		/* fields in a permissions format */
8673c0ea289SJerry Gilliam 
8683c0ea289SJerry Gilliam 	ptr = prev_member;
8693c0ea289SJerry Gilliam 	while (isspace(*ptr))
8703c0ea289SJerry Gilliam 		ptr++;
8713c0ea289SJerry Gilliam 
8723c0ea289SJerry Gilliam 	while (*ptr) {
8733c0ea289SJerry Gilliam 		/* comma allowed in minor name token only */
8743c0ea289SJerry Gilliam 		if (*ptr == ',' && nfields > 0) {
8753c0ea289SJerry Gilliam 			break;
8763c0ea289SJerry Gilliam 		} else if (isspace(*ptr)) {
8773c0ea289SJerry Gilliam 			*current_entry++ = *ptr++;
8783c0ea289SJerry Gilliam 			while (isspace(*ptr))
8793c0ea289SJerry Gilliam 				ptr++;
8803c0ea289SJerry Gilliam 			if (++nfields == maxfields)
8813c0ea289SJerry Gilliam 				break;
8823c0ea289SJerry Gilliam 		} else
8833c0ea289SJerry Gilliam 			*current_entry++ = *ptr++;
8843c0ea289SJerry Gilliam 	}
8853c0ea289SJerry Gilliam 	*current_entry = '\0';
8863c0ea289SJerry Gilliam 
8873c0ea289SJerry Gilliam 	while (isspace(*ptr))
8883c0ea289SJerry Gilliam 		ptr++;
8893c0ea289SJerry Gilliam 	if (*ptr == ',') {
8903c0ea289SJerry Gilliam 		ptr++;	/* skip over optional trailing comma */
8917c478bd9Sstevel@tonic-gate 	}
8923c0ea289SJerry Gilliam 	while (isspace(*ptr))
8933c0ea289SJerry Gilliam 		ptr++;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	return (ptr);
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate void
enter_lock(void)8997c478bd9Sstevel@tonic-gate enter_lock(void)
9007c478bd9Sstevel@tonic-gate {
90149e92448Svikram 	struct flock lock;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/*
9043c0ea289SJerry Gilliam 	 * Attempt to create the lock file.  Open the file itself,
9053c0ea289SJerry Gilliam 	 * and not a symlink to some other file.
9067c478bd9Sstevel@tonic-gate 	 */
9073c0ea289SJerry Gilliam 	add_rem_lock_fd = open(add_rem_lock,
9083c0ea289SJerry Gilliam 	    O_CREAT|O_RDWR|O_NOFOLLOW|O_NOLINKS, S_IRUSR|S_IWUSR);
90949e92448Svikram 	if (add_rem_lock_fd < 0) {
91049e92448Svikram 		(void) fprintf(stderr, gettext(ERR_CREAT_LOCK),
91149e92448Svikram 		    add_rem_lock, strerror(errno));
91249e92448Svikram 		exit(1);
91349e92448Svikram 	}
91449e92448Svikram 
91549e92448Svikram 	lock.l_type = F_WRLCK;
91649e92448Svikram 	lock.l_whence = SEEK_SET;
91749e92448Svikram 	lock.l_start = 0;
91849e92448Svikram 	lock.l_len = 0;
91949e92448Svikram 
92049e92448Svikram 	/* Try for the lock but don't wait. */
92149e92448Svikram 	if (fcntl(add_rem_lock_fd, F_SETLK, &lock) == -1) {
92249e92448Svikram 		if (errno == EACCES || errno == EAGAIN) {
9237c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_PROG_IN_USE));
9247c478bd9Sstevel@tonic-gate 		} else {
92549e92448Svikram 			(void) fprintf(stderr, gettext(ERR_LOCK),
92649e92448Svikram 			    add_rem_lock, strerror(errno));
9277c478bd9Sstevel@tonic-gate 		}
9287c478bd9Sstevel@tonic-gate 		exit(1);
9297c478bd9Sstevel@tonic-gate 	}
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate void
err_exit(void)9337c478bd9Sstevel@tonic-gate err_exit(void)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	/* release memory allocated for moddir */
9367c478bd9Sstevel@tonic-gate 	cleanup_moddir();
9377c478bd9Sstevel@tonic-gate 	/* remove add_drv/rem_drv lock */
9387c478bd9Sstevel@tonic-gate 	exit_unlock();
9397c478bd9Sstevel@tonic-gate 	exit(1);
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate void
cleanup_moddir(void)9437c478bd9Sstevel@tonic-gate cleanup_moddir(void)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	struct drvmod_dir *walk_ptr;
9467c478bd9Sstevel@tonic-gate 	struct drvmod_dir *free_ptr = moddir;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	while (free_ptr != NULL) {
9497c478bd9Sstevel@tonic-gate 		walk_ptr = free_ptr->next;
9507c478bd9Sstevel@tonic-gate 		free(free_ptr);
9517c478bd9Sstevel@tonic-gate 		free_ptr = walk_ptr;
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate }
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate void
exit_unlock(void)9567c478bd9Sstevel@tonic-gate exit_unlock(void)
9577c478bd9Sstevel@tonic-gate {
95849e92448Svikram 	struct flock unlock;
9597c478bd9Sstevel@tonic-gate 
96049e92448Svikram 	if (add_rem_lock_fd < 0)
96149e92448Svikram 		return;
96249e92448Svikram 
96349e92448Svikram 	unlock.l_type = F_UNLCK;
96449e92448Svikram 	unlock.l_whence = SEEK_SET;
96549e92448Svikram 	unlock.l_start = 0;
96649e92448Svikram 	unlock.l_len = 0;
96749e92448Svikram 
96849e92448Svikram 	if (fcntl(add_rem_lock_fd, F_SETLK, &unlock) == -1) {
96949e92448Svikram 		(void) fprintf(stderr, gettext(ERR_UNLOCK),
97049e92448Svikram 		    add_rem_lock, strerror(errno));
97149e92448Svikram 	} else {
97249e92448Svikram 		(void) close(add_rem_lock_fd);
97349e92448Svikram 		add_rem_lock_fd = -1;
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate /*
9787c478bd9Sstevel@tonic-gate  * error adding driver; need to back out any changes to files.
9797c478bd9Sstevel@tonic-gate  * check flag to see which files need entries removed
9807c478bd9Sstevel@tonic-gate  * entry removal based on driver name
9817c478bd9Sstevel@tonic-gate  */
9827c478bd9Sstevel@tonic-gate void
remove_entry(int c_flag,char * driver_name)9837c478bd9Sstevel@tonic-gate remove_entry(
9847c478bd9Sstevel@tonic-gate 	int c_flag,
9857c478bd9Sstevel@tonic-gate 	char *driver_name)
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	if (c_flag & CLEAN_NAM_MAJ) {
9897c478bd9Sstevel@tonic-gate 		if (delete_entry(name_to_major, driver_name, " ",
9907c478bd9Sstevel@tonic-gate 		    NULL) == ERROR) {
9917c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_CLEAN),
9927c478bd9Sstevel@tonic-gate 			    name_to_major, driver_name);
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	if (c_flag & CLEAN_DRV_ALIAS) {
9977c478bd9Sstevel@tonic-gate 		if (delete_entry(driver_aliases, driver_name, " ",
9987c478bd9Sstevel@tonic-gate 		    NULL) == ERROR) {
9997c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DEL_ENTRY),
10007c478bd9Sstevel@tonic-gate 			    driver_name, driver_aliases);
10017c478bd9Sstevel@tonic-gate 		}
10027c478bd9Sstevel@tonic-gate 	}
1003