xref: /onnv-gate/usr/src/cmd/modload/update_drv.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
54145Scth  * Common Development and Distribution License (the "License").
64145Scth  * 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 /*
228565SJerry.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 <locale.h>
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include "addrem.h"
330Sstevel@tonic-gate #include "errmsg.h"
340Sstevel@tonic-gate #include "plcysubr.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /* function prototypes */
370Sstevel@tonic-gate static void	usage();
380Sstevel@tonic-gate static int	unload_drv(char *, int, int);
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * try to modunload driver.
430Sstevel@tonic-gate  * return -1 on failure and 0 on success
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate static int
unload_drv(char * driver_name,int force_flag,int verbose_flag)460Sstevel@tonic-gate unload_drv(char *driver_name, int force_flag, int verbose_flag)
470Sstevel@tonic-gate {
480Sstevel@tonic-gate 	int modid;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	get_modid(driver_name, &modid);
510Sstevel@tonic-gate 	if (modid != -1) {
520Sstevel@tonic-gate 		if (modctl(MODUNLOAD, modid) < 0) {
530Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MODUN), driver_name);
540Sstevel@tonic-gate 			if (force_flag == 0) { /* no force flag */
550Sstevel@tonic-gate 				if (verbose_flag) {
560Sstevel@tonic-gate 					(void) fprintf(stderr,
570Sstevel@tonic-gate 					    gettext(NOUPDATE), driver_name);
580Sstevel@tonic-gate 				}
590Sstevel@tonic-gate 				/* clean up and exit. remove lock file */
600Sstevel@tonic-gate 				err_exit();
610Sstevel@tonic-gate 			}
620Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(FORCE_UPDATE),
630Sstevel@tonic-gate 			    driver_name);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 			return (-1);
660Sstevel@tonic-gate 		}
670Sstevel@tonic-gate 	}
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	return (0);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static void
usage()740Sstevel@tonic-gate usage()
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(UPD_DRV_USAGE));
770Sstevel@tonic-gate 	exit(1);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 
810Sstevel@tonic-gate int
main(int argc,char * argv[])820Sstevel@tonic-gate main(int argc, char *argv[])
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	int	error, opt, major;
850Sstevel@tonic-gate 	int	cleanup_flag = 0;
860Sstevel@tonic-gate 	int	update_conf = 1;	/* reload driver.conf by default */
870Sstevel@tonic-gate 	int	verbose_flag = 0;	/* -v option */
880Sstevel@tonic-gate 	int	force_flag = 0;		/* -f option */
890Sstevel@tonic-gate 	int	a_flag = 0;		/* -a option */
900Sstevel@tonic-gate 	int	d_flag = 0;		/* -d option */
910Sstevel@tonic-gate 	int	i_flag = 0;		/* -i option */
920Sstevel@tonic-gate 	int	l_flag = 0;		/* -l option */
930Sstevel@tonic-gate 	int	m_flag = 0;		/* -m option */
948565SJerry.Gilliam@Sun.COM 	int	n_flag = 0;		/* -n option */
950Sstevel@tonic-gate 	char	*perms = NULL;
968331SJerry.Gilliam@Sun.COM 	char	*aliases = NULL;
970Sstevel@tonic-gate 	char	*basedir = NULL;
980Sstevel@tonic-gate 	char	*policy = NULL;
998331SJerry.Gilliam@Sun.COM 	char	*aliases2 = NULL;
1000Sstevel@tonic-gate 	char	*priv = NULL;
1010Sstevel@tonic-gate 	char	*driver_name;
1020Sstevel@tonic-gate 	int	found;
1030Sstevel@tonic-gate 	major_t major_num;
1040Sstevel@tonic-gate 	int	rval;
105*10842SJerry.Gilliam@Sun.COM 	int	config_flags;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1080Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1090Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	/*  must be run by root */
1140Sstevel@tonic-gate 	if (getuid() != 0) {
1150Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NOT_ROOT));
1160Sstevel@tonic-gate 		exit(1);
1170Sstevel@tonic-gate 	}
1180Sstevel@tonic-gate 
1198565SJerry.Gilliam@Sun.COM 	while ((opt = getopt(argc, argv, "m:ni:b:p:adlfuvP:")) != EOF) {
1200Sstevel@tonic-gate 		switch (opt) {
1210Sstevel@tonic-gate 		case 'a':
1220Sstevel@tonic-gate 			a_flag++;
1230Sstevel@tonic-gate 			break;
1240Sstevel@tonic-gate 		case 'b':
1250Sstevel@tonic-gate 			update_conf = 0;	/* don't update .conf file */
1260Sstevel@tonic-gate 			basedir = optarg;
1270Sstevel@tonic-gate 			break;
1280Sstevel@tonic-gate 		case 'd':
1290Sstevel@tonic-gate 			d_flag++;
1300Sstevel@tonic-gate 			break;
1310Sstevel@tonic-gate 		case 'f':
1320Sstevel@tonic-gate 			force_flag++;
1330Sstevel@tonic-gate 			break;
1340Sstevel@tonic-gate 		case 'i':
1350Sstevel@tonic-gate 			i_flag++;
1360Sstevel@tonic-gate 			aliases = optarg;
1370Sstevel@tonic-gate 			if (check_space_within_quote(aliases) == ERROR) {
1380Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_SPACE),
1395001Sjg 				    aliases);
1400Sstevel@tonic-gate 				exit(1);
1410Sstevel@tonic-gate 			}
1420Sstevel@tonic-gate 			break;
1430Sstevel@tonic-gate 		case 'l':	/* private option */
1440Sstevel@tonic-gate 			l_flag++;
1450Sstevel@tonic-gate 			break;
1460Sstevel@tonic-gate 		case 'm':
1470Sstevel@tonic-gate 			m_flag++;
1480Sstevel@tonic-gate 			perms = optarg;
1490Sstevel@tonic-gate 			break;
1508565SJerry.Gilliam@Sun.COM 		case 'n':
1518565SJerry.Gilliam@Sun.COM 			n_flag++;
1528565SJerry.Gilliam@Sun.COM 			update_conf = 0;
1538565SJerry.Gilliam@Sun.COM 			break;
1540Sstevel@tonic-gate 		case 'p':
1550Sstevel@tonic-gate 			policy = optarg;
1560Sstevel@tonic-gate 			break;
1570Sstevel@tonic-gate 		case 'v':
1580Sstevel@tonic-gate 			verbose_flag++;
1590Sstevel@tonic-gate 			break;
1600Sstevel@tonic-gate 		case 'P':
1610Sstevel@tonic-gate 			priv = optarg;
1620Sstevel@tonic-gate 			break;
1630Sstevel@tonic-gate 		case '?' :
1640Sstevel@tonic-gate 		default:
1650Sstevel@tonic-gate 			usage();
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/*
1700Sstevel@tonic-gate 	 * check for flags and extra args
1710Sstevel@tonic-gate 	 */
1720Sstevel@tonic-gate 	if ((argv[optind] == NULL) || (optind + 1 != argc)) {
1730Sstevel@tonic-gate 		usage();
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/*
1770Sstevel@tonic-gate 	 * - cannot be adding and removing at the same time
1780Sstevel@tonic-gate 	 * - if -a or -d is specified, it's an error if none of
1790Sstevel@tonic-gate 	 *   -i/-m/-p/-P is specified.
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 	if ((a_flag && d_flag) ||
1820Sstevel@tonic-gate 	    ((a_flag || d_flag) &&
1830Sstevel@tonic-gate 	    !m_flag && !i_flag && priv == NULL && policy == NULL)) {
1840Sstevel@tonic-gate 		usage();
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	/*
1880Sstevel@tonic-gate 	 * - with -d option or -a option either -i 'identify_name',
1890Sstevel@tonic-gate 	 *	-m 'permission',  -p 'policy' or -P 'priv' should be specified
1900Sstevel@tonic-gate 	 */
1910Sstevel@tonic-gate 	if (m_flag || i_flag || policy != NULL || priv != NULL) {
1920Sstevel@tonic-gate 		if (!(a_flag || d_flag))
1930Sstevel@tonic-gate 			usage();
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	driver_name = argv[optind];
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	/* set up update_drv filenames */
1990Sstevel@tonic-gate 	if ((build_filenames(basedir)) == ERROR) {
2000Sstevel@tonic-gate 		exit(1);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/* no lock is needed for listing minor perm entry */
2040Sstevel@tonic-gate 	if (l_flag) {
2050Sstevel@tonic-gate 		list_entry(minor_perm, driver_name, ":");
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 		return (NOERR);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/* must be only running version of add_drv/update_drv/rem_drv */
2110Sstevel@tonic-gate 	enter_lock();
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if ((check_perms_aliases(m_flag, i_flag)) == ERROR) {
2140Sstevel@tonic-gate 		err_exit();
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/* update_drv doesn't modify /etc/name_to_major file */
2180Sstevel@tonic-gate 	if ((check_name_to_major(R_OK)) == ERROR)
2190Sstevel@tonic-gate 		err_exit();
2200Sstevel@tonic-gate 
2218565SJerry.Gilliam@Sun.COM 	if ((n_flag == 0) &&
2228565SJerry.Gilliam@Sun.COM 	    (basedir == NULL || (strcmp(basedir, "/") == 0)) &&
2238565SJerry.Gilliam@Sun.COM 	    (priv != NULL) && check_priv_entry(priv, a_flag) != 0)
2240Sstevel@tonic-gate 		err_exit();
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	if (policy != NULL && (policy = check_plcy_entry(policy, driver_name,
2270Sstevel@tonic-gate 	    d_flag ? B_TRUE : B_FALSE)) == NULL)
2280Sstevel@tonic-gate 		err_exit();
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/*
2310Sstevel@tonic-gate 	 * ADD: -a option
2320Sstevel@tonic-gate 	 * i_flag: update /etc/driver_aliases
2330Sstevel@tonic-gate 	 * m_flag: update /etc/minor_perm
2340Sstevel@tonic-gate 	 * -p: update /etc/security/device_policy
2350Sstevel@tonic-gate 	 * -P: update /etc/security/extra_privs
2360Sstevel@tonic-gate 	 * if force_flag is specified continue w/ the next operation
2370Sstevel@tonic-gate 	 */
2380Sstevel@tonic-gate 	if (a_flag) {
2390Sstevel@tonic-gate 		if (m_flag) {
2400Sstevel@tonic-gate 			/* check if the permissions are valid */
2410Sstevel@tonic-gate 			if ((error = check_perm_opts(perms)) == ERROR) {
2420Sstevel@tonic-gate 				if (force_flag == 0) { /* no force flag */
2430Sstevel@tonic-gate 					exit_unlock();
2440Sstevel@tonic-gate 					return (error);
2450Sstevel@tonic-gate 				}
2460Sstevel@tonic-gate 			}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 			/*
2490Sstevel@tonic-gate 			 * update the file, if and only if
2500Sstevel@tonic-gate 			 * we didn't run into error earlier.
2510Sstevel@tonic-gate 			 */
2520Sstevel@tonic-gate 			if ((error != ERROR) &&
2530Sstevel@tonic-gate 			    (error = update_minor_entry(driver_name, perms))) {
2540Sstevel@tonic-gate 				if (force_flag == 0) { /* no force flag */
2550Sstevel@tonic-gate 					exit_unlock();
2560Sstevel@tonic-gate 					return (error);
2570Sstevel@tonic-gate 				}
2580Sstevel@tonic-gate 			}
2590Sstevel@tonic-gate 			cleanup_flag |= CLEAN_NAM_MAJ;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 			/*
2620Sstevel@tonic-gate 			 * Notify running system of minor perm change
2630Sstevel@tonic-gate 			 */
2648565SJerry.Gilliam@Sun.COM 			if ((n_flag == 0) &&
2658565SJerry.Gilliam@Sun.COM 			    (basedir == NULL || (strcmp(basedir, "/") == 0))) {
2660Sstevel@tonic-gate 				rval = devfs_add_minor_perm(driver_name,
2670Sstevel@tonic-gate 				    log_minorperm_error);
2680Sstevel@tonic-gate 				if (rval) {
2690Sstevel@tonic-gate 					(void) fprintf(stderr,
2700Sstevel@tonic-gate 					    gettext(ERR_UPDATE_PERM),
2710Sstevel@tonic-gate 					    driver_name);
2720Sstevel@tonic-gate 				}
2730Sstevel@tonic-gate 			}
2740Sstevel@tonic-gate 		}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 		if (priv != NULL) {
2770Sstevel@tonic-gate 			(void) append_to_file(driver_name, priv, extra_privs,
2785001Sjg 			    ',', ":", 0);
2790Sstevel@tonic-gate 			cleanup_flag |= CLEAN_DRV_PRIV;
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 		if (policy != NULL) {
2830Sstevel@tonic-gate 			if ((error = update_device_policy(device_policy,
2840Sstevel@tonic-gate 			    policy, B_TRUE)) != 0) {
2850Sstevel@tonic-gate 				exit_unlock();
2860Sstevel@tonic-gate 				return (error);
2870Sstevel@tonic-gate 			}
2880Sstevel@tonic-gate 			cleanup_flag |= CLEAN_DEV_POLICY;
2890Sstevel@tonic-gate 		}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (i_flag) {
292579Scth 			found = get_major_no(driver_name, name_to_major);
293579Scth 			if (found == ERROR) {
294579Scth 				(void) fprintf(stderr, gettext(ERR_MAX_MAJOR),
295579Scth 				    name_to_major);
296579Scth 				err_exit();
297579Scth 			}
298579Scth 
299579Scth 			if (found == UNIQUE) {
300579Scth 				(void) fprintf(stderr,
301579Scth 				    gettext(ERR_NOT_INSTALLED), driver_name);
302579Scth 				err_exit();
303579Scth 			}
304579Scth 
305579Scth 			major_num = (major_t)found;
306579Scth 
3078331SJerry.Gilliam@Sun.COM 			/*
3088331SJerry.Gilliam@Sun.COM 			 * To ease the nuisance of using update_drv
3098331SJerry.Gilliam@Sun.COM 			 * in packaging scripts, do not require that
3108331SJerry.Gilliam@Sun.COM 			 * existing driver aliases be trimmed from
3118331SJerry.Gilliam@Sun.COM 			 * the command line.  If an invocation asks
3128331SJerry.Gilliam@Sun.COM 			 * to add an alias and it's already there,
3138331SJerry.Gilliam@Sun.COM 			 * drive on.  We implement this by removing
3148331SJerry.Gilliam@Sun.COM 			 * duplicates now and add the remainder.
3158331SJerry.Gilliam@Sun.COM 			 */
3168331SJerry.Gilliam@Sun.COM 			error = trim_duplicate_aliases(driver_name,
3178331SJerry.Gilliam@Sun.COM 			    aliases, &aliases2);
3188331SJerry.Gilliam@Sun.COM 			if (error == ERROR) {
3190Sstevel@tonic-gate 				exit_unlock();
3200Sstevel@tonic-gate 				return (error);
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 
3234145Scth 			/*
3248331SJerry.Gilliam@Sun.COM 			 * if the list of aliases to be added is
3258331SJerry.Gilliam@Sun.COM 			 * now empty, we're done.
3268331SJerry.Gilliam@Sun.COM 			 */
3278331SJerry.Gilliam@Sun.COM 			if (aliases2 == NULL)
3288331SJerry.Gilliam@Sun.COM 				goto done;
3298331SJerry.Gilliam@Sun.COM 
3308331SJerry.Gilliam@Sun.COM 			/*
3314145Scth 			 * unless force_flag is specified check that
3324145Scth 			 * path-oriented aliases we are adding exist
3334145Scth 			 */
3348331SJerry.Gilliam@Sun.COM 			if ((force_flag == 0) && ((error =
3358331SJerry.Gilliam@Sun.COM 			    aliases_paths_exist(aliases2)) == ERROR)) {
3364145Scth 				exit_unlock();
3374145Scth 				return (error);
3384145Scth 			}
3394145Scth 
3400Sstevel@tonic-gate 			/* update the file */
3410Sstevel@tonic-gate 			if ((error = update_driver_aliases(driver_name,
3428331SJerry.Gilliam@Sun.COM 			    aliases2)) == ERROR) {
3430Sstevel@tonic-gate 				exit_unlock();
3440Sstevel@tonic-gate 				return (error);
3450Sstevel@tonic-gate 			}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 
3485001Sjg 			/* optionally update the running system - not -b */
3495001Sjg 			if (update_conf) {
3508831SJerry.Gilliam@Sun.COM 				/* paranoia - if we crash whilst configuring */
3518831SJerry.Gilliam@Sun.COM 				sync();
352*10842SJerry.Gilliam@Sun.COM 				config_flags = (verbose_flag) ?
353*10842SJerry.Gilliam@Sun.COM 				    CONFIG_DRV_VERBOSE : 0;
3545001Sjg 				cleanup_flag |= CLEAN_DRV_ALIAS;
3555001Sjg 				if (config_driver(driver_name, major_num,
3568331SJerry.Gilliam@Sun.COM 				    aliases2, NULL, cleanup_flag,
357*10842SJerry.Gilliam@Sun.COM 				    config_flags) == ERROR) {
3585001Sjg 					err_exit();
3595001Sjg 				}
3600Sstevel@tonic-gate 			}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		}
3638331SJerry.Gilliam@Sun.COM 
3648331SJerry.Gilliam@Sun.COM done:
3655878Sjg 		if (update_conf && (i_flag || policy != NULL)) {
3660Sstevel@tonic-gate 			/* load the driver */
3670Sstevel@tonic-gate 			load_driver(driver_name, verbose_flag);
3685878Sjg 		}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		exit_unlock();
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		return (0);
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/*
3770Sstevel@tonic-gate 	 * DELETE: -d option
3780Sstevel@tonic-gate 	 * i_flag: update /etc/driver_aliases
3790Sstevel@tonic-gate 	 * m_flag: update /etc/minor_perm
3800Sstevel@tonic-gate 	 * -p: update /etc/security/device_policy
3810Sstevel@tonic-gate 	 * -P: update /etc/security/extra_privs
382*10842SJerry.Gilliam@Sun.COM 	 * if force_flag is specified continue w/ the next operation
3830Sstevel@tonic-gate 	 */
3840Sstevel@tonic-gate 	if (d_flag) {
3850Sstevel@tonic-gate 		int err = NOERR;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 		if (m_flag) {
3880Sstevel@tonic-gate 			/*
3890Sstevel@tonic-gate 			 * On a running system, we first need to
3900Sstevel@tonic-gate 			 * remove devfs's idea of the minor perms.
3910Sstevel@tonic-gate 			 * We don't have any ability to do this singly
3920Sstevel@tonic-gate 			 * at this point.
3930Sstevel@tonic-gate 			 */
3948565SJerry.Gilliam@Sun.COM 			if ((n_flag == 0) &&
3958565SJerry.Gilliam@Sun.COM 			    (basedir == NULL || (strcmp(basedir, "/") == 0))) {
3960Sstevel@tonic-gate 				rval = devfs_rm_minor_perm(driver_name,
3970Sstevel@tonic-gate 				    log_minorperm_error);
3980Sstevel@tonic-gate 				if (rval) {
3990Sstevel@tonic-gate 					(void) fprintf(stderr,
4000Sstevel@tonic-gate 					    gettext(ERR_UPDATE_PERM),
4010Sstevel@tonic-gate 					    driver_name);
4020Sstevel@tonic-gate 				}
4030Sstevel@tonic-gate 			}
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 			if ((error = delete_entry(minor_perm,
4060Sstevel@tonic-gate 			    driver_name, ":", perms)) != NOERR) {
4070Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
4080Sstevel@tonic-gate 				    driver_name, minor_perm);
4090Sstevel@tonic-gate 				err = error;
4100Sstevel@tonic-gate 			}
4110Sstevel@tonic-gate 			/*
4120Sstevel@tonic-gate 			 * Notify running system of new minor perm state
4130Sstevel@tonic-gate 			 */
4148565SJerry.Gilliam@Sun.COM 			if ((n_flag == 0) &&
4158565SJerry.Gilliam@Sun.COM 			    (basedir == NULL || (strcmp(basedir, "/") == 0))) {
4160Sstevel@tonic-gate 				rval = devfs_add_minor_perm(driver_name,
4170Sstevel@tonic-gate 				    log_minorperm_error);
4180Sstevel@tonic-gate 				if (rval) {
4190Sstevel@tonic-gate 					(void) fprintf(stderr,
4200Sstevel@tonic-gate 					    gettext(ERR_UPDATE_PERM),
4210Sstevel@tonic-gate 					    driver_name);
4220Sstevel@tonic-gate 				}
4230Sstevel@tonic-gate 			}
4240Sstevel@tonic-gate 		}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		if (i_flag) {
4278831SJerry.Gilliam@Sun.COM 			found = get_major_no(driver_name, name_to_major);
4288831SJerry.Gilliam@Sun.COM 			if (found == ERROR) {
4298831SJerry.Gilliam@Sun.COM 				(void) fprintf(stderr, gettext(ERR_MAX_MAJOR),
4308831SJerry.Gilliam@Sun.COM 				    name_to_major);
4318831SJerry.Gilliam@Sun.COM 				err_exit();
4328831SJerry.Gilliam@Sun.COM 			}
4338831SJerry.Gilliam@Sun.COM 
4348831SJerry.Gilliam@Sun.COM 			if (found == UNIQUE) {
4358831SJerry.Gilliam@Sun.COM 				(void) fprintf(stderr,
4368831SJerry.Gilliam@Sun.COM 				    gettext(ERR_NOT_INSTALLED), driver_name);
4378831SJerry.Gilliam@Sun.COM 				err_exit();
4388831SJerry.Gilliam@Sun.COM 			}
4398831SJerry.Gilliam@Sun.COM 
4408831SJerry.Gilliam@Sun.COM 			major_num = (major_t)found;
4418831SJerry.Gilliam@Sun.COM 
4428831SJerry.Gilliam@Sun.COM 			/*
4438831SJerry.Gilliam@Sun.COM 			 * verify that the aliases to be deleted exist
4448831SJerry.Gilliam@Sun.COM 			 * before removal.  With -f, failing to
4458831SJerry.Gilliam@Sun.COM 			 * remove an alias is not an error so we
4468831SJerry.Gilliam@Sun.COM 			 * can continue on to update the kernel.
4478831SJerry.Gilliam@Sun.COM 			 */
4488831SJerry.Gilliam@Sun.COM 			error = NOERR;
4499268SJerry.Gilliam@Sun.COM 			rval = aliases_exist(aliases);
4508831SJerry.Gilliam@Sun.COM 			if (rval == ERROR && (force_flag == 0)) {
4518831SJerry.Gilliam@Sun.COM 				(void) fprintf(stderr,
4528831SJerry.Gilliam@Sun.COM 				    gettext(ERR_ALIAS_NOT_BOUND),
4538831SJerry.Gilliam@Sun.COM 				    driver_name);
4548831SJerry.Gilliam@Sun.COM 				if (err != NOERR)
4558831SJerry.Gilliam@Sun.COM 					err = rval;
4568831SJerry.Gilliam@Sun.COM 			}
4578831SJerry.Gilliam@Sun.COM 			if (rval == NOERR)
4588831SJerry.Gilliam@Sun.COM 				error = delete_entry(driver_aliases,
4598831SJerry.Gilliam@Sun.COM 				    driver_name, ":", aliases);
4608831SJerry.Gilliam@Sun.COM 			if (error != NOERR && (force_flag == 0)) {
4610Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
4620Sstevel@tonic-gate 				    driver_name, driver_aliases);
4630Sstevel@tonic-gate 				if (err != NOERR)
4640Sstevel@tonic-gate 					err = error;
4650Sstevel@tonic-gate 			}
4668831SJerry.Gilliam@Sun.COM 
4678831SJerry.Gilliam@Sun.COM 			/*
4688831SJerry.Gilliam@Sun.COM 			 * optionally update the running system - not -b.
4698831SJerry.Gilliam@Sun.COM 			 * Unless -f is specified, error if one or more
4708831SJerry.Gilliam@Sun.COM 			 * devices remain bound to the alias.
4718831SJerry.Gilliam@Sun.COM 			 */
4728831SJerry.Gilliam@Sun.COM 			if (err == NOERR && update_conf) {
4738831SJerry.Gilliam@Sun.COM 				/* paranoia - if we crash whilst configuring */
4748831SJerry.Gilliam@Sun.COM 				sync();
475*10842SJerry.Gilliam@Sun.COM 
476*10842SJerry.Gilliam@Sun.COM 				config_flags = 0;
477*10842SJerry.Gilliam@Sun.COM 				if (verbose_flag)
478*10842SJerry.Gilliam@Sun.COM 					config_flags |= CONFIG_DRV_VERBOSE;
479*10842SJerry.Gilliam@Sun.COM 				if (force_flag)
480*10842SJerry.Gilliam@Sun.COM 					config_flags |= CONFIG_DRV_FORCE;
4818831SJerry.Gilliam@Sun.COM 				error = unconfig_driver(driver_name, major_num,
482*10842SJerry.Gilliam@Sun.COM 				    aliases, config_flags);
4838831SJerry.Gilliam@Sun.COM 				if (error == ERROR && force_flag == 0) {
4848831SJerry.Gilliam@Sun.COM 					(void) fprintf(stderr,
4858831SJerry.Gilliam@Sun.COM 					    gettext(ERR_DEV_IN_USE),
4868831SJerry.Gilliam@Sun.COM 					    driver_name);
4878831SJerry.Gilliam@Sun.COM 					if (err != NOERR)
4888831SJerry.Gilliam@Sun.COM 						err = error;
4898831SJerry.Gilliam@Sun.COM 				}
4908831SJerry.Gilliam@Sun.COM 			}
4910Sstevel@tonic-gate 		}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		if (priv != NULL) {
4940Sstevel@tonic-gate 			if ((error = delete_entry(extra_privs, driver_name, ":",
4950Sstevel@tonic-gate 			    priv)) != NOERR) {
4960Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
4970Sstevel@tonic-gate 				    driver_name, extra_privs);
4980Sstevel@tonic-gate 				if (err != NOERR)
4990Sstevel@tonic-gate 					err = error;
5000Sstevel@tonic-gate 			}
5010Sstevel@tonic-gate 		}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		if (policy != NULL) {
5040Sstevel@tonic-gate 			if ((error = delete_plcy_entry(device_policy,
5055001Sjg 			    policy)) != NOERR) {
5060Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
5070Sstevel@tonic-gate 				    driver_name, device_policy);
5080Sstevel@tonic-gate 				if (err != NOERR)
5090Sstevel@tonic-gate 					err = error;
5100Sstevel@tonic-gate 			}
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		if (err == NOERR && update_conf) {
5140Sstevel@tonic-gate 			if (i_flag || m_flag) {
5150Sstevel@tonic-gate 				/* try to unload the driver */
5160Sstevel@tonic-gate 				(void) unload_drv(driver_name,
5170Sstevel@tonic-gate 				    force_flag, verbose_flag);
5180Sstevel@tonic-gate 			}
5190Sstevel@tonic-gate 			/* reload the policy */
5200Sstevel@tonic-gate 			if (policy != NULL)
5210Sstevel@tonic-gate 				load_driver(driver_name, verbose_flag);
5220Sstevel@tonic-gate 		}
5230Sstevel@tonic-gate 		exit_unlock();
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		return (err);
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	/* driver name must exist (for update_conf stuff) */
5290Sstevel@tonic-gate 	major = get_major_no(driver_name, name_to_major);
5300Sstevel@tonic-gate 	if (major == ERROR) {
5310Sstevel@tonic-gate 		err_exit();
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	/*
5350Sstevel@tonic-gate 	 * Update driver.conf file:
5360Sstevel@tonic-gate 	 *	First try to unload driver module. If it fails, there may
5370Sstevel@tonic-gate 	 *	be attached devices using the old driver.conf properties,
5380Sstevel@tonic-gate 	 *	so we cannot safely update driver.conf
5390Sstevel@tonic-gate 	 *
5400Sstevel@tonic-gate 	 *	The user may specify -f to force a driver.conf update.
5410Sstevel@tonic-gate 	 *	In this case, we will update driver.conf cache. All attached
5420Sstevel@tonic-gate 	 *	devices still reference old driver.conf properties, including
5430Sstevel@tonic-gate 	 *	driver global properties. Devices attached in the future will
5440Sstevel@tonic-gate 	 *	referent properties in the updated driver.conf file.
5450Sstevel@tonic-gate 	 */
5460Sstevel@tonic-gate 	if (update_conf) {
5470Sstevel@tonic-gate 		(void) unload_drv(driver_name, force_flag, verbose_flag);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		if ((modctl(MODUNLOADDRVCONF, major) != 0) ||
550*10842SJerry.Gilliam@Sun.COM 		    (modctl(MODLOADDRVCONF, major, 0) != 0)) {
5510Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DRVCONF),
5520Sstevel@tonic-gate 			    driver_name);
5530Sstevel@tonic-gate 			err_exit();
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		if (verbose_flag) {
5570Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(DRVCONF_UPDATED),
5580Sstevel@tonic-gate 			    driver_name);
5590Sstevel@tonic-gate 		}
5605878Sjg 		load_driver(driver_name, verbose_flag);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	exit_unlock();
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	return (NOERR);
5660Sstevel@tonic-gate }
567