1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <locale.h>
31*0Sstevel@tonic-gate #include <stdlib.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include "addrem.h"
36*0Sstevel@tonic-gate #include "errmsg.h"
37*0Sstevel@tonic-gate #include "plcysubr.h"
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate /* function prototypes */
40*0Sstevel@tonic-gate static void	usage();
41*0Sstevel@tonic-gate static int	unload_drv(char *, int, int);
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate /*
45*0Sstevel@tonic-gate  * try to modunload driver.
46*0Sstevel@tonic-gate  * return -1 on failure and 0 on success
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate static int
49*0Sstevel@tonic-gate unload_drv(char *driver_name, int force_flag, int verbose_flag)
50*0Sstevel@tonic-gate {
51*0Sstevel@tonic-gate 	int modid;
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate 	get_modid(driver_name, &modid);
54*0Sstevel@tonic-gate 	if (modid != -1) {
55*0Sstevel@tonic-gate 		if (modctl(MODUNLOAD, modid) < 0) {
56*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_MODUN), driver_name);
57*0Sstevel@tonic-gate 			if (force_flag == 0) { /* no force flag */
58*0Sstevel@tonic-gate 				if (verbose_flag) {
59*0Sstevel@tonic-gate 					(void) fprintf(stderr,
60*0Sstevel@tonic-gate 					    gettext(NOUPDATE), driver_name);
61*0Sstevel@tonic-gate 				}
62*0Sstevel@tonic-gate 				/* clean up and exit. remove lock file */
63*0Sstevel@tonic-gate 				err_exit();
64*0Sstevel@tonic-gate 			}
65*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(FORCE_UPDATE),
66*0Sstevel@tonic-gate 			    driver_name);
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 			return (-1);
69*0Sstevel@tonic-gate 		}
70*0Sstevel@tonic-gate 	}
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	return (0);
73*0Sstevel@tonic-gate }
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static void
77*0Sstevel@tonic-gate usage()
78*0Sstevel@tonic-gate {
79*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(UPD_DRV_USAGE));
80*0Sstevel@tonic-gate 	exit(1);
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate int
85*0Sstevel@tonic-gate main(int argc, char *argv[])
86*0Sstevel@tonic-gate {
87*0Sstevel@tonic-gate 	int	error, opt, major;
88*0Sstevel@tonic-gate 	int	cleanup_flag = 0;
89*0Sstevel@tonic-gate 	int	update_conf = 1;	/* reload driver.conf by default */
90*0Sstevel@tonic-gate 	int	verbose_flag = 0;	/* -v option */
91*0Sstevel@tonic-gate 	int	force_flag = 0;		/* -f option */
92*0Sstevel@tonic-gate 	int	a_flag = 0;		/* -a option */
93*0Sstevel@tonic-gate 	int	d_flag = 0;		/* -d option */
94*0Sstevel@tonic-gate 	int	i_flag = 0;		/* -i option */
95*0Sstevel@tonic-gate 	int	l_flag = 0;		/* -l option */
96*0Sstevel@tonic-gate 	int	m_flag = 0;		/* -m option */
97*0Sstevel@tonic-gate 	char	*perms = NULL;
98*0Sstevel@tonic-gate 	char	*aliases = 0;
99*0Sstevel@tonic-gate 	char	*basedir = NULL;
100*0Sstevel@tonic-gate 	char	*policy = NULL;
101*0Sstevel@tonic-gate 	char	*priv = NULL;
102*0Sstevel@tonic-gate 	char	*driver_name;
103*0Sstevel@tonic-gate 	int	found;
104*0Sstevel@tonic-gate 	major_t major_num;
105*0Sstevel@tonic-gate 	int	rval;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
108*0Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
109*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
110*0Sstevel@tonic-gate #endif
111*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	/*  must be run by root */
114*0Sstevel@tonic-gate 	if (getuid() != 0) {
115*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NOT_ROOT));
116*0Sstevel@tonic-gate 		exit(1);
117*0Sstevel@tonic-gate 	}
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "m:i:b:p:adlfuvP:")) != EOF) {
120*0Sstevel@tonic-gate 		switch (opt) {
121*0Sstevel@tonic-gate 		case 'a':
122*0Sstevel@tonic-gate 			a_flag++;
123*0Sstevel@tonic-gate 			break;
124*0Sstevel@tonic-gate 		case 'b':
125*0Sstevel@tonic-gate 			update_conf = 0;	/* don't update .conf file */
126*0Sstevel@tonic-gate 			basedir = optarg;
127*0Sstevel@tonic-gate 			break;
128*0Sstevel@tonic-gate 		case 'd':
129*0Sstevel@tonic-gate 			d_flag++;
130*0Sstevel@tonic-gate 			break;
131*0Sstevel@tonic-gate 		case 'f':
132*0Sstevel@tonic-gate 			force_flag++;
133*0Sstevel@tonic-gate 			break;
134*0Sstevel@tonic-gate 		case 'i':
135*0Sstevel@tonic-gate 			i_flag++;
136*0Sstevel@tonic-gate 			aliases = optarg;
137*0Sstevel@tonic-gate 			if (check_space_within_quote(aliases) == ERROR) {
138*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_SPACE),
139*0Sstevel@tonic-gate 					aliases);
140*0Sstevel@tonic-gate 				exit(1);
141*0Sstevel@tonic-gate 			}
142*0Sstevel@tonic-gate 			break;
143*0Sstevel@tonic-gate 		case 'l':	/* private option */
144*0Sstevel@tonic-gate 			l_flag++;
145*0Sstevel@tonic-gate 			break;
146*0Sstevel@tonic-gate 		case 'm':
147*0Sstevel@tonic-gate 			m_flag++;
148*0Sstevel@tonic-gate 			perms = optarg;
149*0Sstevel@tonic-gate 			break;
150*0Sstevel@tonic-gate 		case 'p':
151*0Sstevel@tonic-gate 			policy = optarg;
152*0Sstevel@tonic-gate 			break;
153*0Sstevel@tonic-gate 		case 'v':
154*0Sstevel@tonic-gate 			verbose_flag++;
155*0Sstevel@tonic-gate 			break;
156*0Sstevel@tonic-gate 		case 'P':
157*0Sstevel@tonic-gate 			priv = optarg;
158*0Sstevel@tonic-gate 			break;
159*0Sstevel@tonic-gate 		case '?' :
160*0Sstevel@tonic-gate 		default:
161*0Sstevel@tonic-gate 			usage();
162*0Sstevel@tonic-gate 		}
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/*
166*0Sstevel@tonic-gate 	 * check for flags and extra args
167*0Sstevel@tonic-gate 	 */
168*0Sstevel@tonic-gate 	if ((argv[optind] == NULL) || (optind + 1 != argc)) {
169*0Sstevel@tonic-gate 		usage();
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	/*
173*0Sstevel@tonic-gate 	 * - cannot be adding and removing at the same time
174*0Sstevel@tonic-gate 	 * - if -a or -d is specified, it's an error if none of
175*0Sstevel@tonic-gate 	 *   -i/-m/-p/-P is specified.
176*0Sstevel@tonic-gate 	 */
177*0Sstevel@tonic-gate 	if ((a_flag && d_flag) ||
178*0Sstevel@tonic-gate 	    ((a_flag || d_flag) &&
179*0Sstevel@tonic-gate 	    !m_flag && !i_flag && priv == NULL && policy == NULL)) {
180*0Sstevel@tonic-gate 		usage();
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	/*
184*0Sstevel@tonic-gate 	 * - with -d option or -a option either -i 'identify_name',
185*0Sstevel@tonic-gate 	 *	-m 'permission',  -p 'policy' or -P 'priv' should be specified
186*0Sstevel@tonic-gate 	 */
187*0Sstevel@tonic-gate 	if (m_flag || i_flag || policy != NULL || priv != NULL) {
188*0Sstevel@tonic-gate 		if (!(a_flag || d_flag))
189*0Sstevel@tonic-gate 			usage();
190*0Sstevel@tonic-gate 	}
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	driver_name = argv[optind];
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	/* set up update_drv filenames */
195*0Sstevel@tonic-gate 	if ((build_filenames(basedir)) == ERROR) {
196*0Sstevel@tonic-gate 		exit(1);
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	/* no lock is needed for listing minor perm entry */
200*0Sstevel@tonic-gate 	if (l_flag) {
201*0Sstevel@tonic-gate 		list_entry(minor_perm, driver_name, ":");
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 		return (NOERR);
204*0Sstevel@tonic-gate 	}
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	/* must be only running version of add_drv/update_drv/rem_drv */
207*0Sstevel@tonic-gate 	enter_lock();
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if ((check_perms_aliases(m_flag, i_flag)) == ERROR) {
210*0Sstevel@tonic-gate 		err_exit();
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	/* update_drv doesn't modify /etc/name_to_major file */
214*0Sstevel@tonic-gate 	if ((check_name_to_major(R_OK)) == ERROR)
215*0Sstevel@tonic-gate 		err_exit();
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	if (priv != NULL && check_priv_entry(priv, a_flag) != 0)
218*0Sstevel@tonic-gate 		err_exit();
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	if (policy != NULL && (policy = check_plcy_entry(policy, driver_name,
221*0Sstevel@tonic-gate 	    d_flag ? B_TRUE : B_FALSE)) == NULL)
222*0Sstevel@tonic-gate 		err_exit();
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	/*
225*0Sstevel@tonic-gate 	 * ADD: -a option
226*0Sstevel@tonic-gate 	 * i_flag: update /etc/driver_aliases
227*0Sstevel@tonic-gate 	 * m_flag: update /etc/minor_perm
228*0Sstevel@tonic-gate 	 * -p: update /etc/security/device_policy
229*0Sstevel@tonic-gate 	 * -P: update /etc/security/extra_privs
230*0Sstevel@tonic-gate 	 * if force_flag is specified continue w/ the next operation
231*0Sstevel@tonic-gate 	 */
232*0Sstevel@tonic-gate 	if (a_flag) {
233*0Sstevel@tonic-gate 		if (m_flag) {
234*0Sstevel@tonic-gate 			/* check if the permissions are valid */
235*0Sstevel@tonic-gate 			if ((error = check_perm_opts(perms)) == ERROR) {
236*0Sstevel@tonic-gate 				if (force_flag == 0) { /* no force flag */
237*0Sstevel@tonic-gate 					exit_unlock();
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 					return (error);
240*0Sstevel@tonic-gate 				}
241*0Sstevel@tonic-gate 			}
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 			/*
244*0Sstevel@tonic-gate 			 * update the file, if and only if
245*0Sstevel@tonic-gate 			 * we didn't run into error earlier.
246*0Sstevel@tonic-gate 			 */
247*0Sstevel@tonic-gate 			if ((error != ERROR) &&
248*0Sstevel@tonic-gate 			    (error = update_minor_entry(driver_name, perms))) {
249*0Sstevel@tonic-gate 				if (force_flag == 0) { /* no force flag */
250*0Sstevel@tonic-gate 					exit_unlock();
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 					return (error);
253*0Sstevel@tonic-gate 				}
254*0Sstevel@tonic-gate 			}
255*0Sstevel@tonic-gate 			cleanup_flag |= CLEAN_NAM_MAJ;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 			/*
258*0Sstevel@tonic-gate 			 * Notify running system of minor perm change
259*0Sstevel@tonic-gate 			 */
260*0Sstevel@tonic-gate 			if (basedir == NULL || (strcmp(basedir, "/") == 0)) {
261*0Sstevel@tonic-gate 				rval = devfs_add_minor_perm(driver_name,
262*0Sstevel@tonic-gate 				    log_minorperm_error);
263*0Sstevel@tonic-gate 				if (rval) {
264*0Sstevel@tonic-gate 					(void) fprintf(stderr,
265*0Sstevel@tonic-gate 					    gettext(ERR_UPDATE_PERM),
266*0Sstevel@tonic-gate 					    driver_name);
267*0Sstevel@tonic-gate 				}
268*0Sstevel@tonic-gate 			}
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 		if (priv != NULL) {
272*0Sstevel@tonic-gate 			(void) append_to_file(driver_name, priv, extra_privs,
273*0Sstevel@tonic-gate 					',', ":");
274*0Sstevel@tonic-gate 			cleanup_flag |= CLEAN_DRV_PRIV;
275*0Sstevel@tonic-gate 		}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 		if (policy != NULL) {
278*0Sstevel@tonic-gate 			if ((error = update_device_policy(device_policy,
279*0Sstevel@tonic-gate 			    policy, B_TRUE)) != 0) {
280*0Sstevel@tonic-gate 				exit_unlock();
281*0Sstevel@tonic-gate 				return (error);
282*0Sstevel@tonic-gate 			}
283*0Sstevel@tonic-gate 			cleanup_flag |= CLEAN_DEV_POLICY;
284*0Sstevel@tonic-gate 		}
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 		if (i_flag) {
287*0Sstevel@tonic-gate 			/* check if the alias is unique */
288*0Sstevel@tonic-gate 			if ((error = aliases_unique(aliases)) == ERROR) {
289*0Sstevel@tonic-gate 				exit_unlock();
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 				return (error);
292*0Sstevel@tonic-gate 			}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 			/* update the file */
295*0Sstevel@tonic-gate 			if ((error = update_driver_aliases(driver_name,
296*0Sstevel@tonic-gate 			    aliases)) == ERROR) {
297*0Sstevel@tonic-gate 				exit_unlock();
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 				return (error);
300*0Sstevel@tonic-gate 			}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 			found = get_major_no(driver_name, name_to_major);
303*0Sstevel@tonic-gate 			if (found == ERROR) {
304*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_MAX_MAJOR),
305*0Sstevel@tonic-gate 				    name_to_major);
306*0Sstevel@tonic-gate 				err_exit();
307*0Sstevel@tonic-gate 			}
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 			if (found == UNIQUE) {
310*0Sstevel@tonic-gate 				(void) fprintf(stderr,
311*0Sstevel@tonic-gate 				    gettext(ERR_NOT_INSTALLED), driver_name);
312*0Sstevel@tonic-gate 				err_exit();
313*0Sstevel@tonic-gate 			}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 			major_num = (major_t)found;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 			/* paranoia - if we crash whilst configuring */
318*0Sstevel@tonic-gate 			sync();
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 			cleanup_flag |= CLEAN_DRV_ALIAS;
321*0Sstevel@tonic-gate 			if (config_driver(driver_name, major_num, aliases, NULL,
322*0Sstevel@tonic-gate 			    cleanup_flag, verbose_flag) == ERROR) {
323*0Sstevel@tonic-gate 				err_exit();
324*0Sstevel@tonic-gate 			}
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 		}
327*0Sstevel@tonic-gate 		if (update_conf && (i_flag || policy != NULL))
328*0Sstevel@tonic-gate 			/* load the driver */
329*0Sstevel@tonic-gate 			load_driver(driver_name, verbose_flag);
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 		exit_unlock();
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 		return (0);
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	/*
338*0Sstevel@tonic-gate 	 * DELETE: -d option
339*0Sstevel@tonic-gate 	 * i_flag: update /etc/driver_aliases
340*0Sstevel@tonic-gate 	 * m_flag: update /etc/minor_perm
341*0Sstevel@tonic-gate 	 * -p: update /etc/security/device_policy
342*0Sstevel@tonic-gate 	 * -P: update /etc/security/extra_privs
343*0Sstevel@tonic-gate 	 */
344*0Sstevel@tonic-gate 	if (d_flag) {
345*0Sstevel@tonic-gate 		int err = NOERR;
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 		if (m_flag) {
348*0Sstevel@tonic-gate 			/*
349*0Sstevel@tonic-gate 			 * On a running system, we first need to
350*0Sstevel@tonic-gate 			 * remove devfs's idea of the minor perms.
351*0Sstevel@tonic-gate 			 * We don't have any ability to do this singly
352*0Sstevel@tonic-gate 			 * at this point.
353*0Sstevel@tonic-gate 			 */
354*0Sstevel@tonic-gate 			if (basedir == NULL || (strcmp(basedir, "/") == 0)) {
355*0Sstevel@tonic-gate 				rval = devfs_rm_minor_perm(driver_name,
356*0Sstevel@tonic-gate 				    log_minorperm_error);
357*0Sstevel@tonic-gate 				if (rval) {
358*0Sstevel@tonic-gate 					(void) fprintf(stderr,
359*0Sstevel@tonic-gate 					    gettext(ERR_UPDATE_PERM),
360*0Sstevel@tonic-gate 					    driver_name);
361*0Sstevel@tonic-gate 				}
362*0Sstevel@tonic-gate 			}
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 			if ((error = delete_entry(minor_perm,
365*0Sstevel@tonic-gate 			    driver_name, ":", perms)) != NOERR) {
366*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
367*0Sstevel@tonic-gate 				    driver_name, minor_perm);
368*0Sstevel@tonic-gate 				err = error;
369*0Sstevel@tonic-gate 			}
370*0Sstevel@tonic-gate 			/*
371*0Sstevel@tonic-gate 			 * Notify running system of new minor perm state
372*0Sstevel@tonic-gate 			 */
373*0Sstevel@tonic-gate 			if (basedir == NULL || (strcmp(basedir, "/") == 0)) {
374*0Sstevel@tonic-gate 				rval = devfs_add_minor_perm(driver_name,
375*0Sstevel@tonic-gate 				    log_minorperm_error);
376*0Sstevel@tonic-gate 				if (rval) {
377*0Sstevel@tonic-gate 					(void) fprintf(stderr,
378*0Sstevel@tonic-gate 					    gettext(ERR_UPDATE_PERM),
379*0Sstevel@tonic-gate 					    driver_name);
380*0Sstevel@tonic-gate 				}
381*0Sstevel@tonic-gate 			}
382*0Sstevel@tonic-gate 		}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 		if (i_flag) {
385*0Sstevel@tonic-gate 			if ((error = delete_entry(driver_aliases,
386*0Sstevel@tonic-gate 			    driver_name, ":", aliases)) != NOERR) {
387*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
388*0Sstevel@tonic-gate 				    driver_name, driver_aliases);
389*0Sstevel@tonic-gate 				if (err != NOERR)
390*0Sstevel@tonic-gate 					err = error;
391*0Sstevel@tonic-gate 			}
392*0Sstevel@tonic-gate 		}
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 		if (priv != NULL) {
395*0Sstevel@tonic-gate 			if ((error = delete_entry(extra_privs, driver_name, ":",
396*0Sstevel@tonic-gate 			    priv)) != NOERR) {
397*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
398*0Sstevel@tonic-gate 				    driver_name, extra_privs);
399*0Sstevel@tonic-gate 				if (err != NOERR)
400*0Sstevel@tonic-gate 					err = error;
401*0Sstevel@tonic-gate 			}
402*0Sstevel@tonic-gate 		}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 		if (policy != NULL) {
405*0Sstevel@tonic-gate 			if ((error = delete_plcy_entry(device_policy,
406*0Sstevel@tonic-gate 				policy)) != NOERR) {
407*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_NO_ENTRY),
408*0Sstevel@tonic-gate 				    driver_name, device_policy);
409*0Sstevel@tonic-gate 				if (err != NOERR)
410*0Sstevel@tonic-gate 					err = error;
411*0Sstevel@tonic-gate 			}
412*0Sstevel@tonic-gate 		}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		if (err == NOERR && update_conf) {
415*0Sstevel@tonic-gate 			if (i_flag || m_flag) {
416*0Sstevel@tonic-gate 				/* try to unload the driver */
417*0Sstevel@tonic-gate 				(void) unload_drv(driver_name,
418*0Sstevel@tonic-gate 				    force_flag, verbose_flag);
419*0Sstevel@tonic-gate 			}
420*0Sstevel@tonic-gate 			/* reload the policy */
421*0Sstevel@tonic-gate 			if (policy != NULL)
422*0Sstevel@tonic-gate 				load_driver(driver_name, verbose_flag);
423*0Sstevel@tonic-gate 		}
424*0Sstevel@tonic-gate 		exit_unlock();
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 		return (err);
427*0Sstevel@tonic-gate 	}
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	/* driver name must exist (for update_conf stuff) */
430*0Sstevel@tonic-gate 	major = get_major_no(driver_name, name_to_major);
431*0Sstevel@tonic-gate 	if (major == ERROR) {
432*0Sstevel@tonic-gate 		err_exit();
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	/*
436*0Sstevel@tonic-gate 	 * Update driver.conf file:
437*0Sstevel@tonic-gate 	 *	First try to unload driver module. If it fails, there may
438*0Sstevel@tonic-gate 	 *	be attached devices using the old driver.conf properties,
439*0Sstevel@tonic-gate 	 *	so we cannot safely update driver.conf
440*0Sstevel@tonic-gate 	 *
441*0Sstevel@tonic-gate 	 *	The user may specify -f to force a driver.conf update.
442*0Sstevel@tonic-gate 	 *	In this case, we will update driver.conf cache. All attached
443*0Sstevel@tonic-gate 	 *	devices still reference old driver.conf properties, including
444*0Sstevel@tonic-gate 	 *	driver global properties. Devices attached in the future will
445*0Sstevel@tonic-gate 	 *	referent properties in the updated driver.conf file.
446*0Sstevel@tonic-gate 	 */
447*0Sstevel@tonic-gate 	if (update_conf) {
448*0Sstevel@tonic-gate 		(void) unload_drv(driver_name, force_flag, verbose_flag);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 		if ((modctl(MODUNLOADDRVCONF, major) != 0) ||
451*0Sstevel@tonic-gate 		    (modctl(MODLOADDRVCONF, major) != 0)) {
452*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_DRVCONF),
453*0Sstevel@tonic-gate 			    driver_name);
454*0Sstevel@tonic-gate 			err_exit();
455*0Sstevel@tonic-gate 		}
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 		if (verbose_flag) {
458*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(DRVCONF_UPDATED),
459*0Sstevel@tonic-gate 			    driver_name);
460*0Sstevel@tonic-gate 		}
461*0Sstevel@tonic-gate 	}
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	/* rebuild /devices & /dev */
464*0Sstevel@tonic-gate 	load_driver(driver_name, verbose_flag);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	exit_unlock();
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 	return (NOERR);
469*0Sstevel@tonic-gate }
470