4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #include <sys/types.h>
36 /* function prototypes */
38 static int unload_drv(char *, int, int);
42 * try to modunload driver.
43 * return -1 on failure and 0 on success
46 unload_drv(char *driver_name
, int force_flag
, int verbose_flag
)
50 get_modid(driver_name
, &modid
);
52 if (modctl(MODUNLOAD
, modid
) < 0) {
53 (void) fprintf(stderr
, gettext(ERR_MODUN
), driver_name
);
54 if (force_flag
== 0) { /* no force flag */
56 (void) fprintf(stderr
,
57 gettext(NOUPDATE
), driver_name
);
59 /* clean up and exit. remove lock file */
62 (void) fprintf(stderr
, gettext(FORCE_UPDATE
),
76 (void) fprintf(stderr
, gettext(UPD_DRV_USAGE
));
82 main(int argc
, char *argv
[])
84 int error
, opt
, major
;
86 int update_conf
= 1; /* reload driver.conf by default */
87 int verbose_flag
= 0; /* -v option */
88 int force_flag
= 0; /* -f option */
89 int a_flag
= 0; /* -a option */
90 int d_flag
= 0; /* -d option */
91 int i_flag
= 0; /* -i option */
92 int l_flag
= 0; /* -l option */
93 int m_flag
= 0; /* -m option */
94 int n_flag
= 0; /* -n option */
99 char *aliases2
= NULL
;
107 (void) setlocale(LC_ALL
, "");
108 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
109 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
111 (void) textdomain(TEXT_DOMAIN
);
113 /* must be run by root */
115 (void) fprintf(stderr
, gettext(ERR_NOT_ROOT
));
119 while ((opt
= getopt(argc
, argv
, "m:ni:b:p:adlfuvP:")) != EOF
) {
125 update_conf
= 0; /* don't update .conf file */
137 if (check_space_within_quote(aliases
) == ERROR
) {
138 (void) fprintf(stderr
, gettext(ERR_NO_SPACE
),
143 case 'l': /* private option */
170 * check for flags and extra args
172 if ((argv
[optind
] == NULL
) || (optind
+ 1 != argc
)) {
177 * - cannot be adding and removing at the same time
178 * - if -a or -d is specified, it's an error if none of
179 * -i/-m/-p/-P is specified.
181 if ((a_flag
&& d_flag
) ||
182 ((a_flag
|| d_flag
) &&
183 !m_flag
&& !i_flag
&& priv
== NULL
&& policy
== NULL
)) {
188 * - with -d option or -a option either -i 'identify_name',
189 * -m 'permission', -p 'policy' or -P 'priv' should be specified
191 if (m_flag
|| i_flag
|| policy
!= NULL
|| priv
!= NULL
) {
192 if (!(a_flag
|| d_flag
))
196 driver_name
= argv
[optind
];
198 /* set up update_drv filenames */
199 if ((build_filenames(basedir
)) == ERROR
) {
203 /* no lock is needed for listing minor perm entry */
205 list_entry(minor_perm
, driver_name
, ":");
210 /* must be only running version of add_drv/update_drv/rem_drv */
213 if ((check_perms_aliases(m_flag
, i_flag
)) == ERROR
) {
217 /* update_drv doesn't modify /etc/name_to_major file */
218 if ((check_name_to_major(R_OK
)) == ERROR
)
222 (basedir
== NULL
|| (strcmp(basedir
, "/") == 0)) &&
223 (priv
!= NULL
) && check_priv_entry(priv
, a_flag
) != 0)
226 if (policy
!= NULL
&& (policy
= check_plcy_entry(policy
, driver_name
,
227 d_flag
? B_TRUE
: B_FALSE
)) == NULL
)
232 * i_flag: update /etc/driver_aliases
233 * m_flag: update /etc/minor_perm
234 * -p: update /etc/security/device_policy
235 * -P: update /etc/security/extra_privs
236 * if force_flag is specified continue w/ the next operation
240 /* check if the permissions are valid */
241 if ((error
= check_perm_opts(perms
)) == ERROR
) {
242 if (force_flag
== 0) { /* no force flag */
249 * update the file, if and only if
250 * we didn't run into error earlier.
252 if ((error
!= ERROR
) &&
253 (error
= update_minor_entry(driver_name
, perms
))) {
254 if (force_flag
== 0) { /* no force flag */
259 cleanup_flag
|= CLEAN_NAM_MAJ
;
262 * Notify running system of minor perm change
265 (basedir
== NULL
|| (strcmp(basedir
, "/") == 0))) {
266 rval
= devfs_add_minor_perm(driver_name
,
267 log_minorperm_error
);
269 (void) fprintf(stderr
,
270 gettext(ERR_UPDATE_PERM
),
277 (void) append_to_file(driver_name
, priv
, extra_privs
,
279 cleanup_flag
|= CLEAN_DRV_PRIV
;
282 if (policy
!= NULL
) {
283 if ((error
= update_device_policy(device_policy
,
284 policy
, B_TRUE
)) != 0) {
288 cleanup_flag
|= CLEAN_DEV_POLICY
;
292 found
= get_major_no(driver_name
, name_to_major
);
293 if (found
== ERROR
) {
294 (void) fprintf(stderr
, gettext(ERR_MAX_MAJOR
),
299 if (found
== UNIQUE
) {
300 (void) fprintf(stderr
,
301 gettext(ERR_NOT_INSTALLED
), driver_name
);
305 major_num
= (major_t
)found
;
308 * To ease the nuisance of using update_drv
309 * in packaging scripts, do not require that
310 * existing driver aliases be trimmed from
311 * the command line. If an invocation asks
312 * to add an alias and it's already there,
313 * drive on. We implement this by removing
314 * duplicates now and add the remainder.
316 error
= trim_duplicate_aliases(driver_name
,
318 if (error
== ERROR
) {
324 * if the list of aliases to be added is
325 * now empty, we're done.
327 if (aliases2
== NULL
)
331 * unless force_flag is specified check that
332 * path-oriented aliases we are adding exist
334 if ((force_flag
== 0) && ((error
=
335 aliases_paths_exist(aliases2
)) == ERROR
)) {
340 /* update the file */
341 if ((error
= update_driver_aliases(driver_name
,
342 aliases2
)) == ERROR
) {
348 /* optionally update the running system - not -b */
350 /* paranoia - if we crash whilst configuring */
352 config_flags
= (verbose_flag
) ?
353 CONFIG_DRV_VERBOSE
: 0;
354 cleanup_flag
|= CLEAN_DRV_ALIAS
;
355 if (config_driver(driver_name
, major_num
,
356 aliases2
, NULL
, cleanup_flag
,
357 config_flags
) == ERROR
) {
365 if (update_conf
&& (i_flag
|| policy
!= NULL
)) {
366 /* load the driver */
367 load_driver(driver_name
, verbose_flag
);
378 * i_flag: update /etc/driver_aliases
379 * m_flag: update /etc/minor_perm
380 * -p: update /etc/security/device_policy
381 * -P: update /etc/security/extra_privs
382 * if force_flag is specified continue w/ the next operation
389 * On a running system, we first need to
390 * remove devfs's idea of the minor perms.
391 * We don't have any ability to do this singly
395 (basedir
== NULL
|| (strcmp(basedir
, "/") == 0))) {
396 rval
= devfs_rm_minor_perm(driver_name
,
397 log_minorperm_error
);
399 (void) fprintf(stderr
,
400 gettext(ERR_UPDATE_PERM
),
405 if ((error
= delete_entry(minor_perm
,
406 driver_name
, ":", perms
)) != NOERR
) {
407 (void) fprintf(stderr
, gettext(ERR_NO_ENTRY
),
408 driver_name
, minor_perm
);
412 * Notify running system of new minor perm state
415 (basedir
== NULL
|| (strcmp(basedir
, "/") == 0))) {
416 rval
= devfs_add_minor_perm(driver_name
,
417 log_minorperm_error
);
419 (void) fprintf(stderr
,
420 gettext(ERR_UPDATE_PERM
),
427 found
= get_major_no(driver_name
, name_to_major
);
428 if (found
== ERROR
) {
429 (void) fprintf(stderr
, gettext(ERR_MAX_MAJOR
),
434 if (found
== UNIQUE
) {
435 (void) fprintf(stderr
,
436 gettext(ERR_NOT_INSTALLED
), driver_name
);
440 major_num
= (major_t
)found
;
443 * verify that the aliases to be deleted exist
444 * before removal. With -f, failing to
445 * remove an alias is not an error so we
446 * can continue on to update the kernel.
449 rval
= aliases_exist(aliases
);
450 if (rval
== ERROR
&& (force_flag
== 0)) {
451 (void) fprintf(stderr
,
452 gettext(ERR_ALIAS_NOT_BOUND
),
458 error
= delete_entry(driver_aliases
,
459 driver_name
, ":", aliases
);
460 if (error
!= NOERR
&& (force_flag
== 0)) {
461 (void) fprintf(stderr
, gettext(ERR_NO_ENTRY
),
462 driver_name
, driver_aliases
);
468 * optionally update the running system - not -b.
469 * Unless -f is specified, error if one or more
470 * devices remain bound to the alias.
472 if (err
== NOERR
&& update_conf
) {
473 /* paranoia - if we crash whilst configuring */
478 config_flags
|= CONFIG_DRV_VERBOSE
;
480 config_flags
|= CONFIG_DRV_FORCE
;
481 error
= unconfig_driver(driver_name
, major_num
,
482 aliases
, config_flags
);
483 if (error
== ERROR
&& force_flag
== 0) {
484 (void) fprintf(stderr
,
485 gettext(ERR_DEV_IN_USE
),
494 if ((error
= delete_entry(extra_privs
, driver_name
, ":",
496 (void) fprintf(stderr
, gettext(ERR_NO_ENTRY
),
497 driver_name
, extra_privs
);
503 if (policy
!= NULL
) {
504 if ((error
= delete_plcy_entry(device_policy
,
506 (void) fprintf(stderr
, gettext(ERR_NO_ENTRY
),
507 driver_name
, device_policy
);
513 if (err
== NOERR
&& update_conf
) {
514 if (i_flag
|| m_flag
) {
515 /* try to unload the driver */
516 (void) unload_drv(driver_name
,
517 force_flag
, verbose_flag
);
519 /* reload the policy */
521 load_driver(driver_name
, verbose_flag
);
528 /* driver name must exist (for update_conf stuff) */
529 major
= get_major_no(driver_name
, name_to_major
);
530 if (major
== ERROR
) {
535 * Update driver.conf file:
536 * First try to unload driver module. If it fails, there may
537 * be attached devices using the old driver.conf properties,
538 * so we cannot safely update driver.conf
540 * The user may specify -f to force a driver.conf update.
541 * In this case, we will update driver.conf cache. All attached
542 * devices still reference old driver.conf properties, including
543 * driver global properties. Devices attached in the future will
544 * referent properties in the updated driver.conf file.
547 (void) unload_drv(driver_name
, force_flag
, verbose_flag
);
549 if ((modctl(MODUNLOADDRVCONF
, major
) != 0) ||
550 (modctl(MODLOADDRVCONF
, major
, 0) != 0)) {
551 (void) fprintf(stderr
, gettext(ERR_DRVCONF
),
557 (void) fprintf(stderr
, gettext(DRVCONF_UPDATED
),
560 load_driver(driver_name
, verbose_flag
);