1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "@(#)devfsadm.c 1.98 08/05/07 SMI"
28
29 /*
30 * Devfsadm replaces drvconfig, audlinks, disks, tapes, ports, devlinks
31 * as a general purpose device administrative utility. It creates
32 * devices special files in /devices and logical links in /dev, and
33 * coordinates updates to /etc/path_to_instance with the kernel. It
34 * operates in both command line mode to handle user or script invoked
35 * reconfiguration updates, and operates in daemon mode to handle dynamic
36 * reconfiguration for hotplugging support.
37 */
38
39 #include <string.h>
40 #include <deflt.h>
41 #include <tsol/label.h>
42 #include <bsm/devices.h>
43 #include <bsm/devalloc.h>
44 #include <utime.h>
45 #include <sys/param.h>
46 #include <bsm/libbsm.h>
47 #include "devfsadm_impl.h"
48
49 /* externs from devalloc.c */
50 extern void _reset_devalloc(int);
51 extern void _update_devalloc_db(devlist_t *, int, int, char *, char *);
52 extern int _da_check_for_usb(char *, char *);
53
54 /* create or remove nodes or links. unset with -n */
55 static int file_mods = TRUE;
56
57 /* cleanup mode. Set with -C */
58 static int cleanup = FALSE;
59
60 /* devlinks -d compatibility */
61 static int devlinks_debug = FALSE;
62
63 /* flag to check if system is labeled */
64 int system_labeled = FALSE;
65
66 /* flag to enable/disable device allocation with -e/-d */
67 static int devalloc_flag = 0;
68
69 /* flag that indicates if device allocation is on or not */
70 static int devalloc_is_on = 0;
71
72 /* flag to update device allocation database for this device type */
73 static int update_devdb = 0;
74
75 /*
76 * devices to be deallocated with -d :
77 * audio, floppy, cd, floppy, tape, rmdisk.
78 */
79 static char *devalloc_list[10] = {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_CD_CHAN,
80 DDI_NT_FD, DDI_NT_TAPE, DDI_NT_BLOCK_CHAN,
81 DDI_NT_UGEN, DDI_NT_USB_ATTACHMENT_POINT,
82 DDI_NT_SCSI_NEXUS, NULL};
83
84 /* list of allocatable devices */
85 static devlist_t devlist;
86
87 /* load a single driver only. set with -i */
88 static int single_drv = FALSE;
89 static char *driver = NULL;
90
91 /* attempt to load drivers or defer attach nodes */
92 static int load_attach_drv = TRUE;
93
94 /* set if invoked via /usr/lib/devfsadm/devfsadmd */
95 static int daemon_mode = FALSE;
96
97 /* output directed to syslog during daemon mode if set */
98 static int logflag = FALSE;
99
100 /* build links in /dev. -x to turn off */
101 static int build_dev = TRUE;
102
103 /* build nodes in /devices. -y to turn off */
104 static int build_devices = TRUE;
105
106 /* -z to turn off */
107 static int flush_path_to_inst_enable = TRUE;
108
109 /* variables used for path_to_inst flushing */
110 static int inst_count = 0;
111 static mutex_t count_lock;
112 static cond_t cv;
113
114 /* variables for minor_fini thread */
115 static mutex_t minor_fini_mutex;
116 static int minor_fini_canceled = TRUE;
117 static int minor_fini_delayed = FALSE;
118 static cond_t minor_fini_cv;
119 static int minor_fini_timeout = MINOR_FINI_TIMEOUT_DEFAULT;
120
121 /* single-threads /dev modification */
122 static sema_t dev_sema;
123
124 /* the program we were invoked as; ie argv[0] */
125 static char *prog;
126
127 /* pointers to create/remove link lists */
128 static create_list_t *create_head = NULL;
129 static remove_list_t *remove_head = NULL;
130
131 /* supports the class -c option */
132 static char **classes = NULL;
133 static int num_classes = 0;
134
135 /* used with verbose option -v or -V */
136 static int num_verbose = 0;
137 static char **verbose = NULL;
138
139 static struct mperm *minor_perms = NULL;
140 static driver_alias_t *driver_aliases = NULL;
141
142 /* set if -r alternate root given */
143 static char *root_dir = "";
144
145 /* /devices or <rootdir>/devices */
146 static char *devices_dir = DEVICES;
147
148 /* /dev or <rootdir>/dev */
149 static char *dev_dir = DEV;
150
151 /* /etc/dev or <rootdir>/etc/dev */
152 static char *etc_dev_dir = ETCDEV;
153
154 /*
155 * writable root (for lock files and doors during install).
156 * This is also root dir for /dev attr dir during install.
157 */
158 static char *attr_root = NULL;
159
160 /* /etc/path_to_inst unless -p used */
161 static char *inst_file = INSTANCE_FILE;
162
163 /* /usr/lib/devfsadm/linkmods unless -l used */
164 static char *module_dirs = MODULE_DIRS;
165
166 /* default uid/gid used if /etc/minor_perm entry not found */
167 static uid_t root_uid;
168 static gid_t sys_gid;
169
170 /* /etc/devlink.tab unless devlinks -t used */
171 static char *devlinktab_file = NULL;
172
173 /* File and data structure to reserve enumerate IDs */
174 static char *enumerate_file = ENUMERATE_RESERVED;
175 static enumerate_file_t *enumerate_reserved = NULL;
176
177 /* set if /dev link is new. speeds up rm_stale_links */
178 static int linknew = TRUE;
179
180 /* variables for devlink.tab compat processing */
181 static devlinktab_list_t *devlinktab_list = NULL;
182 static unsigned int devlinktab_line = 0;
183
184 /* cache head for devfsadm_enumerate*() functions */
185 static numeral_set_t *head_numeral_set = NULL;
186
187 /* list list of devfsadm modules */
188 static module_t *module_head = NULL;
189
190 /* name_to_major list used in utility function */
191 static n2m_t *n2m_list = NULL;
192
193 /* cache of some links used for performance */
194 static linkhead_t *headlinkhead = NULL;
195
196 /* locking variables to prevent multiples writes to /dev */
197 static int hold_dev_lock = FALSE;
198 static int hold_daemon_lock = FALSE;
199 static int dev_lock_fd;
200 static int daemon_lock_fd;
201 static char dev_lockfile[PATH_MAX + 1];
202 static char daemon_lockfile[PATH_MAX + 1];
203
204 /* last devinfo node/minor processed. used for performance */
205 static di_node_t lnode;
206 static di_minor_t lminor;
207 static char lphy_path[PATH_MAX + 1] = {""};
208
209 /* Globals used by the link database */
210 static di_devlink_handle_t devlink_cache;
211 static int update_database = FALSE;
212
213 /* Globals used to set logindev perms */
214 static struct login_dev *login_dev_cache = NULL;
215 static int login_dev_enable = FALSE;
216
217 /* Global to use devinfo snapshot cache */
218 static int use_snapshot_cache = FALSE;
219
220 /* Global for no-further-processing hash */
221 static item_t **nfp_hash;
222 static mutex_t nfp_mutex = DEFAULTMUTEX;
223
224 /*
225 * Packaged directories - not removed even when empty.
226 * The dirs must be listed in canonical form
227 * i.e. without leading "/dev/"
228 */
229 static char *packaged_dirs[] =
230 {"dsk", "rdsk", "term", NULL};
231
232 /* RCM related globals */
233 static void *librcm_hdl;
234 static rcm_handle_t *rcm_hdl = NULL;
235 static thread_t process_rcm_events_tid;
236 static struct rcm_eventq *volatile rcm_eventq_head = NULL;
237 static struct rcm_eventq *rcm_eventq_tail = NULL;
238 static mutex_t rcm_eventq_lock;
239 static cond_t rcm_eventq_cv;
240 static volatile int need_to_exit_rcm_event_thread = 0;
241
242 /* Devname globals */
243 static int devname_debug_msg = 1;
244 static nvlist_t *devname_maps = NULL;
245 static int devname_first_call = 1;
246 static int load_devname_nsmaps = FALSE;
247 static int lookup_door_fd = -1;
248 static char *lookup_door_path;
249
250 static void load_dev_acl(void);
251 static void update_drvconf(major_t);
252 static void check_reconfig_state(void);
253 static void devname_setup_nsmaps(void);
254 static int s_stat(const char *, struct stat *);
255
256 static int is_blank(char *);
257
258 /* sysevent queue related globals */
259 static mutex_t syseventq_mutex = DEFAULTMUTEX;
260 static syseventq_t *syseventq_front;
261 static syseventq_t *syseventq_back;
262 static void process_syseventq();
263
264 int
265 main(int argc, char *argv[])
266 {
267 struct passwd *pw;
268 struct group *gp;
269 pid_t pid;
270 int cond = 0;
271
272 (void) setlocale(LC_ALL, "");
273 (void) textdomain(TEXT_DOMAIN);
274
275 if ((prog = strrchr(argv[0], '/')) == NULL) {
276 prog = argv[0];
277 } else {
278 prog++;
279 }
280
281 if (getuid() != 0) {
282 err_print(MUST_BE_ROOT);
283 devfsadm_exit(1);
284 }
285
286 /*
287 * Close all files except stdin/stdout/stderr
288 */
289 closefrom(3);
290
291 if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
292 root_uid = pw->pw_uid;
293 } else {
294 err_print(CANT_FIND_USER, DEFAULT_DEV_USER);
295 root_uid = (uid_t)0; /* assume 0 is root */
296 }
297
298 /* the default group is sys */
299
300 if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
301 sys_gid = gp->gr_gid;
302 } else {
303 err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP);
304 sys_gid = (gid_t)3; /* assume 3 is sys */
305 }
306
307 (void) umask(0);
308
309 system_labeled = is_system_labeled();
310 if (system_labeled == FALSE) {
311 /*
312 * is_system_labeled() will return false in case we are
313 * starting before the first reboot after Trusted Extensions
314 * is enabled. Check the setting in /etc/system to see if
315 * TX is enabled (even if not yet booted).
316 */
317 if (defopen("/etc/system") == 0) {
318 if (defread("set sys_labeling=1") != NULL)
319 system_labeled = TRUE;
320
321 /* close defaults file */
322 (void) defopen(NULL);
323 }
324 }
325 /*
326 * Check if device allocation is enabled.
327 */
328 if (system_labeled) {
329 /*
330 * In TX, the first line in /etc/security/device_allocate has
331 * DEVICE_ALLOCATION=ON if the feature is enabled.
332 */
333 devalloc_is_on = da_is_on();
334 } else if (auditon(A_GETCOND, (caddr_t)&cond, sizeof (cond)) == 0) {
335 /*
336 * Device allocation (and auditing) is enabled if BSM is
337 * enabled. auditon returns -1 and sets errno to EINVAL if BSM
338 * is not enabled.
339 */
340 devalloc_is_on = 1;
341 }
342
343 #ifdef DEBUG
344 if (system_labeled == FALSE) {
345 struct stat tx_stat;
346
347 /* test hook: see also mkdevalloc.c and allocate.c */
348 system_labeled = is_system_labeled_debug(&tx_stat);
349 }
350 #endif
351
352 parse_args(argc, argv);
353
354 (void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL);
355
356 /* Initialize device allocation list */
357 devlist.audio = devlist.cd = devlist.floppy = devlist.tape =
358 devlist.rmdisk = NULL;
359
360 if (daemon_mode == TRUE) {
361 /*
362 * Build /dev and /devices before daemonizing if
363 * reconfig booting and daemon invoked with alternate
364 * root. This is to support install.
365 */
366 if (getenv(RECONFIG_BOOT) != NULL && root_dir[0] != '\0') {
367 vprint(INFO_MID, CONFIGURING);
368 load_dev_acl();
369 update_drvconf((major_t)-1);
370 process_devinfo_tree();
371 (void) modctl(MODSETMINIROOT);
372 }
373
374 /*
375 * fork before detaching from tty in order to print error
376 * message if unable to acquire file lock. locks not preserved
377 * across forks. Even under debug we want to fork so that
378 * when executed at boot we don't hang.
379 */
380 if (fork() != 0) {
381 devfsadm_exit(0);
382 }
383
384 /* set directory to / so it coredumps there */
385 if (chdir("/") == -1) {
386 err_print(CHROOT_FAILED, strerror(errno));
387 }
388
389 /* only one daemon can run at a time */
390 if ((pid = enter_daemon_lock()) == getpid()) {
391 detachfromtty();
392 (void) cond_init(&cv, USYNC_THREAD, 0);
393 (void) mutex_init(&count_lock, USYNC_THREAD, 0);
394 if (thr_create(NULL, NULL,
395 (void *(*)(void *))instance_flush_thread,
396 NULL, THR_DETACHED, NULL) != 0) {
397 err_print(CANT_CREATE_THREAD, "daemon",
398 strerror(errno));
399 devfsadm_exit(1);
400 }
401
402 /* start the minor_fini_thread */
403 (void) mutex_init(&minor_fini_mutex, USYNC_THREAD, 0);
404 (void) cond_init(&minor_fini_cv, USYNC_THREAD, 0);
405 if (thr_create(NULL, NULL,
406 (void *(*)(void *))minor_fini_thread,
407 NULL, THR_DETACHED, NULL)) {
408 err_print(CANT_CREATE_THREAD, "minor_fini",
409 strerror(errno));
410 devfsadm_exit(1);
411 }
412
413
414 /*
415 * No need for rcm notifications when running
416 * with an alternate root. So initialize rcm only
417 * when devfsadm is running with root dir "/".
418 * Similarly, logindevperms need only be set
419 * in daemon mode and when root dir is "/".
420 */
421 if (root_dir[0] == '\0') {
422 (void) rcm_init();
423 login_dev_enable = TRUE;
424 }
425 daemon_update();
426 } else {
427 err_print(DAEMON_RUNNING, pid);
428 devfsadm_exit(1);
429 }
430 exit_daemon_lock();
431
432 } else {
433 /* not a daemon, so just build /dev and /devices */
434 process_devinfo_tree();
435 if (devalloc_flag != 0)
436 /* Enable/disable device allocation */
437 _reset_devalloc(devalloc_flag);
438 }
439 return (0);
440 }
441
442 static void
443 update_drvconf(major_t major)
444 {
445 if (modctl(MODLOADDRVCONF, major) != 0)
446 err_print(gettext("update_drvconf failed for major %d\n"),
447 major);
448 }
449
450
451 static void
452 load_dev_acl()
453 {
454 if (load_devpolicy() != 0)
455 err_print(gettext("device policy load failed\n"));
456 load_minor_perm_file();
457 }
458
459 /*
460 * As devfsadm is run early in boot to provide the kernel with
461 * minor_perm info, we might as well check for reconfig at the
462 * same time to avoid running devfsadm twice. This gets invoked
463 * earlier than the env variable RECONFIG_BOOT is set up.
464 */
465 static void
466 check_reconfig_state()
467 {
468 struct stat sb;
469
470 if (s_stat("/reconfigure", &sb) == 0) {
471 (void) modctl(MODDEVNAME, MODDEVNAME_RECONFIG, 0);
472 }
473 }
474
475 static void
476 modctl_sysavail()
477 {
478 /*
479 * Inform /dev that system is available, that
480 * implicit reconfig can now be performed.
481 */
482 (void) modctl(MODDEVNAME, MODDEVNAME_SYSAVAIL, 0);
483 }
484
485 static void
486 set_lock_root(void)
487 {
488 struct stat sb;
489 char *lock_root;
490 size_t len;
491
492 lock_root = attr_root ? attr_root : root_dir;
493
494 len = strlen(lock_root) + strlen(ETCDEV) + 1;
495 etc_dev_dir = s_malloc(len);
496 (void) snprintf(etc_dev_dir, len, "%s%s", lock_root, ETCDEV);
497
498 if (s_stat(etc_dev_dir, &sb) != 0) {
499 s_mkdirp(etc_dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
500 } else if (!S_ISDIR(sb.st_mode)) {
501 err_print(NOT_DIR, etc_dev_dir);
502 devfsadm_exit(1);
503 }
504 }
505
506
507 /*
508 * Parse arguments for all 6 programs handled from devfsadm.
509 */
510 static void
511 parse_args(int argc, char *argv[])
512 {
513 char opt;
514 char get_linkcompat_opts = FALSE;
515 char *compat_class;
516 int num_aliases = 0;
517 int len;
518 int retval;
519 int add_bind = FALSE;
520 struct aliases *ap = NULL;
521 struct aliases *a_head = NULL;
522 struct aliases *a_tail = NULL;
523 struct modconfig mc;
524
525 if (strcmp(prog, DISKS) == 0) {
526 compat_class = "disk";
527 get_linkcompat_opts = TRUE;
528
529 } else if (strcmp(prog, TAPES) == 0) {
530 compat_class = "tape";
531 get_linkcompat_opts = TRUE;
532
533 } else if (strcmp(prog, PORTS) == 0) {
534 compat_class = "port";
535 get_linkcompat_opts = TRUE;
536
537 } else if (strcmp(prog, AUDLINKS) == 0) {
538 compat_class = "audio";
539 get_linkcompat_opts = TRUE;
540
541 } else if (strcmp(prog, DEVLINKS) == 0) {
542 devlinktab_file = DEVLINKTAB_FILE;
543
544 build_devices = FALSE;
545 load_attach_drv = FALSE;
546
547 while ((opt = getopt(argc, argv, "dnr:st:vV:")) != EOF) {
548 switch (opt) {
549 case 'd':
550 file_mods = FALSE;
551 flush_path_to_inst_enable = FALSE;
552 devlinks_debug = TRUE;
553 break;
554 case 'n':
555 /* prevent driver loading and deferred attach */
556 load_attach_drv = FALSE;
557 break;
558 case 'r':
559 set_root_devices_dev_dir(optarg);
560 if (zone_pathcheck(root_dir) !=
561 DEVFSADM_SUCCESS)
562 devfsadm_exit(1);
563 break;
564 case 's':
565 /*
566 * suppress. don't create/remove links/nodes
567 * useful with -v or -V
568 */
569 file_mods = FALSE;
570 flush_path_to_inst_enable = FALSE;
571 break;
572 case 't':
573 /* supply a non-default table file */
574 devlinktab_file = optarg;
575 break;
576 case 'v':
577 /* documented verbose flag */
578 add_verbose_id(VERBOSE_MID);
579 break;
580 case 'V':
581 /* undocumented for extra verbose levels */
582 add_verbose_id(optarg);
583 break;
584 default:
585 usage();
586 break;
587 }
588 }
589
590 if (optind < argc) {
591 usage();
592 }
593
594 } else if (strcmp(prog, DRVCONFIG) == 0) {
595 build_dev = FALSE;
596
597 while ((opt =
598 getopt(argc, argv, "a:bdc:i:m:np:R:r:svV:")) != EOF) {
599 switch (opt) {
600 case 'a':
601 ap = calloc(sizeof (struct aliases), 1);
602 ap->a_name = dequote(optarg);
603 len = strlen(ap->a_name) + 1;
604 if (len > MAXMODCONFNAME) {
605 err_print(ALIAS_TOO_LONG,
606 MAXMODCONFNAME, ap->a_name);
607 devfsadm_exit(1);
608 }
609 ap->a_len = len;
610 if (a_tail == NULL) {
611 a_head = ap;
612 } else {
613 a_tail->a_next = ap;
614 }
615 a_tail = ap;
616 num_aliases++;
617 add_bind = TRUE;
618 break;
619 case 'b':
620 add_bind = TRUE;
621 break;
622 case 'c':
623 (void) strcpy(mc.drvclass, optarg);
624 break;
625 case 'd':
626 /*
627 * need to keep for compatibility, but
628 * do nothing.
629 */
630 break;
631 case 'i':
632 single_drv = TRUE;
633 (void) strcpy(mc.drvname, optarg);
634 driver = s_strdup(optarg);
635 break;
636 case 'm':
637 mc.major = atoi(optarg);
638 break;
639 case 'n':
640 /* prevent driver loading and deferred attach */
641 load_attach_drv = FALSE;
642 break;
643 case 'p':
644 /* specify alternate path_to_inst file */
645 inst_file = s_strdup(optarg);
646 break;
647 case 'R':
648 /*
649 * Private flag for suninstall to populate
650 * device information on the installed root.
651 */
652 root_dir = s_strdup(optarg);
653 if (zone_pathcheck(root_dir) !=
654 DEVFSADM_SUCCESS)
655 devfsadm_exit(devfsadm_copy());
656 break;
657 case 'r':
658 devices_dir = s_strdup(optarg);
659 if (zone_pathcheck(devices_dir) !=
660 DEVFSADM_SUCCESS)
661 devfsadm_exit(1);
662 break;
663 case 's':
664 /*
665 * suppress. don't create nodes
666 * useful with -v or -V
667 */
668 file_mods = FALSE;
669 flush_path_to_inst_enable = FALSE;
670 break;
671 case 'v':
672 /* documented verbose flag */
673 add_verbose_id(VERBOSE_MID);
674 break;
675 case 'V':
676 /* undocumented for extra verbose levels */
677 add_verbose_id(optarg);
678 break;
679 default:
680 usage();
681 }
682 }
683
684 if (optind < argc) {
685 usage();
686 }
687
688 if ((add_bind == TRUE) && (mc.major == -1 ||
689 mc.drvname[0] == NULL)) {
690 err_print(MAJOR_AND_B_FLAG);
691 devfsadm_exit(1);
692 }
693 if (add_bind == TRUE) {
694 mc.num_aliases = num_aliases;
695 mc.ap = a_head;
696 retval = modctl(MODADDMAJBIND, NULL, (caddr_t)&mc);
697 if (retval < 0) {
698 err_print(MODCTL_ADDMAJBIND);
699 }
700 devfsadm_exit(retval);
701 }
702
703 } else if ((strcmp(prog, DEVFSADM) == 0) ||
704 (strcmp(prog, DEVFSADMD) == 0)) {
705 char *zonename = NULL;
706 int init_drvconf = 0;
707 int init_perm = 0;
708 int public_mode = 0;
709 int init_sysavail = 0;
710
711 if (strcmp(prog, DEVFSADMD) == 0) {
712 daemon_mode = TRUE;
713 }
714
715 devlinktab_file = DEVLINKTAB_FILE;
716
717 while ((opt = getopt(argc, argv,
718 "a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) {
719 if (opt == 'I' || opt == 'P' || opt == 'S') {
720 if (public_mode)
721 usage();
722 } else {
723 if (init_perm || init_drvconf || init_sysavail)
724 usage();
725 public_mode = 1;
726 }
727 switch (opt) {
728 case 'a':
729 attr_root = s_strdup(optarg);
730 break;
731 case 'C':
732 cleanup = TRUE;
733 break;
734 case 'c':
735 num_classes++;
736 classes = s_realloc(classes,
737 num_classes * sizeof (char *));
738 classes[num_classes - 1] = optarg;
739 break;
740 case 'd':
741 if (daemon_mode == FALSE) {
742 /*
743 * Device allocation to be disabled.
744 */
745 devalloc_flag = DA_OFF;
746 build_dev = FALSE;
747 }
748 break;
749 case 'e':
750 if (daemon_mode == FALSE) {
751 /*
752 * Device allocation to be enabled.
753 */
754 devalloc_flag = DA_ON;
755 build_dev = FALSE;
756 }
757 break;
758 case 'I': /* update kernel driver.conf cache */
759 if (daemon_mode == TRUE)
760 usage();
761 init_drvconf = 1;
762 break;
763 case 'i':
764 single_drv = TRUE;
765 driver = s_strdup(optarg);
766 break;
767 case 'l':
768 /* specify an alternate module load path */
769 module_dirs = s_strdup(optarg);
770 break;
771 case 'm':
772 load_devname_nsmaps = TRUE;
773 break;
774 case 'n':
775 /* prevent driver loading and deferred attach */
776 load_attach_drv = FALSE;
777 break;
778 case 'p':
779 /* specify alternate path_to_inst file */
780 inst_file = s_strdup(optarg);
781 break;
782 case 'P':
783 if (daemon_mode == TRUE)
784 usage();
785 /* load minor_perm and device_policy */
786 init_perm = 1;
787 break;
788 case 'R':
789 /*
790 * Private flag for suninstall to populate
791 * device information on the installed root.
792 */
793 root_dir = s_strdup(optarg);
794 devfsadm_exit(devfsadm_copy());
795 break;
796 case 'r':
797 set_root_devices_dev_dir(optarg);
798 break;
799 case 's':
800 /*
801 * suppress. don't create/remove links/nodes
802 * useful with -v or -V
803 */
804 file_mods = FALSE;
805 flush_path_to_inst_enable = FALSE;
806 break;
807 case 'S':
808 if (daemon_mode == TRUE)
809 usage();
810 init_sysavail = 1;
811 break;
812 case 't':
813 devlinktab_file = optarg;
814 break;
815 case 'v':
816 /* documented verbose flag */
817 add_verbose_id(VERBOSE_MID);
818 break;
819 case 'V':
820 /* undocumented: specify verbose lvl */
821 add_verbose_id(optarg);
822 break;
823 case 'x':
824 /*
825 * x is the "private switch" option. The
826 * goal is to not suck up all the other
827 * option letters.
828 */
829 if (strcmp(optarg, "update_devlinksdb") == 0) {
830 update_database = TRUE;
831 } else if (strcmp(optarg, "no_dev") == 0) {
832 /* don't build /dev */
833 build_dev = FALSE;
834 } else if (strcmp(optarg, "no_devices") == 0) {
835 /* don't build /devices */
836 build_devices = FALSE;
837 } else if (strcmp(optarg, "no_p2i") == 0) {
838 /* don't flush path_to_inst */
839 flush_path_to_inst_enable = FALSE;
840 } else if (strcmp(optarg, "use_dicache") == 0) {
841 use_snapshot_cache = TRUE;
842 } else {
843 usage();
844 }
845 break;
846 default:
847 usage();
848 break;
849 }
850 }
851 if (optind < argc) {
852 usage();
853 }
854
855 /*
856 * We're not in zone mode; Check to see if the rootpath
857 * collides with any zonepaths.
858 */
859 if (zonename == NULL) {
860 if (zone_pathcheck(root_dir) != DEVFSADM_SUCCESS)
861 devfsadm_exit(1);
862 }
863
864 if (init_drvconf || init_perm || init_sysavail) {
865 /*
866 * Load minor perm before force-loading drivers
867 * so the correct permissions are picked up.
868 */
869 if (init_perm) {
870 check_reconfig_state();
871 load_dev_acl();
872 }
873 if (init_drvconf)
874 update_drvconf((major_t)-1);
875 if (init_sysavail)
876 modctl_sysavail();
877 devfsadm_exit(0);
878 /* NOTREACHED */
879 }
880
881 if (load_devname_nsmaps == TRUE) {
882 devname_setup_nsmaps();
883 devfsadm_exit(0);
884 }
885 }
886
887
888 if (get_linkcompat_opts == TRUE) {
889
890 build_devices = FALSE;
891 load_attach_drv = FALSE;
892 num_classes++;
893 classes = s_realloc(classes, num_classes *
894 sizeof (char *));
895 classes[num_classes - 1] = compat_class;
896
897 while ((opt = getopt(argc, argv, "Cnr:svV:")) != EOF) {
898 switch (opt) {
899 case 'C':
900 cleanup = TRUE;
901 break;
902 case 'n':
903 /* prevent driver loading or deferred attach */
904 load_attach_drv = FALSE;
905 break;
906 case 'r':
907 set_root_devices_dev_dir(optarg);
908 if (zone_pathcheck(root_dir) !=
909 DEVFSADM_SUCCESS)
910 devfsadm_exit(1);
911 break;
912 case 's':
913 /* suppress. don't create/remove links/nodes */
914 /* useful with -v or -V */
915 file_mods = FALSE;
916 flush_path_to_inst_enable = FALSE;
917 break;
918 case 'v':
919 /* documented verbose flag */
920 add_verbose_id(VERBOSE_MID);
921 break;
922 case 'V':
923 /* undocumented for extra verbose levels */
924 add_verbose_id(optarg);
925 break;
926 default:
927 usage();
928 }
929 }
930 if (optind < argc) {
931 usage();
932 }
933 }
934 set_lock_root();
935 }
936
937 void
938 usage(void)
939 {
940 if (strcmp(prog, DEVLINKS) == 0) {
941 err_print(DEVLINKS_USAGE);
942 } else if (strcmp(prog, DRVCONFIG) == 0) {
943 err_print(DRVCONFIG_USAGE);
944 } else if ((strcmp(prog, DEVFSADM) == 0) ||
945 (strcmp(prog, DEVFSADMD) == 0)) {
946 err_print(DEVFSADM_USAGE);
947 } else {
948 err_print(COMPAT_LINK_USAGE);
949 }
950
951 devfsadm_exit(1);
952 }
953
954 static void
955 devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass)
956 {
957 char *msg, *name;
958 struct mlist mlist = {0};
959 di_node_t node;
960
961 vprint(CHATTY_MID, "devi_tree_walk: root=%s, minor=%s, driver=%s,"
962 " error=%d, flags=%u\n", dcip->dci_root,
963 dcip->dci_minor ? dcip->dci_minor : "<NULL>",
964 dcip->dci_driver ? dcip->dci_driver : "<NULL>", dcip->dci_error,
965 dcip->dci_flags);
966
967 assert(dcip->dci_root);
968
969 if (dcip->dci_flags & DCA_LOAD_DRV) {
970 node = di_init_driver(dcip->dci_driver, flags);
971 msg = DRIVER_FAILURE;
972 name = dcip->dci_driver;
973 } else {
974 node = di_init(dcip->dci_root, flags);
975 msg = DI_INIT_FAILED;
976 name = dcip->dci_root;
977 }
978
979 if (node == DI_NODE_NIL) {
980 dcip->dci_error = errno;
981 /*
982 * Rapid hotplugging (commonly seen during USB testing),
983 * may remove a device before the create event for it
984 * has been processed. To prevent alarming users with
985 * a superfluous message, we suppress error messages
986 * for ENXIO and hotplug.
987 */
988 if (!(errno == ENXIO && (dcip->dci_flags & DCA_HOT_PLUG)))
989 err_print(msg, name, strerror(dcip->dci_error));
990 return;
991 }
992
993 if (dcip->dci_flags & DCA_FLUSH_PATHINST)
994 flush_path_to_inst();
995
996 dcip->dci_arg = &mlist;
997
998 vprint(CHATTY_MID, "walking device tree\n");
999
1000 (void) di_walk_minor(node, NULL, DI_CHECK_ALIAS, dcip,
1001 check_minor_type);
1002
1003 process_deferred_links(dcip, DCA_CREATE_LINK);
1004
1005 dcip->dci_arg = NULL;
1006
1007 /*
1008 * Finished creating devfs files and dev links.
1009 * Log sysevent and notify RCM.
1010 */
1011 if (ev_subclass)
1012 build_and_enq_event(EC_DEV_ADD, ev_subclass, dcip->dci_root,
1013 node, dcip->dci_minor);
1014
1015 if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl)
1016 (void) notify_rcm(node, dcip->dci_minor);
1017
1018 /* Add new device to device allocation database */
1019 if (system_labeled && update_devdb) {
1020 _update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir);
1021 update_devdb = 0;
1022 }
1023
1024 di_fini(node);
1025 }
1026
1027 static void
1028 process_deferred_links(struct dca_impl *dcip, int flags)
1029 {
1030 struct mlist *dep;
1031 struct minor *mp, *smp;
1032
1033 vprint(CHATTY_MID, "processing deferred links\n");
1034
1035 dep = dcip->dci_arg;
1036
1037 /*
1038 * The list head is not used during the deferred create phase
1039 */
1040 dcip->dci_arg = NULL;
1041
1042 assert(dep);
1043 assert((dep->head == NULL) ^ (dep->tail != NULL));
1044 assert(flags == DCA_FREE_LIST || flags == DCA_CREATE_LINK);
1045
1046 for (smp = NULL, mp = dep->head; mp; mp = mp->next) {
1047 if (flags == DCA_CREATE_LINK)
1048 (void) check_minor_type(mp->node, mp->minor, dcip);
1049 free(smp);
1050 smp = mp;
1051 }
1052
1053 free(smp);
1054 }
1055
1056 /*
1057 * Called in non-daemon mode to take a snap shot of the devinfo tree.
1058 * Then it calls the appropriate functions to build /devices and /dev.
1059 * It also flushes path_to_inst.
1060 * Except in the devfsadm -i (single driver case), the flags used by devfsadm
1061 * needs to match DI_CACHE_SNAPSHOT_FLAGS. That will make DINFOCACHE snapshot
1062 * updated.
1063 */
1064 void
1065 process_devinfo_tree()
1066 {
1067 uint_t flags;
1068 struct dca_impl dci;
1069 char name[MAXNAMELEN];
1070 char *fcn = "process_devinfo_tree: ";
1071
1072 vprint(CHATTY_MID, "%senter\n", fcn);
1073
1074 dca_impl_init("/", NULL, &dci);
1075
1076 lock_dev();
1077
1078 /*
1079 * Update kernel driver.conf cache when devfsadm/drvconfig
1080 * is invoked to build /devices and /dev.
1081 */
1082 if (load_attach_drv == TRUE)
1083 update_drvconf((major_t)-1);
1084
1085 if (single_drv == TRUE) {
1086 /*
1087 * load a single driver, but walk the entire devinfo tree
1088 */
1089 if (load_attach_drv == FALSE)
1090 err_print(DRV_LOAD_REQD);
1091
1092 vprint(CHATTY_MID, "%sattaching driver (%s)\n", fcn, driver);
1093
1094 dci.dci_flags |= DCA_LOAD_DRV;
1095 (void) snprintf(name, sizeof (name), "%s", driver);
1096 dci.dci_driver = name;
1097 flags = DINFOCPYALL | DINFOPATH;
1098
1099 } else if (load_attach_drv == TRUE) {
1100 /*
1101 * Load and attach all drivers, then walk the entire tree.
1102 * If the cache flag is set, use DINFOCACHE to get cached
1103 * data.
1104 */
1105 if (use_snapshot_cache == TRUE) {
1106 flags = DINFOCACHE;
1107 vprint(CHATTY_MID, "%susing snapshot cache\n", fcn);
1108 } else {
1109 vprint(CHATTY_MID, "%sattaching all drivers\n", fcn);
1110 flags = DI_CACHE_SNAPSHOT_FLAGS;
1111 if (cleanup) {
1112 /*
1113 * remove dangling entries from /etc/devices
1114 * files.
1115 */
1116 flags |= DINFOCLEANUP;
1117 }
1118 }
1119 } else {
1120 /*
1121 * For devlinks, disks, ports, tapes and devfsadm -n,
1122 * just need to take a snapshot with active devices.
1123 */
1124 vprint(CHATTY_MID, "%staking snapshot of active devices\n",
1125 fcn);
1126 flags = DINFOCPYALL;
1127 }
1128
1129 if (((load_attach_drv == TRUE) || (single_drv == TRUE)) &&
1130 (build_devices == TRUE)) {
1131 dci.dci_flags |= DCA_FLUSH_PATHINST;
1132 }
1133
1134 /* handle pre-cleanup operations desired by the modules. */
1135 pre_and_post_cleanup(RM_PRE);
1136
1137 devi_tree_walk(&dci, flags, NULL);
1138
1139 if (dci.dci_error) {
1140 devfsadm_exit(1);
1141 }
1142
1143 /* handle post-cleanup operations desired by the modules. */
1144 pre_and_post_cleanup(RM_POST);
1145
1146 unlock_dev(SYNC_STATE);
1147 }
1148
1149 /*ARGSUSED*/
1150 static void
1151 print_cache_signal(int signo)
1152 {
1153 if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) {
1154 err_print("signal SIGUSR1 failed: %s\n", strerror(errno));
1155 devfsadm_exit(1);
1156 }
1157 }
1158
1159 static void
1160 revoke_lookup_door(void)
1161 {
1162 if (lookup_door_fd != -1) {
1163 if (door_revoke(lookup_door_fd) == -1) {
1164 err_print("door_revoke of %s failed - %s\n",
1165 lookup_door_path, strerror(errno));
1166 }
1167 }
1168 }
1169
1170 /*ARGSUSED*/
1171 static void
1172 catch_exit(int signo)
1173 {
1174 revoke_lookup_door();
1175 }
1176
1177 /*
1178 * Register with eventd for messages. Create doors for synchronous
1179 * link creation.
1180 */
1181 static void
1182 daemon_update(void)
1183 {
1184 int fd;
1185 char *fcn = "daemon_update: ";
1186 char door_file[MAXPATHLEN];
1187 const char *subclass_list;
1188 sysevent_handle_t *sysevent_hp;
1189 vprint(CHATTY_MID, "%senter\n", fcn);
1190
1191 if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) {
1192 err_print("signal SIGUSR1 failed: %s\n", strerror(errno));
1193 devfsadm_exit(1);
1194 }
1195 if (signal(SIGTERM, catch_exit) == SIG_ERR) {
1196 err_print("signal SIGTERM failed: %s\n", strerror(errno));
1197 devfsadm_exit(1);
1198 }
1199
1200 if (snprintf(door_file, sizeof (door_file),
1201 "%s%s", attr_root ? attr_root : root_dir, DEVFSADM_SERVICE_DOOR)
1202 >= sizeof (door_file)) {
1203 err_print("update_daemon failed to open sysevent service "
1204 "door\n");
1205 devfsadm_exit(1);
1206 }
1207 if ((sysevent_hp = sysevent_open_channel_alt(
1208 door_file)) == NULL) {
1209 err_print(CANT_CREATE_DOOR,
1210 door_file, strerror(errno));
1211 devfsadm_exit(1);
1212 }
1213 if (sysevent_bind_subscriber(sysevent_hp, event_handler) != 0) {
1214 err_print(CANT_CREATE_DOOR,
1215 door_file, strerror(errno));
1216 (void) sysevent_close_channel(sysevent_hp);
1217 devfsadm_exit(1);
1218 }
1219 subclass_list = EC_SUB_ALL;
1220 if (sysevent_register_event(sysevent_hp, EC_ALL, &subclass_list, 1)
1221 != 0) {
1222 err_print(CANT_CREATE_DOOR,
1223 door_file, strerror(errno));
1224 (void) sysevent_unbind_subscriber(sysevent_hp);
1225 (void) sysevent_close_channel(sysevent_hp);
1226 devfsadm_exit(1);
1227 }
1228 if (snprintf(door_file, sizeof (door_file), "%s/%s",
1229 etc_dev_dir, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) {
1230 err_print(CANT_CREATE_DOOR, DEVFSADM_SYNCH_DOOR,
1231 strerror(ENAMETOOLONG));
1232 devfsadm_exit(1);
1233 }
1234
1235 (void) s_unlink(door_file);
1236 if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) {
1237 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1238 devfsadm_exit(1);
1239 }
1240 (void) close(fd);
1241
1242 if ((fd = door_create(sync_handler, NULL,
1243 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1244 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1245 (void) s_unlink(door_file);
1246 devfsadm_exit(1);
1247 }
1248
1249 if (fattach(fd, door_file) == -1) {
1250 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1251 (void) s_unlink(door_file);
1252 devfsadm_exit(1);
1253 }
1254
1255 /*
1256 * devname_lookup_door
1257 */
1258 if (snprintf(door_file, sizeof (door_file), "%s/%s",
1259 etc_dev_dir, DEVNAME_LOOKUP_DOOR) >= sizeof (door_file)) {
1260 err_print(CANT_CREATE_DOOR, DEVNAME_LOOKUP_DOOR,
1261 strerror(ENAMETOOLONG));
1262 devfsadm_exit(1);
1263 }
1264
1265 (void) s_unlink(door_file);
1266 if ((fd = open(door_file, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR)) == -1) {
1267 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1268 devfsadm_exit(1);
1269 }
1270 (void) close(fd);
1271
1272 if ((fd = door_create(devname_lookup_handler, NULL,
1273 DOOR_REFUSE_DESC)) == -1) {
1274 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1275 (void) s_unlink(door_file);
1276 devfsadm_exit(1);
1277 }
1278
1279 (void) fdetach(door_file);
1280 lookup_door_path = s_strdup(door_file);
1281 retry:
1282 if (fattach(fd, door_file) == -1) {
1283 if (errno == EBUSY)
1284 goto retry;
1285 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1286 (void) s_unlink(door_file);
1287 devfsadm_exit(1);
1288 }
1289 lookup_door_fd = fd;
1290
1291 /* pass down the door name to kernel for door_ki_open */
1292 if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0)
1293 err_print(DEVNAME_CONTACT_FAILED, strerror(errno));
1294 else
1295 devname_setup_nsmaps();
1296
1297 vprint(CHATTY_MID, "%spausing\n", fcn);
1298 for (;;) {
1299 (void) pause();
1300 }
1301 }
1302
1303 /*ARGSUSED*/
1304 static void
1305 sync_handler(void *cookie, char *ap, size_t asize,
1306 door_desc_t *dp, uint_t ndesc)
1307 {
1308 door_cred_t dcred;
1309 struct dca_off *dcp, rdca;
1310 struct dca_impl dci;
1311
1312 /*
1313 * Must be root to make this call
1314 * If caller is not root, don't touch its data.
1315 */
1316 if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) {
1317 dcp = ⤷
1318 dcp->dca_error = EPERM;
1319 goto out;
1320 }
1321
1322 assert(ap);
1323 assert(asize == sizeof (*dcp));
1324
1325 dcp = (void *)ap;
1326
1327 /*
1328 * Root is always present and is the first component of "name" member
1329 */
1330 assert(dcp->dca_root == 0);
1331
1332 /*
1333 * The structure passed in by the door_client uses offsets
1334 * instead of pointers to work across address space boundaries.
1335 * Now copy the data into a structure (dca_impl) which uses
1336 * pointers.
1337 */
1338 dci.dci_root = &dcp->dca_name[dcp->dca_root];
1339 dci.dci_minor = dcp->dca_minor ? &dcp->dca_name[dcp->dca_minor] : NULL;
1340 dci.dci_driver =
1341 dcp->dca_driver ? &dcp->dca_name[dcp->dca_driver] : NULL;
1342 dci.dci_error = 0;
1343 dci.dci_flags = dcp->dca_flags | (dci.dci_driver ? DCA_LOAD_DRV : 0);
1344 dci.dci_arg = NULL;
1345
1346 lock_dev();
1347 devi_tree_walk(&dci, DINFOCPYALL, NULL);
1348 dcp->dca_error = dci.dci_error;
1349
1350 if (dcp->dca_flags & DCA_DEVLINK_SYNC)
1351 unlock_dev(SYNC_STATE);
1352 else
1353 unlock_dev(CACHE_STATE);
1354
1355 out: (void) door_return((char *)dcp, sizeof (*dcp), NULL, 0);
1356 }
1357
1358 static void
1359 lock_dev(void)
1360 {
1361 vprint(CHATTY_MID, "lock_dev(): entered\n");
1362
1363 if (build_dev == FALSE)
1364 return;
1365
1366 /* lockout other threads from /dev */
1367 while (sema_wait(&dev_sema) != 0)
1368 ;
1369
1370 /*
1371 * Lock out other devfsadm processes from /dev.
1372 * If this wasn't the last process to run,
1373 * clear caches
1374 */
1375 if (enter_dev_lock() != getpid()) {
1376 invalidate_enumerate_cache();
1377 rm_all_links_from_cache();
1378 (void) di_devlink_close(&devlink_cache, DI_LINK_ERROR);
1379
1380 /* send any sysevents that were queued up. */
1381 process_syseventq();
1382 }
1383
1384 /*
1385 * (re)load the reverse links database if not
1386 * already cached.
1387 */
1388 if (devlink_cache == NULL)
1389 devlink_cache = di_devlink_open(root_dir, 0);
1390
1391 /*
1392 * If modules were unloaded, reload them. Also use module status
1393 * as an indication that we should check to see if other binding
1394 * files need to be reloaded.
1395 */
1396 if (module_head == NULL) {
1397 load_modules();
1398 read_minor_perm_file();
1399 read_driver_aliases_file();
1400 read_devlinktab_file();
1401 read_logindevperm_file();
1402 read_enumerate_file();
1403 }
1404
1405 if (module_head != NULL)
1406 return;
1407
1408 if (strcmp(prog, DEVLINKS) == 0) {
1409 if (devlinktab_list == NULL) {
1410 err_print(NO_LINKTAB, devlinktab_file);
1411 err_print(NO_MODULES, module_dirs);
1412 err_print(ABORTING);
1413 devfsadm_exit(1);
1414 }
1415 } else {
1416 err_print(NO_MODULES, module_dirs);
1417 if (strcmp(prog, DEVFSADM) == 0) {
1418 err_print(MODIFY_PATH);
1419 }
1420 }
1421 }
1422
1423 /*
1424 * Unlock the device. If we are processing a CACHE_STATE call, we signal a
1425 * minor_fini_thread delayed SYNC_STATE at the end of the call. If we are
1426 * processing a SYNC_STATE call, we cancel any minor_fini_thread SYNC_STATE
1427 * at both the start and end of the call since we will be doing the SYNC_STATE.
1428 */
1429 static void
1430 unlock_dev(int flag)
1431 {
1432 assert(flag == SYNC_STATE || flag == CACHE_STATE);
1433
1434 vprint(CHATTY_MID, "unlock_dev(): entered\n");
1435
1436 /* If we are starting a SYNC_STATE, cancel minor_fini_thread SYNC */
1437 if (flag == SYNC_STATE) {
1438 (void) mutex_lock(&minor_fini_mutex);
1439 minor_fini_canceled = TRUE;
1440 minor_fini_delayed = FALSE;
1441 (void) mutex_unlock(&minor_fini_mutex);
1442 }
1443
1444 if (build_dev == FALSE)
1445 return;
1446
1447 if (devlink_cache == NULL) {
1448 err_print(NO_DEVLINK_CACHE);
1449 }
1450 assert(devlink_cache);
1451
1452 if (flag == SYNC_STATE) {
1453 unload_modules();
1454 if (update_database)
1455 (void) di_devlink_update(devlink_cache);
1456 (void) di_devlink_close(&devlink_cache, 0);
1457
1458 /*
1459 * now that the devlinks db cache has been flushed, it is safe
1460 * to send any sysevents that were queued up.
1461 */
1462 process_syseventq();
1463 }
1464
1465 exit_dev_lock();
1466
1467 (void) mutex_lock(&minor_fini_mutex);
1468 if (flag == SYNC_STATE) {
1469 /* We did a SYNC_STATE, cancel minor_fini_thread SYNC */
1470 minor_fini_canceled = TRUE;
1471 minor_fini_delayed = FALSE;
1472 } else {
1473 /* We did a CACHE_STATE, start delayed minor_fini_thread SYNC */
1474 minor_fini_canceled = FALSE;
1475 minor_fini_delayed = TRUE;
1476 (void) cond_signal(&minor_fini_cv);
1477 }
1478 (void) mutex_unlock(&minor_fini_mutex);
1479
1480 (void) sema_post(&dev_sema);
1481 }
1482
1483 /*
1484 * Check that if -r is set, it is not any part of a zone--- that is, that
1485 * the zonepath is not a substring of the root path.
1486 */
1487 static int
1488 zone_pathcheck(char *checkpath)
1489 {
1490 void *dlhdl = NULL;
1491 char *name;
1492 char root[MAXPATHLEN]; /* resolved devfsadm root path */
1493 char zroot[MAXPATHLEN]; /* zone root path */
1494 char rzroot[MAXPATHLEN]; /* resolved zone root path */
1495 char tmp[MAXPATHLEN];
1496 FILE *cookie;
1497 int err = DEVFSADM_SUCCESS;
1498
1499 if (checkpath[0] == '\0')
1500 return (DEVFSADM_SUCCESS);
1501
1502 /*
1503 * Check if zones is available on this system.
1504 */
1505 if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) {
1506 return (DEVFSADM_SUCCESS);
1507 }
1508
1509 bzero(root, sizeof (root));
1510 if (resolvepath(checkpath, root, sizeof (root) - 1) == -1) {
1511 /*
1512 * In this case the user has done "devfsadm -r" on some path
1513 * which does not yet exist, or we got some other misc. error.
1514 * We punt and don't resolve the path in this case.
1515 */
1516 (void) strlcpy(root, checkpath, sizeof (root));
1517 }
1518
1519 if (strlen(root) > 0 && (root[strlen(root) - 1] != '/')) {
1520 (void) snprintf(tmp, sizeof (tmp), "%s/", root);
1521 (void) strlcpy(root, tmp, sizeof (root));
1522 }
1523
1524 cookie = setzoneent();
1525 while ((name = getzoneent(cookie)) != NULL) {
1526 /* Skip the global zone */
1527 if (strcmp(name, GLOBAL_ZONENAME) == 0) {
1528 free(name);
1529 continue;
1530 }
1531
1532 if (zone_get_zonepath(name, zroot, sizeof (zroot)) != Z_OK) {
1533 free(name);
1534 continue;
1535 }
1536
1537 bzero(rzroot, sizeof (rzroot));
1538 if (resolvepath(zroot, rzroot, sizeof (rzroot) - 1) == -1) {
1539 /*
1540 * Zone path doesn't exist, or other misc error,
1541 * so we try using the non-resolved pathname.
1542 */
1543 (void) strlcpy(rzroot, zroot, sizeof (rzroot));
1544 }
1545 if (strlen(rzroot) > 0 && (rzroot[strlen(rzroot) - 1] != '/')) {
1546 (void) snprintf(tmp, sizeof (tmp), "%s/", rzroot);
1547 (void) strlcpy(rzroot, tmp, sizeof (rzroot));
1548 }
1549
1550 /*
1551 * Finally, the comparison. If the zone root path is a
1552 * leading substring of the root path, fail.
1553 */
1554 if (strncmp(rzroot, root, strlen(rzroot)) == 0) {
1555 err_print(ZONE_PATHCHECK, root, name);
1556 err = DEVFSADM_FAILURE;
1557 free(name);
1558 break;
1559 }
1560 free(name);
1561 }
1562 endzoneent(cookie);
1563 (void) dlclose(dlhdl);
1564 return (err);
1565 }
1566
1567 /*
1568 * Called by the daemon when it receives an event from the devfsadm SLM
1569 * to syseventd.
1570 *
1571 * The devfsadm SLM uses a private event channel for communication to
1572 * devfsadmd set-up via private libsysevent interfaces. This handler is
1573 * used to bind to the devfsadmd channel for event delivery.
1574 * The devfsadmd SLM insures single calls to this routine as well as
1575 * synchronized event delivery.
1576 *
1577 */
1578 static void
1579 event_handler(sysevent_t *ev)
1580 {
1581 char *path;
1582 char *minor;
1583 char *subclass;
1584 char *dev_ev_subclass;
1585 char *driver_name;
1586 nvlist_t *attr_list = NULL;
1587 int err = 0;
1588 int instance;
1589 int branch_event = 0;
1590
1591 subclass = sysevent_get_subclass_name(ev);
1592 vprint(EVENT_MID, "event_handler: %s id:0X%llx\n",
1593 subclass, sysevent_get_seq(ev));
1594
1595 if (strcmp(subclass, ESC_DEVFS_START) == 0) {
1596 return;
1597 }
1598
1599 /* Check if event is an instance modification */
1600 if (strcmp(subclass, ESC_DEVFS_INSTANCE_MOD) == 0) {
1601 devfs_instance_mod();
1602 return;
1603 }
1604 if (sysevent_get_attr_list(ev, &attr_list) != 0) {
1605 vprint(EVENT_MID, "event_handler: can not get attr list\n");
1606 return;
1607 }
1608
1609 if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0 ||
1610 strcmp(subclass, ESC_DEVFS_DEVI_REMOVE) == 0 ||
1611 strcmp(subclass, ESC_DEVFS_MINOR_CREATE) == 0 ||
1612 strcmp(subclass, ESC_DEVFS_MINOR_REMOVE) == 0) {
1613 if ((err = nvlist_lookup_string(attr_list, DEVFS_PATHNAME,
1614 &path)) != 0)
1615 goto out;
1616
1617 if (nvlist_lookup_string(attr_list, DEVFS_DEVI_CLASS,
1618 &dev_ev_subclass) != 0)
1619 dev_ev_subclass = NULL;
1620
1621 if (nvlist_lookup_string(attr_list, DEVFS_DRIVER_NAME,
1622 &driver_name) != 0)
1623 driver_name = NULL;
1624
1625 if (nvlist_lookup_int32(attr_list, DEVFS_INSTANCE,
1626 &instance) != 0)
1627 instance = -1;
1628
1629 if (nvlist_lookup_int32(attr_list, DEVFS_BRANCH_EVENT,
1630 &branch_event) != 0)
1631 branch_event = 0;
1632
1633 if (nvlist_lookup_string(attr_list, DEVFS_MINOR_NAME,
1634 &minor) != 0)
1635 minor = NULL;
1636
1637 lock_dev();
1638
1639 if (strcmp(ESC_DEVFS_DEVI_ADD, subclass) == 0) {
1640 add_minor_pathname(path, NULL, dev_ev_subclass);
1641 if (branch_event) {
1642 build_and_enq_event(EC_DEV_BRANCH,
1643 ESC_DEV_BRANCH_ADD, path, DI_NODE_NIL,
1644 NULL);
1645 }
1646
1647 } else if (strcmp(ESC_DEVFS_MINOR_CREATE, subclass) == 0) {
1648 add_minor_pathname(path, minor, dev_ev_subclass);
1649
1650 } else if (strcmp(ESC_DEVFS_MINOR_REMOVE, subclass) == 0) {
1651 hot_cleanup(path, minor, dev_ev_subclass, driver_name,
1652 instance);
1653
1654 } else { /* ESC_DEVFS_DEVI_REMOVE */
1655 hot_cleanup(path, NULL, dev_ev_subclass,
1656 driver_name, instance);
1657 if (branch_event) {
1658 build_and_enq_event(EC_DEV_BRANCH,
1659 ESC_DEV_BRANCH_REMOVE, path, DI_NODE_NIL,
1660 NULL);
1661 }
1662 }
1663
1664 unlock_dev(CACHE_STATE);
1665
1666 } else if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0 ||
1667 strcmp(subclass, ESC_DEVFS_BRANCH_REMOVE) == 0) {
1668 if ((err = nvlist_lookup_string(attr_list,
1669 DEVFS_PATHNAME, &path)) != 0)
1670 goto out;
1671
1672 /* just log ESC_DEV_BRANCH... event */
1673 if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0)
1674 dev_ev_subclass = ESC_DEV_BRANCH_ADD;
1675 else
1676 dev_ev_subclass = ESC_DEV_BRANCH_REMOVE;
1677
1678 lock_dev();
1679 build_and_enq_event(EC_DEV_BRANCH, dev_ev_subclass, path,
1680 DI_NODE_NIL, NULL);
1681 unlock_dev(CACHE_STATE);
1682 } else
1683 err_print(UNKNOWN_EVENT, subclass);
1684
1685 out:
1686 if (err)
1687 err_print(EVENT_ATTR_LOOKUP_FAILED, strerror(err));
1688 nvlist_free(attr_list);
1689 }
1690
1691 static void
1692 dca_impl_init(char *root, char *minor, struct dca_impl *dcip)
1693 {
1694 assert(root);
1695
1696 dcip->dci_root = root;
1697 dcip->dci_minor = minor;
1698 dcip->dci_driver = NULL;
1699 dcip->dci_error = 0;
1700 dcip->dci_flags = 0;
1701 dcip->dci_arg = NULL;
1702 }
1703
1704 /*
1705 * Kernel logs a message when a devinfo node is attached. Try to create
1706 * /dev and /devices for each minor node. minorname can be NULL.
1707 */
1708 void
1709 add_minor_pathname(char *node, char *minor, char *ev_subclass)
1710 {
1711 struct dca_impl dci;
1712
1713 vprint(CHATTY_MID, "add_minor_pathname: node_path=%s minor=%s\n",
1714 node, minor ? minor : "NULL");
1715
1716 dca_impl_init(node, minor, &dci);
1717
1718 /*
1719 * Restrict hotplug link creation if daemon
1720 * started with -i option.
1721 */
1722 if (single_drv == TRUE) {
1723 dci.dci_driver = driver;
1724 }
1725
1726 /*
1727 * We are being invoked in response to a hotplug
1728 * event. Also, notify RCM if nodetype indicates
1729 * a network device has been hotplugged.
1730 */
1731 dci.dci_flags = DCA_HOT_PLUG | DCA_CHECK_TYPE;
1732
1733 devi_tree_walk(&dci, DINFOPROP|DINFOMINOR, ev_subclass);
1734 }
1735
1736 static di_node_t
1737 find_clone_node()
1738 {
1739 static di_node_t clone_node = DI_NODE_NIL;
1740
1741 if (clone_node == DI_NODE_NIL)
1742 clone_node = di_init("/pseudo/clone@0", DINFOPROP);
1743 return (clone_node);
1744 }
1745
1746 static int
1747 is_descendent_of(di_node_t node, char *driver)
1748 {
1749 while (node != DI_NODE_NIL) {
1750 char *drv = di_driver_name(node);
1751 if (strcmp(drv, driver) == 0)
1752 return (1);
1753 node = di_parent_node(node);
1754 }
1755 return (0);
1756 }
1757
1758 /*
1759 * Checks the minor type. If it is an alias node, then lookup
1760 * the real node/minor first, then call minor_process() to
1761 * do the real work.
1762 */
1763 static int
1764 check_minor_type(di_node_t node, di_minor_t minor, void *arg)
1765 {
1766 ddi_minor_type minor_type;
1767 di_node_t clone_node;
1768 char *mn;
1769 char *nt;
1770 struct mlist *dep;
1771 struct dca_impl *dcip = arg;
1772
1773 assert(dcip);
1774
1775 dep = dcip->dci_arg;
1776
1777 mn = di_minor_name(minor);
1778
1779 /*
1780 * We match driver here instead of in minor_process
1781 * as we want the actual driver name. This check is
1782 * unnecessary during deferred processing.
1783 */
1784 if (dep &&
1785 ((dcip->dci_driver && !is_descendent_of(node, dcip->dci_driver)) ||
1786 (dcip->dci_minor && strcmp(mn, dcip->dci_minor)))) {
1787 return (DI_WALK_CONTINUE);
1788 }
1789
1790 if ((dcip->dci_flags & DCA_CHECK_TYPE) &&
1791 (nt = di_minor_nodetype(minor)) &&
1792 (strcmp(nt, DDI_NT_NET) == 0)) {
1793 dcip->dci_flags |= DCA_NOTIFY_RCM;
1794 dcip->dci_flags &= ~DCA_CHECK_TYPE;
1795 }
1796
1797 minor_type = di_minor_type(minor);
1798
1799 if (minor_type == DDM_MINOR) {
1800 minor_process(node, minor, dep);
1801
1802 } else if (minor_type == DDM_ALIAS) {
1803 struct mlist *cdep, clone_del = {0};
1804
1805 clone_node = find_clone_node();
1806 if (clone_node == DI_NODE_NIL) {
1807 err_print(DI_INIT_FAILED, "clone", strerror(errno));
1808 return (DI_WALK_CONTINUE);
1809 }
1810
1811 cdep = dep ? &clone_del : NULL;
1812
1813 minor_process(clone_node, minor, cdep);
1814
1815 /*
1816 * cache "alias" minor node and free "clone" minor
1817 */
1818 if (cdep != NULL && cdep->head != NULL) {
1819 assert(cdep->tail != NULL);
1820 cache_deferred_minor(dep, node, minor);
1821 dcip->dci_arg = cdep;
1822 process_deferred_links(dcip, DCA_FREE_LIST);
1823 dcip->dci_arg = dep;
1824 }
1825 }
1826
1827 return (DI_WALK_CONTINUE);
1828 }
1829
1830
1831 /*
1832 * This is the entry point for each minor node, whether walking
1833 * the entire tree via di_walk_minor() or processing a hotplug event
1834 * for a single devinfo node (via hotplug ndi_devi_online()).
1835 */
1836 /*ARGSUSED*/
1837 static void
1838 minor_process(di_node_t node, di_minor_t minor, struct mlist *dep)
1839 {
1840 create_list_t *create;
1841 int defer;
1842
1843 vprint(CHATTY_MID, "minor_process: node=%s, minor=%s\n",
1844 di_node_name(node), di_minor_name(minor));
1845
1846 if (dep != NULL) {
1847
1848 /*
1849 * Reset /devices node to minor_perm perm/ownership
1850 * if we are here to deactivate device allocation
1851 */
1852 if (build_devices == TRUE) {
1853 reset_node_permissions(node, minor);
1854 }
1855
1856 if (build_dev == FALSE) {
1857 return;
1858 }
1859
1860 /*
1861 * This function will create any nodes for /etc/devlink.tab.
1862 * If devlink.tab handles link creation, we don't call any
1863 * devfsadm modules since that could cause duplicate caching
1864 * in the enumerate functions if different re strings are
1865 * passed that are logically identical. I'm still not
1866 * convinced this would cause any harm, but better to be safe.
1867 *
1868 * Deferred processing is available only for devlinks
1869 * created through devfsadm modules.
1870 */
1871 if (process_devlink_compat(minor, node) == TRUE) {
1872 return;
1873 }
1874 } else {
1875 vprint(CHATTY_MID, "minor_process: deferred processing\n");
1876 }
1877
1878 /*
1879 * look for relevant link create rules in the modules, and
1880 * invoke the link create callback function to build a link
1881 * if there is a match.
1882 */
1883 defer = 0;
1884 for (create = create_head; create != NULL; create = create->next) {
1885 if ((minor_matches_rule(node, minor, create) == TRUE) &&
1886 class_ok(create->create->device_class) ==
1887 DEVFSADM_SUCCESS) {
1888 if (call_minor_init(create->modptr) ==
1889 DEVFSADM_FAILURE) {
1890 continue;
1891 }
1892
1893 /*
1894 * If NOT doing the deferred creates (i.e. 1st pass) and
1895 * rule requests deferred processing cache the minor
1896 * data.
1897 *
1898 * If deferred processing (2nd pass), create links
1899 * ONLY if rule requests deferred processing.
1900 */
1901 if (dep && ((create->create->flags & CREATE_MASK) ==
1902 CREATE_DEFER)) {
1903 defer = 1;
1904 continue;
1905 } else if (dep == NULL &&
1906 ((create->create->flags & CREATE_MASK) !=
1907 CREATE_DEFER)) {
1908 continue;
1909 }
1910
1911 if ((*(create->create->callback_fcn))
1912 (minor, node) == DEVFSADM_TERMINATE) {
1913 break;
1914 }
1915 }
1916 }
1917
1918 if (defer)
1919 cache_deferred_minor(dep, node, minor);
1920 }
1921
1922
1923 /*
1924 * Cache node and minor in defer list.
1925 */
1926 static void
1927 cache_deferred_minor(
1928 struct mlist *dep,
1929 di_node_t node,
1930 di_minor_t minor)
1931 {
1932 struct minor *mp;
1933 const char *fcn = "cache_deferred_minor";
1934
1935 vprint(CHATTY_MID, "%s node=%s, minor=%s\n", fcn,
1936 di_node_name(node), di_minor_name(minor));
1937
1938 if (dep == NULL) {
1939 vprint(CHATTY_MID, "%s: cannot cache during "
1940 "deferred processing. Ignoring minor\n", fcn);
1941 return;
1942 }
1943
1944 mp = (struct minor *)s_zalloc(sizeof (struct minor));
1945 mp->node = node;
1946 mp->minor = minor;
1947 mp->next = NULL;
1948
1949 assert(dep->head == NULL || dep->tail != NULL);
1950 if (dep->head == NULL) {
1951 dep->head = mp;
1952 } else {
1953 dep->tail->next = mp;
1954 }
1955 dep->tail = mp;
1956 }
1957
1958 /*
1959 * Check to see if "create" link creation rule matches this node/minor.
1960 * If it does, return TRUE.
1961 */
1962 static int
1963 minor_matches_rule(di_node_t node, di_minor_t minor, create_list_t *create)
1964 {
1965 char *m_nodetype, *m_drvname;
1966
1967 if (create->create->node_type != NULL) {
1968
1969 m_nodetype = di_minor_nodetype(minor);
1970 assert(m_nodetype != NULL);
1971
1972 switch (create->create->flags & TYPE_MASK) {
1973 case TYPE_EXACT:
1974 if (strcmp(create->create->node_type, m_nodetype) !=
1975 0) {
1976 return (FALSE);
1977 }
1978 break;
1979 case TYPE_PARTIAL:
1980 if (strncmp(create->create->node_type, m_nodetype,
1981 strlen(create->create->node_type)) != 0) {
1982 return (FALSE);
1983 }
1984 break;
1985 case TYPE_RE:
1986 if (regexec(&(create->node_type_comp), m_nodetype,
1987 0, NULL, 0) != 0) {
1988 return (FALSE);
1989 }
1990 break;
1991 }
1992 }
1993
1994 if (create->create->drv_name != NULL) {
1995 m_drvname = di_driver_name(node);
1996 switch (create->create->flags & DRV_MASK) {
1997 case DRV_EXACT:
1998 if (strcmp(create->create->drv_name, m_drvname) != 0) {
1999 return (FALSE);
2000 }
2001 break;
2002 case DRV_RE:
2003 if (regexec(&(create->drv_name_comp), m_drvname,
2004 0, NULL, 0) != 0) {
2005 return (FALSE);
2006 }
2007 break;
2008 }
2009 }
2010
2011 return (TRUE);
2012 }
2013
2014 /*
2015 * If no classes were given on the command line, then return DEVFSADM_SUCCESS.
2016 * Otherwise, return DEVFSADM_SUCCESS if the device "class" from the module
2017 * matches one of the device classes given on the command line,
2018 * otherwise, return DEVFSADM_FAILURE.
2019 */
2020 static int
2021 class_ok(char *class)
2022 {
2023 int i;
2024
2025 if (num_classes == 0) {
2026 return (DEVFSADM_SUCCESS);
2027 }
2028
2029 for (i = 0; i < num_classes; i++) {
2030 if (strcmp(class, classes[i]) == 0) {
2031 return (DEVFSADM_SUCCESS);
2032 }
2033 }
2034 return (DEVFSADM_FAILURE);
2035 }
2036
2037 /*
2038 * call minor_fini on active modules, then unload ALL modules
2039 */
2040 static void
2041 unload_modules(void)
2042 {
2043 module_t *module_free;
2044 create_list_t *create_free;
2045 remove_list_t *remove_free;
2046
2047 while (create_head != NULL) {
2048 create_free = create_head;
2049 create_head = create_head->next;
2050
2051 if ((create_free->create->flags & TYPE_RE) == TYPE_RE) {
2052 regfree(&(create_free->node_type_comp));
2053 }
2054 if ((create_free->create->flags & DRV_RE) == DRV_RE) {
2055 regfree(&(create_free->drv_name_comp));
2056 }
2057 free(create_free);
2058 }
2059
2060 while (remove_head != NULL) {
2061 remove_free = remove_head;
2062 remove_head = remove_head->next;
2063 free(remove_free);
2064 }
2065
2066 while (module_head != NULL) {
2067
2068 if ((module_head->minor_fini != NULL) &&
2069 ((module_head->flags & MODULE_ACTIVE) == MODULE_ACTIVE)) {
2070 (void) (*(module_head->minor_fini))();
2071 }
2072
2073 vprint(MODLOAD_MID, "unloading module %s\n", module_head->name);
2074 free(module_head->name);
2075 (void) dlclose(module_head->dlhandle);
2076
2077 module_free = module_head;
2078 module_head = module_head->next;
2079 free(module_free);
2080 }
2081 }
2082
2083 /*
2084 * Load devfsadm logical link processing modules.
2085 */
2086 static void
2087 load_modules(void)
2088 {
2089 DIR *mod_dir;
2090 struct dirent *entp;
2091 char cdir[PATH_MAX + 1];
2092 char *last;
2093 char *mdir = module_dirs;
2094 char *fcn = "load_modules: ";
2095
2096 while (*mdir != '\0') {
2097
2098 while (*mdir == ':') {
2099 mdir++;
2100 }
2101
2102 if (*mdir == '\0') {
2103 continue;
2104 }
2105
2106 last = strchr(mdir, ':');
2107
2108 if (last == NULL) {
2109 last = mdir + strlen(mdir);
2110 }
2111
2112 (void) strncpy(cdir, mdir, last - mdir);
2113 cdir[last - mdir] = '\0';
2114 mdir += strlen(cdir);
2115
2116 if ((mod_dir = opendir(cdir)) == NULL) {
2117 vprint(MODLOAD_MID, "%sopendir(%s): %s\n",
2118 fcn, cdir, strerror(errno));
2119 continue;
2120 }
2121
2122 while ((entp = readdir(mod_dir)) != NULL) {
2123
2124 if ((strcmp(entp->d_name, ".") == 0) ||
2125 (strcmp(entp->d_name, "..") == 0)) {
2126 continue;
2127 }
2128
2129 load_module(entp->d_name, cdir);
2130 }
2131 s_closedir(mod_dir);
2132 }
2133 }
2134
2135 static void
2136 load_module(char *mname, char *cdir)
2137 {
2138 _devfsadm_create_reg_t *create_reg;
2139 _devfsadm_remove_reg_V1_t *remove_reg;
2140 create_list_t *create_list_element;
2141 create_list_t **create_list_next;
2142 remove_list_t *remove_list_element;
2143 remove_list_t **remove_list_next;
2144 char epath[PATH_MAX + 1], *end;
2145 char *fcn = "load_module: ";
2146 char *dlerrstr;
2147 void *dlhandle;
2148 module_t *module;
2149 int flags;
2150 int n;
2151 int i;
2152
2153 /* ignore any file which does not end in '.so' */
2154 if ((end = strstr(mname, MODULE_SUFFIX)) != NULL) {
2155 if (end[strlen(MODULE_SUFFIX)] != '\0') {
2156 return;
2157 }
2158 } else {
2159 return;
2160 }
2161
2162 (void) snprintf(epath, sizeof (epath), "%s/%s", cdir, mname);
2163
2164 if ((dlhandle = dlopen(epath, RTLD_LAZY)) == NULL) {
2165 dlerrstr = dlerror();
2166 err_print(DLOPEN_FAILED, epath,
2167 dlerrstr ? dlerrstr : "unknown error");
2168 return;
2169 }
2170
2171 /* dlsym the _devfsadm_create_reg structure */
2172 if (NULL == (create_reg = (_devfsadm_create_reg_t *)
2173 dlsym(dlhandle, _DEVFSADM_CREATE_REG))) {
2174 vprint(MODLOAD_MID, "dlsym(%s, %s): symbol not found\n", epath,
2175 _DEVFSADM_CREATE_REG);
2176 } else {
2177 vprint(MODLOAD_MID, "%sdlsym(%s, %s) succeeded\n",
2178 fcn, epath, _DEVFSADM_CREATE_REG);
2179 }
2180
2181 /* dlsym the _devfsadm_remove_reg structure */
2182 if (NULL == (remove_reg = (_devfsadm_remove_reg_V1_t *)
2183 dlsym(dlhandle, _DEVFSADM_REMOVE_REG))) {
2184 vprint(MODLOAD_MID, "dlsym(%s,\n\t%s): symbol not found\n",
2185 epath, _DEVFSADM_REMOVE_REG);
2186 } else {
2187 vprint(MODLOAD_MID, "dlsym(%s, %s): succeeded\n",
2188 epath, _DEVFSADM_REMOVE_REG);
2189 }
2190
2191 vprint(MODLOAD_MID, "module %s loaded\n", epath);
2192
2193 module = (module_t *)s_malloc(sizeof (module_t));
2194 module->name = s_strdup(epath);
2195 module->dlhandle = dlhandle;
2196
2197 /* dlsym other module functions, to be called later */
2198 module->minor_fini = (int (*)())dlsym(dlhandle, MINOR_FINI);
2199 module->minor_init = (int (*)())dlsym(dlhandle, MINOR_INIT);
2200 module->flags = 0;
2201
2202 /*
2203 * put a ptr to each struct devfsadm_create on "create_head"
2204 * list sorted in interpose_lvl.
2205 */
2206 if (create_reg != NULL) {
2207 for (i = 0; i < create_reg->count; i++) {
2208 int flags = create_reg->tblp[i].flags;
2209
2210 create_list_element = (create_list_t *)
2211 s_malloc(sizeof (create_list_t));
2212
2213 create_list_element->create = &(create_reg->tblp[i]);
2214 create_list_element->modptr = module;
2215
2216 if (((flags & CREATE_MASK) != 0) &&
2217 ((flags & CREATE_MASK) != CREATE_DEFER)) {
2218 free(create_list_element);
2219 err_print("illegal flag combination in "
2220 "module create\n");
2221 err_print(IGNORING_ENTRY, i, epath);
2222 continue;
2223 }
2224
2225 if (((flags & TYPE_MASK) == 0) ^
2226 (create_reg->tblp[i].node_type == NULL)) {
2227 free(create_list_element);
2228 err_print("flags value incompatible with "
2229 "node_type value in module create\n");
2230 err_print(IGNORING_ENTRY, i, epath);
2231 continue;
2232 }
2233
2234 if (((flags & TYPE_MASK) != 0) &&
2235 ((flags & TYPE_MASK) != TYPE_EXACT) &&
2236 ((flags & TYPE_MASK) != TYPE_RE) &&
2237 ((flags & TYPE_MASK) != TYPE_PARTIAL)) {
2238 free(create_list_element);
2239 err_print("illegal TYPE_* flag combination in "
2240 "module create\n");
2241 err_print(IGNORING_ENTRY, i, epath);
2242 continue;
2243 }
2244
2245 /* precompile regular expression for efficiency */
2246 if ((flags & TYPE_RE) == TYPE_RE) {
2247 if ((n = regcomp(&(create_list_element->
2248 node_type_comp),
2249 create_reg->tblp[i].node_type,
2250 REG_EXTENDED)) != 0) {
2251 free(create_list_element);
2252 err_print(REGCOMP_FAILED,
2253 create_reg->tblp[i].node_type, n);
2254 err_print(IGNORING_ENTRY, i, epath);
2255 continue;
2256 }
2257 }
2258
2259 if (((flags & DRV_MASK) == 0) ^
2260 (create_reg->tblp[i].drv_name == NULL)) {
2261 if ((flags & TYPE_RE) == TYPE_RE) {
2262 regfree(&(create_list_element->
2263 node_type_comp));
2264 }
2265 free(create_list_element);
2266 err_print("flags value incompatible with "
2267 "drv_name value in module create\n");
2268 err_print(IGNORING_ENTRY, i, epath);
2269 continue;
2270 }
2271
2272 if (((flags & DRV_MASK) != 0) &&
2273 ((flags & DRV_MASK) != DRV_EXACT) &&
2274 ((flags & DRV_MASK) != DRV_RE)) {
2275 if ((flags & TYPE_RE) == TYPE_RE) {
2276 regfree(&(create_list_element->
2277 node_type_comp));
2278 }
2279 free(create_list_element);
2280 err_print("illegal DRV_* flag combination in "
2281 "module create\n");
2282 err_print(IGNORING_ENTRY, i, epath);
2283 continue;
2284 }
2285
2286 /* precompile regular expression for efficiency */
2287 if ((create_reg->tblp[i].flags & DRV_RE) == DRV_RE) {
2288 if ((n = regcomp(&(create_list_element->
2289 drv_name_comp),
2290 create_reg->tblp[i].drv_name,
2291 REG_EXTENDED)) != 0) {
2292 if ((flags & TYPE_RE) == TYPE_RE) {
2293 regfree(&(create_list_element->
2294 node_type_comp));
2295 }
2296 free(create_list_element);
2297 err_print(REGCOMP_FAILED,
2298 create_reg->tblp[i].drv_name, n);
2299 err_print(IGNORING_ENTRY, i, epath);
2300 continue;
2301 }
2302 }
2303
2304
2305 /* add to list sorted by interpose level */
2306 for (create_list_next = &(create_head);
2307 (*create_list_next != NULL) &&
2308 (*create_list_next)->create->interpose_lvl >=
2309 create_list_element->create->interpose_lvl;
2310 create_list_next = &((*create_list_next)->next))
2311 ;
2312 create_list_element->next = *create_list_next;
2313 *create_list_next = create_list_element;
2314 }
2315 }
2316
2317 /*
2318 * put a ptr to each struct devfsadm_remove on "remove_head"
2319 * list sorted by interpose_lvl.
2320 */
2321 flags = 0;
2322 if (remove_reg != NULL) {
2323 if (remove_reg->version < DEVFSADM_V1)
2324 flags |= RM_NOINTERPOSE;
2325 for (i = 0; i < remove_reg->count; i++) {
2326
2327 remove_list_element = (remove_list_t *)
2328 s_malloc(sizeof (remove_list_t));
2329
2330 remove_list_element->remove = &(remove_reg->tblp[i]);
2331 remove_list_element->remove->flags |= flags;
2332 remove_list_element->modptr = module;
2333
2334 for (remove_list_next = &(remove_head);
2335 (*remove_list_next != NULL) &&
2336 (*remove_list_next)->remove->interpose_lvl >=
2337 remove_list_element->remove->interpose_lvl;
2338 remove_list_next = &((*remove_list_next)->next))
2339 ;
2340 remove_list_element->next = *remove_list_next;
2341 *remove_list_next = remove_list_element;
2342 }
2343 }
2344
2345 module->next = module_head;
2346 module_head = module;
2347 }
2348
2349 /*
2350 * After we have completed a CACHE_STATE, if a SYNC_STATE does not occur
2351 * within 'timeout' secs the minor_fini_thread needs to do a SYNC_STATE
2352 * so that we still call the minor_fini routines.
2353 */
2354 /*ARGSUSED*/
2355 static void
2356 minor_fini_thread(void *arg)
2357 {
2358 timestruc_t abstime;
2359
2360 vprint(INITFINI_MID, "minor_fini_thread starting\n");
2361
2362 (void) mutex_lock(&minor_fini_mutex);
2363 for (;;) {
2364 /* wait the gather period, or until signaled */
2365 abstime.tv_sec = time(NULL) + minor_fini_timeout;
2366 abstime.tv_nsec = 0;
2367 (void) cond_timedwait(&minor_fini_cv,
2368 &minor_fini_mutex, &abstime);
2369
2370 /* if minor_fini was canceled, go wait again */
2371 if (minor_fini_canceled == TRUE)
2372 continue;
2373
2374 /* if minor_fini was delayed, go wait again */
2375 if (minor_fini_delayed == TRUE) {
2376 minor_fini_delayed = FALSE;
2377 continue;
2378 }
2379
2380 /* done with cancellations and delays, do the SYNC_STATE */
2381 (void) mutex_unlock(&minor_fini_mutex);
2382
2383 lock_dev();
2384 unlock_dev(SYNC_STATE);
2385 vprint(INITFINI_MID, "minor_fini sync done\n");
2386
2387 (void) mutex_lock(&minor_fini_mutex);
2388 }
2389 }
2390
2391
2392 /*
2393 * Attempt to initialize module, if a minor_init routine exists. Set
2394 * the active flag if the routine exists and succeeds. If it doesn't
2395 * exist, just set the active flag.
2396 */
2397 static int
2398 call_minor_init(module_t *module)
2399 {
2400 char *fcn = "call_minor_init: ";
2401
2402 if ((module->flags & MODULE_ACTIVE) == MODULE_ACTIVE) {
2403 return (DEVFSADM_SUCCESS);
2404 }
2405
2406 vprint(INITFINI_MID, "%smodule %s. current state: inactive\n",
2407 fcn, module->name);
2408
2409 if (module->minor_init == NULL) {
2410 module->flags |= MODULE_ACTIVE;
2411 vprint(INITFINI_MID, "minor_init not defined\n");
2412 return (DEVFSADM_SUCCESS);
2413 }
2414
2415 if ((*(module->minor_init))() == DEVFSADM_FAILURE) {
2416 err_print(FAILED_FOR_MODULE, MINOR_INIT, module->name);
2417 return (DEVFSADM_FAILURE);
2418 }
2419
2420 vprint(INITFINI_MID, "minor_init() returns DEVFSADM_SUCCESS. "
2421 "new state: active\n");
2422
2423 module->flags |= MODULE_ACTIVE;
2424 return (DEVFSADM_SUCCESS);
2425 }
2426
2427 /*
2428 * Creates a symlink 'link' to the physical path of node:minor.
2429 * Construct link contents, then call create_link_common().
2430 */
2431 /*ARGSUSED*/
2432 int
2433 devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags)
2434 {
2435 char rcontents[PATH_MAX];
2436 char devlink[PATH_MAX];
2437 char phy_path[PATH_MAX];
2438 char *acontents;
2439 char *dev_path;
2440 int numslashes;
2441 int rv;
2442 int i, link_exists;
2443 int last_was_slash = FALSE;
2444
2445 /*
2446 * try to use devices path
2447 */
2448 if ((node == lnode) && (minor == lminor)) {
2449 acontents = lphy_path;
2450 } else if (di_minor_type(minor) == DDM_ALIAS) {
2451 /* use /pseudo/clone@0:<driver> as the phys path */
2452 (void) snprintf(phy_path, sizeof (phy_path),
2453 "/pseudo/clone@0:%s",
2454 di_driver_name(di_minor_devinfo(minor)));
2455 acontents = phy_path;
2456 } else {
2457 if ((dev_path = di_devfs_path(node)) == NULL) {
2458 err_print(DI_DEVFS_PATH_FAILED, strerror(errno));
2459 devfsadm_exit(1);
2460 }
2461 (void) snprintf(phy_path, sizeof (phy_path), "%s:%s",
2462 dev_path, di_minor_name(minor));
2463 di_devfs_path_free(dev_path);
2464 acontents = phy_path;
2465 }
2466
2467 /* prepend link with dev_dir contents */
2468 (void) strlcpy(devlink, dev_dir, sizeof (devlink));
2469 (void) strlcat(devlink, "/", sizeof (devlink));
2470 (void) strlcat(devlink, link, sizeof (devlink));
2471
2472 /*
2473 * Calculate # of ../ to add. Account for double '//' in path.
2474 * Ignore all leading slashes.
2475 */
2476 for (i = 0; link[i] == '/'; i++)
2477 ;
2478 for (numslashes = 0; link[i] != '\0'; i++) {
2479 if (link[i] == '/') {
2480 if (last_was_slash == FALSE) {
2481 numslashes++;
2482 last_was_slash = TRUE;
2483 }
2484 } else {
2485 last_was_slash = FALSE;
2486 }
2487 }
2488 /* Don't count any trailing '/' */
2489 if (link[i-1] == '/') {
2490 numslashes--;
2491 }
2492
2493 rcontents[0] = '\0';
2494 do {
2495 (void) strlcat(rcontents, "../", sizeof (rcontents));
2496 } while (numslashes-- != 0);
2497
2498 (void) strlcat(rcontents, "devices", sizeof (rcontents));
2499 (void) strlcat(rcontents, acontents, sizeof (rcontents));
2500
2501 if (devlinks_debug == TRUE) {
2502 vprint(INFO_MID, "adding link %s ==> %s\n", devlink, rcontents);
2503 }
2504
2505 if ((rv = create_link_common(devlink, rcontents, &link_exists))
2506 == DEVFSADM_SUCCESS) {
2507 linknew = TRUE;
2508 add_link_to_cache(link, acontents);
2509 } else {
2510 linknew = FALSE;
2511 }
2512
2513 if (link_exists == TRUE) {
2514 /* Link exists or was just created */
2515 (void) di_devlink_add_link(devlink_cache, link, rcontents,
2516 DI_PRIMARY_LINK);
2517
2518 if (system_labeled && (flags & DA_ADD)) {
2519 /*
2520 * Add this to the list of allocatable devices. If this
2521 * is a hotplugged, removable disk, add it as rmdisk.
2522 */
2523 int instance = di_instance(node);
2524
2525 if ((flags & DA_CD) &&
2526 (_da_check_for_usb(devlink, root_dir) == 1)) {
2527 (void) da_add_list(&devlist, devlink, instance,
2528 DA_ADD|DA_RMDISK);
2529 update_devdb = DA_RMDISK;
2530 } else if (linknew == TRUE) {
2531 (void) da_add_list(&devlist, devlink, instance,
2532 flags);
2533 update_devdb = flags;
2534 }
2535 }
2536 }
2537
2538 return (rv);
2539 }
2540
2541 /*
2542 * Creates a symlink link to primary_link. Calculates relative
2543 * directory offsets, then calls link_common().
2544 */
2545 /*ARGSUSED*/
2546 int
2547 devfsadm_secondary_link(char *link, char *primary_link, int flags)
2548 {
2549 char contents[PATH_MAX + 1];
2550 char devlink[PATH_MAX + 1];
2551 int rv, link_exists;
2552 char *fpath;
2553 char *tpath;
2554 char *op;
2555
2556 /* prepend link with dev_dir contents */
2557 (void) strcpy(devlink, dev_dir);
2558 (void) strcat(devlink, "/");
2559 (void) strcat(devlink, link);
2560 /*
2561 * building extra link, so use first link as link contents, but first
2562 * make it relative.
2563 */
2564 fpath = link;
2565 tpath = primary_link;
2566 op = contents;
2567
2568 while (*fpath == *tpath && *fpath != '\0') {
2569 fpath++, tpath++;
2570 }
2571
2572 /* Count directories to go up, if any, and add "../" */
2573 while (*fpath != '\0') {
2574 if (*fpath == '/') {
2575 (void) strcpy(op, "../");
2576 op += 3;
2577 }
2578 fpath++;
2579 }
2580
2581 /*
2582 * Back up to the start of the current path component, in
2583 * case in the middle
2584 */
2585 while (tpath != primary_link && *(tpath-1) != '/') {
2586 tpath--;
2587 }
2588 (void) strcpy(op, tpath);
2589
2590 if (devlinks_debug == TRUE) {
2591 vprint(INFO_MID, "adding extra link %s ==> %s\n",
2592 devlink, contents);
2593 }
2594
2595 if ((rv = create_link_common(devlink, contents, &link_exists))
2596 == DEVFSADM_SUCCESS) {
2597 /*
2598 * we need to save the ultimate /devices contents, and not the
2599 * secondary link, since hotcleanup only looks at /devices path.
2600 * Since we don't have devices path here, we can try to get it
2601 * by readlink'ing the secondary link. This assumes the primary
2602 * link was created first.
2603 */
2604 add_link_to_cache(link, lphy_path);
2605 linknew = TRUE;
2606 if (system_labeled &&
2607 ((flags & DA_AUDIO) && (flags & DA_ADD))) {
2608 /*
2609 * Add this device to the list of allocatable devices.
2610 */
2611 int instance = 0;
2612
2613 op = strrchr(contents, '/');
2614 op++;
2615 (void) sscanf(op, "%d", &instance);
2616 (void) da_add_list(&devlist, devlink, instance, flags);
2617 update_devdb = flags;
2618 }
2619 } else {
2620 linknew = FALSE;
2621 }
2622
2623 /*
2624 * If link exists or was just created, add it to the database
2625 */
2626 if (link_exists == TRUE) {
2627 (void) di_devlink_add_link(devlink_cache, link, contents,
2628 DI_SECONDARY_LINK);
2629 }
2630
2631 return (rv);
2632 }
2633
2634 /* returns pointer to the devices directory */
2635 char *
2636 devfsadm_get_devices_dir()
2637 {
2638 return (devices_dir);
2639 }
2640
2641 /*
2642 * Does the actual link creation. VERBOSE_MID only used if there is
2643 * a change. CHATTY_MID used otherwise.
2644 */
2645 static int
2646 create_link_common(char *devlink, char *contents, int *exists)
2647 {
2648 int try;
2649 int linksize;
2650 int max_tries = 0;
2651 static int prev_link_existed = TRUE;
2652 char checkcontents[PATH_MAX + 1];
2653 char *hide;
2654
2655 *exists = FALSE;
2656
2657 /* Database is not updated when file_mods == FALSE */
2658 if (file_mods == FALSE) {
2659 linksize = readlink(devlink, checkcontents, PATH_MAX);
2660 if (linksize > 0) {
2661 checkcontents[linksize] = '\0';
2662 if (strcmp(checkcontents, contents) != 0) {
2663 vprint(CHATTY_MID, REMOVING_LINK,
2664 devlink, checkcontents);
2665 return (DEVFSADM_SUCCESS);
2666 } else {
2667 vprint(CHATTY_MID, "link exists and is correct:"
2668 " %s -> %s\n", devlink, contents);
2669 /* failure only in that the link existed */
2670 return (DEVFSADM_FAILURE);
2671 }
2672 } else {
2673 vprint(VERBOSE_MID, CREATING_LINK, devlink, contents);
2674 return (DEVFSADM_SUCCESS);
2675 }
2676 }
2677
2678 /*
2679 * systems calls are expensive, so predict whether to readlink
2680 * or symlink first, based on previous attempt
2681 */
2682 if (prev_link_existed == FALSE) {
2683 try = CREATE_LINK;
2684 } else {
2685 try = READ_LINK;
2686 }
2687
2688 while (++max_tries <= 3) {
2689
2690 switch (try) {
2691 case CREATE_LINK:
2692
2693 if (symlink(contents, devlink) == 0) {
2694 vprint(VERBOSE_MID, CREATING_LINK, devlink,
2695 contents);
2696 prev_link_existed = FALSE;
2697 /* link successfully created */
2698 *exists = TRUE;
2699 set_logindev_perms(devlink);
2700 return (DEVFSADM_SUCCESS);
2701 } else {
2702 switch (errno) {
2703
2704 case ENOENT:
2705 /* dirpath to node doesn't exist */
2706 hide = strrchr(devlink, '/');
2707 *hide = '\0';
2708 s_mkdirp(devlink, S_IRWXU|S_IRGRP|
2709 S_IXGRP|S_IROTH|S_IXOTH);
2710 *hide = '/';
2711 break;
2712 case EEXIST:
2713 try = READ_LINK;
2714 break;
2715 default:
2716 err_print(SYMLINK_FAILED, devlink,
2717 contents, strerror(errno));
2718 return (DEVFSADM_FAILURE);
2719 }
2720 }
2721 break;
2722
2723 case READ_LINK:
2724
2725 linksize = readlink(devlink, checkcontents, PATH_MAX);
2726 if (linksize >= 0) {
2727 checkcontents[linksize] = '\0';
2728 if (strcmp(checkcontents, contents) != 0) {
2729 s_unlink(devlink);
2730 vprint(VERBOSE_MID, REMOVING_LINK,
2731 devlink, checkcontents);
2732 try = CREATE_LINK;
2733 } else {
2734 prev_link_existed = TRUE;
2735 vprint(CHATTY_MID,
2736 "link exists and is correct:"
2737 " %s -> %s\n", devlink, contents);
2738 *exists = TRUE;
2739 /* failure in that the link existed */
2740 return (DEVFSADM_FAILURE);
2741 }
2742 } else {
2743 switch (errno) {
2744 case EINVAL:
2745 /* not a symlink, remove and create */
2746 s_unlink(devlink);
2747 default:
2748 /* maybe it didn't exist at all */
2749 try = CREATE_LINK;
2750 break;
2751 }
2752 }
2753 break;
2754 }
2755 }
2756 err_print(MAX_ATTEMPTS, devlink, contents);
2757 return (DEVFSADM_FAILURE);
2758 }
2759
2760 static void
2761 set_logindev_perms(char *devlink)
2762 {
2763 struct login_dev *newdev;
2764 struct passwd pwd, *resp;
2765 char pwd_buf[PATH_MAX];
2766 int rv;
2767 struct stat sb;
2768 char *devfs_path = NULL;
2769
2770 /*
2771 * We only want logindev perms to be set when a device is
2772 * hotplugged or an application requests synchronous creates.
2773 * So we enable this only in daemon mode. In addition,
2774 * login(1) only fixes the std. /dev dir. So we don't
2775 * change perms if alternate root is set.
2776 * login_dev_enable is TRUE only in these cases.
2777 */
2778 if (login_dev_enable != TRUE)
2779 return;
2780
2781 /*
2782 * Normally, /etc/logindevperm has few (8 - 10 entries) which
2783 * may be regular expressions (globs were converted to RE).
2784 * So just do a linear search through the list.
2785 */
2786 for (newdev = login_dev_cache; newdev; newdev = newdev->ldev_next) {
2787 vprint(FILES_MID, "matching %s with %s\n", devlink,
2788 newdev->ldev_device);
2789
2790 if (regexec(&newdev->ldev_device_regex, devlink, 0,
2791 NULL, 0) == 0) {
2792 vprint(FILES_MID, "matched %s with %s\n", devlink,
2793 newdev->ldev_device);
2794 break;
2795 }
2796 }
2797
2798 if (newdev == NULL)
2799 return;
2800
2801 /*
2802 * we have a match, now find the driver associated with this
2803 * minor node using a snapshot on the physical path
2804 */
2805 (void) resolve_link(devlink, NULL, NULL, &devfs_path, 0);
2806 if (devfs_path) {
2807 di_node_t node;
2808 char *drv = NULL;
2809 struct driver_list *list;
2810 char *p;
2811
2812 /* truncate on : so we can take a snapshot */
2813 (void) strcpy(pwd_buf, devfs_path);
2814 p = strrchr(pwd_buf, ':');
2815 if (p == NULL) {
2816 free(devfs_path);
2817 return;
2818 }
2819 *p = '\0';
2820
2821 vprint(FILES_MID, "link=%s->physpath=%s\n",
2822 devlink, pwd_buf);
2823
2824 node = di_init(pwd_buf, DINFOMINOR);
2825
2826 if (node) {
2827 drv = di_driver_name(node);
2828
2829 if (drv) {
2830 vprint(FILES_MID, "%s: driver is %s\n",
2831 devlink, drv);
2832 }
2833 di_fini(node);
2834 }
2835 /* search thru the driver list specified in logindevperm */
2836 list = newdev->ldev_driver_list;
2837 if ((drv != NULL) && (list != NULL)) {
2838 while (list) {
2839 if (strcmp(list->driver_name,
2840 drv) == 0) {
2841 vprint(FILES_MID,
2842 "driver %s match!\n", drv);
2843 break;
2844 }
2845 list = list->next;
2846 }
2847 if (list == NULL) {
2848 vprint(FILES_MID, "no driver match!\n");
2849 free(devfs_path);
2850 return;
2851 }
2852 }
2853 free(devfs_path);
2854 } else {
2855 return;
2856 }
2857
2858 vprint(FILES_MID, "changing permissions of %s\n", devlink);
2859
2860 /*
2861 * We have a match. We now attempt to determine the
2862 * owner and group of the console user.
2863 *
2864 * stat() the console device newdev->ldev_console
2865 * which will always exist - it will have the right owner but
2866 * not the right group. Use getpwuid_r() to determine group for this
2867 * uid.
2868 * Note, it is safe to use name service here since if name services
2869 * are not available (during boot or in single-user mode), then
2870 * console owner will be root and its gid can be found in
2871 * local files.
2872 */
2873 if (stat(newdev->ldev_console, &sb) == -1) {
2874 vprint(VERBOSE_MID, STAT_FAILED, newdev->ldev_console,
2875 strerror(errno));
2876 return;
2877 }
2878
2879 resp = NULL;
2880 rv = getpwuid_r(sb.st_uid, &pwd, pwd_buf, sizeof (pwd_buf), &resp);
2881 if (rv || resp == NULL) {
2882 rv = rv ? rv : EINVAL;
2883 vprint(VERBOSE_MID, GID_FAILED, sb.st_uid,
2884 strerror(rv));
2885 return;
2886 }
2887
2888 assert(&pwd == resp);
2889
2890 sb.st_gid = resp->pw_gid;
2891
2892 if (chmod(devlink, newdev->ldev_perms) == -1) {
2893 vprint(VERBOSE_MID, CHMOD_FAILED, devlink,
2894 strerror(errno));
2895 return;
2896 }
2897
2898 if (chown(devlink, sb.st_uid, sb.st_gid) == -1) {
2899 vprint(VERBOSE_MID, CHOWN_FAILED, devlink,
2900 strerror(errno));
2901 }
2902 }
2903
2904 /*
2905 * Reset /devices node with appropriate permissions and
2906 * ownership as specified in /etc/minor_perm.
2907 */
2908 static void
2909 reset_node_permissions(di_node_t node, di_minor_t minor)
2910 {
2911 int spectype;
2912 char phy_path[PATH_MAX + 1];
2913 mode_t mode;
2914 dev_t dev;
2915 uid_t uid;
2916 gid_t gid;
2917 struct stat sb;
2918 char *dev_path, *aminor = NULL;
2919
2920 /* lphy_path starts with / */
2921 if ((dev_path = di_devfs_path(node)) == NULL) {
2922 err_print(DI_DEVFS_PATH_FAILED, strerror(errno));
2923 devfsadm_exit(1);
2924 }
2925 (void) strcpy(lphy_path, dev_path);
2926 di_devfs_path_free(dev_path);
2927
2928 (void) strcat(lphy_path, ":");
2929 if (di_minor_type(minor) == DDM_ALIAS) {
2930 char *driver;
2931 aminor = di_minor_name(minor);
2932 driver = di_driver_name(di_minor_devinfo(minor));
2933 (void) strcat(lphy_path, driver);
2934 } else
2935 (void) strcat(lphy_path, di_minor_name(minor));
2936
2937 (void) strcpy(phy_path, devices_dir);
2938 (void) strcat(phy_path, lphy_path);
2939
2940 lnode = node;
2941 lminor = minor;
2942
2943 vprint(CHATTY_MID, "reset_node_permissions: phy_path=%s lphy_path=%s\n",
2944 phy_path, lphy_path);
2945
2946 dev = di_minor_devt(minor);
2947 spectype = di_minor_spectype(minor); /* block or char */
2948
2949 getattr(phy_path, aminor, spectype, dev, &mode, &uid, &gid);
2950
2951 /*
2952 * compare and set permissions and ownership
2953 *
2954 * Under devfs, a quick insertion and removal of USB devices
2955 * would cause stat of physical path to fail. In this case,
2956 * we emit a verbose message, but don't print errors.
2957 */
2958 if ((stat(phy_path, &sb) == -1) || (sb.st_rdev != dev)) {
2959 vprint(VERBOSE_MID, NO_DEVFS_NODE, phy_path);
2960 return;
2961 }
2962
2963 /*
2964 * If we are here for a new device
2965 * If device allocation is on
2966 * then
2967 * set ownership to root:other and permissions to 0000
2968 * else
2969 * set ownership and permissions as specified in minor_perm
2970 * If we are here for an existing device
2971 * If device allocation is to be turned on
2972 * then
2973 * reset ownership to root:other and permissions to 0000
2974 * else if device allocation is to be turned off
2975 * reset ownership and permissions to those specified in
2976 * minor_perm
2977 * else
2978 * preserve existing/user-modified ownership and
2979 * permissions
2980 *
2981 * devfs indicates a new device by faking access time to be zero.
2982 */
2983 if (sb.st_atime != 0) {
2984 int i;
2985 char *nt;
2986
2987 if ((devalloc_flag == 0) && (devalloc_is_on != 1))
2988 /*
2989 * Leave existing devices as they are if we are not
2990 * turning device allocation on/off.
2991 */
2992 return;
2993
2994 nt = di_minor_nodetype(minor);
2995
2996 if (nt == NULL)
2997 return;
2998
2999 for (i = 0; devalloc_list[i]; i++) {
3000 if (strcmp(nt, devalloc_list[i]) == 0)
3001 /*
3002 * One of the types recognized by devalloc,
3003 * reset attrs.
3004 */
3005 break;
3006 }
3007 if (devalloc_list[i] == NULL)
3008 return;
3009 }
3010
3011 if (file_mods == FALSE) {
3012 /* Nothing more to do if simulating */
3013 vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode);
3014 return;
3015 }
3016
3017 if ((devalloc_flag == DA_ON) || (devalloc_is_on == 1)) {
3018 /*
3019 * we are here either to turn device allocation on
3020 * or to add a new device while device allocation in on
3021 */
3022 mode = DEALLOC_MODE;
3023 uid = DA_UID;
3024 gid = DA_GID;
3025 }
3026
3027 if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) ||
3028 (sb.st_mode != mode)) {
3029 if (chmod(phy_path, mode) == -1)
3030 vprint(VERBOSE_MID, CHMOD_FAILED,
3031 phy_path, strerror(errno));
3032 }
3033 if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) ||
3034 (sb.st_uid != uid || sb.st_gid != gid)) {
3035 if (chown(phy_path, uid, gid) == -1)
3036 vprint(VERBOSE_MID, CHOWN_FAILED,
3037 phy_path, strerror(errno));
3038 }
3039
3040 /* Report that we actually did something */
3041 vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode);
3042 }
3043
3044 /*
3045 * Removes logical link and the minor node it refers to. If file is a
3046 * link, we recurse and try to remove the minor node (or link if path is
3047 * a double link) that file's link contents refer to.
3048 */
3049 static void
3050 devfsadm_rm_work(char *file, int recurse, int file_type)
3051 {
3052 char *fcn = "devfsadm_rm_work: ";
3053 int linksize;
3054 char contents[PATH_MAX + 1];
3055 char nextfile[PATH_MAX + 1];
3056 char newfile[PATH_MAX + 1];
3057 char *ptr;
3058
3059 vprint(REMOVE_MID, "%s%s\n", fcn, file);
3060
3061 /* TYPE_LINK split into multiple if's due to excessive indentations */
3062 if (file_type == TYPE_LINK) {
3063 (void) strcpy(newfile, dev_dir);
3064 (void) strcat(newfile, "/");
3065 (void) strcat(newfile, file);
3066 }
3067
3068 if ((file_type == TYPE_LINK) && (recurse == TRUE) &&
3069 ((linksize = readlink(newfile, contents, PATH_MAX)) > 0)) {
3070 contents[linksize] = '\0';
3071
3072 if (is_minor_node(contents, &ptr) == DEVFSADM_TRUE) {
3073 devfsadm_rm_work(++ptr, FALSE, TYPE_DEVICES);
3074 } else {
3075 if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) {
3076 devfsadm_rm_work(&contents[strlen(DEV) + 1],
3077 TRUE, TYPE_LINK);
3078 } else {
3079 if ((ptr = strrchr(file, '/')) != NULL) {
3080 *ptr = '\0';
3081 (void) strcpy(nextfile, file);
3082 *ptr = '/';
3083 (void) strcat(nextfile, "/");
3084 } else {
3085 (void) strcpy(nextfile, "");
3086 }
3087 (void) strcat(nextfile, contents);
3088 devfsadm_rm_work(nextfile, TRUE, TYPE_LINK);
3089 }
3090 }
3091 }
3092
3093 if (file_type == TYPE_LINK) {
3094 vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile);
3095 if (file_mods == TRUE) {
3096 rm_link_from_cache(file);
3097 s_unlink(newfile);
3098 rm_parent_dir_if_empty(newfile);
3099 invalidate_enumerate_cache();
3100 (void) di_devlink_rm_link(devlink_cache, file);
3101