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