1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Devfsadm replaces drvconfig, audlinks, disks, tapes, ports, devlinks 31*7c478bd9Sstevel@tonic-gate * as a general purpose device administrative utility. It creates 32*7c478bd9Sstevel@tonic-gate * devices special files in /devices and logical links in /dev, and 33*7c478bd9Sstevel@tonic-gate * coordinates updates to /etc/path_to_instance with the kernel. It 34*7c478bd9Sstevel@tonic-gate * operates in both command line mode to handle user or script invoked 35*7c478bd9Sstevel@tonic-gate * reconfiguration updates, and operates in daemon mode to handle dynamic 36*7c478bd9Sstevel@tonic-gate * reconfiguration for hotplugging support. 37*7c478bd9Sstevel@tonic-gate */ 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include "devfsadm_impl.h" 40*7c478bd9Sstevel@tonic-gate #include <utime.h> 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* globals */ 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* create or remove nodes or links. unset with -n */ 45*7c478bd9Sstevel@tonic-gate static int file_mods = TRUE; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* cleanup mode. Set with -C */ 48*7c478bd9Sstevel@tonic-gate static int cleanup = FALSE; 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* devlinks -d compatibility */ 51*7c478bd9Sstevel@tonic-gate static int devlinks_debug = FALSE; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* turn off device allocation with devfsadm -d */ 54*7c478bd9Sstevel@tonic-gate static int devalloc_off = FALSE; 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate /* devices to be deallocated with -d */ 57*7c478bd9Sstevel@tonic-gate static char *devalloc[5] = 58*7c478bd9Sstevel@tonic-gate {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_FD, DDI_NT_TAPE, NULL}; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* load a single driver only. set with -i */ 61*7c478bd9Sstevel@tonic-gate static int single_drv = FALSE; 62*7c478bd9Sstevel@tonic-gate static char *driver = NULL; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* attempt to load drivers or defer attach nodes */ 65*7c478bd9Sstevel@tonic-gate static int load_attach_drv = TRUE; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* set if invoked via /usr/lib/devfsadm/devfsadmd */ 68*7c478bd9Sstevel@tonic-gate static int daemon_mode = FALSE; 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* output directed to syslog during daemon mode if set */ 71*7c478bd9Sstevel@tonic-gate static int logflag = FALSE; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* build links in /dev. -x to turn off */ 74*7c478bd9Sstevel@tonic-gate static int build_dev = TRUE; 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* build nodes in /devices. -y to turn off */ 77*7c478bd9Sstevel@tonic-gate static int build_devices = TRUE; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* -z to turn off */ 80*7c478bd9Sstevel@tonic-gate static int flush_path_to_inst_enable = TRUE; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /* variables used for path_to_inst flushing */ 83*7c478bd9Sstevel@tonic-gate static int inst_count = 0; 84*7c478bd9Sstevel@tonic-gate static mutex_t count_lock; 85*7c478bd9Sstevel@tonic-gate static cond_t cv; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* variables for minor_fini calling system */ 88*7c478bd9Sstevel@tonic-gate static int minor_fini_timeout = MINOR_FINI_TIMEOUT_DEFAULT; 89*7c478bd9Sstevel@tonic-gate static mutex_t minor_fini_mutex; 90*7c478bd9Sstevel@tonic-gate static int minor_fini_thread_created = FALSE; 91*7c478bd9Sstevel@tonic-gate static int minor_fini_delay_restart = FALSE; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* single-threads /dev modification */ 94*7c478bd9Sstevel@tonic-gate static sema_t dev_sema; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* the program we were invoked as; ie argv[0] */ 97*7c478bd9Sstevel@tonic-gate static char *prog; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* pointers to create/remove link lists */ 100*7c478bd9Sstevel@tonic-gate static create_list_t *create_head = NULL; 101*7c478bd9Sstevel@tonic-gate static remove_list_t *remove_head = NULL; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate /* supports the class -c option */ 104*7c478bd9Sstevel@tonic-gate static char **classes = NULL; 105*7c478bd9Sstevel@tonic-gate static int num_classes = 0; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* used with verbose option -v or -V */ 108*7c478bd9Sstevel@tonic-gate static int num_verbose = 0; 109*7c478bd9Sstevel@tonic-gate static char **verbose = NULL; 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate static struct mperm *minor_perms = NULL; 112*7c478bd9Sstevel@tonic-gate static driver_alias_t *driver_aliases = NULL; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate /* set if -r alternate root given */ 115*7c478bd9Sstevel@tonic-gate static char *root_dir = ""; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* /devices or <rootdir>/devices */ 118*7c478bd9Sstevel@tonic-gate static char *devices_dir = DEVICES; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* /dev or <rootdir>/dev */ 121*7c478bd9Sstevel@tonic-gate static char *dev_dir = DEV; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* /dev for the global zone */ 124*7c478bd9Sstevel@tonic-gate static char *global_dev_dir = DEV; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* /etc/path_to_inst unless -p used */ 127*7c478bd9Sstevel@tonic-gate static char *inst_file = INSTANCE_FILE; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* /usr/lib/devfsadm/linkmods unless -l used */ 130*7c478bd9Sstevel@tonic-gate static char *module_dirs = MODULE_DIRS; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* default uid/gid used if /etc/minor_perm entry not found */ 133*7c478bd9Sstevel@tonic-gate static uid_t root_uid; 134*7c478bd9Sstevel@tonic-gate static gid_t sys_gid; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate /* /etc/devlink.tab unless devlinks -t used */ 137*7c478bd9Sstevel@tonic-gate static char *devlinktab_file = NULL; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* set if /dev link is new. speeds up rm_stale_links */ 140*7c478bd9Sstevel@tonic-gate static int linknew = TRUE; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* variables for devlink.tab compat processing */ 143*7c478bd9Sstevel@tonic-gate static devlinktab_list_t *devlinktab_list = NULL; 144*7c478bd9Sstevel@tonic-gate static unsigned int devlinktab_line = 0; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* cache head for devfsadm_enumerate*() functions */ 147*7c478bd9Sstevel@tonic-gate static numeral_set_t *head_numeral_set = NULL; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* list list of devfsadm modules */ 150*7c478bd9Sstevel@tonic-gate static module_t *module_head = NULL; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* name_to_major list used in utility function */ 153*7c478bd9Sstevel@tonic-gate static n2m_t *n2m_list = NULL; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* cache of some links used for performance */ 156*7c478bd9Sstevel@tonic-gate static linkhead_t *headlinkhead = NULL; 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* locking variables to prevent multiples writes to /dev */ 159*7c478bd9Sstevel@tonic-gate static int hold_dev_lock = FALSE; 160*7c478bd9Sstevel@tonic-gate static int hold_daemon_lock = FALSE; 161*7c478bd9Sstevel@tonic-gate static int dev_lock_fd; 162*7c478bd9Sstevel@tonic-gate static int daemon_lock_fd; 163*7c478bd9Sstevel@tonic-gate static char dev_lockfile[PATH_MAX + 1]; 164*7c478bd9Sstevel@tonic-gate static char daemon_lockfile[PATH_MAX + 1]; 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate /* last devinfo node/minor processed. used for performance */ 167*7c478bd9Sstevel@tonic-gate static di_node_t lnode; 168*7c478bd9Sstevel@tonic-gate static di_minor_t lminor; 169*7c478bd9Sstevel@tonic-gate static char lphy_path[PATH_MAX + 1] = {""}; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate /* Globals used by the link database */ 172*7c478bd9Sstevel@tonic-gate static di_devlink_handle_t devlink_cache; 173*7c478bd9Sstevel@tonic-gate static int update_database = FALSE; 174*7c478bd9Sstevel@tonic-gate static int devlink_door_fd = -1; /* fd of devlink handler door */ 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* Globals used to set logindev perms */ 177*7c478bd9Sstevel@tonic-gate static struct login_dev *login_dev_cache = NULL; 178*7c478bd9Sstevel@tonic-gate static int login_dev_enable = FALSE; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* Global to use devinfo snapshot cache */ 181*7c478bd9Sstevel@tonic-gate static int use_snapshot_cache = FALSE; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate /* Zone-related information */ 184*7c478bd9Sstevel@tonic-gate static int zone_cmd_mode = 0; 185*7c478bd9Sstevel@tonic-gate static mutex_t zone_mutex; /* protects zone registration/unregistration ops */ 186*7c478bd9Sstevel@tonic-gate static struct zone_devinfo *zone_head; /* linked list of zones */ 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* 189*7c478bd9Sstevel@tonic-gate * Packaged directories - not removed even when empty. 190*7c478bd9Sstevel@tonic-gate * The dirs must be listed in canonical form 191*7c478bd9Sstevel@tonic-gate * i.e. without leading "/dev/" 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate static char *packaged_dirs[] = 194*7c478bd9Sstevel@tonic-gate {"dsk", "rdsk", "term", NULL}; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* RCM related globals */ 197*7c478bd9Sstevel@tonic-gate static void *librcm_hdl; 198*7c478bd9Sstevel@tonic-gate static rcm_handle_t *rcm_hdl = NULL; 199*7c478bd9Sstevel@tonic-gate static thread_t process_rcm_events_tid; 200*7c478bd9Sstevel@tonic-gate static struct rcm_eventq *volatile rcm_eventq_head = NULL; 201*7c478bd9Sstevel@tonic-gate static struct rcm_eventq *rcm_eventq_tail = NULL; 202*7c478bd9Sstevel@tonic-gate static mutex_t rcm_eventq_lock; 203*7c478bd9Sstevel@tonic-gate static cond_t rcm_eventq_cv; 204*7c478bd9Sstevel@tonic-gate static volatile int need_to_exit_rcm_event_thread = 0; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate static void load_dev_acl(void); 207*7c478bd9Sstevel@tonic-gate static void update_drvconf(major_t); 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate int 211*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 212*7c478bd9Sstevel@tonic-gate { 213*7c478bd9Sstevel@tonic-gate struct passwd *pw; 214*7c478bd9Sstevel@tonic-gate struct group *gp; 215*7c478bd9Sstevel@tonic-gate pid_t pid; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 218*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) { 221*7c478bd9Sstevel@tonic-gate prog = argv[0]; 222*7c478bd9Sstevel@tonic-gate } else { 223*7c478bd9Sstevel@tonic-gate prog++; 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate if (getuid() != 0) { 227*7c478bd9Sstevel@tonic-gate err_print(MUST_BE_ROOT); 228*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate /* 232*7c478bd9Sstevel@tonic-gate * Close all files except stdin/stdout/stderr 233*7c478bd9Sstevel@tonic-gate */ 234*7c478bd9Sstevel@tonic-gate closefrom(3); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 237*7c478bd9Sstevel@tonic-gate root_uid = pw->pw_uid; 238*7c478bd9Sstevel@tonic-gate } else { 239*7c478bd9Sstevel@tonic-gate err_print(CANT_FIND_USER, DEFAULT_DEV_USER); 240*7c478bd9Sstevel@tonic-gate root_uid = (uid_t)0; /* assume 0 is root */ 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /* the default group is sys */ 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 246*7c478bd9Sstevel@tonic-gate sys_gid = gp->gr_gid; 247*7c478bd9Sstevel@tonic-gate } else { 248*7c478bd9Sstevel@tonic-gate err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP); 249*7c478bd9Sstevel@tonic-gate sys_gid = (gid_t)3; /* assume 3 is sys */ 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate (void) umask(0); 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate parse_args(argc, argv); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate (void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate if (daemon_mode == TRUE) { 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * Build /dev and /devices before daemonizing if 261*7c478bd9Sstevel@tonic-gate * reconfig booting and daemon invoked with alternate 262*7c478bd9Sstevel@tonic-gate * root. This is to support install. 263*7c478bd9Sstevel@tonic-gate */ 264*7c478bd9Sstevel@tonic-gate if (getenv(RECONFIG_BOOT) != NULL && root_dir[0] != '\0') { 265*7c478bd9Sstevel@tonic-gate vprint(INFO_MID, CONFIGURING); 266*7c478bd9Sstevel@tonic-gate load_dev_acl(); 267*7c478bd9Sstevel@tonic-gate update_drvconf((major_t)-1); 268*7c478bd9Sstevel@tonic-gate process_devinfo_tree(); 269*7c478bd9Sstevel@tonic-gate (void) modctl(MODSETMINIROOT); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * fork before detaching from tty in order to print error 274*7c478bd9Sstevel@tonic-gate * message if unable to acquire file lock. locks not preserved 275*7c478bd9Sstevel@tonic-gate * across forks. Even under debug we want to fork so that 276*7c478bd9Sstevel@tonic-gate * when executed at boot we don't hang. 277*7c478bd9Sstevel@tonic-gate */ 278*7c478bd9Sstevel@tonic-gate if (fork() != 0) { 279*7c478bd9Sstevel@tonic-gate devfsadm_exit(0); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* set directory to / so it coredumps there */ 283*7c478bd9Sstevel@tonic-gate if (chdir("/") == -1) { 284*7c478bd9Sstevel@tonic-gate err_print(CHROOT_FAILED, strerror(errno)); 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* only one daemon can run at a time */ 288*7c478bd9Sstevel@tonic-gate if ((pid = enter_daemon_lock()) == getpid()) { 289*7c478bd9Sstevel@tonic-gate thread_t thread; 290*7c478bd9Sstevel@tonic-gate detachfromtty(); 291*7c478bd9Sstevel@tonic-gate (void) cond_init(&cv, USYNC_THREAD, 0); 292*7c478bd9Sstevel@tonic-gate (void) mutex_init(&count_lock, USYNC_THREAD, 0); 293*7c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, 294*7c478bd9Sstevel@tonic-gate (void *(*)(void *))instance_flush_thread, 295*7c478bd9Sstevel@tonic-gate NULL, 296*7c478bd9Sstevel@tonic-gate THR_DETACHED, 297*7c478bd9Sstevel@tonic-gate &thread) != 0) { 298*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_THREAD, "daemon", 299*7c478bd9Sstevel@tonic-gate strerror(errno)); 300*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate * No need for rcm notifications when running 305*7c478bd9Sstevel@tonic-gate * with an alternate root. So initialize rcm only 306*7c478bd9Sstevel@tonic-gate * when devfsadm is running with root dir "/". 307*7c478bd9Sstevel@tonic-gate * Similarly, logindevperms need only be set 308*7c478bd9Sstevel@tonic-gate * in daemon mode and when root dir is "/". 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate if (root_dir[0] == '\0') { 311*7c478bd9Sstevel@tonic-gate (void) rcm_init(); 312*7c478bd9Sstevel@tonic-gate login_dev_enable = TRUE; 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate daemon_update(); 316*7c478bd9Sstevel@tonic-gate } else { 317*7c478bd9Sstevel@tonic-gate err_print(DAEMON_RUNNING, pid); 318*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate exit_daemon_lock(); 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate } else { 323*7c478bd9Sstevel@tonic-gate /* not a daemon, so just build /dev and /devices */ 324*7c478bd9Sstevel@tonic-gate process_devinfo_tree(); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate return (0); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate static void 330*7c478bd9Sstevel@tonic-gate update_drvconf(major_t major) 331*7c478bd9Sstevel@tonic-gate { 332*7c478bd9Sstevel@tonic-gate if (modctl(MODLOADDRVCONF, major) != 0) 333*7c478bd9Sstevel@tonic-gate err_print(gettext("update_drvconf failed for major %d\n"), 334*7c478bd9Sstevel@tonic-gate major); 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate static void 339*7c478bd9Sstevel@tonic-gate load_dev_acl() 340*7c478bd9Sstevel@tonic-gate { 341*7c478bd9Sstevel@tonic-gate if (load_devpolicy() != 0) 342*7c478bd9Sstevel@tonic-gate err_print(gettext("device policy load failed\n")); 343*7c478bd9Sstevel@tonic-gate load_minor_perm_file(); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * set_zone_params sets us up to run against a specific zone. It should 348*7c478bd9Sstevel@tonic-gate * only be called from parse_args. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate static int 351*7c478bd9Sstevel@tonic-gate set_zone_params(char *zone_name) 352*7c478bd9Sstevel@tonic-gate { 353*7c478bd9Sstevel@tonic-gate char zpath[MAXPATHLEN]; 354*7c478bd9Sstevel@tonic-gate zone_dochandle_t hdl; 355*7c478bd9Sstevel@tonic-gate void *dlhdl; 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate assert(daemon_mode == FALSE); 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 360*7c478bd9Sstevel@tonic-gate err_print(INVALID_ZONE, zone_name); 361*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) { 365*7c478bd9Sstevel@tonic-gate err_print(ZONE_LIB_MISSING); 366*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) { 370*7c478bd9Sstevel@tonic-gate err_print(ZONE_ROOTPATH_FAILED, zone_name, strerror(errno)); 371*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 372*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate set_root_devices_dev_dir(zpath, 1); 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate if ((hdl = zonecfg_init_handle()) == NULL) { 377*7c478bd9Sstevel@tonic-gate err_print(ZONE_REP_FAILED, zone_name, strerror(errno)); 378*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 379*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate if ((zonecfg_get_snapshot_handle(zone_name, hdl)) != Z_OK) { 383*7c478bd9Sstevel@tonic-gate err_print(ZONE_REP_FAILED, zone_name, strerror(errno)); 384*7c478bd9Sstevel@tonic-gate zonecfg_fini_handle(hdl); 385*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 386*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 387*7c478bd9Sstevel@tonic-gate } 388*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate zone_head = s_malloc(sizeof (struct zone_devinfo)); 391*7c478bd9Sstevel@tonic-gate zone_head->zone_path = s_strdup(zpath); 392*7c478bd9Sstevel@tonic-gate zone_head->zone_name = s_strdup(zone_name); 393*7c478bd9Sstevel@tonic-gate zone_head->zone_dochdl = hdl; 394*7c478bd9Sstevel@tonic-gate zone_head->zone_next = NULL; 395*7c478bd9Sstevel@tonic-gate zone_cmd_mode = 1; 396*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate /* 400*7c478bd9Sstevel@tonic-gate * Parse arguments for all 6 programs handled from devfsadm. 401*7c478bd9Sstevel@tonic-gate */ 402*7c478bd9Sstevel@tonic-gate static void 403*7c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[]) 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate char opt; 406*7c478bd9Sstevel@tonic-gate char get_linkcompat_opts = FALSE; 407*7c478bd9Sstevel@tonic-gate char *compat_class; 408*7c478bd9Sstevel@tonic-gate int num_aliases = 0; 409*7c478bd9Sstevel@tonic-gate int len; 410*7c478bd9Sstevel@tonic-gate int retval; 411*7c478bd9Sstevel@tonic-gate int add_bind = FALSE; 412*7c478bd9Sstevel@tonic-gate struct aliases *ap = NULL; 413*7c478bd9Sstevel@tonic-gate struct aliases *a_head = NULL; 414*7c478bd9Sstevel@tonic-gate struct aliases *a_tail = NULL; 415*7c478bd9Sstevel@tonic-gate struct modconfig mc; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate if (strcmp(prog, DISKS) == 0) { 418*7c478bd9Sstevel@tonic-gate compat_class = "disk"; 419*7c478bd9Sstevel@tonic-gate get_linkcompat_opts = TRUE; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate } else if (strcmp(prog, TAPES) == 0) { 422*7c478bd9Sstevel@tonic-gate compat_class = "tape"; 423*7c478bd9Sstevel@tonic-gate get_linkcompat_opts = TRUE; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate } else if (strcmp(prog, PORTS) == 0) { 426*7c478bd9Sstevel@tonic-gate compat_class = "port"; 427*7c478bd9Sstevel@tonic-gate get_linkcompat_opts = TRUE; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate } else if (strcmp(prog, AUDLINKS) == 0) { 430*7c478bd9Sstevel@tonic-gate compat_class = "audio"; 431*7c478bd9Sstevel@tonic-gate get_linkcompat_opts = TRUE; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate } else if (strcmp(prog, DEVLINKS) == 0) { 434*7c478bd9Sstevel@tonic-gate devlinktab_file = DEVLINKTAB_FILE; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate build_devices = FALSE; 437*7c478bd9Sstevel@tonic-gate load_attach_drv = FALSE; 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "dnr:st:vV:")) != EOF) { 440*7c478bd9Sstevel@tonic-gate switch (opt) { 441*7c478bd9Sstevel@tonic-gate case 'd': 442*7c478bd9Sstevel@tonic-gate file_mods = FALSE; 443*7c478bd9Sstevel@tonic-gate flush_path_to_inst_enable = FALSE; 444*7c478bd9Sstevel@tonic-gate devlinks_debug = TRUE; 445*7c478bd9Sstevel@tonic-gate break; 446*7c478bd9Sstevel@tonic-gate case 'n': 447*7c478bd9Sstevel@tonic-gate /* prevent driver loading and deferred attach */ 448*7c478bd9Sstevel@tonic-gate load_attach_drv = FALSE; 449*7c478bd9Sstevel@tonic-gate break; 450*7c478bd9Sstevel@tonic-gate case 'r': 451*7c478bd9Sstevel@tonic-gate set_root_devices_dev_dir(optarg, 0); 452*7c478bd9Sstevel@tonic-gate if (zone_pathcheck(root_dir) != 453*7c478bd9Sstevel@tonic-gate DEVFSADM_SUCCESS) 454*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 455*7c478bd9Sstevel@tonic-gate break; 456*7c478bd9Sstevel@tonic-gate case 's': 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * suppress. don't create/remove links/nodes 459*7c478bd9Sstevel@tonic-gate * useful with -v or -V 460*7c478bd9Sstevel@tonic-gate */ 461*7c478bd9Sstevel@tonic-gate file_mods = FALSE; 462*7c478bd9Sstevel@tonic-gate flush_path_to_inst_enable = FALSE; 463*7c478bd9Sstevel@tonic-gate break; 464*7c478bd9Sstevel@tonic-gate case 't': 465*7c478bd9Sstevel@tonic-gate /* supply a non-default table file */ 466*7c478bd9Sstevel@tonic-gate devlinktab_file = optarg; 467*7c478bd9Sstevel@tonic-gate break; 468*7c478bd9Sstevel@tonic-gate case 'v': 469*7c478bd9Sstevel@tonic-gate /* documented verbose flag */ 470*7c478bd9Sstevel@tonic-gate add_verbose_id(VERBOSE_MID); 471*7c478bd9Sstevel@tonic-gate break; 472*7c478bd9Sstevel@tonic-gate case 'V': 473*7c478bd9Sstevel@tonic-gate /* undocumented for extra verbose levels */ 474*7c478bd9Sstevel@tonic-gate add_verbose_id(optarg); 475*7c478bd9Sstevel@tonic-gate break; 476*7c478bd9Sstevel@tonic-gate default: 477*7c478bd9Sstevel@tonic-gate usage(); 478*7c478bd9Sstevel@tonic-gate break; 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate if (optind < argc) { 483*7c478bd9Sstevel@tonic-gate usage(); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate } else if (strcmp(prog, DRVCONFIG) == 0) { 487*7c478bd9Sstevel@tonic-gate build_dev = FALSE; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate while ((opt = 490*7c478bd9Sstevel@tonic-gate getopt(argc, argv, "a:bdc:i:m:np:R:r:svV:")) != EOF) { 491*7c478bd9Sstevel@tonic-gate switch (opt) { 492*7c478bd9Sstevel@tonic-gate case 'a': 493*7c478bd9Sstevel@tonic-gate ap = calloc(sizeof (struct aliases), 1); 494*7c478bd9Sstevel@tonic-gate ap->a_name = dequote(optarg); 495*7c478bd9Sstevel@tonic-gate len = strlen(ap->a_name) + 1; 496*7c478bd9Sstevel@tonic-gate if (len > MAXMODCONFNAME) { 497*7c478bd9Sstevel@tonic-gate err_print(ALIAS_TOO_LONG, 498*7c478bd9Sstevel@tonic-gate MAXMODCONFNAME, ap->a_name); 499*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate ap->a_len = len; 502*7c478bd9Sstevel@tonic-gate if (a_tail == NULL) { 503*7c478bd9Sstevel@tonic-gate a_head = ap; 504*7c478bd9Sstevel@tonic-gate } else { 505*7c478bd9Sstevel@tonic-gate a_tail->a_next = ap; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate a_tail = ap; 508*7c478bd9Sstevel@tonic-gate num_aliases++; 509*7c478bd9Sstevel@tonic-gate add_bind = TRUE; 510*7c478bd9Sstevel@tonic-gate break; 511*7c478bd9Sstevel@tonic-gate case 'b': 512*7c478bd9Sstevel@tonic-gate add_bind = TRUE; 513*7c478bd9Sstevel@tonic-gate break; 514*7c478bd9Sstevel@tonic-gate case 'c': 515*7c478bd9Sstevel@tonic-gate (void) strcpy(mc.drvclass, optarg); 516*7c478bd9Sstevel@tonic-gate break; 517*7c478bd9Sstevel@tonic-gate case 'd': 518*7c478bd9Sstevel@tonic-gate /* 519*7c478bd9Sstevel@tonic-gate * need to keep for compatibility, but 520*7c478bd9Sstevel@tonic-gate * do nothing. 521*7c478bd9Sstevel@tonic-gate */ 522*7c478bd9Sstevel@tonic-gate break; 523*7c478bd9Sstevel@tonic-gate case 'i': 524*7c478bd9Sstevel@tonic-gate single_drv = TRUE; 525*7c478bd9Sstevel@tonic-gate (void) strcpy(mc.drvname, optarg); 526*7c478bd9Sstevel@tonic-gate driver = s_strdup(optarg); 527*7c478bd9Sstevel@tonic-gate break; 528*7c478bd9Sstevel@tonic-gate case 'm': 529*7c478bd9Sstevel@tonic-gate mc.major = atoi(optarg); 530*7c478bd9Sstevel@tonic-gate break; 531*7c478bd9Sstevel@tonic-gate case 'n': 532*7c478bd9Sstevel@tonic-gate /* prevent driver loading and deferred attach */ 533*7c478bd9Sstevel@tonic-gate load_attach_drv = FALSE; 534*7c478bd9Sstevel@tonic-gate break; 535*7c478bd9Sstevel@tonic-gate case 'p': 536*7c478bd9Sstevel@tonic-gate /* specify alternate path_to_inst file */ 537*7c478bd9Sstevel@tonic-gate inst_file = s_strdup(optarg); 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate case 'R': 540*7c478bd9Sstevel@tonic-gate /* 541*7c478bd9Sstevel@tonic-gate * Private flag for suninstall to populate 542*7c478bd9Sstevel@tonic-gate * device information on the installed root. 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate root_dir = s_strdup(optarg); 545*7c478bd9Sstevel@tonic-gate if (zone_pathcheck(root_dir) != 546*7c478bd9Sstevel@tonic-gate DEVFSADM_SUCCESS) 547*7c478bd9Sstevel@tonic-gate devfsadm_exit(devfsadm_copy()); 548*7c478bd9Sstevel@tonic-gate break; 549*7c478bd9Sstevel@tonic-gate case 'r': 550*7c478bd9Sstevel@tonic-gate devices_dir = s_strdup(optarg); 551*7c478bd9Sstevel@tonic-gate if (zone_pathcheck(devices_dir) != 552*7c478bd9Sstevel@tonic-gate DEVFSADM_SUCCESS) 553*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 554*7c478bd9Sstevel@tonic-gate break; 555*7c478bd9Sstevel@tonic-gate case 's': 556*7c478bd9Sstevel@tonic-gate /* 557*7c478bd9Sstevel@tonic-gate * suppress. don't create nodes 558*7c478bd9Sstevel@tonic-gate * useful with -v or -V 559*7c478bd9Sstevel@tonic-gate */ 560*7c478bd9Sstevel@tonic-gate file_mods = FALSE; 561*7c478bd9Sstevel@tonic-gate flush_path_to_inst_enable = FALSE; 562*7c478bd9Sstevel@tonic-gate break; 563*7c478bd9Sstevel@tonic-gate case 'v': 564*7c478bd9Sstevel@tonic-gate /* documented verbose flag */ 565*7c478bd9Sstevel@tonic-gate add_verbose_id(VERBOSE_MID); 566*7c478bd9Sstevel@tonic-gate break; 567*7c478bd9Sstevel@tonic-gate case 'V': 568*7c478bd9Sstevel@tonic-gate /* undocumented for extra verbose levels */ 569*7c478bd9Sstevel@tonic-gate add_verbose_id(optarg); 570*7c478bd9Sstevel@tonic-gate break; 571*7c478bd9Sstevel@tonic-gate default: 572*7c478bd9Sstevel@tonic-gate usage(); 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate if (optind < argc) { 577*7c478bd9Sstevel@tonic-gate usage(); 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate if ((add_bind == TRUE) && (mc.major == -1 || 581*7c478bd9Sstevel@tonic-gate mc.drvname[0] == NULL)) { 582*7c478bd9Sstevel@tonic-gate err_print(MAJOR_AND_B_FLAG); 583*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate if (add_bind == TRUE) { 586*7c478bd9Sstevel@tonic-gate mc.num_aliases = num_aliases; 587*7c478bd9Sstevel@tonic-gate mc.ap = a_head; 588*7c478bd9Sstevel@tonic-gate retval = modctl(MODADDMAJBIND, NULL, (caddr_t)&mc); 589*7c478bd9Sstevel@tonic-gate if (retval < 0) { 590*7c478bd9Sstevel@tonic-gate err_print(MODCTL_ADDMAJBIND); 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate devfsadm_exit(retval); 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate } else if ((strcmp(prog, DEVFSADM) == 0) || 596*7c478bd9Sstevel@tonic-gate (strcmp(prog, DEVFSADMD) == 0)) { 597*7c478bd9Sstevel@tonic-gate char *zonename = NULL; 598*7c478bd9Sstevel@tonic-gate enum zreg_op zoneop; 599*7c478bd9Sstevel@tonic-gate int init_drvconf = 0; 600*7c478bd9Sstevel@tonic-gate int init_perm = 0; 601*7c478bd9Sstevel@tonic-gate int public_mode = 0; 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate if (strcmp(prog, DEVFSADMD) == 0) { 604*7c478bd9Sstevel@tonic-gate daemon_mode = TRUE; 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate devlinktab_file = DEVLINKTAB_FILE; 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, 610*7c478bd9Sstevel@tonic-gate "Cc:dIi:l:np:PR:r:st:vV:x:z:Z:")) != EOF) { 611*7c478bd9Sstevel@tonic-gate if (opt == 'I' || opt == 'P') { 612*7c478bd9Sstevel@tonic-gate if (public_mode) 613*7c478bd9Sstevel@tonic-gate usage(); 614*7c478bd9Sstevel@tonic-gate } else { 615*7c478bd9Sstevel@tonic-gate if (init_perm || init_drvconf) 616*7c478bd9Sstevel@tonic-gate usage(); 617*7c478bd9Sstevel@tonic-gate public_mode = 1; 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate switch (opt) { 620*7c478bd9Sstevel@tonic-gate case 'C': 621*7c478bd9Sstevel@tonic-gate cleanup = TRUE; 622*7c478bd9Sstevel@tonic-gate break; 623*7c478bd9Sstevel@tonic-gate case 'c': 624*7c478bd9Sstevel@tonic-gate num_classes++; 625*7c478bd9Sstevel@tonic-gate classes = s_realloc(classes, num_classes * 626*7c478bd9Sstevel@tonic-gate sizeof (char *)); 627*7c478bd9Sstevel@tonic-gate classes[num_classes - 1] = optarg; 628*7c478bd9Sstevel@tonic-gate break; 629*7c478bd9Sstevel@tonic-gate case 'd': 630*7c478bd9Sstevel@tonic-gate if (daemon_mode == FALSE) { 631*7c478bd9Sstevel@tonic-gate devalloc_off = TRUE; 632*7c478bd9Sstevel@tonic-gate build_dev = FALSE; 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate break; 635*7c478bd9Sstevel@tonic-gate case 'I': /* update kernel driver.conf cache */ 636*7c478bd9Sstevel@tonic-gate if (daemon_mode == TRUE) 637*7c478bd9Sstevel@tonic-gate usage(); 638*7c478bd9Sstevel@tonic-gate init_drvconf = 1; 639*7c478bd9Sstevel@tonic-gate break; 640*7c478bd9Sstevel@tonic-gate case 'i': 641*7c478bd9Sstevel@tonic-gate single_drv = TRUE; 642*7c478bd9Sstevel@tonic-gate driver = s_strdup(optarg); 643*7c478bd9Sstevel@tonic-gate break; 644*7c478bd9Sstevel@tonic-gate case 'l': 645*7c478bd9Sstevel@tonic-gate /* specify an alternate module load path */ 646*7c478bd9Sstevel@tonic-gate module_dirs = s_strdup(optarg); 647*7c478bd9Sstevel@tonic-gate break; 648*7c478bd9Sstevel@tonic-gate case 'n': 649*7c478bd9Sstevel@tonic-gate /* prevent driver loading and deferred attach */ 650*7c478bd9Sstevel@tonic-gate load_attach_drv = FALSE; 651*7c478bd9Sstevel@tonic-gate break; 652*7c478bd9Sstevel@tonic-gate case 'p': 653*7c478bd9Sstevel@tonic-gate /* specify alternate path_to_inst file */ 654*7c478bd9Sstevel@tonic-gate inst_file = s_strdup(optarg); 655*7c478bd9Sstevel@tonic-gate break; 656*7c478bd9Sstevel@tonic-gate case 'P': 657*7c478bd9Sstevel@tonic-gate if (daemon_mode == TRUE) 658*7c478bd9Sstevel@tonic-gate usage(); 659*7c478bd9Sstevel@tonic-gate /* load minor_perm and device_policy */ 660*7c478bd9Sstevel@tonic-gate init_perm = 1; 661*7c478bd9Sstevel@tonic-gate break; 662*7c478bd9Sstevel@tonic-gate case 'R': 663*7c478bd9Sstevel@tonic-gate /* 664*7c478bd9Sstevel@tonic-gate * Private flag for suninstall to populate 665*7c478bd9Sstevel@tonic-gate * device information on the installed root. 666*7c478bd9Sstevel@tonic-gate */ 667*7c478bd9Sstevel@tonic-gate root_dir = s_strdup(optarg); 668*7c478bd9Sstevel@tonic-gate devfsadm_exit(devfsadm_copy()); 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate case 'r': 671*7c478bd9Sstevel@tonic-gate set_root_devices_dev_dir(optarg, 0); 672*7c478bd9Sstevel@tonic-gate break; 673*7c478bd9Sstevel@tonic-gate case 's': 674*7c478bd9Sstevel@tonic-gate /* 675*7c478bd9Sstevel@tonic-gate * suppress. don't create/remove links/nodes 676*7c478bd9Sstevel@tonic-gate * useful with -v or -V 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate file_mods = FALSE; 679*7c478bd9Sstevel@tonic-gate flush_path_to_inst_enable = FALSE; 680*7c478bd9Sstevel@tonic-gate break; 681*7c478bd9Sstevel@tonic-gate case 't': 682*7c478bd9Sstevel@tonic-gate devlinktab_file = optarg; 683*7c478bd9Sstevel@tonic-gate break; 684*7c478bd9Sstevel@tonic-gate case 'v': 685*7c478bd9Sstevel@tonic-gate /* documented verbose flag */ 686*7c478bd9Sstevel@tonic-gate add_verbose_id(VERBOSE_MID); 687*7c478bd9Sstevel@tonic-gate break; 688*7c478bd9Sstevel@tonic-gate case 'V': 689*7c478bd9Sstevel@tonic-gate /* undocumented: specify verbose lvl */ 690*7c478bd9Sstevel@tonic-gate add_verbose_id(optarg); 691*7c478bd9Sstevel@tonic-gate break; 692*7c478bd9Sstevel@tonic-gate case 'x': 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * x is the "private switch" option. The 695*7c478bd9Sstevel@tonic-gate * goal is to not suck up all the other 696*7c478bd9Sstevel@tonic-gate * option letters. 697*7c478bd9Sstevel@tonic-gate */ 698*7c478bd9Sstevel@tonic-gate if (strcmp(optarg, "update_devlinksdb") == 0) { 699*7c478bd9Sstevel@tonic-gate update_database = TRUE; 700*7c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "no_dev") == 0) { 701*7c478bd9Sstevel@tonic-gate /* don't build /dev */ 702*7c478bd9Sstevel@tonic-gate build_dev = FALSE; 703*7c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "no_devices") == 0) { 704*7c478bd9Sstevel@tonic-gate /* don't build /devices */ 705*7c478bd9Sstevel@tonic-gate build_devices = FALSE; 706*7c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "no_p2i") == 0) { 707*7c478bd9Sstevel@tonic-gate /* don't flush path_to_inst */ 708*7c478bd9Sstevel@tonic-gate flush_path_to_inst_enable = FALSE; 709*7c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "use_dicache") == 0) { 710*7c478bd9Sstevel@tonic-gate use_snapshot_cache = TRUE; 711*7c478bd9Sstevel@tonic-gate } else { 712*7c478bd9Sstevel@tonic-gate usage(); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate break; 715*7c478bd9Sstevel@tonic-gate case 'z': 716*7c478bd9Sstevel@tonic-gate zonename = optarg; 717*7c478bd9Sstevel@tonic-gate zoneop = ZONE_REG; 718*7c478bd9Sstevel@tonic-gate break; 719*7c478bd9Sstevel@tonic-gate case 'Z': 720*7c478bd9Sstevel@tonic-gate zonename = optarg; 721*7c478bd9Sstevel@tonic-gate zoneop = ZONE_UNREG; 722*7c478bd9Sstevel@tonic-gate break; 723*7c478bd9Sstevel@tonic-gate default: 724*7c478bd9Sstevel@tonic-gate usage(); 725*7c478bd9Sstevel@tonic-gate break; 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate if (optind < argc) { 730*7c478bd9Sstevel@tonic-gate usage(); 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate /* 734*7c478bd9Sstevel@tonic-gate * We're not in zone mode; Check to see if the rootpath 735*7c478bd9Sstevel@tonic-gate * collides with any zonepaths. 736*7c478bd9Sstevel@tonic-gate */ 737*7c478bd9Sstevel@tonic-gate if (zonename == NULL) { 738*7c478bd9Sstevel@tonic-gate if (zone_pathcheck(root_dir) != DEVFSADM_SUCCESS) 739*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate if (zonename != NULL) { 743*7c478bd9Sstevel@tonic-gate /* 744*7c478bd9Sstevel@tonic-gate * -z and -Z cannot be used if we're the daemon. The 745*7c478bd9Sstevel@tonic-gate * daemon always manages all zones. 746*7c478bd9Sstevel@tonic-gate */ 747*7c478bd9Sstevel@tonic-gate if (daemon_mode == TRUE) 748*7c478bd9Sstevel@tonic-gate usage(); 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate /* 751*7c478bd9Sstevel@tonic-gate * -z and -Z are private flags, but to be paranoid we 752*7c478bd9Sstevel@tonic-gate * check whether they have been combined with -r. 753*7c478bd9Sstevel@tonic-gate */ 754*7c478bd9Sstevel@tonic-gate if (*root_dir != '\0') 755*7c478bd9Sstevel@tonic-gate usage(); 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate if (set_zone_params(optarg) != DEVFSADM_SUCCESS) 758*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate call_zone_register(zonename, zoneop); 761*7c478bd9Sstevel@tonic-gate if (zoneop == ZONE_UNREG) 762*7c478bd9Sstevel@tonic-gate devfsadm_exit(0); 763*7c478bd9Sstevel@tonic-gate /* 764*7c478bd9Sstevel@tonic-gate * If we are in ZONE_REG mode we plow on, laying out 765*7c478bd9Sstevel@tonic-gate * devices for this zone. 766*7c478bd9Sstevel@tonic-gate */ 767*7c478bd9Sstevel@tonic-gate } 768*7c478bd9Sstevel@tonic-gate if (init_drvconf || init_perm) { 769*7c478bd9Sstevel@tonic-gate /* 770*7c478bd9Sstevel@tonic-gate * Load minor perm before force-loading drivers 771*7c478bd9Sstevel@tonic-gate * so the correct permissions are picked up. 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate if (init_perm) 774*7c478bd9Sstevel@tonic-gate load_dev_acl(); 775*7c478bd9Sstevel@tonic-gate if (init_drvconf) 776*7c478bd9Sstevel@tonic-gate update_drvconf((major_t)-1); 777*7c478bd9Sstevel@tonic-gate devfsadm_exit(0); 778*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate if (get_linkcompat_opts == TRUE) { 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate build_devices = FALSE; 786*7c478bd9Sstevel@tonic-gate load_attach_drv = FALSE; 787*7c478bd9Sstevel@tonic-gate num_classes++; 788*7c478bd9Sstevel@tonic-gate classes = s_realloc(classes, num_classes * 789*7c478bd9Sstevel@tonic-gate sizeof (char *)); 790*7c478bd9Sstevel@tonic-gate classes[num_classes - 1] = compat_class; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "Cnr:svV:")) != EOF) { 793*7c478bd9Sstevel@tonic-gate switch (opt) { 794*7c478bd9Sstevel@tonic-gate case 'C': 795*7c478bd9Sstevel@tonic-gate cleanup = TRUE; 796*7c478bd9Sstevel@tonic-gate break; 797*7c478bd9Sstevel@tonic-gate case 'n': 798*7c478bd9Sstevel@tonic-gate /* prevent driver loading or deferred attach */ 799*7c478bd9Sstevel@tonic-gate load_attach_drv = FALSE; 800*7c478bd9Sstevel@tonic-gate break; 801*7c478bd9Sstevel@tonic-gate case 'r': 802*7c478bd9Sstevel@tonic-gate set_root_devices_dev_dir(optarg, 0); 803*7c478bd9Sstevel@tonic-gate if (zone_pathcheck(root_dir) != 804*7c478bd9Sstevel@tonic-gate DEVFSADM_SUCCESS) 805*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 806*7c478bd9Sstevel@tonic-gate break; 807*7c478bd9Sstevel@tonic-gate case 's': 808*7c478bd9Sstevel@tonic-gate /* suppress. don't create/remove links/nodes */ 809*7c478bd9Sstevel@tonic-gate /* useful with -v or -V */ 810*7c478bd9Sstevel@tonic-gate file_mods = FALSE; 811*7c478bd9Sstevel@tonic-gate flush_path_to_inst_enable = FALSE; 812*7c478bd9Sstevel@tonic-gate break; 813*7c478bd9Sstevel@tonic-gate case 'v': 814*7c478bd9Sstevel@tonic-gate /* documented verbose flag */ 815*7c478bd9Sstevel@tonic-gate add_verbose_id(VERBOSE_MID); 816*7c478bd9Sstevel@tonic-gate break; 817*7c478bd9Sstevel@tonic-gate case 'V': 818*7c478bd9Sstevel@tonic-gate /* undocumented for extra verbose levels */ 819*7c478bd9Sstevel@tonic-gate add_verbose_id(optarg); 820*7c478bd9Sstevel@tonic-gate break; 821*7c478bd9Sstevel@tonic-gate default: 822*7c478bd9Sstevel@tonic-gate usage(); 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate if (optind < argc) { 826*7c478bd9Sstevel@tonic-gate usage(); 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate } 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate void 832*7c478bd9Sstevel@tonic-gate usage(void) 833*7c478bd9Sstevel@tonic-gate { 834*7c478bd9Sstevel@tonic-gate if (strcmp(prog, DEVLINKS) == 0) { 835*7c478bd9Sstevel@tonic-gate err_print(DEVLINKS_USAGE); 836*7c478bd9Sstevel@tonic-gate } else if (strcmp(prog, DRVCONFIG) == 0) { 837*7c478bd9Sstevel@tonic-gate err_print(DRVCONFIG_USAGE); 838*7c478bd9Sstevel@tonic-gate } else if ((strcmp(prog, DEVFSADM) == 0) || 839*7c478bd9Sstevel@tonic-gate (strcmp(prog, DEVFSADMD) == 0)) { 840*7c478bd9Sstevel@tonic-gate err_print(DEVFSADM_USAGE); 841*7c478bd9Sstevel@tonic-gate } else { 842*7c478bd9Sstevel@tonic-gate err_print(COMPAT_LINK_USAGE); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate static void 849*7c478bd9Sstevel@tonic-gate devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass) 850*7c478bd9Sstevel@tonic-gate { 851*7c478bd9Sstevel@tonic-gate char *msg, *name; 852*7c478bd9Sstevel@tonic-gate struct mlist mlist = {0}; 853*7c478bd9Sstevel@tonic-gate di_node_t node; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "devi_tree_walk: root=%s, minor=%s, driver=%s," 856*7c478bd9Sstevel@tonic-gate " error=%d, flags=%u\n", dcip->dci_root, 857*7c478bd9Sstevel@tonic-gate dcip->dci_minor ? dcip->dci_minor : "<NULL>", 858*7c478bd9Sstevel@tonic-gate dcip->dci_driver ? dcip->dci_driver : "<NULL>", dcip->dci_error, 859*7c478bd9Sstevel@tonic-gate dcip->dci_flags); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate assert(dcip->dci_root); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate if (dcip->dci_flags & DCA_LOAD_DRV) { 864*7c478bd9Sstevel@tonic-gate node = di_init_driver(dcip->dci_driver, flags); 865*7c478bd9Sstevel@tonic-gate msg = DRIVER_FAILURE; 866*7c478bd9Sstevel@tonic-gate name = dcip->dci_driver; 867*7c478bd9Sstevel@tonic-gate } else { 868*7c478bd9Sstevel@tonic-gate node = di_init(dcip->dci_root, flags); 869*7c478bd9Sstevel@tonic-gate msg = DI_INIT_FAILED; 870*7c478bd9Sstevel@tonic-gate name = dcip->dci_root; 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate if (node == DI_NODE_NIL) { 874*7c478bd9Sstevel@tonic-gate dcip->dci_error = errno; 875*7c478bd9Sstevel@tonic-gate /* 876*7c478bd9Sstevel@tonic-gate * Rapid hotplugging (commonly seen during USB testing), 877*7c478bd9Sstevel@tonic-gate * may remove a device before the create event for it 878*7c478bd9Sstevel@tonic-gate * has been processed. To prevent alarming users with 879*7c478bd9Sstevel@tonic-gate * a superfluous message, we suppress error messages 880*7c478bd9Sstevel@tonic-gate * for ENXIO and hotplug. 881*7c478bd9Sstevel@tonic-gate */ 882*7c478bd9Sstevel@tonic-gate if (!(errno == ENXIO && (dcip->dci_flags & DCA_HOT_PLUG))) 883*7c478bd9Sstevel@tonic-gate err_print(msg, name, strerror(dcip->dci_error)); 884*7c478bd9Sstevel@tonic-gate return; 885*7c478bd9Sstevel@tonic-gate } 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate if (dcip->dci_flags & DCA_FLUSH_PATHINST) 888*7c478bd9Sstevel@tonic-gate flush_path_to_inst(); 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate dcip->dci_arg = &mlist; 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "walking device tree\n"); 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate (void) di_walk_minor(node, NULL, DI_CHECK_ALIAS, dcip, 895*7c478bd9Sstevel@tonic-gate check_minor_type); 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate process_deferred_links(dcip, DCA_CREATE_LINK); 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate dcip->dci_arg = NULL; 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* 902*7c478bd9Sstevel@tonic-gate * Finished creating devfs files and dev links. 903*7c478bd9Sstevel@tonic-gate * Log sysevent and notify RCM. 904*7c478bd9Sstevel@tonic-gate */ 905*7c478bd9Sstevel@tonic-gate if (ev_subclass) 906*7c478bd9Sstevel@tonic-gate build_and_log_event(EC_DEV_ADD, ev_subclass, dcip->dci_root, 907*7c478bd9Sstevel@tonic-gate node); 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl) 910*7c478bd9Sstevel@tonic-gate (void) notify_rcm(node, dcip->dci_minor); 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate di_fini(node); 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate static void 916*7c478bd9Sstevel@tonic-gate process_deferred_links(struct dca_impl *dcip, int flags) 917*7c478bd9Sstevel@tonic-gate { 918*7c478bd9Sstevel@tonic-gate struct mlist *dep; 919*7c478bd9Sstevel@tonic-gate struct minor *mp, *smp; 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "processing deferred links\n"); 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate dep = dcip->dci_arg; 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate /* 926*7c478bd9Sstevel@tonic-gate * The list head is not used during the deferred create phase 927*7c478bd9Sstevel@tonic-gate */ 928*7c478bd9Sstevel@tonic-gate dcip->dci_arg = NULL; 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate assert(dep); 931*7c478bd9Sstevel@tonic-gate assert((dep->head == NULL) ^ (dep->tail != NULL)); 932*7c478bd9Sstevel@tonic-gate assert(flags == DCA_FREE_LIST || flags == DCA_CREATE_LINK); 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate for (smp = NULL, mp = dep->head; mp; mp = mp->next) { 935*7c478bd9Sstevel@tonic-gate if (flags == DCA_CREATE_LINK) 936*7c478bd9Sstevel@tonic-gate (void) check_minor_type(mp->node, mp->minor, dcip); 937*7c478bd9Sstevel@tonic-gate free(smp); 938*7c478bd9Sstevel@tonic-gate smp = mp; 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate free(smp); 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate /* 945*7c478bd9Sstevel@tonic-gate * Called in non-daemon mode to take a snap shot of the devinfo tree. 946*7c478bd9Sstevel@tonic-gate * Then it calls the appropriate functions to build /devices and /dev. 947*7c478bd9Sstevel@tonic-gate * It also flushes path_to_inst. 948*7c478bd9Sstevel@tonic-gate */ 949*7c478bd9Sstevel@tonic-gate void 950*7c478bd9Sstevel@tonic-gate process_devinfo_tree() 951*7c478bd9Sstevel@tonic-gate { 952*7c478bd9Sstevel@tonic-gate uint_t flags = DINFOCPYALL; 953*7c478bd9Sstevel@tonic-gate struct dca_impl dci; 954*7c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 955*7c478bd9Sstevel@tonic-gate char *fcn = "process_devinfo_tree: "; 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%senter\n", fcn); 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate dca_impl_init("/", NULL, &dci); 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate lock_dev(); 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate /* 964*7c478bd9Sstevel@tonic-gate * Update kernel driver.conf cache when devfsadm/drvconfig 965*7c478bd9Sstevel@tonic-gate * is invoked to build /devices and /dev. 966*7c478bd9Sstevel@tonic-gate */ 967*7c478bd9Sstevel@tonic-gate if (load_attach_drv == TRUE) 968*7c478bd9Sstevel@tonic-gate update_drvconf((major_t)-1); 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate if (single_drv == TRUE) { 971*7c478bd9Sstevel@tonic-gate /* 972*7c478bd9Sstevel@tonic-gate * load a single driver, but walk the entire devinfo tree 973*7c478bd9Sstevel@tonic-gate */ 974*7c478bd9Sstevel@tonic-gate if (load_attach_drv == FALSE) 975*7c478bd9Sstevel@tonic-gate err_print(DRV_LOAD_REQD); 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%sattaching driver (%s)\n", fcn, driver); 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate dci.dci_flags |= DCA_LOAD_DRV; 980*7c478bd9Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%s", driver); 981*7c478bd9Sstevel@tonic-gate dci.dci_driver = name; 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate } else if (load_attach_drv == TRUE) { 984*7c478bd9Sstevel@tonic-gate /* 985*7c478bd9Sstevel@tonic-gate * load and attach all drivers, then walk the entire tree. 986*7c478bd9Sstevel@tonic-gate * If the cache flag is set, use DINFOCACHE to get cached 987*7c478bd9Sstevel@tonic-gate * data. 988*7c478bd9Sstevel@tonic-gate */ 989*7c478bd9Sstevel@tonic-gate if (use_snapshot_cache == TRUE) { 990*7c478bd9Sstevel@tonic-gate flags = DINFOCACHE; 991*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%susing snapshot cache\n", fcn); 992*7c478bd9Sstevel@tonic-gate } else { 993*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%sattaching all drivers\n", fcn); 994*7c478bd9Sstevel@tonic-gate flags |= DINFOFORCE; 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate } 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate if (((load_attach_drv == TRUE) || (single_drv == TRUE)) && 999*7c478bd9Sstevel@tonic-gate (build_devices == TRUE)) { 1000*7c478bd9Sstevel@tonic-gate dci.dci_flags |= DCA_FLUSH_PATHINST; 1001*7c478bd9Sstevel@tonic-gate } 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate /* handle pre-cleanup operations desired by the modules. */ 1004*7c478bd9Sstevel@tonic-gate pre_and_post_cleanup(RM_PRE); 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate devi_tree_walk(&dci, flags, NULL); 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate if (dci.dci_error) { 1009*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate /* handle post-cleanup operations desired by the modules. */ 1013*7c478bd9Sstevel@tonic-gate pre_and_post_cleanup(RM_POST); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate * Remove dangling entries from /etc/devices/devid_cache 1017*7c478bd9Sstevel@tonic-gate * if we forceloaded the entire device tree. 1018*7c478bd9Sstevel@tonic-gate */ 1019*7c478bd9Sstevel@tonic-gate if (cleanup && (flags & DINFOFORCE) == 0) 1020*7c478bd9Sstevel@tonic-gate (void) modctl(MODCLEANUP, NULL, 0, NULL); 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate unlock_dev(SYNC_STATE); 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1026*7c478bd9Sstevel@tonic-gate static void 1027*7c478bd9Sstevel@tonic-gate print_cache_signal(int signo) 1028*7c478bd9Sstevel@tonic-gate { 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) { 1031*7c478bd9Sstevel@tonic-gate err_print("signal SIGUSR1 failed: %s\n", strerror(errno)); 1032*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate /* 1037*7c478bd9Sstevel@tonic-gate * Register with eventd for messages. Create doors for synchronous 1038*7c478bd9Sstevel@tonic-gate * link creation. 1039*7c478bd9Sstevel@tonic-gate */ 1040*7c478bd9Sstevel@tonic-gate static void 1041*7c478bd9Sstevel@tonic-gate daemon_update(void) 1042*7c478bd9Sstevel@tonic-gate { 1043*7c478bd9Sstevel@tonic-gate int fd; 1044*7c478bd9Sstevel@tonic-gate char *fcn = "daemon_update: "; 1045*7c478bd9Sstevel@tonic-gate char door_file[MAXPATHLEN]; 1046*7c478bd9Sstevel@tonic-gate const char *subclass_list; 1047*7c478bd9Sstevel@tonic-gate sysevent_handle_t *sysevent_hp; 1048*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%senter\n", fcn); 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) { 1051*7c478bd9Sstevel@tonic-gate err_print("signal SIGUSR1 failed: %s\n", strerror(errno)); 1052*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate if (snprintf(door_file, sizeof (door_file), 1056*7c478bd9Sstevel@tonic-gate "%s%s", root_dir, DEVFSADM_SERVICE_DOOR) >= sizeof (door_file)) { 1057*7c478bd9Sstevel@tonic-gate err_print("update_daemon failed to open sysevent service " 1058*7c478bd9Sstevel@tonic-gate "door\n"); 1059*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate if ((sysevent_hp = sysevent_open_channel_alt( 1062*7c478bd9Sstevel@tonic-gate door_file)) == NULL) { 1063*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_DOOR, 1064*7c478bd9Sstevel@tonic-gate door_file, strerror(errno)); 1065*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate if (sysevent_bind_subscriber(sysevent_hp, event_handler) != 0) { 1068*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_DOOR, 1069*7c478bd9Sstevel@tonic-gate door_file, strerror(errno)); 1070*7c478bd9Sstevel@tonic-gate (void) sysevent_close_channel(sysevent_hp); 1071*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate subclass_list = EC_SUB_ALL; 1074*7c478bd9Sstevel@tonic-gate if (sysevent_register_event(sysevent_hp, EC_ALL, &subclass_list, 1) 1075*7c478bd9Sstevel@tonic-gate != 0) { 1076*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_DOOR, 1077*7c478bd9Sstevel@tonic-gate door_file, strerror(errno)); 1078*7c478bd9Sstevel@tonic-gate (void) sysevent_unbind_subscriber(sysevent_hp); 1079*7c478bd9Sstevel@tonic-gate (void) sysevent_close_channel(sysevent_hp); 1080*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate if (snprintf(door_file, sizeof (door_file), 1084*7c478bd9Sstevel@tonic-gate "%s/%s", dev_dir, ZONE_REG_DOOR) >= sizeof (door_file)) { 1085*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_ZONE_DOOR, door_file, 1086*7c478bd9Sstevel@tonic-gate strerror(ENAMETOOLONG)); 1087*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1090*7c478bd9Sstevel@tonic-gate if ((fd = open(door_file, O_RDWR | O_CREAT, ZONE_DOOR_PERMS)) == -1) { 1091*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_ZONE_DOOR, door_file, strerror(errno)); 1092*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate (void) close(fd); 1095*7c478bd9Sstevel@tonic-gate if ((fd = door_create(zone_reg_handler, NULL, 1096*7c478bd9Sstevel@tonic-gate DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 1097*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_ZONE_DOOR, door_file, strerror(errno)); 1098*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1099*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate if (fattach(fd, door_file) == -1) { 1102*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_ZONE_DOOR, door_file, strerror(errno)); 1103*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1104*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate (void) snprintf(door_file, sizeof (door_file), "%s/%s", dev_dir, 1108*7c478bd9Sstevel@tonic-gate DEVFSADM_SYNCH_DOOR); 1109*7c478bd9Sstevel@tonic-gate 1110*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1111*7c478bd9Sstevel@tonic-gate if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) { 1112*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1113*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate (void) close(fd); 1116*7c478bd9Sstevel@tonic-gate 1117*7c478bd9Sstevel@tonic-gate if ((fd = door_create(sync_handler, NULL, 1118*7c478bd9Sstevel@tonic-gate DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 1119*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1120*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1121*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate if (fattach(fd, door_file) == -1) { 1125*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1126*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1127*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate devlink_door_fd = fd; 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate /* 1132*7c478bd9Sstevel@tonic-gate * Make sure devfsadm is managing any and all configured system zones. 1133*7c478bd9Sstevel@tonic-gate */ 1134*7c478bd9Sstevel@tonic-gate if (register_all_zones() != DEVFSADM_SUCCESS) { 1135*7c478bd9Sstevel@tonic-gate err_print(ZONE_LIST_FAILED, strerror(errno)); 1136*7c478bd9Sstevel@tonic-gate } 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%spausing\n", fcn); 1139*7c478bd9Sstevel@tonic-gate for (;;) { 1140*7c478bd9Sstevel@tonic-gate (void) pause(); 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1145*7c478bd9Sstevel@tonic-gate static void 1146*7c478bd9Sstevel@tonic-gate sync_handler(void *cookie, char *ap, size_t asize, 1147*7c478bd9Sstevel@tonic-gate door_desc_t *dp, uint_t ndesc) 1148*7c478bd9Sstevel@tonic-gate { 1149*7c478bd9Sstevel@tonic-gate door_cred_t dcred; 1150*7c478bd9Sstevel@tonic-gate struct dca_off *dcp, rdca; 1151*7c478bd9Sstevel@tonic-gate struct dca_impl dci; 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate /* 1154*7c478bd9Sstevel@tonic-gate * Must be root to make this call 1155*7c478bd9Sstevel@tonic-gate * If caller is not root, don't touch its data. 1156*7c478bd9Sstevel@tonic-gate */ 1157*7c478bd9Sstevel@tonic-gate if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) { 1158*7c478bd9Sstevel@tonic-gate dcp = ⤷ 1159*7c478bd9Sstevel@tonic-gate dcp->dca_error = EPERM; 1160*7c478bd9Sstevel@tonic-gate goto out; 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate assert(ap); 1164*7c478bd9Sstevel@tonic-gate assert(asize == sizeof (*dcp)); 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate dcp = (void *)ap; 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * Root is always present and is the first component of "name" member 1170*7c478bd9Sstevel@tonic-gate */ 1171*7c478bd9Sstevel@tonic-gate assert(dcp->dca_root == 0); 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate /* 1174*7c478bd9Sstevel@tonic-gate * The structure passed in by the door_client uses offsets 1175*7c478bd9Sstevel@tonic-gate * instead of pointers to work across address space boundaries. 1176*7c478bd9Sstevel@tonic-gate * Now copy the data into a structure (dca_impl) which uses 1177*7c478bd9Sstevel@tonic-gate * pointers. 1178*7c478bd9Sstevel@tonic-gate */ 1179*7c478bd9Sstevel@tonic-gate dci.dci_root = &dcp->dca_name[dcp->dca_root]; 1180*7c478bd9Sstevel@tonic-gate dci.dci_minor = dcp->dca_minor ? &dcp->dca_name[dcp->dca_minor] : NULL; 1181*7c478bd9Sstevel@tonic-gate dci.dci_driver = 1182*7c478bd9Sstevel@tonic-gate dcp->dca_driver ? &dcp->dca_name[dcp->dca_driver] : NULL; 1183*7c478bd9Sstevel@tonic-gate dci.dci_error = 0; 1184*7c478bd9Sstevel@tonic-gate dci.dci_flags = dcp->dca_flags | (dci.dci_driver ? DCA_LOAD_DRV : 0); 1185*7c478bd9Sstevel@tonic-gate dci.dci_arg = NULL; 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate lock_dev(); 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate devi_tree_walk(&dci, DINFOCPYALL, NULL); 1190*7c478bd9Sstevel@tonic-gate 1191*7c478bd9Sstevel@tonic-gate unlock_dev(CACHE_STATE); 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate dcp->dca_error = dci.dci_error; 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate startup_cache_sync_thread(); 1196*7c478bd9Sstevel@tonic-gate 1197*7c478bd9Sstevel@tonic-gate out: 1198*7c478bd9Sstevel@tonic-gate (void) door_return((char *)dcp, sizeof (*dcp), NULL, 0); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate static void 1202*7c478bd9Sstevel@tonic-gate lock_dev(void) 1203*7c478bd9Sstevel@tonic-gate { 1204*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "lock_dev(): entered\n"); 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate if (build_dev == FALSE) 1207*7c478bd9Sstevel@tonic-gate return; 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate /* lockout other threads from /dev */ 1210*7c478bd9Sstevel@tonic-gate while (sema_wait(&dev_sema) != 0); 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * Lock out other devfsadm processes from /dev. 1214*7c478bd9Sstevel@tonic-gate * If this wasn't the last process to run, 1215*7c478bd9Sstevel@tonic-gate * clear caches 1216*7c478bd9Sstevel@tonic-gate */ 1217*7c478bd9Sstevel@tonic-gate if (enter_dev_lock() != getpid()) { 1218*7c478bd9Sstevel@tonic-gate invalidate_enumerate_cache(); 1219*7c478bd9Sstevel@tonic-gate rm_all_links_from_cache(); 1220*7c478bd9Sstevel@tonic-gate (void) di_devlink_close(&devlink_cache, DI_LINK_ERROR); 1221*7c478bd9Sstevel@tonic-gate devlink_cache = NULL; 1222*7c478bd9Sstevel@tonic-gate } 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate /* 1225*7c478bd9Sstevel@tonic-gate * (re)load the reverse links database if not 1226*7c478bd9Sstevel@tonic-gate * already cached. 1227*7c478bd9Sstevel@tonic-gate */ 1228*7c478bd9Sstevel@tonic-gate if (devlink_cache == NULL) 1229*7c478bd9Sstevel@tonic-gate devlink_cache = di_devlink_open(root_dir, 0); 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate /* 1233*7c478bd9Sstevel@tonic-gate * If modules were unloaded, reload them. Also use module status 1234*7c478bd9Sstevel@tonic-gate * as an indication that we should check to see if other binding 1235*7c478bd9Sstevel@tonic-gate * files need to be reloaded. 1236*7c478bd9Sstevel@tonic-gate */ 1237*7c478bd9Sstevel@tonic-gate if (module_head == NULL) { 1238*7c478bd9Sstevel@tonic-gate load_modules(); 1239*7c478bd9Sstevel@tonic-gate read_minor_perm_file(); 1240*7c478bd9Sstevel@tonic-gate read_driver_aliases_file(); 1241*7c478bd9Sstevel@tonic-gate read_devlinktab_file(); 1242*7c478bd9Sstevel@tonic-gate read_logindevperm_file(); 1243*7c478bd9Sstevel@tonic-gate } 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate if (module_head != NULL) 1246*7c478bd9Sstevel@tonic-gate return; 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate if (strcmp(prog, DEVLINKS) == 0) { 1249*7c478bd9Sstevel@tonic-gate if (devlinktab_list == NULL) { 1250*7c478bd9Sstevel@tonic-gate err_print(NO_LINKTAB, devlinktab_file); 1251*7c478bd9Sstevel@tonic-gate err_print(NO_MODULES, module_dirs); 1252*7c478bd9Sstevel@tonic-gate err_print(ABORTING); 1253*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate } else { 1256*7c478bd9Sstevel@tonic-gate err_print(NO_MODULES, module_dirs); 1257*7c478bd9Sstevel@tonic-gate if (strcmp(prog, DEVFSADM) == 0) { 1258*7c478bd9Sstevel@tonic-gate err_print(MODIFY_PATH); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate } 1261*7c478bd9Sstevel@tonic-gate } 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate static void 1264*7c478bd9Sstevel@tonic-gate unlock_dev(int flag) 1265*7c478bd9Sstevel@tonic-gate { 1266*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "unlock_dev(): entered\n"); 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate if (build_dev == FALSE) 1269*7c478bd9Sstevel@tonic-gate return; 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate assert(devlink_cache); 1272*7c478bd9Sstevel@tonic-gate assert(flag == SYNC_STATE || flag == CACHE_STATE); 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate 1275*7c478bd9Sstevel@tonic-gate if (flag == SYNC_STATE) { 1276*7c478bd9Sstevel@tonic-gate unload_modules(); 1277*7c478bd9Sstevel@tonic-gate if (update_database) 1278*7c478bd9Sstevel@tonic-gate (void) di_devlink_update(devlink_cache); 1279*7c478bd9Sstevel@tonic-gate (void) di_devlink_close(&devlink_cache, 0); 1280*7c478bd9Sstevel@tonic-gate devlink_cache = NULL; 1281*7c478bd9Sstevel@tonic-gate } 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate exit_dev_lock(); 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate (void) sema_post(&dev_sema); 1286*7c478bd9Sstevel@tonic-gate } 1287*7c478bd9Sstevel@tonic-gate 1288*7c478bd9Sstevel@tonic-gate /* 1289*7c478bd9Sstevel@tonic-gate * Contact the daemon to register the identified zone. We do everything with 1290*7c478bd9Sstevel@tonic-gate * zone names, for simplicity. 1291*7c478bd9Sstevel@tonic-gate */ 1292*7c478bd9Sstevel@tonic-gate static void 1293*7c478bd9Sstevel@tonic-gate call_zone_register(char *zone_name, int regop) 1294*7c478bd9Sstevel@tonic-gate { 1295*7c478bd9Sstevel@tonic-gate int doorfd, ret, retries = 0; 1296*7c478bd9Sstevel@tonic-gate door_arg_t arg; 1297*7c478bd9Sstevel@tonic-gate struct zreg z; 1298*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 1299*7c478bd9Sstevel@tonic-gate 1300*7c478bd9Sstevel@tonic-gate assert(regop == ZONE_REG || regop == ZONE_UNREG); 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 1303*7c478bd9Sstevel@tonic-gate err_print(INVALID_ZONE, zone_name); 1304*7c478bd9Sstevel@tonic-gate return; 1305*7c478bd9Sstevel@tonic-gate } 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate z.zreg_error = 0; 1308*7c478bd9Sstevel@tonic-gate z.zreg_op = regop; 1309*7c478bd9Sstevel@tonic-gate (void) strlcpy(z.zreg_zonename, zone_name, ZONENAME_MAX); 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "/dev/%s", ZONE_REG_DOOR); 1312*7c478bd9Sstevel@tonic-gate if ((doorfd = open(path, O_RDWR)) == -1) { 1313*7c478bd9Sstevel@tonic-gate return; 1314*7c478bd9Sstevel@tonic-gate } 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate bzero(&arg, sizeof (arg)); 1317*7c478bd9Sstevel@tonic-gate arg.data_ptr = (char *)&z; 1318*7c478bd9Sstevel@tonic-gate arg.data_size = sizeof (z); 1319*7c478bd9Sstevel@tonic-gate arg.rbuf = (char *)&z; 1320*7c478bd9Sstevel@tonic-gate arg.rsize = sizeof (z); 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * If the daemon is running, tell it about the zone. If not, it's 1324*7c478bd9Sstevel@tonic-gate * ok. When it next gets run by the system (because there is 1325*7c478bd9Sstevel@tonic-gate * device-related work to do), it will load the list of zones from 1326*7c478bd9Sstevel@tonic-gate * the kernel. 1327*7c478bd9Sstevel@tonic-gate */ 1328*7c478bd9Sstevel@tonic-gate while (((ret = door_call(doorfd, &arg)) == -1) && retries++ < 3) { 1329*7c478bd9Sstevel@tonic-gate (void) sleep(retries); 1330*7c478bd9Sstevel@tonic-gate } 1331*7c478bd9Sstevel@tonic-gate (void) close(doorfd); 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate if (ret != 0) { 1334*7c478bd9Sstevel@tonic-gate return; 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate switch (z.zreg_error) { 1338*7c478bd9Sstevel@tonic-gate case ZONE_SUCCESS: 1339*7c478bd9Sstevel@tonic-gate break; 1340*7c478bd9Sstevel@tonic-gate case ZONE_ERR_NOZONE: 1341*7c478bd9Sstevel@tonic-gate err_print(ZONE_REG_FAILED, zone_name, strerror(z.zreg_errno)); 1342*7c478bd9Sstevel@tonic-gate break; 1343*7c478bd9Sstevel@tonic-gate case ZONE_ERR_DOOR: 1344*7c478bd9Sstevel@tonic-gate err_print(ZONE_DOOR_MKFAIL, zone_name, strerror(z.zreg_errno)); 1345*7c478bd9Sstevel@tonic-gate break; 1346*7c478bd9Sstevel@tonic-gate case ZONE_ERR_REPOSITORY: 1347*7c478bd9Sstevel@tonic-gate err_print(ZONE_REP_FAILED, zone_name, strerror(z.zreg_errno)); 1348*7c478bd9Sstevel@tonic-gate break; 1349*7c478bd9Sstevel@tonic-gate case ZONE_ERR_NOLIB: 1350*7c478bd9Sstevel@tonic-gate err_print(ZONE_LIB_MISSING); 1351*7c478bd9Sstevel@tonic-gate break; 1352*7c478bd9Sstevel@tonic-gate default: 1353*7c478bd9Sstevel@tonic-gate err_print(ZONE_REG_FAILED, zone_name, strerror(z.zreg_errno)); 1354*7c478bd9Sstevel@tonic-gate break; 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate } 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate /* 1359*7c478bd9Sstevel@tonic-gate * The following routines are the daemon-side code for managing the set of 1360*7c478bd9Sstevel@tonic-gate * currently registered zones. 1361*7c478bd9Sstevel@tonic-gate * 1362*7c478bd9Sstevel@tonic-gate * TODO: improve brain-dead list performance--- use libuutil avl tree or hash? 1363*7c478bd9Sstevel@tonic-gate */ 1364*7c478bd9Sstevel@tonic-gate static void 1365*7c478bd9Sstevel@tonic-gate zlist_insert(struct zone_devinfo *newzone) 1366*7c478bd9Sstevel@tonic-gate { 1367*7c478bd9Sstevel@tonic-gate struct zone_devinfo *z; 1368*7c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&zone_mutex)); 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate if (zone_head == NULL) { 1371*7c478bd9Sstevel@tonic-gate zone_head = newzone; 1372*7c478bd9Sstevel@tonic-gate return; 1373*7c478bd9Sstevel@tonic-gate } 1374*7c478bd9Sstevel@tonic-gate z = zlist_remove(newzone->zone_name); 1375*7c478bd9Sstevel@tonic-gate if (z != NULL) 1376*7c478bd9Sstevel@tonic-gate delete_zone(z); 1377*7c478bd9Sstevel@tonic-gate newzone->zone_next = zone_head; 1378*7c478bd9Sstevel@tonic-gate zone_head = newzone; 1379*7c478bd9Sstevel@tonic-gate } 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate static void 1382*7c478bd9Sstevel@tonic-gate delete_zone(struct zone_devinfo *z) { 1383*7c478bd9Sstevel@tonic-gate char door_file[PATH_MAX]; 1384*7c478bd9Sstevel@tonic-gate 1385*7c478bd9Sstevel@tonic-gate /* 1386*7c478bd9Sstevel@tonic-gate * Tidy up by withdrawing our door from the zone. 1387*7c478bd9Sstevel@tonic-gate */ 1388*7c478bd9Sstevel@tonic-gate (void) snprintf(door_file, sizeof (door_file), "%s/dev/%s", 1389*7c478bd9Sstevel@tonic-gate z->zone_path, DEVFSADM_SYNCH_DOOR); 1390*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate zonecfg_fini_handle(z->zone_dochdl); 1393*7c478bd9Sstevel@tonic-gate free(z->zone_path); 1394*7c478bd9Sstevel@tonic-gate free(z->zone_name); 1395*7c478bd9Sstevel@tonic-gate free(z); 1396*7c478bd9Sstevel@tonic-gate } 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate static struct zone_devinfo * 1399*7c478bd9Sstevel@tonic-gate zlist_remove(char *zone_name) 1400*7c478bd9Sstevel@tonic-gate { 1401*7c478bd9Sstevel@tonic-gate struct zone_devinfo *z, *unlinked = NULL, **prevnextp; 1402*7c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&zone_mutex)); 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate prevnextp = &zone_head; 1405*7c478bd9Sstevel@tonic-gate for (z = zone_head; z != NULL; z = z->zone_next) { 1406*7c478bd9Sstevel@tonic-gate if (strcmp(zone_name, z->zone_name) == 0) { 1407*7c478bd9Sstevel@tonic-gate unlinked = z; 1408*7c478bd9Sstevel@tonic-gate *prevnextp = z->zone_next; 1409*7c478bd9Sstevel@tonic-gate return (unlinked); 1410*7c478bd9Sstevel@tonic-gate } 1411*7c478bd9Sstevel@tonic-gate prevnextp = &(z->zone_next); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate return (NULL); 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate /* 1417*7c478bd9Sstevel@tonic-gate * Delete all zones. Note that this should *only* be called in the exit 1418*7c478bd9Sstevel@tonic-gate * path of the daemon, as it does not take the zone_mutex-- this is because 1419*7c478bd9Sstevel@tonic-gate * we could wind up calling devfsadm_exit() with that zone_mutex_held. 1420*7c478bd9Sstevel@tonic-gate */ 1421*7c478bd9Sstevel@tonic-gate static void 1422*7c478bd9Sstevel@tonic-gate zlist_deleteall_unlocked(void) 1423*7c478bd9Sstevel@tonic-gate { 1424*7c478bd9Sstevel@tonic-gate struct zone_devinfo *tofree; 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate while (zone_head != NULL) { 1427*7c478bd9Sstevel@tonic-gate tofree = zone_head; 1428*7c478bd9Sstevel@tonic-gate zone_head = zone_head->zone_next; 1429*7c478bd9Sstevel@tonic-gate delete_zone(tofree); 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate assert(zone_head == NULL); 1432*7c478bd9Sstevel@tonic-gate } 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate static int 1435*7c478bd9Sstevel@tonic-gate zone_register(char *zone_name) 1436*7c478bd9Sstevel@tonic-gate { 1437*7c478bd9Sstevel@tonic-gate char door_file[MAXPATHLEN], zpath[MAXPATHLEN]; 1438*7c478bd9Sstevel@tonic-gate int fd; 1439*7c478bd9Sstevel@tonic-gate int need_unlink = 0, error = ZONE_SUCCESS, myerrno = 0; 1440*7c478bd9Sstevel@tonic-gate zone_dochandle_t hdl = NULL; 1441*7c478bd9Sstevel@tonic-gate void *dlhdl = NULL; 1442*7c478bd9Sstevel@tonic-gate struct zone_devinfo *newzone = NULL; 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&zone_mutex)); 1445*7c478bd9Sstevel@tonic-gate 1446*7c478bd9Sstevel@tonic-gate if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) { 1447*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_NOLIB; 1448*7c478bd9Sstevel@tonic-gate goto bad; 1449*7c478bd9Sstevel@tonic-gate } 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) { 1452*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_NOZONE; 1453*7c478bd9Sstevel@tonic-gate myerrno = errno; 1454*7c478bd9Sstevel@tonic-gate goto bad; 1455*7c478bd9Sstevel@tonic-gate } 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate if (snprintf(door_file, sizeof (door_file), "%s/dev/%s", 1458*7c478bd9Sstevel@tonic-gate zpath, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) { 1459*7c478bd9Sstevel@tonic-gate myerrno = ENAMETOOLONG; /* synthesize a reasonable errno */ 1460*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_DOOR; 1461*7c478bd9Sstevel@tonic-gate goto bad; 1462*7c478bd9Sstevel@tonic-gate } 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1465*7c478bd9Sstevel@tonic-gate if ((fd = open(door_file, O_RDWR | O_CREAT, ZONE_DOOR_PERMS)) == -1) { 1466*7c478bd9Sstevel@tonic-gate myerrno = errno; 1467*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_DOOR; 1468*7c478bd9Sstevel@tonic-gate goto bad; 1469*7c478bd9Sstevel@tonic-gate } 1470*7c478bd9Sstevel@tonic-gate need_unlink = 1; 1471*7c478bd9Sstevel@tonic-gate (void) close(fd); 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate if (fattach(devlink_door_fd, door_file) == -1) { 1474*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_DOOR; 1475*7c478bd9Sstevel@tonic-gate myerrno = errno; 1476*7c478bd9Sstevel@tonic-gate goto bad; 1477*7c478bd9Sstevel@tonic-gate } 1478*7c478bd9Sstevel@tonic-gate 1479*7c478bd9Sstevel@tonic-gate if ((hdl = zonecfg_init_handle()) == NULL) { 1480*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_REPOSITORY; 1481*7c478bd9Sstevel@tonic-gate myerrno = errno; 1482*7c478bd9Sstevel@tonic-gate goto bad; 1483*7c478bd9Sstevel@tonic-gate } 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate if ((zonecfg_get_snapshot_handle(zone_name, hdl)) != Z_OK) { 1486*7c478bd9Sstevel@tonic-gate error = ZONE_ERR_REPOSITORY; 1487*7c478bd9Sstevel@tonic-gate myerrno = errno; 1488*7c478bd9Sstevel@tonic-gate goto bad; 1489*7c478bd9Sstevel@tonic-gate } 1490*7c478bd9Sstevel@tonic-gate 1491*7c478bd9Sstevel@tonic-gate newzone = s_malloc(sizeof (struct zone_devinfo)); 1492*7c478bd9Sstevel@tonic-gate newzone->zone_path = s_strdup(zpath); 1493*7c478bd9Sstevel@tonic-gate newzone->zone_name = s_strdup(zone_name); 1494*7c478bd9Sstevel@tonic-gate newzone->zone_next = NULL; 1495*7c478bd9Sstevel@tonic-gate newzone->zone_dochdl = hdl; 1496*7c478bd9Sstevel@tonic-gate zlist_insert(newzone); 1497*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate return (ZONE_SUCCESS); 1500*7c478bd9Sstevel@tonic-gate 1501*7c478bd9Sstevel@tonic-gate bad: 1502*7c478bd9Sstevel@tonic-gate (void) devfsadm_errprint("%s[%ld]: failed to register zone %s: %s", 1503*7c478bd9Sstevel@tonic-gate prog, getpid(), zone_name, strerror(myerrno)); 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate assert(newzone == NULL); 1506*7c478bd9Sstevel@tonic-gate if (need_unlink) 1507*7c478bd9Sstevel@tonic-gate (void) s_unlink(door_file); 1508*7c478bd9Sstevel@tonic-gate if (hdl) 1509*7c478bd9Sstevel@tonic-gate zonecfg_fini_handle(hdl); 1510*7c478bd9Sstevel@tonic-gate if (dlhdl) 1511*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 1512*7c478bd9Sstevel@tonic-gate errno = myerrno; 1513*7c478bd9Sstevel@tonic-gate return (error); 1514*7c478bd9Sstevel@tonic-gate } 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate static int 1517*7c478bd9Sstevel@tonic-gate zone_unregister(char *zone_name) 1518*7c478bd9Sstevel@tonic-gate { 1519*7c478bd9Sstevel@tonic-gate struct zone_devinfo *z; 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&zone_mutex)); 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate if ((z = zlist_remove(zone_name)) == NULL) 1524*7c478bd9Sstevel@tonic-gate return (ZONE_ERR_NOZONE); 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate delete_zone(z); 1527*7c478bd9Sstevel@tonic-gate return (ZONE_SUCCESS); 1528*7c478bd9Sstevel@tonic-gate } 1529*7c478bd9Sstevel@tonic-gate 1530*7c478bd9Sstevel@tonic-gate /* 1531*7c478bd9Sstevel@tonic-gate * Called by the daemon when it receives a door call to the zone registration 1532*7c478bd9Sstevel@tonic-gate * door. 1533*7c478bd9Sstevel@tonic-gate */ 1534*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1535*7c478bd9Sstevel@tonic-gate static void 1536*7c478bd9Sstevel@tonic-gate zone_reg_handler(void *cookie, char *ap, size_t asize, door_desc_t *dp, 1537*7c478bd9Sstevel@tonic-gate uint_t ndesc) 1538*7c478bd9Sstevel@tonic-gate { 1539*7c478bd9Sstevel@tonic-gate door_cred_t dcred; 1540*7c478bd9Sstevel@tonic-gate struct zreg *zregp, rzreg; 1541*7c478bd9Sstevel@tonic-gate 1542*7c478bd9Sstevel@tonic-gate /* 1543*7c478bd9Sstevel@tonic-gate * We coarsely lock the whole registration process. 1544*7c478bd9Sstevel@tonic-gate */ 1545*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&zone_mutex); 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate /* 1548*7c478bd9Sstevel@tonic-gate * Must be root to make this call 1549*7c478bd9Sstevel@tonic-gate * If caller is not root, don't touch its data. 1550*7c478bd9Sstevel@tonic-gate */ 1551*7c478bd9Sstevel@tonic-gate if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) { 1552*7c478bd9Sstevel@tonic-gate zregp = &rzreg; 1553*7c478bd9Sstevel@tonic-gate zregp->zreg_error = ZONE_ERR_REPOSITORY; 1554*7c478bd9Sstevel@tonic-gate zregp->zreg_errno = EPERM; 1555*7c478bd9Sstevel@tonic-gate goto out; 1556*7c478bd9Sstevel@tonic-gate } 1557*7c478bd9Sstevel@tonic-gate 1558*7c478bd9Sstevel@tonic-gate assert(ap); 1559*7c478bd9Sstevel@tonic-gate assert(asize == sizeof (*zregp)); 1560*7c478bd9Sstevel@tonic-gate 1561*7c478bd9Sstevel@tonic-gate zregp = (struct zreg *)(void *)ap; 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate /* 1564*7c478bd9Sstevel@tonic-gate * Kernel must know about this zone; one way of discovering this 1565*7c478bd9Sstevel@tonic-gate * is by looking up the zone id. 1566*7c478bd9Sstevel@tonic-gate */ 1567*7c478bd9Sstevel@tonic-gate if (getzoneidbyname(zregp->zreg_zonename) == -1) { 1568*7c478bd9Sstevel@tonic-gate zregp->zreg_error = ZONE_ERR_REPOSITORY; 1569*7c478bd9Sstevel@tonic-gate zregp->zreg_errno = errno; 1570*7c478bd9Sstevel@tonic-gate goto out; 1571*7c478bd9Sstevel@tonic-gate } 1572*7c478bd9Sstevel@tonic-gate 1573*7c478bd9Sstevel@tonic-gate if (zregp->zreg_op == ZONE_REG) { 1574*7c478bd9Sstevel@tonic-gate zregp->zreg_error = zone_register(zregp->zreg_zonename); 1575*7c478bd9Sstevel@tonic-gate zregp->zreg_errno = errno; 1576*7c478bd9Sstevel@tonic-gate } else { 1577*7c478bd9Sstevel@tonic-gate zregp->zreg_error = zone_unregister(zregp->zreg_zonename); 1578*7c478bd9Sstevel@tonic-gate zregp->zreg_errno = errno; 1579*7c478bd9Sstevel@tonic-gate } 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate out: 1582*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&zone_mutex); 1583*7c478bd9Sstevel@tonic-gate (void) door_return((char *)zregp, sizeof (*zregp), NULL, 0); 1584*7c478bd9Sstevel@tonic-gate } 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate static int 1587*7c478bd9Sstevel@tonic-gate register_all_zones(void) 1588*7c478bd9Sstevel@tonic-gate { 1589*7c478bd9Sstevel@tonic-gate zoneid_t *zids = NULL; 1590*7c478bd9Sstevel@tonic-gate uint_t nzents, nzents_saved; 1591*7c478bd9Sstevel@tonic-gate int i; 1592*7c478bd9Sstevel@tonic-gate 1593*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&zone_mutex); 1594*7c478bd9Sstevel@tonic-gate if (zone_list(NULL, &nzents) != 0) 1595*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 1596*7c478bd9Sstevel@tonic-gate 1597*7c478bd9Sstevel@tonic-gate again: 1598*7c478bd9Sstevel@tonic-gate assert(zids == NULL); 1599*7c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&zone_mutex)); 1600*7c478bd9Sstevel@tonic-gate if (nzents == 0) { 1601*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&zone_mutex); 1602*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 1603*7c478bd9Sstevel@tonic-gate } 1604*7c478bd9Sstevel@tonic-gate zids = s_zalloc(nzents * sizeof (zoneid_t)); 1605*7c478bd9Sstevel@tonic-gate nzents_saved = nzents; 1606*7c478bd9Sstevel@tonic-gate if (zone_list(zids, &nzents) != 0) { 1607*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&zone_mutex); 1608*7c478bd9Sstevel@tonic-gate free(zids); 1609*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate if (nzents != nzents_saved) { 1612*7c478bd9Sstevel@tonic-gate /* list changed, try again */ 1613*7c478bd9Sstevel@tonic-gate free(zids); 1614*7c478bd9Sstevel@tonic-gate zids = NULL; 1615*7c478bd9Sstevel@tonic-gate goto again; 1616*7c478bd9Sstevel@tonic-gate } 1617*7c478bd9Sstevel@tonic-gate 1618*7c478bd9Sstevel@tonic-gate assert(zids != NULL); 1619*7c478bd9Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 1620*7c478bd9Sstevel@tonic-gate char name[ZONENAME_MAX]; 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate if (zids[i] == GLOBAL_ZONEID) 1623*7c478bd9Sstevel@tonic-gate continue; 1624*7c478bd9Sstevel@tonic-gate if (getzonenamebyid(zids[i], name, sizeof (name)) >= 0) 1625*7c478bd9Sstevel@tonic-gate (void) zone_register(name); 1626*7c478bd9Sstevel@tonic-gate } 1627*7c478bd9Sstevel@tonic-gate 1628*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&zone_mutex); 1629*7c478bd9Sstevel@tonic-gate free(zids); 1630*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 1631*7c478bd9Sstevel@tonic-gate } 1632*7c478bd9Sstevel@tonic-gate 1633*7c478bd9Sstevel@tonic-gate /* 1634*7c478bd9Sstevel@tonic-gate * Check that if -r is set, it is not any part of a zone--- that is, that 1635*7c478bd9Sstevel@tonic-gate * the zonepath is not a substring of the root path. 1636*7c478bd9Sstevel@tonic-gate */ 1637*7c478bd9Sstevel@tonic-gate static int 1638*7c478bd9Sstevel@tonic-gate zone_pathcheck(char *checkpath) 1639*7c478bd9Sstevel@tonic-gate { 1640*7c478bd9Sstevel@tonic-gate void *dlhdl = NULL; 1641*7c478bd9Sstevel@tonic-gate char *name; 1642*7c478bd9Sstevel@tonic-gate char root[MAXPATHLEN]; /* resolved devfsadm root path */ 1643*7c478bd9Sstevel@tonic-gate char zroot[MAXPATHLEN]; /* zone root path */ 1644*7c478bd9Sstevel@tonic-gate char rzroot[MAXPATHLEN]; /* resolved zone root path */ 1645*7c478bd9Sstevel@tonic-gate char tmp[MAXPATHLEN]; 1646*7c478bd9Sstevel@tonic-gate FILE *cookie; 1647*7c478bd9Sstevel@tonic-gate int err = DEVFSADM_SUCCESS; 1648*7c478bd9Sstevel@tonic-gate 1649*7c478bd9Sstevel@tonic-gate if (checkpath[0] == '\0') 1650*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate /* 1653*7c478bd9Sstevel@tonic-gate * Check if zones is available on this system. 1654*7c478bd9Sstevel@tonic-gate */ 1655*7c478bd9Sstevel@tonic-gate if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) { 1656*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 1657*7c478bd9Sstevel@tonic-gate } 1658*7c478bd9Sstevel@tonic-gate 1659*7c478bd9Sstevel@tonic-gate bzero(root, sizeof (root)); 1660*7c478bd9Sstevel@tonic-gate if (resolvepath(checkpath, root, sizeof (root) - 1) == -1) { 1661*7c478bd9Sstevel@tonic-gate /* 1662*7c478bd9Sstevel@tonic-gate * In this case the user has done 'devfsadm -r' on some path 1663*7c478bd9Sstevel@tonic-gate * which does not yet exist, or we got some other misc. error. 1664*7c478bd9Sstevel@tonic-gate * We punt and don't resolve the path in this case. 1665*7c478bd9Sstevel@tonic-gate */ 1666*7c478bd9Sstevel@tonic-gate (void) strlcpy(root, checkpath, sizeof (root)); 1667*7c478bd9Sstevel@tonic-gate } 1668*7c478bd9Sstevel@tonic-gate 1669*7c478bd9Sstevel@tonic-gate if (strlen(root) > 0 && (root[strlen(root) - 1] != '/')) { 1670*7c478bd9Sstevel@tonic-gate (void) snprintf(tmp, sizeof (tmp), "%s/", root); 1671*7c478bd9Sstevel@tonic-gate (void) strlcpy(root, tmp, sizeof (root)); 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate cookie = setzoneent(); 1675*7c478bd9Sstevel@tonic-gate while ((name = getzoneent(cookie)) != NULL) { 1676*7c478bd9Sstevel@tonic-gate /* Skip the global zone */ 1677*7c478bd9Sstevel@tonic-gate if (strcmp(name, GLOBAL_ZONENAME) == 0) { 1678*7c478bd9Sstevel@tonic-gate free(name); 1679*7c478bd9Sstevel@tonic-gate continue; 1680*7c478bd9Sstevel@tonic-gate } 1681*7c478bd9Sstevel@tonic-gate 1682*7c478bd9Sstevel@tonic-gate if (zone_get_zonepath(name, zroot, sizeof (zroot)) != Z_OK) { 1683*7c478bd9Sstevel@tonic-gate free(name); 1684*7c478bd9Sstevel@tonic-gate continue; 1685*7c478bd9Sstevel@tonic-gate } 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate bzero(rzroot, sizeof (rzroot)); 1688*7c478bd9Sstevel@tonic-gate if (resolvepath(zroot, rzroot, sizeof (rzroot) - 1) == -1) { 1689*7c478bd9Sstevel@tonic-gate /* 1690*7c478bd9Sstevel@tonic-gate * Zone path doesn't exist, or other misc error, 1691*7c478bd9Sstevel@tonic-gate * so we try using the non-resolved pathname. 1692*7c478bd9Sstevel@tonic-gate */ 1693*7c478bd9Sstevel@tonic-gate (void) strlcpy(rzroot, zroot, sizeof (rzroot)); 1694*7c478bd9Sstevel@tonic-gate } 1695*7c478bd9Sstevel@tonic-gate if (strlen(rzroot) > 0 && (rzroot[strlen(rzroot) - 1] != '/')) { 1696*7c478bd9Sstevel@tonic-gate (void) snprintf(tmp, sizeof (tmp), "%s/", rzroot); 1697*7c478bd9Sstevel@tonic-gate (void) strlcpy(rzroot, tmp, sizeof (rzroot)); 1698*7c478bd9Sstevel@tonic-gate } 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate /* 1701*7c478bd9Sstevel@tonic-gate * Finally, the comparison. If the zone root path is a 1702*7c478bd9Sstevel@tonic-gate * leading substring of the root path, fail. 1703*7c478bd9Sstevel@tonic-gate */ 1704*7c478bd9Sstevel@tonic-gate if (strncmp(rzroot, root, strlen(rzroot)) == 0) { 1705*7c478bd9Sstevel@tonic-gate err_print(ZONE_PATHCHECK, root, name); 1706*7c478bd9Sstevel@tonic-gate err = DEVFSADM_FAILURE; 1707*7c478bd9Sstevel@tonic-gate free(name); 1708*7c478bd9Sstevel@tonic-gate break; 1709*7c478bd9Sstevel@tonic-gate } 1710*7c478bd9Sstevel@tonic-gate free(name); 1711*7c478bd9Sstevel@tonic-gate } 1712*7c478bd9Sstevel@tonic-gate endzoneent(cookie); 1713*7c478bd9Sstevel@tonic-gate (void) dlclose(dlhdl); 1714*7c478bd9Sstevel@tonic-gate return (err); 1715*7c478bd9Sstevel@tonic-gate } 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate /* 1718*7c478bd9Sstevel@tonic-gate * Called by the daemon when it receives an event from the devfsadm SLM 1719*7c478bd9Sstevel@tonic-gate * to syseventd. 1720*7c478bd9Sstevel@tonic-gate * 1721*7c478bd9Sstevel@tonic-gate * The devfsadm SLM uses a private event channel for communication to 1722*7c478bd9Sstevel@tonic-gate * devfsadmd set-up via private libsysevent interfaces. This handler is 1723*7c478bd9Sstevel@tonic-gate * used to bind to the devfsadmd channel for event delivery. 1724*7c478bd9Sstevel@tonic-gate * The devfsadmd SLM insures single calls to this routine as well as 1725*7c478bd9Sstevel@tonic-gate * synchronized event delivery. 1726*7c478bd9Sstevel@tonic-gate * 1727*7c478bd9Sstevel@tonic-gate */ 1728*7c478bd9Sstevel@tonic-gate static void 1729*7c478bd9Sstevel@tonic-gate event_handler(sysevent_t *ev) 1730*7c478bd9Sstevel@tonic-gate { 1731*7c478bd9Sstevel@tonic-gate char *path; 1732*7c478bd9Sstevel@tonic-gate char *minor; 1733*7c478bd9Sstevel@tonic-gate char *subclass; 1734*7c478bd9Sstevel@tonic-gate char *dev_ev_subclass; 1735*7c478bd9Sstevel@tonic-gate char *driver_name; 1736*7c478bd9Sstevel@tonic-gate nvlist_t *attr_list = NULL; 1737*7c478bd9Sstevel@tonic-gate int err = 0; 1738*7c478bd9Sstevel@tonic-gate int instance; 1739*7c478bd9Sstevel@tonic-gate int branch_event = 0; 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate subclass = sysevent_get_subclass_name(ev); 1742*7c478bd9Sstevel@tonic-gate vprint(EVENT_MID, "event_handler: %s id:0X%llx\n", 1743*7c478bd9Sstevel@tonic-gate subclass, sysevent_get_seq(ev)); 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate /* Check if event is an instance modification */ 1746*7c478bd9Sstevel@tonic-gate if (strcmp(subclass, ESC_DEVFS_INSTANCE_MOD) == 0) { 1747*7c478bd9Sstevel@tonic-gate devfs_instance_mod(); 1748*7c478bd9Sstevel@tonic-gate return; 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate if (sysevent_get_attr_list(ev, &attr_list) != 0) { 1751*7c478bd9Sstevel@tonic-gate vprint(EVENT_MID, "event_handler: can not get attr list\n"); 1752*7c478bd9Sstevel@tonic-gate return; 1753*7c478bd9Sstevel@tonic-gate } 1754*7c478bd9Sstevel@tonic-gate 1755*7c478bd9Sstevel@tonic-gate if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0 || 1756*7c478bd9Sstevel@tonic-gate strcmp(subclass, ESC_DEVFS_DEVI_REMOVE) == 0 || 1757*7c478bd9Sstevel@tonic-gate strcmp(subclass, ESC_DEVFS_MINOR_CREATE) == 0 || 1758*7c478bd9Sstevel@tonic-gate strcmp(subclass, ESC_DEVFS_MINOR_REMOVE) == 0) { 1759*7c478bd9Sstevel@tonic-gate if ((err = nvlist_lookup_string(attr_list, DEVFS_PATHNAME, 1760*7c478bd9Sstevel@tonic-gate &path)) != 0) 1761*7c478bd9Sstevel@tonic-gate goto out; 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0 || 1764*7c478bd9Sstevel@tonic-gate strcmp(subclass, ESC_DEVFS_DEVI_REMOVE) == 0) { 1765*7c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(attr_list, DEVFS_DEVI_CLASS, 1766*7c478bd9Sstevel@tonic-gate &dev_ev_subclass) != 0) 1767*7c478bd9Sstevel@tonic-gate dev_ev_subclass = NULL; 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(attr_list, DEVFS_DRIVER_NAME, 1770*7c478bd9Sstevel@tonic-gate &driver_name) != 0) 1771*7c478bd9Sstevel@tonic-gate driver_name = NULL; 1772*7c478bd9Sstevel@tonic-gate 1773*7c478bd9Sstevel@tonic-gate if (nvlist_lookup_int32(attr_list, DEVFS_INSTANCE, 1774*7c478bd9Sstevel@tonic-gate &instance) != 0) 1775*7c478bd9Sstevel@tonic-gate instance = -1; 1776*7c478bd9Sstevel@tonic-gate 1777*7c478bd9Sstevel@tonic-gate if (nvlist_lookup_int32(attr_list, DEVFS_BRANCH_EVENT, 1778*7c478bd9Sstevel@tonic-gate &branch_event) != 0) 1779*7c478bd9Sstevel@tonic-gate branch_event = 0; 1780*7c478bd9Sstevel@tonic-gate 1781*7c478bd9Sstevel@tonic-gate } else { 1782*7c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(attr_list, DEVFS_MINOR_NAME, 1783*7c478bd9Sstevel@tonic-gate &minor) != 0) 1784*7c478bd9Sstevel@tonic-gate minor = NULL; 1785*7c478bd9Sstevel@tonic-gate } 1786*7c478bd9Sstevel@tonic-gate 1787*7c478bd9Sstevel@tonic-gate lock_dev(); 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate if (strcmp(ESC_DEVFS_DEVI_ADD, subclass) == 0) { 1790*7c478bd9Sstevel@tonic-gate add_minor_pathname(path, NULL, dev_ev_subclass); 1791*7c478bd9Sstevel@tonic-gate if (branch_event) { 1792*7c478bd9Sstevel@tonic-gate build_and_log_event(EC_DEV_BRANCH, 1793*7c478bd9Sstevel@tonic-gate ESC_DEV_BRANCH_ADD, path, DI_NODE_NIL); 1794*7c478bd9Sstevel@tonic-gate } 1795*7c478bd9Sstevel@tonic-gate 1796*7c478bd9Sstevel@tonic-gate } else if (strcmp(ESC_DEVFS_MINOR_CREATE, subclass) == 0) { 1797*7c478bd9Sstevel@tonic-gate add_minor_pathname(path, minor, NULL); 1798*7c478bd9Sstevel@tonic-gate 1799*7c478bd9Sstevel@tonic-gate } else if (strcmp(ESC_DEVFS_MINOR_REMOVE, subclass) == 0) { 1800*7c478bd9Sstevel@tonic-gate hot_cleanup(path, minor, NULL, NULL, -1); 1801*7c478bd9Sstevel@tonic-gate 1802*7c478bd9Sstevel@tonic-gate } else { /* ESC_DEVFS_DEVI_REMOVE */ 1803*7c478bd9Sstevel@tonic-gate hot_cleanup(path, NULL, dev_ev_subclass, 1804*7c478bd9Sstevel@tonic-gate driver_name, instance); 1805*7c478bd9Sstevel@tonic-gate if (branch_event) { 1806*7c478bd9Sstevel@tonic-gate build_and_log_event(EC_DEV_BRANCH, 1807*7c478bd9Sstevel@tonic-gate ESC_DEV_BRANCH_REMOVE, path, DI_NODE_NIL); 1808*7c478bd9Sstevel@tonic-gate } 1809*7c478bd9Sstevel@tonic-gate } 1810*7c478bd9Sstevel@tonic-gate 1811*7c478bd9Sstevel@tonic-gate unlock_dev(CACHE_STATE); 1812*7c478bd9Sstevel@tonic-gate startup_cache_sync_thread(); 1813*7c478bd9Sstevel@tonic-gate 1814*7c478bd9Sstevel@tonic-gate } else if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0 || 1815*7c478bd9Sstevel@tonic-gate strcmp(subclass, ESC_DEVFS_BRANCH_REMOVE) == 0) { 1816*7c478bd9Sstevel@tonic-gate if ((err = nvlist_lookup_string(attr_list, 1817*7c478bd9Sstevel@tonic-gate DEVFS_PATHNAME, &path)) != 0) 1818*7c478bd9Sstevel@tonic-gate goto out; 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate /* just log ESC_DEV_BRANCH... event */ 1821*7c478bd9Sstevel@tonic-gate if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0) 1822*7c478bd9Sstevel@tonic-gate dev_ev_subclass = ESC_DEV_BRANCH_ADD; 1823*7c478bd9Sstevel@tonic-gate else 1824*7c478bd9Sstevel@tonic-gate dev_ev_subclass = ESC_DEV_BRANCH_REMOVE; 1825*7c478bd9Sstevel@tonic-gate 1826*7c478bd9Sstevel@tonic-gate build_and_log_event(EC_DEV_BRANCH, dev_ev_subclass, path, 1827*7c478bd9Sstevel@tonic-gate DI_NODE_NIL); 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate } else 1830*7c478bd9Sstevel@tonic-gate err_print(UNKNOWN_EVENT, subclass); 1831*7c478bd9Sstevel@tonic-gate 1832*7c478bd9Sstevel@tonic-gate out: 1833*7c478bd9Sstevel@tonic-gate if (err) 1834*7c478bd9Sstevel@tonic-gate err_print(EVENT_ATTR_LOOKUP_FAILED, strerror(err)); 1835*7c478bd9Sstevel@tonic-gate nvlist_free(attr_list); 1836*7c478bd9Sstevel@tonic-gate } 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate static void 1839*7c478bd9Sstevel@tonic-gate dca_impl_init(char *root, char *minor, struct dca_impl *dcip) 1840*7c478bd9Sstevel@tonic-gate { 1841*7c478bd9Sstevel@tonic-gate assert(root); 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate dcip->dci_root = root; 1844*7c478bd9Sstevel@tonic-gate dcip->dci_minor = minor; 1845*7c478bd9Sstevel@tonic-gate dcip->dci_driver = NULL; 1846*7c478bd9Sstevel@tonic-gate dcip->dci_error = 0; 1847*7c478bd9Sstevel@tonic-gate dcip->dci_flags = 0; 1848*7c478bd9Sstevel@tonic-gate dcip->dci_arg = NULL; 1849*7c478bd9Sstevel@tonic-gate } 1850*7c478bd9Sstevel@tonic-gate 1851*7c478bd9Sstevel@tonic-gate /* 1852*7c478bd9Sstevel@tonic-gate * Kernel logs a message when a devinfo node is attached. Try to create 1853*7c478bd9Sstevel@tonic-gate * /dev and /devices for each minor node. minorname can be NULL. 1854*7c478bd9Sstevel@tonic-gate */ 1855*7c478bd9Sstevel@tonic-gate void 1856*7c478bd9Sstevel@tonic-gate add_minor_pathname(char *node, char *minor, char *ev_subclass) 1857*7c478bd9Sstevel@tonic-gate { 1858*7c478bd9Sstevel@tonic-gate struct dca_impl dci; 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "add_minor_pathname: node_path=%s minor=%s\n", 1861*7c478bd9Sstevel@tonic-gate node, minor ? minor : "NULL"); 1862*7c478bd9Sstevel@tonic-gate 1863*7c478bd9Sstevel@tonic-gate dca_impl_init(node, minor, &dci); 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate /* 1866*7c478bd9Sstevel@tonic-gate * Restrict hotplug link creation if daemon 1867*7c478bd9Sstevel@tonic-gate * started with -i option. 1868*7c478bd9Sstevel@tonic-gate */ 1869*7c478bd9Sstevel@tonic-gate if (single_drv == TRUE) { 1870*7c478bd9Sstevel@tonic-gate dci.dci_driver = driver; 1871*7c478bd9Sstevel@tonic-gate } 1872*7c478bd9Sstevel@tonic-gate 1873*7c478bd9Sstevel@tonic-gate /* 1874*7c478bd9Sstevel@tonic-gate * We are being invoked in response to a hotplug 1875*7c478bd9Sstevel@tonic-gate * event. Also, notify RCM if nodetype indicates 1876*7c478bd9Sstevel@tonic-gate * a network device has been hotplugged. 1877*7c478bd9Sstevel@tonic-gate */ 1878*7c478bd9Sstevel@tonic-gate dci.dci_flags = DCA_HOT_PLUG | DCA_CHECK_TYPE; 1879*7c478bd9Sstevel@tonic-gate 1880*7c478bd9Sstevel@tonic-gate devi_tree_walk(&dci, DINFOPROP|DINFOMINOR, ev_subclass); 1881*7c478bd9Sstevel@tonic-gate } 1882*7c478bd9Sstevel@tonic-gate 1883*7c478bd9Sstevel@tonic-gate static di_node_t 1884*7c478bd9Sstevel@tonic-gate find_clone_node() 1885*7c478bd9Sstevel@tonic-gate { 1886*7c478bd9Sstevel@tonic-gate static di_node_t clone_node = DI_NODE_NIL; 1887*7c478bd9Sstevel@tonic-gate 1888*7c478bd9Sstevel@tonic-gate if (clone_node == DI_NODE_NIL) 1889*7c478bd9Sstevel@tonic-gate clone_node = di_init("/pseudo/clone@0", DINFOPROP); 1890*7c478bd9Sstevel@tonic-gate return (clone_node); 1891*7c478bd9Sstevel@tonic-gate } 1892*7c478bd9Sstevel@tonic-gate 1893*7c478bd9Sstevel@tonic-gate static int 1894*7c478bd9Sstevel@tonic-gate is_descendent_of(di_node_t node, char *driver) 1895*7c478bd9Sstevel@tonic-gate { 1896*7c478bd9Sstevel@tonic-gate while (node != DI_NODE_NIL) { 1897*7c478bd9Sstevel@tonic-gate char *drv = di_driver_name(node); 1898*7c478bd9Sstevel@tonic-gate if (strcmp(drv, driver) == 0) 1899*7c478bd9Sstevel@tonic-gate return (1); 1900*7c478bd9Sstevel@tonic-gate node = di_parent_node(node); 1901*7c478bd9Sstevel@tonic-gate } 1902*7c478bd9Sstevel@tonic-gate return (0); 1903*7c478bd9Sstevel@tonic-gate } 1904*7c478bd9Sstevel@tonic-gate 1905*7c478bd9Sstevel@tonic-gate /* 1906*7c478bd9Sstevel@tonic-gate * Checks the minor type. If it is an alias node, then lookup 1907*7c478bd9Sstevel@tonic-gate * the real node/minor first, then call minor_process() to 1908*7c478bd9Sstevel@tonic-gate * do the real work. 1909*7c478bd9Sstevel@tonic-gate */ 1910*7c478bd9Sstevel@tonic-gate static int 1911*7c478bd9Sstevel@tonic-gate check_minor_type(di_node_t node, di_minor_t minor, void *arg) 1912*7c478bd9Sstevel@tonic-gate { 1913*7c478bd9Sstevel@tonic-gate ddi_minor_type minor_type; 1914*7c478bd9Sstevel@tonic-gate di_node_t clone_node; 1915*7c478bd9Sstevel@tonic-gate char *mn; 1916*7c478bd9Sstevel@tonic-gate char *nt; 1917*7c478bd9Sstevel@tonic-gate struct mlist *dep; 1918*7c478bd9Sstevel@tonic-gate struct dca_impl *dcip = arg; 1919*7c478bd9Sstevel@tonic-gate 1920*7c478bd9Sstevel@tonic-gate assert(dcip); 1921*7c478bd9Sstevel@tonic-gate 1922*7c478bd9Sstevel@tonic-gate dep = dcip->dci_arg; 1923*7c478bd9Sstevel@tonic-gate 1924*7c478bd9Sstevel@tonic-gate mn = di_minor_name(minor); 1925*7c478bd9Sstevel@tonic-gate 1926*7c478bd9Sstevel@tonic-gate /* 1927*7c478bd9Sstevel@tonic-gate * We match driver here instead of in minor_process 1928*7c478bd9Sstevel@tonic-gate * as we want the actual driver name. This check is 1929*7c478bd9Sstevel@tonic-gate * unnecessary during deferred processing. 1930*7c478bd9Sstevel@tonic-gate */ 1931*7c478bd9Sstevel@tonic-gate if (dep && 1932*7c478bd9Sstevel@tonic-gate ((dcip->dci_driver && !is_descendent_of(node, dcip->dci_driver)) || 1933*7c478bd9Sstevel@tonic-gate (dcip->dci_minor && strcmp(mn, dcip->dci_minor)))) { 1934*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1935*7c478bd9Sstevel@tonic-gate } 1936*7c478bd9Sstevel@tonic-gate 1937*7c478bd9Sstevel@tonic-gate if ((dcip->dci_flags & DCA_CHECK_TYPE) && 1938*7c478bd9Sstevel@tonic-gate (nt = di_minor_nodetype(minor)) && 1939*7c478bd9Sstevel@tonic-gate (strcmp(nt, DDI_NT_NET) == 0 || strcmp(nt, DDI_NT_MAC) == 0)) { 1940*7c478bd9Sstevel@tonic-gate dcip->dci_flags |= DCA_NOTIFY_RCM; 1941*7c478bd9Sstevel@tonic-gate dcip->dci_flags &= ~DCA_CHECK_TYPE; 1942*7c478bd9Sstevel@tonic-gate } 1943*7c478bd9Sstevel@tonic-gate 1944*7c478bd9Sstevel@tonic-gate minor_type = di_minor_type(minor); 1945*7c478bd9Sstevel@tonic-gate 1946*7c478bd9Sstevel@tonic-gate if (minor_type == DDM_MINOR) { 1947*7c478bd9Sstevel@tonic-gate minor_process(node, minor, dep); 1948*7c478bd9Sstevel@tonic-gate 1949*7c478bd9Sstevel@tonic-gate } else if (minor_type == DDM_ALIAS) { 1950*7c478bd9Sstevel@tonic-gate struct mlist *cdep, clone_del = {0}; 1951*7c478bd9Sstevel@tonic-gate 1952*7c478bd9Sstevel@tonic-gate clone_node = find_clone_node(); 1953*7c478bd9Sstevel@tonic-gate if (clone_node == DI_NODE_NIL) { 1954*7c478bd9Sstevel@tonic-gate err_print(DI_INIT_FAILED, "clone", strerror(errno)); 1955*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate cdep = dep ? &clone_del : NULL; 1959*7c478bd9Sstevel@tonic-gate 1960*7c478bd9Sstevel@tonic-gate minor_process(clone_node, minor, cdep); 1961*7c478bd9Sstevel@tonic-gate 1962*7c478bd9Sstevel@tonic-gate /* 1963*7c478bd9Sstevel@tonic-gate * cache "alias" minor node and free "clone" minor 1964*7c478bd9Sstevel@tonic-gate */ 1965*7c478bd9Sstevel@tonic-gate if (cdep != NULL && cdep->head != NULL) { 1966*7c478bd9Sstevel@tonic-gate assert(cdep->tail != NULL); 1967*7c478bd9Sstevel@tonic-gate cache_deferred_minor(dep, node, minor); 1968*7c478bd9Sstevel@tonic-gate dcip->dci_arg = cdep; 1969*7c478bd9Sstevel@tonic-gate process_deferred_links(dcip, DCA_FREE_LIST); 1970*7c478bd9Sstevel@tonic-gate dcip->dci_arg = dep; 1971*7c478bd9Sstevel@tonic-gate } 1972*7c478bd9Sstevel@tonic-gate } 1973*7c478bd9Sstevel@tonic-gate 1974*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1975*7c478bd9Sstevel@tonic-gate } 1976*7c478bd9Sstevel@tonic-gate 1977*7c478bd9Sstevel@tonic-gate 1978*7c478bd9Sstevel@tonic-gate /* 1979*7c478bd9Sstevel@tonic-gate * This is the entry point for each minor node, whether walking 1980*7c478bd9Sstevel@tonic-gate * the entire tree via di_walk_minor() or processing a hotplug event 1981*7c478bd9Sstevel@tonic-gate * for a single devinfo node (via hotplug ndi_devi_online()). 1982*7c478bd9Sstevel@tonic-gate */ 1983*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1984*7c478bd9Sstevel@tonic-gate static void 1985*7c478bd9Sstevel@tonic-gate minor_process(di_node_t node, di_minor_t minor, struct mlist *dep) 1986*7c478bd9Sstevel@tonic-gate { 1987*7c478bd9Sstevel@tonic-gate create_list_t *create; 1988*7c478bd9Sstevel@tonic-gate int defer; 1989*7c478bd9Sstevel@tonic-gate 1990*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "minor_process: node=%s, minor=%s\n", 1991*7c478bd9Sstevel@tonic-gate di_node_name(node), di_minor_name(minor)); 1992*7c478bd9Sstevel@tonic-gate 1993*7c478bd9Sstevel@tonic-gate if (dep != NULL) { 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate /* 1996*7c478bd9Sstevel@tonic-gate * Reset /devices node to minor_perm perm/ownership 1997*7c478bd9Sstevel@tonic-gate * if we are here to deactivate device allocation 1998*7c478bd9Sstevel@tonic-gate */ 1999*7c478bd9Sstevel@tonic-gate if (build_devices == TRUE) { 2000*7c478bd9Sstevel@tonic-gate reset_node_permissions(node, minor); 2001*7c478bd9Sstevel@tonic-gate } 2002*7c478bd9Sstevel@tonic-gate 2003*7c478bd9Sstevel@tonic-gate if (build_dev == FALSE) { 2004*7c478bd9Sstevel@tonic-gate return; 2005*7c478bd9Sstevel@tonic-gate } 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate /* 2008*7c478bd9Sstevel@tonic-gate * This function will create any nodes for /etc/devlink.tab. 2009*7c478bd9Sstevel@tonic-gate * If devlink.tab handles link creation, we don't call any 2010*7c478bd9Sstevel@tonic-gate * devfsadm modules since that could cause duplicate caching 2011*7c478bd9Sstevel@tonic-gate * in the enumerate functions if different re strings are 2012*7c478bd9Sstevel@tonic-gate * passed that are logically identical. I'm still not 2013*7c478bd9Sstevel@tonic-gate * convinced this would cause any harm, but better to be safe. 2014*7c478bd9Sstevel@tonic-gate * 2015*7c478bd9Sstevel@tonic-gate * Deferred processing is available only for devlinks 2016*7c478bd9Sstevel@tonic-gate * created through devfsadm modules. 2017*7c478bd9Sstevel@tonic-gate */ 2018*7c478bd9Sstevel@tonic-gate if (process_devlink_compat(minor, node) == TRUE) { 2019*7c478bd9Sstevel@tonic-gate return; 2020*7c478bd9Sstevel@tonic-gate } 2021*7c478bd9Sstevel@tonic-gate } else { 2022*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "minor_process: deferred processing\n"); 2023*7c478bd9Sstevel@tonic-gate } 2024*7c478bd9Sstevel@tonic-gate 2025*7c478bd9Sstevel@tonic-gate /* 2026*7c478bd9Sstevel@tonic-gate * look for relevant link create rules in the modules, and 2027*7c478bd9Sstevel@tonic-gate * invoke the link create callback function to build a link 2028*7c478bd9Sstevel@tonic-gate * if there is a match. 2029*7c478bd9Sstevel@tonic-gate */ 2030*7c478bd9Sstevel@tonic-gate defer = 0; 2031*7c478bd9Sstevel@tonic-gate for (create = create_head; create != NULL; create = create->next) { 2032*7c478bd9Sstevel@tonic-gate if ((minor_matches_rule(node, minor, create) == TRUE) && 2033*7c478bd9Sstevel@tonic-gate class_ok(create->create->device_class) == 2034*7c478bd9Sstevel@tonic-gate DEVFSADM_SUCCESS) { 2035*7c478bd9Sstevel@tonic-gate if (call_minor_init(create->modptr) == 2036*7c478bd9Sstevel@tonic-gate DEVFSADM_FAILURE) { 2037*7c478bd9Sstevel@tonic-gate continue; 2038*7c478bd9Sstevel@tonic-gate } 2039*7c478bd9Sstevel@tonic-gate 2040*7c478bd9Sstevel@tonic-gate /* 2041*7c478bd9Sstevel@tonic-gate * If NOT doing the deferred creates (i.e. 1st pass) and 2042*7c478bd9Sstevel@tonic-gate * rule requests deferred processing cache the minor 2043*7c478bd9Sstevel@tonic-gate * data. 2044*7c478bd9Sstevel@tonic-gate * 2045*7c478bd9Sstevel@tonic-gate * If deferred processing (2nd pass), create links 2046*7c478bd9Sstevel@tonic-gate * ONLY if rule requests deferred processing. 2047*7c478bd9Sstevel@tonic-gate */ 2048*7c478bd9Sstevel@tonic-gate if (dep && ((create->create->flags & CREATE_MASK) == 2049*7c478bd9Sstevel@tonic-gate CREATE_DEFER)) { 2050*7c478bd9Sstevel@tonic-gate defer = 1; 2051*7c478bd9Sstevel@tonic-gate continue; 2052*7c478bd9Sstevel@tonic-gate } else if (dep == NULL && 2053*7c478bd9Sstevel@tonic-gate ((create->create->flags & CREATE_MASK) != 2054*7c478bd9Sstevel@tonic-gate CREATE_DEFER)) { 2055*7c478bd9Sstevel@tonic-gate continue; 2056*7c478bd9Sstevel@tonic-gate } 2057*7c478bd9Sstevel@tonic-gate 2058*7c478bd9Sstevel@tonic-gate if ((*(create->create->callback_fcn)) 2059*7c478bd9Sstevel@tonic-gate (minor, node) == DEVFSADM_TERMINATE) { 2060*7c478bd9Sstevel@tonic-gate break; 2061*7c478bd9Sstevel@tonic-gate } 2062*7c478bd9Sstevel@tonic-gate } 2063*7c478bd9Sstevel@tonic-gate } 2064*7c478bd9Sstevel@tonic-gate 2065*7c478bd9Sstevel@tonic-gate if (defer) 2066*7c478bd9Sstevel@tonic-gate cache_deferred_minor(dep, node, minor); 2067*7c478bd9Sstevel@tonic-gate } 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate 2070*7c478bd9Sstevel@tonic-gate /* 2071*7c478bd9Sstevel@tonic-gate * Cache node and minor in defer list. 2072*7c478bd9Sstevel@tonic-gate */ 2073*7c478bd9Sstevel@tonic-gate static void 2074*7c478bd9Sstevel@tonic-gate cache_deferred_minor( 2075*7c478bd9Sstevel@tonic-gate struct mlist *dep, 2076*7c478bd9Sstevel@tonic-gate di_node_t node, 2077*7c478bd9Sstevel@tonic-gate di_minor_t minor) 2078*7c478bd9Sstevel@tonic-gate { 2079*7c478bd9Sstevel@tonic-gate struct minor *mp; 2080*7c478bd9Sstevel@tonic-gate const char *fcn = "cache_deferred_minor"; 2081*7c478bd9Sstevel@tonic-gate 2082*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%s node=%s, minor=%s\n", fcn, 2083*7c478bd9Sstevel@tonic-gate di_node_name(node), di_minor_name(minor)); 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate if (dep == NULL) { 2086*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%s: cannot cache during " 2087*7c478bd9Sstevel@tonic-gate "deferred processing. Ignoring minor\n", fcn); 2088*7c478bd9Sstevel@tonic-gate return; 2089*7c478bd9Sstevel@tonic-gate } 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate mp = (struct minor *)s_zalloc(sizeof (struct minor)); 2092*7c478bd9Sstevel@tonic-gate mp->node = node; 2093*7c478bd9Sstevel@tonic-gate mp->minor = minor; 2094*7c478bd9Sstevel@tonic-gate mp->next = NULL; 2095*7c478bd9Sstevel@tonic-gate 2096*7c478bd9Sstevel@tonic-gate assert(dep->head == NULL || dep->tail != NULL); 2097*7c478bd9Sstevel@tonic-gate if (dep->head == NULL) { 2098*7c478bd9Sstevel@tonic-gate dep->head = mp; 2099*7c478bd9Sstevel@tonic-gate } else { 2100*7c478bd9Sstevel@tonic-gate dep->tail->next = mp; 2101*7c478bd9Sstevel@tonic-gate } 2102*7c478bd9Sstevel@tonic-gate dep->tail = mp; 2103*7c478bd9Sstevel@tonic-gate } 2104*7c478bd9Sstevel@tonic-gate 2105*7c478bd9Sstevel@tonic-gate /* 2106*7c478bd9Sstevel@tonic-gate * Check to see if "create" link creation rule matches this node/minor. 2107*7c478bd9Sstevel@tonic-gate * If it does, return TRUE. 2108*7c478bd9Sstevel@tonic-gate */ 2109*7c478bd9Sstevel@tonic-gate static int 2110*7c478bd9Sstevel@tonic-gate minor_matches_rule(di_node_t node, di_minor_t minor, create_list_t *create) 2111*7c478bd9Sstevel@tonic-gate { 2112*7c478bd9Sstevel@tonic-gate char *m_nodetype, *m_drvname; 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate if (create->create->node_type != NULL) { 2115*7c478bd9Sstevel@tonic-gate 2116*7c478bd9Sstevel@tonic-gate m_nodetype = di_minor_nodetype(minor); 2117*7c478bd9Sstevel@tonic-gate assert(m_nodetype != NULL); 2118*7c478bd9Sstevel@tonic-gate 2119*7c478bd9Sstevel@tonic-gate switch (create->create->flags & TYPE_MASK) { 2120*7c478bd9Sstevel@tonic-gate case TYPE_EXACT: 2121*7c478bd9Sstevel@tonic-gate if (strcmp(create->create->node_type, m_nodetype) != 2122*7c478bd9Sstevel@tonic-gate 0) { 2123*7c478bd9Sstevel@tonic-gate return (FALSE); 2124*7c478bd9Sstevel@tonic-gate } 2125*7c478bd9Sstevel@tonic-gate break; 2126*7c478bd9Sstevel@tonic-gate case TYPE_PARTIAL: 2127*7c478bd9Sstevel@tonic-gate if (strncmp(create->create->node_type, m_nodetype, 2128*7c478bd9Sstevel@tonic-gate strlen(create->create->node_type)) != 0) { 2129*7c478bd9Sstevel@tonic-gate return (FALSE); 2130*7c478bd9Sstevel@tonic-gate } 2131*7c478bd9Sstevel@tonic-gate break; 2132*7c478bd9Sstevel@tonic-gate case TYPE_RE: 2133*7c478bd9Sstevel@tonic-gate if (regexec(&(create->node_type_comp), m_nodetype, 2134*7c478bd9Sstevel@tonic-gate 0, NULL, 0) != 0) { 2135*7c478bd9Sstevel@tonic-gate return (FALSE); 2136*7c478bd9Sstevel@tonic-gate } 2137*7c478bd9Sstevel@tonic-gate break; 2138*7c478bd9Sstevel@tonic-gate } 2139*7c478bd9Sstevel@tonic-gate } 2140*7c478bd9Sstevel@tonic-gate 2141*7c478bd9Sstevel@tonic-gate if (create->create->drv_name != NULL) { 2142*7c478bd9Sstevel@tonic-gate m_drvname = di_driver_name(node); 2143*7c478bd9Sstevel@tonic-gate switch (create->create->flags & DRV_MASK) { 2144*7c478bd9Sstevel@tonic-gate case DRV_EXACT: 2145*7c478bd9Sstevel@tonic-gate if (strcmp(create->create->drv_name, m_drvname) != 0) { 2146*7c478bd9Sstevel@tonic-gate return (FALSE); 2147*7c478bd9Sstevel@tonic-gate } 2148*7c478bd9Sstevel@tonic-gate break; 2149*7c478bd9Sstevel@tonic-gate case DRV_RE: 2150*7c478bd9Sstevel@tonic-gate if (regexec(&(create->drv_name_comp), m_drvname, 2151*7c478bd9Sstevel@tonic-gate 0, NULL, 0) != 0) { 2152*7c478bd9Sstevel@tonic-gate return (FALSE); 2153*7c478bd9Sstevel@tonic-gate } 2154*7c478bd9Sstevel@tonic-gate break; 2155*7c478bd9Sstevel@tonic-gate } 2156*7c478bd9Sstevel@tonic-gate } 2157*7c478bd9Sstevel@tonic-gate 2158*7c478bd9Sstevel@tonic-gate return (TRUE); 2159*7c478bd9Sstevel@tonic-gate } 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate /* 2162*7c478bd9Sstevel@tonic-gate * If no classes were given on the command line, then return DEVFSADM_SUCCESS. 2163*7c478bd9Sstevel@tonic-gate * Otherwise, return DEVFSADM_SUCCESS if the device "class" from the module 2164*7c478bd9Sstevel@tonic-gate * matches one of the device classes given on the command line, 2165*7c478bd9Sstevel@tonic-gate * otherwise, return DEVFSADM_FAILURE. 2166*7c478bd9Sstevel@tonic-gate */ 2167*7c478bd9Sstevel@tonic-gate static int 2168*7c478bd9Sstevel@tonic-gate class_ok(char *class) 2169*7c478bd9Sstevel@tonic-gate { 2170*7c478bd9Sstevel@tonic-gate int i; 2171*7c478bd9Sstevel@tonic-gate 2172*7c478bd9Sstevel@tonic-gate if (num_classes == 0) { 2173*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2174*7c478bd9Sstevel@tonic-gate } 2175*7c478bd9Sstevel@tonic-gate 2176*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_classes; i++) { 2177*7c478bd9Sstevel@tonic-gate if (strcmp(class, classes[i]) == 0) { 2178*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2179*7c478bd9Sstevel@tonic-gate } 2180*7c478bd9Sstevel@tonic-gate } 2181*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 2182*7c478bd9Sstevel@tonic-gate } 2183*7c478bd9Sstevel@tonic-gate 2184*7c478bd9Sstevel@tonic-gate /* 2185*7c478bd9Sstevel@tonic-gate * call minor_fini on active modules, then unload ALL modules 2186*7c478bd9Sstevel@tonic-gate */ 2187*7c478bd9Sstevel@tonic-gate static void 2188*7c478bd9Sstevel@tonic-gate unload_modules(void) 2189*7c478bd9Sstevel@tonic-gate { 2190*7c478bd9Sstevel@tonic-gate module_t *module_free; 2191*7c478bd9Sstevel@tonic-gate create_list_t *create_free; 2192*7c478bd9Sstevel@tonic-gate remove_list_t *remove_free; 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate while (create_head != NULL) { 2195*7c478bd9Sstevel@tonic-gate create_free = create_head; 2196*7c478bd9Sstevel@tonic-gate create_head = create_head->next; 2197*7c478bd9Sstevel@tonic-gate 2198*7c478bd9Sstevel@tonic-gate if ((create_free->create->flags & TYPE_RE) == TYPE_RE) { 2199*7c478bd9Sstevel@tonic-gate regfree(&(create_free->node_type_comp)); 2200*7c478bd9Sstevel@tonic-gate } 2201*7c478bd9Sstevel@tonic-gate if ((create_free->create->flags & DRV_RE) == DRV_RE) { 2202*7c478bd9Sstevel@tonic-gate regfree(&(create_free->drv_name_comp)); 2203*7c478bd9Sstevel@tonic-gate } 2204*7c478bd9Sstevel@tonic-gate free(create_free); 2205*7c478bd9Sstevel@tonic-gate } 2206*7c478bd9Sstevel@tonic-gate 2207*7c478bd9Sstevel@tonic-gate while (remove_head != NULL) { 2208*7c478bd9Sstevel@tonic-gate remove_free = remove_head; 2209*7c478bd9Sstevel@tonic-gate remove_head = remove_head->next; 2210*7c478bd9Sstevel@tonic-gate free(remove_free); 2211*7c478bd9Sstevel@tonic-gate } 2212*7c478bd9Sstevel@tonic-gate 2213*7c478bd9Sstevel@tonic-gate while (module_head != NULL) { 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate if ((module_head->minor_fini != NULL) && 2216*7c478bd9Sstevel@tonic-gate ((module_head->flags & MODULE_ACTIVE) == MODULE_ACTIVE)) { 2217*7c478bd9Sstevel@tonic-gate (void) (*(module_head->minor_fini))(); 2218*7c478bd9Sstevel@tonic-gate } 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "unloading module %s\n", module_head->name); 2221*7c478bd9Sstevel@tonic-gate free(module_head->name); 2222*7c478bd9Sstevel@tonic-gate (void) dlclose(module_head->dlhandle); 2223*7c478bd9Sstevel@tonic-gate 2224*7c478bd9Sstevel@tonic-gate module_free = module_head; 2225*7c478bd9Sstevel@tonic-gate module_head = module_head->next; 2226*7c478bd9Sstevel@tonic-gate free(module_free); 2227*7c478bd9Sstevel@tonic-gate } 2228*7c478bd9Sstevel@tonic-gate } 2229*7c478bd9Sstevel@tonic-gate 2230*7c478bd9Sstevel@tonic-gate /* 2231*7c478bd9Sstevel@tonic-gate * Load devfsadm logical link processing modules. 2232*7c478bd9Sstevel@tonic-gate */ 2233*7c478bd9Sstevel@tonic-gate static void 2234*7c478bd9Sstevel@tonic-gate load_modules(void) 2235*7c478bd9Sstevel@tonic-gate { 2236*7c478bd9Sstevel@tonic-gate DIR *mod_dir; 2237*7c478bd9Sstevel@tonic-gate struct dirent *entp = NULL; 2238*7c478bd9Sstevel@tonic-gate struct dirent *retp; 2239*7c478bd9Sstevel@tonic-gate char cdir[PATH_MAX + 1]; 2240*7c478bd9Sstevel@tonic-gate char *last; 2241*7c478bd9Sstevel@tonic-gate char *mdir = module_dirs; 2242*7c478bd9Sstevel@tonic-gate char *fcn = "load_modules: "; 2243*7c478bd9Sstevel@tonic-gate 2244*7c478bd9Sstevel@tonic-gate while (*mdir != '\0') { 2245*7c478bd9Sstevel@tonic-gate 2246*7c478bd9Sstevel@tonic-gate while (*mdir == ':') { 2247*7c478bd9Sstevel@tonic-gate mdir++; 2248*7c478bd9Sstevel@tonic-gate } 2249*7c478bd9Sstevel@tonic-gate 2250*7c478bd9Sstevel@tonic-gate if (*mdir == '\0') { 2251*7c478bd9Sstevel@tonic-gate continue; 2252*7c478bd9Sstevel@tonic-gate } 2253*7c478bd9Sstevel@tonic-gate 2254*7c478bd9Sstevel@tonic-gate last = strchr(mdir, ':'); 2255*7c478bd9Sstevel@tonic-gate 2256*7c478bd9Sstevel@tonic-gate if (last == NULL) { 2257*7c478bd9Sstevel@tonic-gate last = mdir + strlen(mdir); 2258*7c478bd9Sstevel@tonic-gate } 2259*7c478bd9Sstevel@tonic-gate 2260*7c478bd9Sstevel@tonic-gate (void) strncpy(cdir, mdir, last - mdir); 2261*7c478bd9Sstevel@tonic-gate cdir[last - mdir] = '\0'; 2262*7c478bd9Sstevel@tonic-gate mdir += strlen(cdir); 2263*7c478bd9Sstevel@tonic-gate 2264*7c478bd9Sstevel@tonic-gate if ((mod_dir = opendir(cdir)) == NULL) { 2265*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "%sopendir(%s): %s\n", 2266*7c478bd9Sstevel@tonic-gate fcn, cdir, strerror(errno)); 2267*7c478bd9Sstevel@tonic-gate continue; 2268*7c478bd9Sstevel@tonic-gate } 2269*7c478bd9Sstevel@tonic-gate 2270*7c478bd9Sstevel@tonic-gate entp = s_malloc(PATH_MAX + 1 + sizeof (struct dirent)); 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate while (readdir_r(mod_dir, entp, &retp) == 0) { 2273*7c478bd9Sstevel@tonic-gate 2274*7c478bd9Sstevel@tonic-gate if (retp == NULL) { 2275*7c478bd9Sstevel@tonic-gate break; 2276*7c478bd9Sstevel@tonic-gate } 2277*7c478bd9Sstevel@tonic-gate 2278*7c478bd9Sstevel@tonic-gate if ((strcmp(entp->d_name, ".") == 0) || 2279*7c478bd9Sstevel@tonic-gate (strcmp(entp->d_name, "..") == 0)) { 2280*7c478bd9Sstevel@tonic-gate continue; 2281*7c478bd9Sstevel@tonic-gate } 2282*7c478bd9Sstevel@tonic-gate 2283*7c478bd9Sstevel@tonic-gate load_module(entp->d_name, cdir); 2284*7c478bd9Sstevel@tonic-gate } 2285*7c478bd9Sstevel@tonic-gate s_closedir(mod_dir); 2286*7c478bd9Sstevel@tonic-gate free(entp); 2287*7c478bd9Sstevel@tonic-gate } 2288*7c478bd9Sstevel@tonic-gate } 2289*7c478bd9Sstevel@tonic-gate 2290*7c478bd9Sstevel@tonic-gate static void 2291*7c478bd9Sstevel@tonic-gate load_module(char *mname, char *cdir) 2292*7c478bd9Sstevel@tonic-gate { 2293*7c478bd9Sstevel@tonic-gate _devfsadm_create_reg_t *create_reg; 2294*7c478bd9Sstevel@tonic-gate _devfsadm_remove_reg_t *remove_reg; 2295*7c478bd9Sstevel@tonic-gate create_list_t *create_list_element; 2296*7c478bd9Sstevel@tonic-gate create_list_t **create_list_next; 2297*7c478bd9Sstevel@tonic-gate remove_list_t *remove_list_element; 2298*7c478bd9Sstevel@tonic-gate remove_list_t **remove_list_next; 2299*7c478bd9Sstevel@tonic-gate char epath[PATH_MAX + 1], *end; 2300*7c478bd9Sstevel@tonic-gate char *fcn = "load_module: "; 2301*7c478bd9Sstevel@tonic-gate char *dlerrstr; 2302*7c478bd9Sstevel@tonic-gate void *dlhandle; 2303*7c478bd9Sstevel@tonic-gate module_t *module; 2304*7c478bd9Sstevel@tonic-gate int n; 2305*7c478bd9Sstevel@tonic-gate int i; 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate /* ignore any file which does not end in '.so' */ 2308*7c478bd9Sstevel@tonic-gate if ((end = strstr(mname, MODULE_SUFFIX)) != NULL) { 2309*7c478bd9Sstevel@tonic-gate if (end[strlen(MODULE_SUFFIX)] != '\0') { 2310*7c478bd9Sstevel@tonic-gate return; 2311*7c478bd9Sstevel@tonic-gate } 2312*7c478bd9Sstevel@tonic-gate } else { 2313*7c478bd9Sstevel@tonic-gate return; 2314*7c478bd9Sstevel@tonic-gate } 2315*7c478bd9Sstevel@tonic-gate 2316*7c478bd9Sstevel@tonic-gate (void) snprintf(epath, sizeof (epath), "%s/%s", cdir, mname); 2317*7c478bd9Sstevel@tonic-gate 2318*7c478bd9Sstevel@tonic-gate if ((dlhandle = dlopen(epath, RTLD_LAZY)) == NULL) { 2319*7c478bd9Sstevel@tonic-gate dlerrstr = dlerror(); 2320*7c478bd9Sstevel@tonic-gate err_print(DLOPEN_FAILED, epath, 2321*7c478bd9Sstevel@tonic-gate dlerrstr ? dlerrstr : "unknown error"); 2322*7c478bd9Sstevel@tonic-gate return; 2323*7c478bd9Sstevel@tonic-gate } 2324*7c478bd9Sstevel@tonic-gate 2325*7c478bd9Sstevel@tonic-gate /* dlsym the _devfsadm_create_reg structure */ 2326*7c478bd9Sstevel@tonic-gate if (NULL == (create_reg = (_devfsadm_create_reg_t *) 2327*7c478bd9Sstevel@tonic-gate dlsym(dlhandle, _DEVFSADM_CREATE_REG))) { 2328*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "dlsym(%s, %s): symbol not found\n", epath, 2329*7c478bd9Sstevel@tonic-gate _DEVFSADM_CREATE_REG); 2330*7c478bd9Sstevel@tonic-gate } else { 2331*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "%sdlsym(%s, %s) succeeded\n", 2332*7c478bd9Sstevel@tonic-gate fcn, epath, _DEVFSADM_CREATE_REG); 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate 2335*7c478bd9Sstevel@tonic-gate /* dlsym the _devfsadm_remove_reg structure */ 2336*7c478bd9Sstevel@tonic-gate if (NULL == (remove_reg = (_devfsadm_remove_reg_t *) 2337*7c478bd9Sstevel@tonic-gate dlsym(dlhandle, _DEVFSADM_REMOVE_REG))) { 2338*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "dlsym(%s,\n\t%s): symbol not found\n", 2339*7c478bd9Sstevel@tonic-gate epath, _DEVFSADM_REMOVE_REG); 2340*7c478bd9Sstevel@tonic-gate } else { 2341*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "dlsym(%s, %s): succeeded\n", 2342*7c478bd9Sstevel@tonic-gate epath, _DEVFSADM_REMOVE_REG); 2343*7c478bd9Sstevel@tonic-gate } 2344*7c478bd9Sstevel@tonic-gate 2345*7c478bd9Sstevel@tonic-gate vprint(MODLOAD_MID, "module %s loaded\n", epath); 2346*7c478bd9Sstevel@tonic-gate 2347*7c478bd9Sstevel@tonic-gate module = (module_t *)s_malloc(sizeof (module_t)); 2348*7c478bd9Sstevel@tonic-gate module->name = s_strdup(epath); 2349*7c478bd9Sstevel@tonic-gate module->dlhandle = dlhandle; 2350*7c478bd9Sstevel@tonic-gate 2351*7c478bd9Sstevel@tonic-gate /* dlsym other module functions, to be called later */ 2352*7c478bd9Sstevel@tonic-gate module->minor_fini = (int (*)())dlsym(dlhandle, MINOR_FINI); 2353*7c478bd9Sstevel@tonic-gate module->minor_init = (int (*)())dlsym(dlhandle, MINOR_INIT); 2354*7c478bd9Sstevel@tonic-gate module->flags = 0; 2355*7c478bd9Sstevel@tonic-gate 2356*7c478bd9Sstevel@tonic-gate /* 2357*7c478bd9Sstevel@tonic-gate * put a ptr to each struct devfsadm_create on "create_head" 2358*7c478bd9Sstevel@tonic-gate * list sorted in interpose_lvl. 2359*7c478bd9Sstevel@tonic-gate */ 2360*7c478bd9Sstevel@tonic-gate if (create_reg != NULL) { 2361*7c478bd9Sstevel@tonic-gate for (i = 0; i < create_reg->count; i++) { 2362*7c478bd9Sstevel@tonic-gate int flags = create_reg->tblp[i].flags; 2363*7c478bd9Sstevel@tonic-gate 2364*7c478bd9Sstevel@tonic-gate create_list_element = (create_list_t *) 2365*7c478bd9Sstevel@tonic-gate s_malloc(sizeof (create_list_t)); 2366*7c478bd9Sstevel@tonic-gate 2367*7c478bd9Sstevel@tonic-gate create_list_element->create = &(create_reg->tblp[i]); 2368*7c478bd9Sstevel@tonic-gate create_list_element->modptr = module; 2369*7c478bd9Sstevel@tonic-gate 2370*7c478bd9Sstevel@tonic-gate if (((flags & CREATE_MASK) != 0) && 2371*7c478bd9Sstevel@tonic-gate ((flags & CREATE_MASK) != CREATE_DEFER)) { 2372*7c478bd9Sstevel@tonic-gate free(create_list_element); 2373*7c478bd9Sstevel@tonic-gate err_print("illegal flag combination in " 2374*7c478bd9Sstevel@tonic-gate "module create\n"); 2375*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2376*7c478bd9Sstevel@tonic-gate continue; 2377*7c478bd9Sstevel@tonic-gate } 2378*7c478bd9Sstevel@tonic-gate 2379*7c478bd9Sstevel@tonic-gate if (((flags & TYPE_MASK) == 0) ^ 2380*7c478bd9Sstevel@tonic-gate (create_reg->tblp[i].node_type == NULL)) { 2381*7c478bd9Sstevel@tonic-gate free(create_list_element); 2382*7c478bd9Sstevel@tonic-gate err_print("flags value incompatible with " 2383*7c478bd9Sstevel@tonic-gate "node_type value in module create\n"); 2384*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2385*7c478bd9Sstevel@tonic-gate continue; 2386*7c478bd9Sstevel@tonic-gate } 2387*7c478bd9Sstevel@tonic-gate 2388*7c478bd9Sstevel@tonic-gate if (((flags & TYPE_MASK) != 0) && 2389*7c478bd9Sstevel@tonic-gate ((flags & TYPE_MASK) != TYPE_EXACT) && 2390*7c478bd9Sstevel@tonic-gate ((flags & TYPE_MASK) != TYPE_RE) && 2391*7c478bd9Sstevel@tonic-gate ((flags & TYPE_MASK) != TYPE_PARTIAL)) { 2392*7c478bd9Sstevel@tonic-gate free(create_list_element); 2393*7c478bd9Sstevel@tonic-gate err_print("illegal TYPE_* flag combination in " 2394*7c478bd9Sstevel@tonic-gate "module create\n"); 2395*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2396*7c478bd9Sstevel@tonic-gate continue; 2397*7c478bd9Sstevel@tonic-gate } 2398*7c478bd9Sstevel@tonic-gate 2399*7c478bd9Sstevel@tonic-gate /* precompile regular expression for efficiency */ 2400*7c478bd9Sstevel@tonic-gate if ((flags & TYPE_RE) == TYPE_RE) { 2401*7c478bd9Sstevel@tonic-gate if ((n = regcomp(&(create_list_element-> 2402*7c478bd9Sstevel@tonic-gate node_type_comp), 2403*7c478bd9Sstevel@tonic-gate create_reg->tblp[i].node_type, 2404*7c478bd9Sstevel@tonic-gate REG_EXTENDED)) != 0) { 2405*7c478bd9Sstevel@tonic-gate free(create_list_element); 2406*7c478bd9Sstevel@tonic-gate err_print(REGCOMP_FAILED, 2407*7c478bd9Sstevel@tonic-gate create_reg->tblp[i].node_type, 2408*7c478bd9Sstevel@tonic-gate n); 2409*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2410*7c478bd9Sstevel@tonic-gate continue; 2411*7c478bd9Sstevel@tonic-gate } 2412*7c478bd9Sstevel@tonic-gate } 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate if (((flags & DRV_MASK) == 0) ^ 2415*7c478bd9Sstevel@tonic-gate (create_reg->tblp[i].drv_name == NULL)) { 2416*7c478bd9Sstevel@tonic-gate if ((flags & TYPE_RE) == TYPE_RE) { 2417*7c478bd9Sstevel@tonic-gate regfree(&(create_list_element-> 2418*7c478bd9Sstevel@tonic-gate node_type_comp)); 2419*7c478bd9Sstevel@tonic-gate } 2420*7c478bd9Sstevel@tonic-gate free(create_list_element); 2421*7c478bd9Sstevel@tonic-gate err_print("flags value incompatible with " 2422*7c478bd9Sstevel@tonic-gate "drv_name value in module create\n"); 2423*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2424*7c478bd9Sstevel@tonic-gate continue; 2425*7c478bd9Sstevel@tonic-gate } 2426*7c478bd9Sstevel@tonic-gate 2427*7c478bd9Sstevel@tonic-gate if (((flags & DRV_MASK) != 0) && 2428*7c478bd9Sstevel@tonic-gate ((flags & DRV_MASK) != DRV_EXACT) && 2429*7c478bd9Sstevel@tonic-gate ((flags & DRV_MASK) != DRV_RE)) { 2430*7c478bd9Sstevel@tonic-gate if ((flags & TYPE_RE) == TYPE_RE) { 2431*7c478bd9Sstevel@tonic-gate regfree(&(create_list_element-> 2432*7c478bd9Sstevel@tonic-gate node_type_comp)); 2433*7c478bd9Sstevel@tonic-gate } 2434*7c478bd9Sstevel@tonic-gate free(create_list_element); 2435*7c478bd9Sstevel@tonic-gate err_print("illegal DRV_* flag combination in " 2436*7c478bd9Sstevel@tonic-gate "module create\n"); 2437*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2438*7c478bd9Sstevel@tonic-gate continue; 2439*7c478bd9Sstevel@tonic-gate } 2440*7c478bd9Sstevel@tonic-gate 2441*7c478bd9Sstevel@tonic-gate /* precompile regular expression for efficiency */ 2442*7c478bd9Sstevel@tonic-gate if ((create_reg->tblp[i].flags & DRV_RE) == DRV_RE) { 2443*7c478bd9Sstevel@tonic-gate if ((n = regcomp(&(create_list_element-> 2444*7c478bd9Sstevel@tonic-gate drv_name_comp), 2445*7c478bd9Sstevel@tonic-gate create_reg->tblp[i].drv_name, 2446*7c478bd9Sstevel@tonic-gate REG_EXTENDED)) != 0) { 2447*7c478bd9Sstevel@tonic-gate if ((flags & TYPE_RE) == TYPE_RE) { 2448*7c478bd9Sstevel@tonic-gate regfree(&(create_list_element-> 2449*7c478bd9Sstevel@tonic-gate node_type_comp)); 2450*7c478bd9Sstevel@tonic-gate } 2451*7c478bd9Sstevel@tonic-gate free(create_list_element); 2452*7c478bd9Sstevel@tonic-gate err_print(REGCOMP_FAILED, 2453*7c478bd9Sstevel@tonic-gate create_reg->tblp[i].drv_name, 2454*7c478bd9Sstevel@tonic-gate n); 2455*7c478bd9Sstevel@tonic-gate err_print(IGNORING_ENTRY, i, epath); 2456*7c478bd9Sstevel@tonic-gate continue; 2457*7c478bd9Sstevel@tonic-gate } 2458*7c478bd9Sstevel@tonic-gate } 2459*7c478bd9Sstevel@tonic-gate 2460*7c478bd9Sstevel@tonic-gate 2461*7c478bd9Sstevel@tonic-gate /* add to list sorted by interpose level */ 2462*7c478bd9Sstevel@tonic-gate for (create_list_next = &(create_head); 2463*7c478bd9Sstevel@tonic-gate (*create_list_next != NULL) && 2464*7c478bd9Sstevel@tonic-gate (*create_list_next)->create->interpose_lvl >= 2465*7c478bd9Sstevel@tonic-gate create_list_element->create->interpose_lvl; 2466*7c478bd9Sstevel@tonic-gate create_list_next = 2467*7c478bd9Sstevel@tonic-gate &((*create_list_next)->next)); 2468*7c478bd9Sstevel@tonic-gate create_list_element->next = *create_list_next; 2469*7c478bd9Sstevel@tonic-gate *create_list_next = create_list_element; 2470*7c478bd9Sstevel@tonic-gate } 2471*7c478bd9Sstevel@tonic-gate } 2472*7c478bd9Sstevel@tonic-gate 2473*7c478bd9Sstevel@tonic-gate /* 2474*7c478bd9Sstevel@tonic-gate * put a ptr to each struct devfsadm_remove on "remove_head" 2475*7c478bd9Sstevel@tonic-gate * list sorted by interpose_lvl. 2476*7c478bd9Sstevel@tonic-gate */ 2477*7c478bd9Sstevel@tonic-gate if (remove_reg != NULL) { 2478*7c478bd9Sstevel@tonic-gate for (i = 0; i < remove_reg->count; i++) { 2479*7c478bd9Sstevel@tonic-gate 2480*7c478bd9Sstevel@tonic-gate remove_list_element = (remove_list_t *) 2481*7c478bd9Sstevel@tonic-gate s_malloc(sizeof (remove_list_t)); 2482*7c478bd9Sstevel@tonic-gate 2483*7c478bd9Sstevel@tonic-gate remove_list_element->remove = &(remove_reg->tblp[i]); 2484*7c478bd9Sstevel@tonic-gate remove_list_element->modptr = module; 2485*7c478bd9Sstevel@tonic-gate 2486*7c478bd9Sstevel@tonic-gate for (remove_list_next = &(remove_head); 2487*7c478bd9Sstevel@tonic-gate (*remove_list_next != NULL) && 2488*7c478bd9Sstevel@tonic-gate (*remove_list_next)->remove->interpose_lvl >= 2489*7c478bd9Sstevel@tonic-gate remove_list_element->remove->interpose_lvl; 2490*7c478bd9Sstevel@tonic-gate remove_list_next = 2491*7c478bd9Sstevel@tonic-gate &((*remove_list_next)->next)); 2492*7c478bd9Sstevel@tonic-gate remove_list_element->next = *remove_list_next; 2493*7c478bd9Sstevel@tonic-gate *remove_list_next = remove_list_element; 2494*7c478bd9Sstevel@tonic-gate } 2495*7c478bd9Sstevel@tonic-gate } 2496*7c478bd9Sstevel@tonic-gate 2497*7c478bd9Sstevel@tonic-gate module->next = module_head; 2498*7c478bd9Sstevel@tonic-gate module_head = module; 2499*7c478bd9Sstevel@tonic-gate } 2500*7c478bd9Sstevel@tonic-gate 2501*7c478bd9Sstevel@tonic-gate /* 2502*7c478bd9Sstevel@tonic-gate * Create a thread to call minor_fini after some delay 2503*7c478bd9Sstevel@tonic-gate */ 2504*7c478bd9Sstevel@tonic-gate static void 2505*7c478bd9Sstevel@tonic-gate startup_cache_sync_thread() 2506*7c478bd9Sstevel@tonic-gate { 2507*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "startup_cache_sync_thread\n"); 2508*7c478bd9Sstevel@tonic-gate 2509*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&minor_fini_mutex); 2510*7c478bd9Sstevel@tonic-gate 2511*7c478bd9Sstevel@tonic-gate minor_fini_delay_restart = TRUE; 2512*7c478bd9Sstevel@tonic-gate 2513*7c478bd9Sstevel@tonic-gate if (minor_fini_thread_created == FALSE) { 2514*7c478bd9Sstevel@tonic-gate 2515*7c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, 2516*7c478bd9Sstevel@tonic-gate (void *(*)(void *))call_minor_fini_thread, NULL, 2517*7c478bd9Sstevel@tonic-gate THR_DETACHED, NULL)) { 2518*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_THREAD, "minor_fini", 2519*7c478bd9Sstevel@tonic-gate strerror(errno)); 2520*7c478bd9Sstevel@tonic-gate 2521*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&minor_fini_mutex); 2522*7c478bd9Sstevel@tonic-gate 2523*7c478bd9Sstevel@tonic-gate /* 2524*7c478bd9Sstevel@tonic-gate * just sync state here instead of 2525*7c478bd9Sstevel@tonic-gate * giving up 2526*7c478bd9Sstevel@tonic-gate */ 2527*7c478bd9Sstevel@tonic-gate lock_dev(); 2528*7c478bd9Sstevel@tonic-gate unlock_dev(SYNC_STATE); 2529*7c478bd9Sstevel@tonic-gate 2530*7c478bd9Sstevel@tonic-gate return; 2531*7c478bd9Sstevel@tonic-gate } 2532*7c478bd9Sstevel@tonic-gate minor_fini_thread_created = TRUE; 2533*7c478bd9Sstevel@tonic-gate } else { 2534*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "restarting delay\n"); 2535*7c478bd9Sstevel@tonic-gate } 2536*7c478bd9Sstevel@tonic-gate 2537*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&minor_fini_mutex); 2538*7c478bd9Sstevel@tonic-gate } 2539*7c478bd9Sstevel@tonic-gate 2540*7c478bd9Sstevel@tonic-gate /* 2541*7c478bd9Sstevel@tonic-gate * after not receiving an event for minor_fini_timeout secs, we need 2542*7c478bd9Sstevel@tonic-gate * to call the minor_fini routines 2543*7c478bd9Sstevel@tonic-gate */ 2544*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2545*7c478bd9Sstevel@tonic-gate static void 2546*7c478bd9Sstevel@tonic-gate call_minor_fini_thread(void *arg) 2547*7c478bd9Sstevel@tonic-gate { 2548*7c478bd9Sstevel@tonic-gate int count = 0; 2549*7c478bd9Sstevel@tonic-gate 2550*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&minor_fini_mutex); 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "call_minor_fini_thread starting\n"); 2553*7c478bd9Sstevel@tonic-gate 2554*7c478bd9Sstevel@tonic-gate do { 2555*7c478bd9Sstevel@tonic-gate minor_fini_delay_restart = FALSE; 2556*7c478bd9Sstevel@tonic-gate 2557*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&minor_fini_mutex); 2558*7c478bd9Sstevel@tonic-gate (void) sleep(minor_fini_timeout); 2559*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&minor_fini_mutex); 2560*7c478bd9Sstevel@tonic-gate 2561*7c478bd9Sstevel@tonic-gate /* 2562*7c478bd9Sstevel@tonic-gate * if minor_fini_delay_restart is still false then 2563*7c478bd9Sstevel@tonic-gate * we can call minor fini routines. 2564*7c478bd9Sstevel@tonic-gate * ensure that at least periodically minor_fini gets 2565*7c478bd9Sstevel@tonic-gate * called satisfying link generators depending on fini 2566*7c478bd9Sstevel@tonic-gate * being eventually called 2567*7c478bd9Sstevel@tonic-gate */ 2568*7c478bd9Sstevel@tonic-gate if ((count++ >= FORCE_CALL_MINOR_FINI) || 2569*7c478bd9Sstevel@tonic-gate (minor_fini_delay_restart == FALSE)) { 2570*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, 2571*7c478bd9Sstevel@tonic-gate "call_minor_fini starting (%d)\n", count); 2572*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&minor_fini_mutex); 2573*7c478bd9Sstevel@tonic-gate 2574*7c478bd9Sstevel@tonic-gate lock_dev(); 2575*7c478bd9Sstevel@tonic-gate unlock_dev(SYNC_STATE); 2576*7c478bd9Sstevel@tonic-gate 2577*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "call_minor_fini done\n"); 2578*7c478bd9Sstevel@tonic-gate 2579*7c478bd9Sstevel@tonic-gate /* 2580*7c478bd9Sstevel@tonic-gate * hang around before exiting just in case 2581*7c478bd9Sstevel@tonic-gate * minor_fini_delay_restart is set again 2582*7c478bd9Sstevel@tonic-gate */ 2583*7c478bd9Sstevel@tonic-gate (void) sleep(1); 2584*7c478bd9Sstevel@tonic-gate 2585*7c478bd9Sstevel@tonic-gate count = 0; 2586*7c478bd9Sstevel@tonic-gate 2587*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&minor_fini_mutex); 2588*7c478bd9Sstevel@tonic-gate } 2589*7c478bd9Sstevel@tonic-gate } while (minor_fini_delay_restart); 2590*7c478bd9Sstevel@tonic-gate 2591*7c478bd9Sstevel@tonic-gate minor_fini_thread_created = FALSE; 2592*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&minor_fini_mutex); 2593*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "call_minor_fini_thread exiting\n"); 2594*7c478bd9Sstevel@tonic-gate } 2595*7c478bd9Sstevel@tonic-gate 2596*7c478bd9Sstevel@tonic-gate /* 2597*7c478bd9Sstevel@tonic-gate * Attempt to initialize module, if a minor_init routine exists. Set 2598*7c478bd9Sstevel@tonic-gate * the active flag if the routine exists and succeeds. If it doesn't 2599*7c478bd9Sstevel@tonic-gate * exist, just set the active flag. 2600*7c478bd9Sstevel@tonic-gate */ 2601*7c478bd9Sstevel@tonic-gate static int 2602*7c478bd9Sstevel@tonic-gate call_minor_init(module_t *module) 2603*7c478bd9Sstevel@tonic-gate { 2604*7c478bd9Sstevel@tonic-gate char *fcn = "call_minor_init: "; 2605*7c478bd9Sstevel@tonic-gate 2606*7c478bd9Sstevel@tonic-gate if ((module->flags & MODULE_ACTIVE) == MODULE_ACTIVE) { 2607*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2608*7c478bd9Sstevel@tonic-gate } 2609*7c478bd9Sstevel@tonic-gate 2610*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "%smodule %s. current state: inactive\n", 2611*7c478bd9Sstevel@tonic-gate fcn, module->name); 2612*7c478bd9Sstevel@tonic-gate 2613*7c478bd9Sstevel@tonic-gate if (module->minor_init == NULL) { 2614*7c478bd9Sstevel@tonic-gate module->flags |= MODULE_ACTIVE; 2615*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "minor_init not defined\n"); 2616*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2617*7c478bd9Sstevel@tonic-gate } 2618*7c478bd9Sstevel@tonic-gate 2619*7c478bd9Sstevel@tonic-gate if ((*(module->minor_init))() == DEVFSADM_FAILURE) { 2620*7c478bd9Sstevel@tonic-gate err_print(FAILED_FOR_MODULE, MINOR_INIT, module->name); 2621*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 2622*7c478bd9Sstevel@tonic-gate } 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate vprint(INITFINI_MID, "minor_init() returns DEVFSADM_SUCCESS. " 2625*7c478bd9Sstevel@tonic-gate "new state: active\n"); 2626*7c478bd9Sstevel@tonic-gate 2627*7c478bd9Sstevel@tonic-gate module->flags |= MODULE_ACTIVE; 2628*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2629*7c478bd9Sstevel@tonic-gate } 2630*7c478bd9Sstevel@tonic-gate 2631*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2632*7c478bd9Sstevel@tonic-gate int 2633*7c478bd9Sstevel@tonic-gate devfsadm_mklink_zone(struct zone_devinfo *z, char *link, di_node_t node, 2634*7c478bd9Sstevel@tonic-gate di_minor_t minor, int flags) 2635*7c478bd9Sstevel@tonic-gate { 2636*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 2637*7c478bd9Sstevel@tonic-gate char phy_path[PATH_MAX]; 2638*7c478bd9Sstevel@tonic-gate char *dev_pathp; 2639*7c478bd9Sstevel@tonic-gate char *acontents, *aminor = NULL; 2640*7c478bd9Sstevel@tonic-gate mode_t mode; 2641*7c478bd9Sstevel@tonic-gate uid_t uid; 2642*7c478bd9Sstevel@tonic-gate gid_t gid; 2643*7c478bd9Sstevel@tonic-gate dev_t dev; 2644*7c478bd9Sstevel@tonic-gate struct zone_devtab out_match; 2645*7c478bd9Sstevel@tonic-gate 2646*7c478bd9Sstevel@tonic-gate if (zonecfg_match_dev(z->zone_dochdl, link, &out_match) != Z_OK) { 2647*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 2648*7c478bd9Sstevel@tonic-gate } 2649*7c478bd9Sstevel@tonic-gate 2650*7c478bd9Sstevel@tonic-gate vprint(ZONE_MID, "zone device match: <device match=\"%s\"> " 2651*7c478bd9Sstevel@tonic-gate "matches /dev/%s\n", out_match.zone_dev_match, link); 2652*7c478bd9Sstevel@tonic-gate 2653*7c478bd9Sstevel@tonic-gate /* 2654*7c478bd9Sstevel@tonic-gate * In daemon mode, zone_path will be non-empty. In non-daemon mode 2655*7c478bd9Sstevel@tonic-gate * it will be empty since we've already stuck the zone into dev_dir, 2656*7c478bd9Sstevel@tonic-gate * etc. 2657*7c478bd9Sstevel@tonic-gate */ 2658*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/dev/%s", z->zone_path, link); 2659*7c478bd9Sstevel@tonic-gate dev = di_minor_devt(minor); 2660*7c478bd9Sstevel@tonic-gate 2661*7c478bd9Sstevel@tonic-gate /* 2662*7c478bd9Sstevel@tonic-gate * If this is an alias node (i.e. a clone node), we have to figure 2663*7c478bd9Sstevel@tonic-gate * out the minor name. 2664*7c478bd9Sstevel@tonic-gate */ 2665*7c478bd9Sstevel@tonic-gate if (di_minor_type(minor) == DDM_ALIAS) { 2666*7c478bd9Sstevel@tonic-gate /* use /pseudo/clone@0:<driver> as the phys path */ 2667*7c478bd9Sstevel@tonic-gate (void) snprintf(phy_path, sizeof (phy_path), 2668*7c478bd9Sstevel@tonic-gate "/pseudo/clone@0:%s", 2669*7c478bd9Sstevel@tonic-gate di_driver_name(di_minor_devinfo(minor))); 2670*7c478bd9Sstevel@tonic-gate aminor = di_minor_name(minor); 2671*7c478bd9Sstevel@tonic-gate acontents = phy_path; 2672*7c478bd9Sstevel@tonic-gate } else { 2673*7c478bd9Sstevel@tonic-gate if ((dev_pathp = di_devfs_path(node)) == NULL) { 2674*7c478bd9Sstevel@tonic-gate err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 2675*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 2676*7c478bd9Sstevel@tonic-gate } 2677*7c478bd9Sstevel@tonic-gate (void) snprintf(phy_path, sizeof (phy_path), "%s:%s", 2678*7c478bd9Sstevel@tonic-gate dev_pathp, di_minor_name(minor)); 2679*7c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_pathp); 2680*7c478bd9Sstevel@tonic-gate acontents = phy_path; 2681*7c478bd9Sstevel@tonic-gate } 2682*7c478bd9Sstevel@tonic-gate 2683*7c478bd9Sstevel@tonic-gate 2684*7c478bd9Sstevel@tonic-gate getattr(acontents, aminor, di_minor_spectype(minor), dev, 2685*7c478bd9Sstevel@tonic-gate &mode, &uid, &gid); 2686*7c478bd9Sstevel@tonic-gate vprint(ZONE_MID, "zone getattr(%s, %s, %d, %lu, 0%lo, %lu, %lu)\n", 2687*7c478bd9Sstevel@tonic-gate acontents, aminor ? aminor : "<NULL>", di_minor_spectype(minor), 2688*7c478bd9Sstevel@tonic-gate dev, mode, uid, gid); 2689*7c478bd9Sstevel@tonic-gate 2690*7c478bd9Sstevel@tonic-gate /* 2691*7c478bd9Sstevel@tonic-gate * Create the node; if the enclosing directory doesn't exist, 2692*7c478bd9Sstevel@tonic-gate * make it too. 2693*7c478bd9Sstevel@tonic-gate */ 2694*7c478bd9Sstevel@tonic-gate top: 2695*7c478bd9Sstevel@tonic-gate if (mknod(path, di_minor_spectype(minor) | mode, dev) == -1) { 2696*7c478bd9Sstevel@tonic-gate if (errno == ENOENT) { 2697*7c478bd9Sstevel@tonic-gate /* dirpath to node doesn't exist */ 2698*7c478bd9Sstevel@tonic-gate char *hide = strrchr(path, '/'); 2699*7c478bd9Sstevel@tonic-gate *hide = '\0'; 2700*7c478bd9Sstevel@tonic-gate s_mkdirp(path, 2701*7c478bd9Sstevel@tonic-gate S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); 2702*7c478bd9Sstevel@tonic-gate *hide = '/'; 2703*7c478bd9Sstevel@tonic-gate goto top; 2704*7c478bd9Sstevel@tonic-gate } else if (errno == EEXIST) { 2705*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2706*7c478bd9Sstevel@tonic-gate } 2707*7c478bd9Sstevel@tonic-gate err_print(MKNOD_FAILED, path, strerror(errno)); 2708*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 2709*7c478bd9Sstevel@tonic-gate } else { 2710*7c478bd9Sstevel@tonic-gate /* 2711*7c478bd9Sstevel@tonic-gate * If we successfully made the node, then set its owner 2712*7c478bd9Sstevel@tonic-gate * and group. Existing nodes will be unaffected. 2713*7c478bd9Sstevel@tonic-gate */ 2714*7c478bd9Sstevel@tonic-gate (void) chown(path, uid, gid); 2715*7c478bd9Sstevel@tonic-gate } 2716*7c478bd9Sstevel@tonic-gate 2717*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2718*7c478bd9Sstevel@tonic-gate } 2719*7c478bd9Sstevel@tonic-gate 2720*7c478bd9Sstevel@tonic-gate /* 2721*7c478bd9Sstevel@tonic-gate * Creates a symlink 'link' to the physical path of node:minor. 2722*7c478bd9Sstevel@tonic-gate * Construct link contents, then call create_link_common(). 2723*7c478bd9Sstevel@tonic-gate */ 2724*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2725*7c478bd9Sstevel@tonic-gate int 2726*7c478bd9Sstevel@tonic-gate devfsadm_mklink_default(char *link, di_node_t node, di_minor_t minor, int flags) 2727*7c478bd9Sstevel@tonic-gate { 2728*7c478bd9Sstevel@tonic-gate char rcontents[PATH_MAX]; 2729*7c478bd9Sstevel@tonic-gate char devlink[PATH_MAX]; 2730*7c478bd9Sstevel@tonic-gate char phy_path[PATH_MAX]; 2731*7c478bd9Sstevel@tonic-gate char *acontents; 2732*7c478bd9Sstevel@tonic-gate char *dev_path; 2733*7c478bd9Sstevel@tonic-gate int numslashes; 2734*7c478bd9Sstevel@tonic-gate int rv; 2735*7c478bd9Sstevel@tonic-gate int i, link_exists; 2736*7c478bd9Sstevel@tonic-gate int last_was_slash = FALSE; 2737*7c478bd9Sstevel@tonic-gate 2738*7c478bd9Sstevel@tonic-gate /* 2739*7c478bd9Sstevel@tonic-gate * try to use devices path 2740*7c478bd9Sstevel@tonic-gate */ 2741*7c478bd9Sstevel@tonic-gate if ((node == lnode) && (minor == lminor)) { 2742*7c478bd9Sstevel@tonic-gate acontents = lphy_path; 2743*7c478bd9Sstevel@tonic-gate } else if (di_minor_type(minor) == DDM_ALIAS) { 2744*7c478bd9Sstevel@tonic-gate /* use /pseudo/clone@0:<driver> as the phys path */ 2745*7c478bd9Sstevel@tonic-gate (void) snprintf(phy_path, sizeof (phy_path), 2746*7c478bd9Sstevel@tonic-gate "/pseudo/clone@0:%s", 2747*7c478bd9Sstevel@tonic-gate di_driver_name(di_minor_devinfo(minor))); 2748*7c478bd9Sstevel@tonic-gate acontents = phy_path; 2749*7c478bd9Sstevel@tonic-gate } else { 2750*7c478bd9Sstevel@tonic-gate if ((dev_path = di_devfs_path(node)) == NULL) { 2751*7c478bd9Sstevel@tonic-gate err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 2752*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 2753*7c478bd9Sstevel@tonic-gate } 2754*7c478bd9Sstevel@tonic-gate (void) snprintf(phy_path, sizeof (phy_path), "%s:%s", 2755*7c478bd9Sstevel@tonic-gate dev_path, di_minor_name(minor)); 2756*7c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path); 2757*7c478bd9Sstevel@tonic-gate acontents = phy_path; 2758*7c478bd9Sstevel@tonic-gate } 2759*7c478bd9Sstevel@tonic-gate 2760*7c478bd9Sstevel@tonic-gate /* prepend link with dev_dir contents */ 2761*7c478bd9Sstevel@tonic-gate (void) strlcpy(devlink, dev_dir, sizeof (devlink)); 2762*7c478bd9Sstevel@tonic-gate (void) strlcat(devlink, "/", sizeof (devlink)); 2763*7c478bd9Sstevel@tonic-gate (void) strlcat(devlink, link, sizeof (devlink)); 2764*7c478bd9Sstevel@tonic-gate 2765*7c478bd9Sstevel@tonic-gate /* 2766*7c478bd9Sstevel@tonic-gate * Calculate # of ../ to add. Account for double '//' in path. 2767*7c478bd9Sstevel@tonic-gate * Ignore all leading slashes. 2768*7c478bd9Sstevel@tonic-gate */ 2769*7c478bd9Sstevel@tonic-gate for (i = 0; link[i] == '/'; i++) 2770*7c478bd9Sstevel@tonic-gate ; 2771*7c478bd9Sstevel@tonic-gate for (numslashes = 0; link[i] != '\0'; i++) { 2772*7c478bd9Sstevel@tonic-gate if (link[i] == '/') { 2773*7c478bd9Sstevel@tonic-gate if (last_was_slash == FALSE) { 2774*7c478bd9Sstevel@tonic-gate numslashes++; 2775*7c478bd9Sstevel@tonic-gate last_was_slash = TRUE; 2776*7c478bd9Sstevel@tonic-gate } 2777*7c478bd9Sstevel@tonic-gate } else { 2778*7c478bd9Sstevel@tonic-gate last_was_slash = FALSE; 2779*7c478bd9Sstevel@tonic-gate } 2780*7c478bd9Sstevel@tonic-gate } 2781*7c478bd9Sstevel@tonic-gate /* Don't count any trailing '/' */ 2782*7c478bd9Sstevel@tonic-gate if (link[i-1] == '/') { 2783*7c478bd9Sstevel@tonic-gate numslashes--; 2784*7c478bd9Sstevel@tonic-gate } 2785*7c478bd9Sstevel@tonic-gate 2786*7c478bd9Sstevel@tonic-gate rcontents[0] = '\0'; 2787*7c478bd9Sstevel@tonic-gate do { 2788*7c478bd9Sstevel@tonic-gate (void) strlcat(rcontents, "../", sizeof (rcontents)); 2789*7c478bd9Sstevel@tonic-gate } while (numslashes-- != 0); 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate (void) strlcat(rcontents, "devices", sizeof (rcontents)); 2792*7c478bd9Sstevel@tonic-gate (void) strlcat(rcontents, acontents, sizeof (rcontents)); 2793*7c478bd9Sstevel@tonic-gate 2794*7c478bd9Sstevel@tonic-gate if (devlinks_debug == TRUE) { 2795*7c478bd9Sstevel@tonic-gate vprint(INFO_MID, "adding link %s ==> %s\n", devlink, rcontents); 2796*7c478bd9Sstevel@tonic-gate } 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate if ((rv = create_link_common(devlink, rcontents, &link_exists)) 2799*7c478bd9Sstevel@tonic-gate == DEVFSADM_SUCCESS) { 2800*7c478bd9Sstevel@tonic-gate linknew = TRUE; 2801*7c478bd9Sstevel@tonic-gate add_link_to_cache(link, acontents); 2802*7c478bd9Sstevel@tonic-gate } else { 2803*7c478bd9Sstevel@tonic-gate linknew = FALSE; 2804*7c478bd9Sstevel@tonic-gate } 2805*7c478bd9Sstevel@tonic-gate 2806*7c478bd9Sstevel@tonic-gate if (link_exists == TRUE) { 2807*7c478bd9Sstevel@tonic-gate /* Link exists or was just created */ 2808*7c478bd9Sstevel@tonic-gate (void) di_devlink_add_link(devlink_cache, link, rcontents, 2809*7c478bd9Sstevel@tonic-gate DI_PRIMARY_LINK); 2810*7c478bd9Sstevel@tonic-gate } 2811*7c478bd9Sstevel@tonic-gate 2812*7c478bd9Sstevel@tonic-gate return (rv); 2813*7c478bd9Sstevel@tonic-gate } 2814*7c478bd9Sstevel@tonic-gate 2815*7c478bd9Sstevel@tonic-gate int 2816*7c478bd9Sstevel@tonic-gate devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags) 2817*7c478bd9Sstevel@tonic-gate { 2818*7c478bd9Sstevel@tonic-gate struct zone_devinfo *z; 2819*7c478bd9Sstevel@tonic-gate int error; 2820*7c478bd9Sstevel@tonic-gate 2821*7c478bd9Sstevel@tonic-gate /* 2822*7c478bd9Sstevel@tonic-gate * If we're in zone mode (also implies !daemon_mode), then the 2823*7c478bd9Sstevel@tonic-gate * zone devinfo list has only one element, the zone we're configuring, 2824*7c478bd9Sstevel@tonic-gate * and we can just use zone_head. 2825*7c478bd9Sstevel@tonic-gate */ 2826*7c478bd9Sstevel@tonic-gate if (zone_cmd_mode) 2827*7c478bd9Sstevel@tonic-gate return (devfsadm_mklink_zone(zone_head, link, node, 2828*7c478bd9Sstevel@tonic-gate minor, flags)); 2829*7c478bd9Sstevel@tonic-gate else if (!daemon_mode) 2830*7c478bd9Sstevel@tonic-gate return (devfsadm_mklink_default(link, node, minor, flags)); 2831*7c478bd9Sstevel@tonic-gate 2832*7c478bd9Sstevel@tonic-gate /* 2833*7c478bd9Sstevel@tonic-gate * We're in daemon mode, so we need to make the link in the global 2834*7c478bd9Sstevel@tonic-gate * zone; then, walk the list of zones, creating the corresponding 2835*7c478bd9Sstevel@tonic-gate * mknod'd nodes in each. 2836*7c478bd9Sstevel@tonic-gate */ 2837*7c478bd9Sstevel@tonic-gate error = devfsadm_mklink_default(link, node, minor, flags); 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&zone_mutex); 2840*7c478bd9Sstevel@tonic-gate for (z = zone_head; z != NULL; z = z->zone_next) { 2841*7c478bd9Sstevel@tonic-gate (void) devfsadm_mklink_zone(z, link, node, minor, flags); 2842*7c478bd9Sstevel@tonic-gate } 2843*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&zone_mutex); 2844*7c478bd9Sstevel@tonic-gate return (error); 2845*7c478bd9Sstevel@tonic-gate } 2846*7c478bd9Sstevel@tonic-gate 2847*7c478bd9Sstevel@tonic-gate /* 2848*7c478bd9Sstevel@tonic-gate * Creates a symlink link to primary_link. Calculates relative 2849*7c478bd9Sstevel@tonic-gate * directory offsets, then calls link_common(). 2850*7c478bd9Sstevel@tonic-gate */ 2851*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2852*7c478bd9Sstevel@tonic-gate int 2853*7c478bd9Sstevel@tonic-gate devfsadm_secondary_link(char *link, char *primary_link, int flags) 2854*7c478bd9Sstevel@tonic-gate { 2855*7c478bd9Sstevel@tonic-gate char contents[PATH_MAX + 1]; 2856*7c478bd9Sstevel@tonic-gate char devlink[PATH_MAX + 1]; 2857*7c478bd9Sstevel@tonic-gate int rv, link_exists; 2858*7c478bd9Sstevel@tonic-gate char *fpath; 2859*7c478bd9Sstevel@tonic-gate char *tpath; 2860*7c478bd9Sstevel@tonic-gate char *op; 2861*7c478bd9Sstevel@tonic-gate 2862*7c478bd9Sstevel@tonic-gate /* prepend link with dev_dir contents */ 2863*7c478bd9Sstevel@tonic-gate (void) strcpy(devlink, dev_dir); 2864*7c478bd9Sstevel@tonic-gate (void) strcat(devlink, "/"); 2865*7c478bd9Sstevel@tonic-gate (void) strcat(devlink, link); 2866*7c478bd9Sstevel@tonic-gate /* 2867*7c478bd9Sstevel@tonic-gate * building extra link, so use first link as link contents, but first 2868*7c478bd9Sstevel@tonic-gate * make it relative. 2869*7c478bd9Sstevel@tonic-gate */ 2870*7c478bd9Sstevel@tonic-gate fpath = link; 2871*7c478bd9Sstevel@tonic-gate tpath = primary_link; 2872*7c478bd9Sstevel@tonic-gate op = contents; 2873*7c478bd9Sstevel@tonic-gate 2874*7c478bd9Sstevel@tonic-gate while (*fpath == *tpath && *fpath != '\0') { 2875*7c478bd9Sstevel@tonic-gate fpath++, tpath++; 2876*7c478bd9Sstevel@tonic-gate } 2877*7c478bd9Sstevel@tonic-gate 2878*7c478bd9Sstevel@tonic-gate /* Count directories to go up, if any, and add "../" */ 2879*7c478bd9Sstevel@tonic-gate while (*fpath != '\0') { 2880*7c478bd9Sstevel@tonic-gate if (*fpath == '/') { 2881*7c478bd9Sstevel@tonic-gate (void) strcpy(op, "../"); 2882*7c478bd9Sstevel@tonic-gate op += 3; 2883*7c478bd9Sstevel@tonic-gate } 2884*7c478bd9Sstevel@tonic-gate fpath++; 2885*7c478bd9Sstevel@tonic-gate } 2886*7c478bd9Sstevel@tonic-gate 2887*7c478bd9Sstevel@tonic-gate /* 2888*7c478bd9Sstevel@tonic-gate * Back up to the start of the current path component, in 2889*7c478bd9Sstevel@tonic-gate * case in the middle 2890*7c478bd9Sstevel@tonic-gate */ 2891*7c478bd9Sstevel@tonic-gate while (tpath != primary_link && *(tpath-1) != '/') { 2892*7c478bd9Sstevel@tonic-gate tpath--; 2893*7c478bd9Sstevel@tonic-gate } 2894*7c478bd9Sstevel@tonic-gate (void) strcpy(op, tpath); 2895*7c478bd9Sstevel@tonic-gate 2896*7c478bd9Sstevel@tonic-gate if (devlinks_debug == TRUE) { 2897*7c478bd9Sstevel@tonic-gate vprint(INFO_MID, "adding extra link %s ==> %s\n", 2898*7c478bd9Sstevel@tonic-gate devlink, contents); 2899*7c478bd9Sstevel@tonic-gate } 2900*7c478bd9Sstevel@tonic-gate 2901*7c478bd9Sstevel@tonic-gate if ((rv = create_link_common(devlink, contents, &link_exists)) 2902*7c478bd9Sstevel@tonic-gate == DEVFSADM_SUCCESS) { 2903*7c478bd9Sstevel@tonic-gate /* 2904*7c478bd9Sstevel@tonic-gate * we need to save the ultimate /devices contents, and not the 2905*7c478bd9Sstevel@tonic-gate * secondary link, since hotcleanup only looks at /devices path. 2906*7c478bd9Sstevel@tonic-gate * Since we don't have devices path here, we can try to get it 2907*7c478bd9Sstevel@tonic-gate * by readlink'ing the secondary link. This assumes the primary 2908*7c478bd9Sstevel@tonic-gate * link was created first. 2909*7c478bd9Sstevel@tonic-gate */ 2910*7c478bd9Sstevel@tonic-gate add_link_to_cache(link, lphy_path); 2911*7c478bd9Sstevel@tonic-gate linknew = TRUE; 2912*7c478bd9Sstevel@tonic-gate } else { 2913*7c478bd9Sstevel@tonic-gate linknew = FALSE; 2914*7c478bd9Sstevel@tonic-gate } 2915*7c478bd9Sstevel@tonic-gate 2916*7c478bd9Sstevel@tonic-gate /* 2917*7c478bd9Sstevel@tonic-gate * If link exists or was just created, add it to the database 2918*7c478bd9Sstevel@tonic-gate */ 2919*7c478bd9Sstevel@tonic-gate if (link_exists == TRUE) { 2920*7c478bd9Sstevel@tonic-gate (void) di_devlink_add_link(devlink_cache, link, contents, 2921*7c478bd9Sstevel@tonic-gate DI_SECONDARY_LINK); 2922*7c478bd9Sstevel@tonic-gate } 2923*7c478bd9Sstevel@tonic-gate 2924*7c478bd9Sstevel@tonic-gate return (rv); 2925*7c478bd9Sstevel@tonic-gate } 2926*7c478bd9Sstevel@tonic-gate 2927*7c478bd9Sstevel@tonic-gate /* returns pointer to the devices directory */ 2928*7c478bd9Sstevel@tonic-gate char * 2929*7c478bd9Sstevel@tonic-gate devfsadm_get_devices_dir() 2930*7c478bd9Sstevel@tonic-gate { 2931*7c478bd9Sstevel@tonic-gate return (devices_dir); 2932*7c478bd9Sstevel@tonic-gate } 2933*7c478bd9Sstevel@tonic-gate 2934*7c478bd9Sstevel@tonic-gate /* 2935*7c478bd9Sstevel@tonic-gate * Does the actual link creation. VERBOSE_MID only used if there is 2936*7c478bd9Sstevel@tonic-gate * a change. CHATTY_MID used otherwise. 2937*7c478bd9Sstevel@tonic-gate */ 2938*7c478bd9Sstevel@tonic-gate static int 2939*7c478bd9Sstevel@tonic-gate create_link_common(char *devlink, char *contents, int *exists) 2940*7c478bd9Sstevel@tonic-gate { 2941*7c478bd9Sstevel@tonic-gate int try; 2942*7c478bd9Sstevel@tonic-gate int linksize; 2943*7c478bd9Sstevel@tonic-gate int max_tries = 0; 2944*7c478bd9Sstevel@tonic-gate static int prev_link_existed = TRUE; 2945*7c478bd9Sstevel@tonic-gate char checkcontents[PATH_MAX + 1]; 2946*7c478bd9Sstevel@tonic-gate char *hide; 2947*7c478bd9Sstevel@tonic-gate 2948*7c478bd9Sstevel@tonic-gate *exists = FALSE; 2949*7c478bd9Sstevel@tonic-gate 2950*7c478bd9Sstevel@tonic-gate /* Database is not updated when file_mods == FALSE */ 2951*7c478bd9Sstevel@tonic-gate if (file_mods == FALSE) { 2952*7c478bd9Sstevel@tonic-gate linksize = readlink(devlink, checkcontents, PATH_MAX); 2953*7c478bd9Sstevel@tonic-gate if (linksize > 0) { 2954*7c478bd9Sstevel@tonic-gate checkcontents[linksize] = '\0'; 2955*7c478bd9Sstevel@tonic-gate if (strcmp(checkcontents, contents) != 0) { 2956*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, REMOVING_LINK, 2957*7c478bd9Sstevel@tonic-gate devlink, checkcontents); 2958*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2959*7c478bd9Sstevel@tonic-gate } else { 2960*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "link exists and is correct:" 2961*7c478bd9Sstevel@tonic-gate " %s -> %s\n", devlink, contents); 2962*7c478bd9Sstevel@tonic-gate /* failure only in that the link existed */ 2963*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 2964*7c478bd9Sstevel@tonic-gate } 2965*7c478bd9Sstevel@tonic-gate } else { 2966*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, CREATING_LINK, devlink, contents); 2967*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2968*7c478bd9Sstevel@tonic-gate } 2969*7c478bd9Sstevel@tonic-gate } 2970*7c478bd9Sstevel@tonic-gate 2971*7c478bd9Sstevel@tonic-gate /* 2972*7c478bd9Sstevel@tonic-gate * systems calls are expensive, so predict whether to readlink 2973*7c478bd9Sstevel@tonic-gate * or symlink first, based on previous attempt 2974*7c478bd9Sstevel@tonic-gate */ 2975*7c478bd9Sstevel@tonic-gate if (prev_link_existed == FALSE) { 2976*7c478bd9Sstevel@tonic-gate try = CREATE_LINK; 2977*7c478bd9Sstevel@tonic-gate } else { 2978*7c478bd9Sstevel@tonic-gate try = READ_LINK; 2979*7c478bd9Sstevel@tonic-gate } 2980*7c478bd9Sstevel@tonic-gate 2981*7c478bd9Sstevel@tonic-gate while (++max_tries <= 3) { 2982*7c478bd9Sstevel@tonic-gate 2983*7c478bd9Sstevel@tonic-gate switch (try) { 2984*7c478bd9Sstevel@tonic-gate case CREATE_LINK: 2985*7c478bd9Sstevel@tonic-gate 2986*7c478bd9Sstevel@tonic-gate if (symlink(contents, devlink) == 0) { 2987*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, CREATING_LINK, devlink, 2988*7c478bd9Sstevel@tonic-gate contents); 2989*7c478bd9Sstevel@tonic-gate prev_link_existed = FALSE; 2990*7c478bd9Sstevel@tonic-gate /* link successfully created */ 2991*7c478bd9Sstevel@tonic-gate *exists = TRUE; 2992*7c478bd9Sstevel@tonic-gate set_logindev_perms(devlink); 2993*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 2994*7c478bd9Sstevel@tonic-gate } else { 2995*7c478bd9Sstevel@tonic-gate switch (errno) { 2996*7c478bd9Sstevel@tonic-gate 2997*7c478bd9Sstevel@tonic-gate case ENOENT: 2998*7c478bd9Sstevel@tonic-gate /* dirpath to node doesn't exist */ 2999*7c478bd9Sstevel@tonic-gate hide = strrchr(devlink, '/'); 3000*7c478bd9Sstevel@tonic-gate *hide = '\0'; 3001*7c478bd9Sstevel@tonic-gate s_mkdirp(devlink, S_IRWXU|S_IRGRP| 3002*7c478bd9Sstevel@tonic-gate S_IXGRP|S_IROTH|S_IXOTH); 3003*7c478bd9Sstevel@tonic-gate *hide = '/'; 3004*7c478bd9Sstevel@tonic-gate break; 3005*7c478bd9Sstevel@tonic-gate case EEXIST: 3006*7c478bd9Sstevel@tonic-gate try = READ_LINK; 3007*7c478bd9Sstevel@tonic-gate break; 3008*7c478bd9Sstevel@tonic-gate default: 3009*7c478bd9Sstevel@tonic-gate err_print(SYMLINK_FAILED, devlink, 3010*7c478bd9Sstevel@tonic-gate contents, strerror(errno)); 3011*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 3012*7c478bd9Sstevel@tonic-gate } 3013*7c478bd9Sstevel@tonic-gate } 3014*7c478bd9Sstevel@tonic-gate break; 3015*7c478bd9Sstevel@tonic-gate 3016*7c478bd9Sstevel@tonic-gate case READ_LINK: 3017*7c478bd9Sstevel@tonic-gate 3018*7c478bd9Sstevel@tonic-gate linksize = readlink(devlink, checkcontents, PATH_MAX); 3019*7c478bd9Sstevel@tonic-gate if (linksize >= 0) { 3020*7c478bd9Sstevel@tonic-gate checkcontents[linksize] = '\0'; 3021*7c478bd9Sstevel@tonic-gate if (strcmp(checkcontents, contents) != 0) { 3022*7c478bd9Sstevel@tonic-gate s_unlink(devlink); 3023*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, REMOVING_LINK, 3024*7c478bd9Sstevel@tonic-gate devlink, checkcontents); 3025*7c478bd9Sstevel@tonic-gate try = CREATE_LINK; 3026*7c478bd9Sstevel@tonic-gate } else { 3027*7c478bd9Sstevel@tonic-gate prev_link_existed = TRUE; 3028*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, 3029*7c478bd9Sstevel@tonic-gate "link exists and is correct:" 3030*7c478bd9Sstevel@tonic-gate " %s -> %s\n", devlink, 3031*7c478bd9Sstevel@tonic-gate contents); 3032*7c478bd9Sstevel@tonic-gate *exists = TRUE; 3033*7c478bd9Sstevel@tonic-gate /* failure in that the link existed */ 3034*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 3035*7c478bd9Sstevel@tonic-gate } 3036*7c478bd9Sstevel@tonic-gate } else { 3037*7c478bd9Sstevel@tonic-gate switch (errno) { 3038*7c478bd9Sstevel@tonic-gate case EINVAL: 3039*7c478bd9Sstevel@tonic-gate /* not a symlink, remove and create */ 3040*7c478bd9Sstevel@tonic-gate s_unlink(devlink); 3041*7c478bd9Sstevel@tonic-gate default: 3042*7c478bd9Sstevel@tonic-gate /* maybe it didn't exist at all */ 3043*7c478bd9Sstevel@tonic-gate try = CREATE_LINK; 3044*7c478bd9Sstevel@tonic-gate break; 3045*7c478bd9Sstevel@tonic-gate } 3046*7c478bd9Sstevel@tonic-gate } 3047*7c478bd9Sstevel@tonic-gate break; 3048*7c478bd9Sstevel@tonic-gate } 3049*7c478bd9Sstevel@tonic-gate } 3050*7c478bd9Sstevel@tonic-gate err_print(MAX_ATTEMPTS, devlink, contents); 3051*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 3052*7c478bd9Sstevel@tonic-gate } 3053*7c478bd9Sstevel@tonic-gate 3054*7c478bd9Sstevel@tonic-gate static void 3055*7c478bd9Sstevel@tonic-gate set_logindev_perms(char *devlink) 3056*7c478bd9Sstevel@tonic-gate { 3057*7c478bd9Sstevel@tonic-gate struct login_dev *newdev; 3058*7c478bd9Sstevel@tonic-gate struct passwd pwd, *resp; 3059*7c478bd9Sstevel@tonic-gate char pwd_buf[PATH_MAX]; 3060*7c478bd9Sstevel@tonic-gate int rv; 3061*7c478bd9Sstevel@tonic-gate struct stat sb; 3062*7c478bd9Sstevel@tonic-gate char *devfs_path = NULL; 3063*7c478bd9Sstevel@tonic-gate 3064*7c478bd9Sstevel@tonic-gate /* 3065*7c478bd9Sstevel@tonic-gate * We only want logindev perms to be set when a device is 3066*7c478bd9Sstevel@tonic-gate * hotplugged or an application requests synchronous creates. 3067*7c478bd9Sstevel@tonic-gate * So we enable this only in daemon mode. In addition, 3068*7c478bd9Sstevel@tonic-gate * login(1) only fixes the std. /dev dir. So we don't 3069*7c478bd9Sstevel@tonic-gate * change perms if alternate root is set. 3070*7c478bd9Sstevel@tonic-gate * login_dev_enable is TRUE only in these cases. 3071*7c478bd9Sstevel@tonic-gate */ 3072*7c478bd9Sstevel@tonic-gate if (login_dev_enable != TRUE) 3073*7c478bd9Sstevel@tonic-gate return; 3074*7c478bd9Sstevel@tonic-gate 3075*7c478bd9Sstevel@tonic-gate /* 3076*7c478bd9Sstevel@tonic-gate * Normally, /etc/logindevperm has few (8 - 10 entries) which 3077*7c478bd9Sstevel@tonic-gate * may be regular expressions (globs were converted to RE). 3078*7c478bd9Sstevel@tonic-gate * So just do a linear search through the list. 3079*7c478bd9Sstevel@tonic-gate */ 3080*7c478bd9Sstevel@tonic-gate for (newdev = login_dev_cache; newdev; newdev = newdev->ldev_next) { 3081*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "matching %s with %s\n", devlink, 3082*7c478bd9Sstevel@tonic-gate newdev->ldev_device); 3083*7c478bd9Sstevel@tonic-gate 3084*7c478bd9Sstevel@tonic-gate if (regexec(&newdev->ldev_device_regex, devlink, 0, 3085*7c478bd9Sstevel@tonic-gate NULL, 0) == 0) { 3086*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "matched %s with %s\n", devlink, 3087*7c478bd9Sstevel@tonic-gate newdev->ldev_device); 3088*7c478bd9Sstevel@tonic-gate break; 3089*7c478bd9Sstevel@tonic-gate } 3090*7c478bd9Sstevel@tonic-gate } 3091*7c478bd9Sstevel@tonic-gate 3092*7c478bd9Sstevel@tonic-gate if (newdev == NULL) 3093*7c478bd9Sstevel@tonic-gate return; 3094*7c478bd9Sstevel@tonic-gate 3095*7c478bd9Sstevel@tonic-gate /* 3096*7c478bd9Sstevel@tonic-gate * we have a match, now find the driver associated with this 3097*7c478bd9Sstevel@tonic-gate * minor node using a snapshot on the physical path 3098*7c478bd9Sstevel@tonic-gate */ 3099*7c478bd9Sstevel@tonic-gate (void) resolve_link(devlink, NULL, NULL, &devfs_path, 0); 3100*7c478bd9Sstevel@tonic-gate if (devfs_path) { 3101*7c478bd9Sstevel@tonic-gate di_node_t node; 3102*7c478bd9Sstevel@tonic-gate char *drv = NULL; 3103*7c478bd9Sstevel@tonic-gate struct driver_list *list; 3104*7c478bd9Sstevel@tonic-gate char *p; 3105*7c478bd9Sstevel@tonic-gate 3106*7c478bd9Sstevel@tonic-gate /* truncate on : so we can take a snapshot */ 3107*7c478bd9Sstevel@tonic-gate (void) strcpy(pwd_buf, devfs_path); 3108*7c478bd9Sstevel@tonic-gate p = strrchr(pwd_buf, ':'); 3109*7c478bd9Sstevel@tonic-gate if (p == NULL) { 3110*7c478bd9Sstevel@tonic-gate free(devfs_path); 3111*7c478bd9Sstevel@tonic-gate return; 3112*7c478bd9Sstevel@tonic-gate } 3113*7c478bd9Sstevel@tonic-gate *p = '\0'; 3114*7c478bd9Sstevel@tonic-gate 3115*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "link=%s->physpath=%s\n", 3116*7c478bd9Sstevel@tonic-gate devlink, pwd_buf); 3117*7c478bd9Sstevel@tonic-gate 3118*7c478bd9Sstevel@tonic-gate node = di_init(pwd_buf, DINFOMINOR); 3119*7c478bd9Sstevel@tonic-gate 3120*7c478bd9Sstevel@tonic-gate if (node) { 3121*7c478bd9Sstevel@tonic-gate drv = di_driver_name(node); 3122*7c478bd9Sstevel@tonic-gate 3123*7c478bd9Sstevel@tonic-gate if (drv) { 3124*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "%s: driver is %s\n", 3125*7c478bd9Sstevel@tonic-gate devlink, drv); 3126*7c478bd9Sstevel@tonic-gate } 3127*7c478bd9Sstevel@tonic-gate di_fini(node); 3128*7c478bd9Sstevel@tonic-gate } 3129*7c478bd9Sstevel@tonic-gate /* search thru the driver list specified in logindevperm */ 3130*7c478bd9Sstevel@tonic-gate list = newdev->ldev_driver_list; 3131*7c478bd9Sstevel@tonic-gate if ((drv != NULL) && (list != NULL)) { 3132*7c478bd9Sstevel@tonic-gate while (list) { 3133*7c478bd9Sstevel@tonic-gate if (strcmp(list->driver_name, 3134*7c478bd9Sstevel@tonic-gate drv) == 0) { 3135*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, 3136*7c478bd9Sstevel@tonic-gate "driver %s match!\n", drv); 3137*7c478bd9Sstevel@tonic-gate break; 3138*7c478bd9Sstevel@tonic-gate } 3139*7c478bd9Sstevel@tonic-gate list = list->next; 3140*7c478bd9Sstevel@tonic-gate } 3141*7c478bd9Sstevel@tonic-gate if (list == NULL) { 3142*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "no driver match!\n"); 3143*7c478bd9Sstevel@tonic-gate free(devfs_path); 3144*7c478bd9Sstevel@tonic-gate return; 3145*7c478bd9Sstevel@tonic-gate } 3146*7c478bd9Sstevel@tonic-gate } 3147*7c478bd9Sstevel@tonic-gate free(devfs_path); 3148*7c478bd9Sstevel@tonic-gate } else { 3149*7c478bd9Sstevel@tonic-gate return; 3150*7c478bd9Sstevel@tonic-gate } 3151*7c478bd9Sstevel@tonic-gate 3152*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "changing permissions of %s\n", devlink); 3153*7c478bd9Sstevel@tonic-gate 3154*7c478bd9Sstevel@tonic-gate /* 3155*7c478bd9Sstevel@tonic-gate * We have a match. We now attempt to determine the 3156*7c478bd9Sstevel@tonic-gate * owner and group of the console user. 3157*7c478bd9Sstevel@tonic-gate * 3158*7c478bd9Sstevel@tonic-gate * stat() the console device newdev->ldev_console 3159*7c478bd9Sstevel@tonic-gate * which will always exist - it will have the right owner but 3160*7c478bd9Sstevel@tonic-gate * not the right group. Use getpwuid_r() to determine group for this 3161*7c478bd9Sstevel@tonic-gate * uid. 3162*7c478bd9Sstevel@tonic-gate * Note, it is safe to use name service here since if name services 3163*7c478bd9Sstevel@tonic-gate * are not available (during boot or in single-user mode), then 3164*7c478bd9Sstevel@tonic-gate * console owner will be root and its gid can be found in 3165*7c478bd9Sstevel@tonic-gate * local files. 3166*7c478bd9Sstevel@tonic-gate */ 3167*7c478bd9Sstevel@tonic-gate if (stat(newdev->ldev_console, &sb) == -1) { 3168*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, STAT_FAILED, newdev->ldev_console, 3169*7c478bd9Sstevel@tonic-gate strerror(errno)); 3170*7c478bd9Sstevel@tonic-gate return; 3171*7c478bd9Sstevel@tonic-gate } 3172*7c478bd9Sstevel@tonic-gate 3173*7c478bd9Sstevel@tonic-gate resp = NULL; 3174*7c478bd9Sstevel@tonic-gate rv = getpwuid_r(sb.st_uid, &pwd, pwd_buf, sizeof (pwd_buf), &resp); 3175*7c478bd9Sstevel@tonic-gate if (rv || resp == NULL) { 3176*7c478bd9Sstevel@tonic-gate rv = rv ? rv : EINVAL; 3177*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, GID_FAILED, sb.st_uid, 3178*7c478bd9Sstevel@tonic-gate strerror(rv)); 3179*7c478bd9Sstevel@tonic-gate return; 3180*7c478bd9Sstevel@tonic-gate } 3181*7c478bd9Sstevel@tonic-gate 3182*7c478bd9Sstevel@tonic-gate assert(&pwd == resp); 3183*7c478bd9Sstevel@tonic-gate 3184*7c478bd9Sstevel@tonic-gate sb.st_gid = resp->pw_gid; 3185*7c478bd9Sstevel@tonic-gate 3186*7c478bd9Sstevel@tonic-gate if (chmod(devlink, newdev->ldev_perms) == -1) { 3187*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, CHMOD_FAILED, devlink, 3188*7c478bd9Sstevel@tonic-gate strerror(errno)); 3189*7c478bd9Sstevel@tonic-gate return; 3190*7c478bd9Sstevel@tonic-gate } 3191*7c478bd9Sstevel@tonic-gate 3192*7c478bd9Sstevel@tonic-gate if (chown(devlink, sb.st_uid, sb.st_gid) == -1) { 3193*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, CHOWN_FAILED, devlink, 3194*7c478bd9Sstevel@tonic-gate strerror(errno)); 3195*7c478bd9Sstevel@tonic-gate } 3196*7c478bd9Sstevel@tonic-gate } 3197*7c478bd9Sstevel@tonic-gate 3198*7c478bd9Sstevel@tonic-gate /* 3199*7c478bd9Sstevel@tonic-gate * Reset /devices node with appropriate permissions and 3200*7c478bd9Sstevel@tonic-gate * ownership as specified in /etc/minor_perm. 3201*7c478bd9Sstevel@tonic-gate */ 3202*7c478bd9Sstevel@tonic-gate static void 3203*7c478bd9Sstevel@tonic-gate reset_node_permissions(di_node_t node, di_minor_t minor) 3204*7c478bd9Sstevel@tonic-gate { 3205*7c478bd9Sstevel@tonic-gate int spectype; 3206*7c478bd9Sstevel@tonic-gate char phy_path[PATH_MAX + 1]; 3207*7c478bd9Sstevel@tonic-gate mode_t mode; 3208*7c478bd9Sstevel@tonic-gate dev_t dev; 3209*7c478bd9Sstevel@tonic-gate uid_t uid; 3210*7c478bd9Sstevel@tonic-gate gid_t gid; 3211*7c478bd9Sstevel@tonic-gate struct stat sb; 3212*7c478bd9Sstevel@tonic-gate char *dev_path, *aminor = NULL; 3213*7c478bd9Sstevel@tonic-gate 3214*7c478bd9Sstevel@tonic-gate /* lphy_path starts with / */ 3215*7c478bd9Sstevel@tonic-gate if ((dev_path = di_devfs_path(node)) == NULL) { 3216*7c478bd9Sstevel@tonic-gate err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 3217*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 3218*7c478bd9Sstevel@tonic-gate } 3219*7c478bd9Sstevel@tonic-gate (void) strcpy(lphy_path, dev_path); 3220*7c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path); 3221*7c478bd9Sstevel@tonic-gate 3222*7c478bd9Sstevel@tonic-gate (void) strcat(lphy_path, ":"); 3223*7c478bd9Sstevel@tonic-gate if (di_minor_type(minor) == DDM_ALIAS) { 3224*7c478bd9Sstevel@tonic-gate char *driver; 3225*7c478bd9Sstevel@tonic-gate aminor = di_minor_name(minor); 3226*7c478bd9Sstevel@tonic-gate driver = di_driver_name(di_minor_devinfo(minor)); 3227*7c478bd9Sstevel@tonic-gate (void) strcat(lphy_path, driver); 3228*7c478bd9Sstevel@tonic-gate } else 3229*7c478bd9Sstevel@tonic-gate (void) strcat(lphy_path, di_minor_name(minor)); 3230*7c478bd9Sstevel@tonic-gate 3231*7c478bd9Sstevel@tonic-gate (void) strcpy(phy_path, devices_dir); 3232*7c478bd9Sstevel@tonic-gate (void) strcat(phy_path, lphy_path); 3233*7c478bd9Sstevel@tonic-gate 3234*7c478bd9Sstevel@tonic-gate lnode = node; 3235*7c478bd9Sstevel@tonic-gate lminor = minor; 3236*7c478bd9Sstevel@tonic-gate 3237*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "reset_node_permissions: phy_path=%s lphy_path=%s\n", 3238*7c478bd9Sstevel@tonic-gate phy_path, lphy_path); 3239*7c478bd9Sstevel@tonic-gate 3240*7c478bd9Sstevel@tonic-gate dev = di_minor_devt(minor); 3241*7c478bd9Sstevel@tonic-gate spectype = di_minor_spectype(minor); /* block or char */ 3242*7c478bd9Sstevel@tonic-gate 3243*7c478bd9Sstevel@tonic-gate getattr(phy_path, aminor, spectype, dev, &mode, &uid, &gid); 3244*7c478bd9Sstevel@tonic-gate 3245*7c478bd9Sstevel@tonic-gate /* 3246*7c478bd9Sstevel@tonic-gate * compare and set permissions and ownership 3247*7c478bd9Sstevel@tonic-gate * 3248*7c478bd9Sstevel@tonic-gate * Under devfs, a quick insertion and removal of USB devices 3249*7c478bd9Sstevel@tonic-gate * would cause stat of physical path to fail. In this case, 3250*7c478bd9Sstevel@tonic-gate * we emit a verbose message, but don't print errors. 3251*7c478bd9Sstevel@tonic-gate */ 3252*7c478bd9Sstevel@tonic-gate if ((stat(phy_path, &sb) == -1) || (sb.st_rdev != dev)) { 3253*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, NO_DEVFS_NODE, phy_path); 3254*7c478bd9Sstevel@tonic-gate return; 3255*7c478bd9Sstevel@tonic-gate } 3256*7c478bd9Sstevel@tonic-gate 3257*7c478bd9Sstevel@tonic-gate /* 3258*7c478bd9Sstevel@tonic-gate * If we are here for deactivating device allocation, set 3259*7c478bd9Sstevel@tonic-gate * default permissions. Otherwise, set default permissions 3260*7c478bd9Sstevel@tonic-gate * only if this is a new device because we want to preserve 3261*7c478bd9Sstevel@tonic-gate * modified user permissions. 3262*7c478bd9Sstevel@tonic-gate * Devfs indicates a new device by faking an access time 3263*7c478bd9Sstevel@tonic-gate * of zero. 3264*7c478bd9Sstevel@tonic-gate */ 3265*7c478bd9Sstevel@tonic-gate if (sb.st_atime != 0) { 3266*7c478bd9Sstevel@tonic-gate int i; 3267*7c478bd9Sstevel@tonic-gate char *nt; 3268*7c478bd9Sstevel@tonic-gate 3269*7c478bd9Sstevel@tonic-gate if (devalloc_off == FALSE) 3270*7c478bd9Sstevel@tonic-gate return; 3271*7c478bd9Sstevel@tonic-gate 3272*7c478bd9Sstevel@tonic-gate nt = di_minor_nodetype(minor); 3273*7c478bd9Sstevel@tonic-gate if (nt == NULL) 3274*7c478bd9Sstevel@tonic-gate return; 3275*7c478bd9Sstevel@tonic-gate for (i = 0; devalloc[i]; i++) { 3276*7c478bd9Sstevel@tonic-gate if (strcmp(nt, devalloc[i]) == 0) 3277*7c478bd9Sstevel@tonic-gate break; 3278*7c478bd9Sstevel@tonic-gate } 3279*7c478bd9Sstevel@tonic-gate 3280*7c478bd9Sstevel@tonic-gate if (devalloc[i] == NULL) 3281*7c478bd9Sstevel@tonic-gate return; 3282*7c478bd9Sstevel@tonic-gate 3283*7c478bd9Sstevel@tonic-gate /* One of the types recognized by devalloc, reset perms */ 3284*7c478bd9Sstevel@tonic-gate } 3285*7c478bd9Sstevel@tonic-gate 3286*7c478bd9Sstevel@tonic-gate if (file_mods == FALSE) { 3287*7c478bd9Sstevel@tonic-gate /* Nothing more to do if simulating */ 3288*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode); 3289*7c478bd9Sstevel@tonic-gate return; 3290*7c478bd9Sstevel@tonic-gate } 3291*7c478bd9Sstevel@tonic-gate 3292*7c478bd9Sstevel@tonic-gate if (sb.st_mode != mode) { 3293*7c478bd9Sstevel@tonic-gate if (chmod(phy_path, mode) == -1) 3294*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, CHMOD_FAILED, 3295*7c478bd9Sstevel@tonic-gate phy_path, strerror(errno)); 3296*7c478bd9Sstevel@tonic-gate } 3297*7c478bd9Sstevel@tonic-gate if (sb.st_uid != uid || sb.st_gid != gid) { 3298*7c478bd9Sstevel@tonic-gate if (chown(phy_path, uid, gid) == -1) 3299*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, CHOWN_FAILED, 3300*7c478bd9Sstevel@tonic-gate phy_path, strerror(errno)); 3301*7c478bd9Sstevel@tonic-gate } 3302*7c478bd9Sstevel@tonic-gate 3303*7c478bd9Sstevel@tonic-gate /* Report that we actually did something */ 3304*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode); 3305*7c478bd9Sstevel@tonic-gate } 3306*7c478bd9Sstevel@tonic-gate 3307*7c478bd9Sstevel@tonic-gate /* 3308*7c478bd9Sstevel@tonic-gate * Removes logical link and the minor node it refers to. If file is a 3309*7c478bd9Sstevel@tonic-gate * link, we recurse and try to remove the minor node (or link if path is 3310*7c478bd9Sstevel@tonic-gate * a double link) that file's link contents refer to. 3311*7c478bd9Sstevel@tonic-gate */ 3312*7c478bd9Sstevel@tonic-gate static void 3313*7c478bd9Sstevel@tonic-gate devfsadm_rm_work(char *file, int recurse, int file_type) 3314*7c478bd9Sstevel@tonic-gate { 3315*7c478bd9Sstevel@tonic-gate char *fcn = "devfsadm_rm_work: "; 3316*7c478bd9Sstevel@tonic-gate int linksize; 3317*7c478bd9Sstevel@tonic-gate char contents[PATH_MAX + 1]; 3318*7c478bd9Sstevel@tonic-gate char nextfile[PATH_MAX + 1]; 3319*7c478bd9Sstevel@tonic-gate char newfile[PATH_MAX + 1]; 3320*7c478bd9Sstevel@tonic-gate char *ptr; 3321*7c478bd9Sstevel@tonic-gate 3322*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%s%s\n", fcn, file); 3323*7c478bd9Sstevel@tonic-gate 3324*7c478bd9Sstevel@tonic-gate /* TYPE_LINK split into multiple if's due to excessive indentations */ 3325*7c478bd9Sstevel@tonic-gate if (file_type == TYPE_LINK) { 3326*7c478bd9Sstevel@tonic-gate (void) strcpy(newfile, dev_dir); 3327*7c478bd9Sstevel@tonic-gate (void) strcat(newfile, "/"); 3328*7c478bd9Sstevel@tonic-gate (void) strcat(newfile, file); 3329*7c478bd9Sstevel@tonic-gate } 3330*7c478bd9Sstevel@tonic-gate 3331*7c478bd9Sstevel@tonic-gate if ((file_type == TYPE_LINK) && (recurse == TRUE) && 3332*7c478bd9Sstevel@tonic-gate ((linksize = readlink(newfile, contents, PATH_MAX)) > 0)) { 3333*7c478bd9Sstevel@tonic-gate contents[linksize] = '\0'; 3334*7c478bd9Sstevel@tonic-gate 3335*7c478bd9Sstevel@tonic-gate if (is_minor_node(contents, &ptr) == DEVFSADM_TRUE) { 3336*7c478bd9Sstevel@tonic-gate devfsadm_rm_work(++ptr, FALSE, TYPE_DEVICES); 3337*7c478bd9Sstevel@tonic-gate } else { 3338*7c478bd9Sstevel@tonic-gate if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { 3339*7c478bd9Sstevel@tonic-gate devfsadm_rm_work(&contents[strlen(DEV) + 1], 3340*7c478bd9Sstevel@tonic-gate TRUE, TYPE_LINK); 3341*7c478bd9Sstevel@tonic-gate } else { 3342*7c478bd9Sstevel@tonic-gate if ((ptr = strrchr(file, '/')) != NULL) { 3343*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 3344*7c478bd9Sstevel@tonic-gate (void) strcpy(nextfile, file); 3345*7c478bd9Sstevel@tonic-gate *ptr = '/'; 3346*7c478bd9Sstevel@tonic-gate (void) strcat(nextfile, "/"); 3347*7c478bd9Sstevel@tonic-gate } else { 3348*7c478bd9Sstevel@tonic-gate (void) strcpy(nextfile, ""); 3349*7c478bd9Sstevel@tonic-gate } 3350*7c478bd9Sstevel@tonic-gate (void) strcat(nextfile, contents); 3351*7c478bd9Sstevel@tonic-gate devfsadm_rm_work(nextfile, TRUE, TYPE_LINK); 3352*7c478bd9Sstevel@tonic-gate } 3353*7c478bd9Sstevel@tonic-gate } 3354*7c478bd9Sstevel@tonic-gate } 3355*7c478bd9Sstevel@tonic-gate 3356*7c478bd9Sstevel@tonic-gate if (file_type == TYPE_LINK) { 3357*7c478bd9Sstevel@tonic-gate vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile); 3358*7c478bd9Sstevel@tonic-gate if (file_mods == TRUE) { 3359*7c478bd9Sstevel@tonic-gate rm_link_from_cache(file); 3360*7c478bd9Sstevel@tonic-gate s_unlink(newfile); 3361*7c478bd9Sstevel@tonic-gate rm_parent_dir_if_empty(newfile); 3362*7c478bd9Sstevel@tonic-gate invalidate_enumerate_cache(); 3363*7c478bd9Sstevel@tonic-gate (void) di_devlink_rm_link(devlink_cache, file); 3364*7c478bd9Sstevel@tonic-gate } 3365*7c478bd9Sstevel@tonic-gate } 3366*7c478bd9Sstevel@tonic-gate 3367*7c478bd9Sstevel@tonic-gate /* 3368*7c478bd9Sstevel@tonic-gate * Note: we don't remove /devices entries because they are 3369*7c478bd9Sstevel@tonic-gate * covered by devfs. 3370*7c478bd9Sstevel@tonic-gate */ 3371*7c478bd9Sstevel@tonic-gate } 3372*7c478bd9Sstevel@tonic-gate 3373*7c478bd9Sstevel@tonic-gate void 3374*7c478bd9Sstevel@tonic-gate devfsadm_rm_link(char *file) 3375*7c478bd9Sstevel@tonic-gate { 3376*7c478bd9Sstevel@tonic-gate devfsadm_rm_work(file, FALSE, TYPE_LINK); 3377*7c478bd9Sstevel@tonic-gate } 3378*7c478bd9Sstevel@tonic-gate 3379*7c478bd9Sstevel@tonic-gate void 3380*7c478bd9Sstevel@tonic-gate devfsadm_rm_all(char *file) 3381*7c478bd9Sstevel@tonic-gate { 3382*7c478bd9Sstevel@tonic-gate devfsadm_rm_work(file, TRUE, TYPE_LINK); 3383*7c478bd9Sstevel@tonic-gate } 3384*7c478bd9Sstevel@tonic-gate 3385*7c478bd9Sstevel@tonic-gate static void 3386*7c478bd9Sstevel@tonic-gate s_rmdir(char *path) 3387*7c478bd9Sstevel@tonic-gate { 3388*7c478bd9Sstevel@tonic-gate int i; 3389*7c478bd9Sstevel@tonic-gate char *rpath, *dir; 3390*7c478bd9Sstevel@tonic-gate const char *fcn = "s_rmdir"; 3391*7c478bd9Sstevel@tonic-gate 3392*7c478bd9Sstevel@tonic-gate /* 3393*7c478bd9Sstevel@tonic-gate * Certain directories are created at install time by packages. 3394*7c478bd9Sstevel@tonic-gate * Some of them (listed in packaged_dirs[]) are required by apps 3395*7c478bd9Sstevel@tonic-gate * and need to be present even when empty. 3396*7c478bd9Sstevel@tonic-gate */ 3397*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%s: checking if %s is packaged\n", fcn, path); 3398*7c478bd9Sstevel@tonic-gate 3399*7c478bd9Sstevel@tonic-gate rpath = path + strlen(dev_dir) + 1; 3400*7c478bd9Sstevel@tonic-gate 3401*7c478bd9Sstevel@tonic-gate for (i = 0; (dir = packaged_dirs[i]) != NULL; i++) { 3402*7c478bd9Sstevel@tonic-gate if (*rpath == *dir) { 3403*7c478bd9Sstevel@tonic-gate if (strcmp(rpath, dir) == 0) { 3404*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%s: skipping packaged dir: " 3405*7c478bd9Sstevel@tonic-gate "%s\n", fcn, path); 3406*7c478bd9Sstevel@tonic-gate return; 3407*7c478bd9Sstevel@tonic-gate } 3408*7c478bd9Sstevel@tonic-gate } 3409*7c478bd9Sstevel@tonic-gate } 3410*7c478bd9Sstevel@tonic-gate 3411*7c478bd9Sstevel@tonic-gate (void) rmdir(path); 3412*7c478bd9Sstevel@tonic-gate } 3413*7c478bd9Sstevel@tonic-gate 3414*7c478bd9Sstevel@tonic-gate /* 3415*7c478bd9Sstevel@tonic-gate * Try to remove any empty directories up the tree. It is assumed that 3416*7c478bd9Sstevel@tonic-gate * pathname is a file that was removed, so start with its parent, and 3417*7c478bd9Sstevel@tonic-gate * work up the tree. 3418*7c478bd9Sstevel@tonic-gate */ 3419*7c478bd9Sstevel@tonic-gate static void 3420*7c478bd9Sstevel@tonic-gate rm_parent_dir_if_empty(char *pathname) 3421*7c478bd9Sstevel@tonic-gate { 3422*7c478bd9Sstevel@tonic-gate char *ptr, path[PATH_MAX + 1]; 3423*7c478bd9Sstevel@tonic-gate char *fcn = "rm_parent_dir_if_empty: "; 3424*7c478bd9Sstevel@tonic-gate struct dirent *entp; 3425*7c478bd9Sstevel@tonic-gate struct dirent *retp; 3426*7c478bd9Sstevel@tonic-gate DIR *dp; 3427*7c478bd9Sstevel@tonic-gate 3428*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%schecking %s if empty\n", fcn, pathname); 3429*7c478bd9Sstevel@tonic-gate 3430*7c478bd9Sstevel@tonic-gate (void) strcpy(path, pathname); 3431*7c478bd9Sstevel@tonic-gate 3432*7c478bd9Sstevel@tonic-gate entp = (struct dirent *)s_malloc(PATH_MAX + 1 + 3433*7c478bd9Sstevel@tonic-gate sizeof (struct dirent)); 3434*7c478bd9Sstevel@tonic-gate 3435*7c478bd9Sstevel@tonic-gate /* 3436*7c478bd9Sstevel@tonic-gate * ascend up the dir tree, deleting all empty dirs. 3437*7c478bd9Sstevel@tonic-gate * Return immediately if a dir is not empty. 3438*7c478bd9Sstevel@tonic-gate */ 3439*7c478bd9Sstevel@tonic-gate for (;;) { 3440*7c478bd9Sstevel@tonic-gate 3441*7c478bd9Sstevel@tonic-gate if ((ptr = strrchr(path, '/')) == NULL) { 3442*7c478bd9Sstevel@tonic-gate return; 3443*7c478bd9Sstevel@tonic-gate } 3444*7c478bd9Sstevel@tonic-gate 3445*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 3446*7c478bd9Sstevel@tonic-gate 3447*7c478bd9Sstevel@tonic-gate if ((dp = opendir(path)) == NULL) { 3448*7c478bd9Sstevel@tonic-gate err_print(OPENDIR_FAILED, path, strerror(errno)); 3449*7c478bd9Sstevel@tonic-gate free(entp); 3450*7c478bd9Sstevel@tonic-gate return; 3451*7c478bd9Sstevel@tonic-gate } 3452*7c478bd9Sstevel@tonic-gate 3453*7c478bd9Sstevel@tonic-gate while (readdir_r(dp, entp, &retp) == 0) { 3454*7c478bd9Sstevel@tonic-gate 3455*7c478bd9Sstevel@tonic-gate if (retp == NULL) { 3456*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%sremoving empty dir %s\n", 3457*7c478bd9Sstevel@tonic-gate fcn, path); 3458*7c478bd9Sstevel@tonic-gate s_rmdir(path); 3459*7c478bd9Sstevel@tonic-gate break; 3460*7c478bd9Sstevel@tonic-gate } 3461*7c478bd9Sstevel@tonic-gate 3462*7c478bd9Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 || 3463*7c478bd9Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0) { 3464*7c478bd9Sstevel@tonic-gate continue; 3465*7c478bd9Sstevel@tonic-gate } 3466*7c478bd9Sstevel@tonic-gate 3467*7c478bd9Sstevel@tonic-gate /* some other file is here, so return */ 3468*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%sdir not empty: %s\n", fcn, path); 3469*7c478bd9Sstevel@tonic-gate free(entp); 3470*7c478bd9Sstevel@tonic-gate s_closedir(dp); 3471*7c478bd9Sstevel@tonic-gate return; 3472*7c478bd9Sstevel@tonic-gate 3473*7c478bd9Sstevel@tonic-gate } 3474*7c478bd9Sstevel@tonic-gate s_closedir(dp); 3475*7c478bd9Sstevel@tonic-gate } 3476*7c478bd9Sstevel@tonic-gate } 3477*7c478bd9Sstevel@tonic-gate 3478*7c478bd9Sstevel@tonic-gate /* 3479*7c478bd9Sstevel@tonic-gate * This function and all the functions it calls below were added to 3480*7c478bd9Sstevel@tonic-gate * handle the unique problem with world wide names (WWN). The problem is 3481*7c478bd9Sstevel@tonic-gate * that if a WWN device is moved to another address on the same controller 3482*7c478bd9Sstevel@tonic-gate * its logical link will change, while the physical node remains the same. 3483*7c478bd9Sstevel@tonic-gate * The result is that two logical links will point to the same physical path 3484*7c478bd9Sstevel@tonic-gate * in /devices, the valid link and a stale link. This function will 3485*7c478bd9Sstevel@tonic-gate * find all the stale nodes, though at a significant performance cost. 3486*7c478bd9Sstevel@tonic-gate * 3487*7c478bd9Sstevel@tonic-gate * Caching is used to increase performance. 3488*7c478bd9Sstevel@tonic-gate * A cache will be built from disk if the cache tag doesn't already exist. 3489*7c478bd9Sstevel@tonic-gate * The cache tag is a regular expression "dir_re", which selects a 3490*7c478bd9Sstevel@tonic-gate * subset of disks to search from typically something like 3491*7c478bd9Sstevel@tonic-gate * "dev/cXt[0-9]+d[0-9]+s[0-9]+". After the cache is built, consistency must 3492*7c478bd9Sstevel@tonic-gate * be maintained, so entries are added as new links are created, and removed 3493*7c478bd9Sstevel@tonic-gate * as old links are deleted. The whole cache is flushed if we are a daemon, 3494*7c478bd9Sstevel@tonic-gate * and another devfsadm process ran in between. 3495*7c478bd9Sstevel@tonic-gate * 3496*7c478bd9Sstevel@tonic-gate * Once the cache is built, this function finds the cache which matches 3497*7c478bd9Sstevel@tonic-gate * dir_re, and then it searches all links in that cache looking for 3498*7c478bd9Sstevel@tonic-gate * any link whose contents match "valid_link_contents" with a corresponding link 3499*7c478bd9Sstevel@tonic-gate * which does not match "valid_link". Any such matches are stale and removed. 3500*7c478bd9Sstevel@tonic-gate */ 3501*7c478bd9Sstevel@tonic-gate void 3502*7c478bd9Sstevel@tonic-gate devfsadm_rm_stale_links(char *dir_re, char *valid_link, di_node_t node, 3503*7c478bd9Sstevel@tonic-gate di_minor_t minor) 3504*7c478bd9Sstevel@tonic-gate { 3505*7c478bd9Sstevel@tonic-gate link_t *link; 3506*7c478bd9Sstevel@tonic-gate linkhead_t *head; 3507*7c478bd9Sstevel@tonic-gate char phy_path[PATH_MAX + 1]; 3508*7c478bd9Sstevel@tonic-gate char *valid_link_contents; 3509*7c478bd9Sstevel@tonic-gate char *dev_path; 3510*7c478bd9Sstevel@tonic-gate char rmlink[PATH_MAX + 1]; 3511*7c478bd9Sstevel@tonic-gate 3512*7c478bd9Sstevel@tonic-gate /* 3513*7c478bd9Sstevel@tonic-gate * try to use devices path 3514*7c478bd9Sstevel@tonic-gate */ 3515*7c478bd9Sstevel@tonic-gate if ((node == lnode) && (minor == lminor)) { 3516*7c478bd9Sstevel@tonic-gate valid_link_contents = lphy_path; 3517*7c478bd9Sstevel@tonic-gate } else { 3518*7c478bd9Sstevel@tonic-gate if ((dev_path = di_devfs_path(node)) == NULL) { 3519*7c478bd9Sstevel@tonic-gate err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 3520*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 3521*7c478bd9Sstevel@tonic-gate } 3522*7c478bd9Sstevel@tonic-gate (void) strcpy(phy_path, dev_path); 3523*7c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path); 3524*7c478bd9Sstevel@tonic-gate 3525*7c478bd9Sstevel@tonic-gate (void) strcat(phy_path, ":"); 3526*7c478bd9Sstevel@tonic-gate (void) strcat(phy_path, di_minor_name(minor)); 3527*7c478bd9Sstevel@tonic-gate valid_link_contents = phy_path; 3528*7c478bd9Sstevel@tonic-gate } 3529*7c478bd9Sstevel@tonic-gate 3530*7c478bd9Sstevel@tonic-gate /* 3531*7c478bd9Sstevel@tonic-gate * As an optimization, check to make sure the corresponding 3532*7c478bd9Sstevel@tonic-gate * devlink was just created before continuing. 3533*7c478bd9Sstevel@tonic-gate */ 3534*7c478bd9Sstevel@tonic-gate 3535*7c478bd9Sstevel@tonic-gate if (linknew == FALSE) { 3536*7c478bd9Sstevel@tonic-gate return; 3537*7c478bd9Sstevel@tonic-gate } 3538*7c478bd9Sstevel@tonic-gate 3539*7c478bd9Sstevel@tonic-gate head = get_cached_links(dir_re); 3540*7c478bd9Sstevel@tonic-gate 3541*7c478bd9Sstevel@tonic-gate assert(head->nextlink == NULL); 3542*7c478bd9Sstevel@tonic-gate 3543*7c478bd9Sstevel@tonic-gate for (link = head->link; link != NULL; link = head->nextlink) { 3544*7c478bd9Sstevel@tonic-gate /* 3545*7c478bd9Sstevel@tonic-gate * See hot_cleanup() for why we do this 3546*7c478bd9Sstevel@tonic-gate */ 3547*7c478bd9Sstevel@tonic-gate head->nextlink = link->next; 3548*7c478bd9Sstevel@tonic-gate if ((strcmp(link->contents, valid_link_contents) == 0) && 3549*7c478bd9Sstevel@tonic-gate (strcmp(link->devlink, valid_link) != 0)) { 3550*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "removing %s -> %s\n" 3551*7c478bd9Sstevel@tonic-gate "valid link is: %s -> %s\n", 3552*7c478bd9Sstevel@tonic-gate link->devlink, link->contents, 3553*7c478bd9Sstevel@tonic-gate valid_link, valid_link_contents); 3554*7c478bd9Sstevel@tonic-gate /* 3555*7c478bd9Sstevel@tonic-gate * Use a copy of the cached link name as the 3556*7c478bd9Sstevel@tonic-gate * cache entry will go away during link removal 3557*7c478bd9Sstevel@tonic-gate */ 3558*7c478bd9Sstevel@tonic-gate (void) snprintf(rmlink, sizeof (rmlink), "%s", 3559*7c478bd9Sstevel@tonic-gate link->devlink); 3560*7c478bd9Sstevel@tonic-gate devfsadm_rm_link(rmlink); 3561*7c478bd9Sstevel@tonic-gate } 3562*7c478bd9Sstevel@tonic-gate } 3563*7c478bd9Sstevel@tonic-gate } 3564*7c478bd9Sstevel@tonic-gate 3565*7c478bd9Sstevel@tonic-gate /* 3566*7c478bd9Sstevel@tonic-gate * Return previously created cache, or create cache. 3567*7c478bd9Sstevel@tonic-gate */ 3568*7c478bd9Sstevel@tonic-gate static linkhead_t * 3569*7c478bd9Sstevel@tonic-gate get_cached_links(char *dir_re) 3570*7c478bd9Sstevel@tonic-gate { 3571*7c478bd9Sstevel@tonic-gate recurse_dev_t rd; 3572*7c478bd9Sstevel@tonic-gate linkhead_t *linkhead; 3573*7c478bd9Sstevel@tonic-gate int n; 3574*7c478bd9Sstevel@tonic-gate 3575*7c478bd9Sstevel@tonic-gate vprint(BUILDCACHE_MID, "get_cached_links: %s\n", dir_re); 3576*7c478bd9Sstevel@tonic-gate 3577*7c478bd9Sstevel@tonic-gate for (linkhead = headlinkhead; linkhead != NULL; 3578*7c478bd9Sstevel@tonic-gate linkhead = linkhead->nexthead) { 3579*7c478bd9Sstevel@tonic-gate if (strcmp(linkhead->dir_re, dir_re) == 0) { 3580*7c478bd9Sstevel@tonic-gate return (linkhead); 3581*7c478bd9Sstevel@tonic-gate } 3582*7c478bd9Sstevel@tonic-gate } 3583*7c478bd9Sstevel@tonic-gate 3584*7c478bd9Sstevel@tonic-gate /* 3585*7c478bd9Sstevel@tonic-gate * This tag is not in cache, so add it, along with all its 3586*7c478bd9Sstevel@tonic-gate * matching /dev entries. This is the only time we go to disk. 3587*7c478bd9Sstevel@tonic-gate */ 3588*7c478bd9Sstevel@tonic-gate linkhead = s_malloc(sizeof (linkhead_t)); 3589*7c478bd9Sstevel@tonic-gate linkhead->nexthead = headlinkhead; 3590*7c478bd9Sstevel@tonic-gate headlinkhead = linkhead; 3591*7c478bd9Sstevel@tonic-gate linkhead->dir_re = s_strdup(dir_re); 3592*7c478bd9Sstevel@tonic-gate 3593*7c478bd9Sstevel@tonic-gate if ((n = regcomp(&(linkhead->dir_re_compiled), dir_re, 3594*7c478bd9Sstevel@tonic-gate REG_EXTENDED)) != 0) { 3595*7c478bd9Sstevel@tonic-gate err_print(REGCOMP_FAILED, dir_re, n); 3596*7c478bd9Sstevel@tonic-gate } 3597*7c478bd9Sstevel@tonic-gate 3598*7c478bd9Sstevel@tonic-gate linkhead->nextlink = NULL; 3599*7c478bd9Sstevel@tonic-gate linkhead->link = NULL; 3600*7c478bd9Sstevel@tonic-gate 3601*7c478bd9Sstevel@tonic-gate rd.fcn = build_devlink_list; 3602*7c478bd9Sstevel@tonic-gate rd.data = (void *)linkhead; 3603*7c478bd9Sstevel@tonic-gate 3604*7c478bd9Sstevel@tonic-gate vprint(BUILDCACHE_MID, "get_cached_links: calling recurse_dev_re\n"); 3605*7c478bd9Sstevel@tonic-gate 3606*7c478bd9Sstevel@tonic-gate /* call build_devlink_list for each directory in the dir_re RE */ 3607*7c478bd9Sstevel@tonic-gate if (dir_re[0] == '/') { 3608*7c478bd9Sstevel@tonic-gate recurse_dev_re("/", &dir_re[1], &rd); 3609*7c478bd9Sstevel@tonic-gate } else { 3610*7c478bd9Sstevel@tonic-gate recurse_dev_re(dev_dir, dir_re, &rd); 3611*7c478bd9Sstevel@tonic-gate } 3612*7c478bd9Sstevel@tonic-gate 3613*7c478bd9Sstevel@tonic-gate return (linkhead); 3614*7c478bd9Sstevel@tonic-gate } 3615*7c478bd9Sstevel@tonic-gate 3616*7c478bd9Sstevel@tonic-gate static void 3617*7c478bd9Sstevel@tonic-gate build_devlink_list(char *devlink, void *data) 3618*7c478bd9Sstevel@tonic-gate { 3619*7c478bd9Sstevel@tonic-gate char *fcn = "build_devlink_list: "; 3620*7c478bd9Sstevel@tonic-gate char *ptr; 3621*7c478bd9Sstevel@tonic-gate char *r_contents; 3622*7c478bd9Sstevel@tonic-gate char *r_devlink; 3623*7c478bd9Sstevel@tonic-gate char contents[PATH_MAX + 1]; 3624*7c478bd9Sstevel@tonic-gate char newlink[PATH_MAX + 1]; 3625*7c478bd9Sstevel@tonic-gate char stage_link[PATH_MAX + 1]; 3626*7c478bd9Sstevel@tonic-gate int linksize; 3627*7c478bd9Sstevel@tonic-gate linkhead_t *linkhead = (linkhead_t *)data; 3628*7c478bd9Sstevel@tonic-gate link_t *link; 3629*7c478bd9Sstevel@tonic-gate int i = 0; 3630*7c478bd9Sstevel@tonic-gate 3631*7c478bd9Sstevel@tonic-gate vprint(BUILDCACHE_MID, "%scheck_link: %s\n", fcn, devlink); 3632*7c478bd9Sstevel@tonic-gate 3633*7c478bd9Sstevel@tonic-gate (void) strcpy(newlink, devlink); 3634*7c478bd9Sstevel@tonic-gate 3635*7c478bd9Sstevel@tonic-gate do { 3636*7c478bd9Sstevel@tonic-gate linksize = readlink(newlink, contents, PATH_MAX); 3637*7c478bd9Sstevel@tonic-gate if (linksize <= 0) { 3638*7c478bd9Sstevel@tonic-gate /* 3639*7c478bd9Sstevel@tonic-gate * The first pass through the do loop we may readlink() 3640*7c478bd9Sstevel@tonic-gate * non-symlink files(EINVAL) from false regexec matches. 3641*7c478bd9Sstevel@tonic-gate * Suppress error messages in those cases or if the link 3642*7c478bd9Sstevel@tonic-gate * content is the empty string. 3643*7c478bd9Sstevel@tonic-gate */ 3644*7c478bd9Sstevel@tonic-gate if (linksize < 0 && (i || errno != EINVAL)) 3645*7c478bd9Sstevel@tonic-gate err_print(READLINK_FAILED, "build_devlink_list", 3646*7c478bd9Sstevel@tonic-gate newlink, strerror(errno)); 3647*7c478bd9Sstevel@tonic-gate return; 3648*7c478bd9Sstevel@tonic-gate } 3649*7c478bd9Sstevel@tonic-gate contents[linksize] = '\0'; 3650*7c478bd9Sstevel@tonic-gate i = 1; 3651*7c478bd9Sstevel@tonic-gate 3652*7c478bd9Sstevel@tonic-gate if (is_minor_node(contents, &r_contents) == DEVFSADM_FALSE) { 3653*7c478bd9Sstevel@tonic-gate /* 3654*7c478bd9Sstevel@tonic-gate * assume that link contents is really a pointer to 3655*7c478bd9Sstevel@tonic-gate * another link, so recurse and read its link contents. 3656*7c478bd9Sstevel@tonic-gate * 3657*7c478bd9Sstevel@tonic-gate * some link contents are absolute: 3658*7c478bd9Sstevel@tonic-gate * /dev/audio -> /dev/sound/0 3659*7c478bd9Sstevel@tonic-gate */ 3660*7c478bd9Sstevel@tonic-gate if (strncmp(contents, DEV "/", 3661*7c478bd9Sstevel@tonic-gate strlen(DEV) + strlen("/")) != 0) { 3662*7c478bd9Sstevel@tonic-gate 3663*7c478bd9Sstevel@tonic-gate if ((ptr = strrchr(newlink, '/')) == NULL) { 3664*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%s%s -> %s invalid " 3665*7c478bd9Sstevel@tonic-gate "link. missing '/'\n", fcn, 3666*7c478bd9Sstevel@tonic-gate newlink, contents); 3667*7c478bd9Sstevel@tonic-gate return; 3668*7c478bd9Sstevel@tonic-gate } 3669*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 3670*7c478bd9Sstevel@tonic-gate (void) strcpy(stage_link, newlink); 3671*7c478bd9Sstevel@tonic-gate *ptr = '/'; 3672*7c478bd9Sstevel@tonic-gate (void) strcat(stage_link, "/"); 3673*7c478bd9Sstevel@tonic-gate (void) strcat(stage_link, contents); 3674*7c478bd9Sstevel@tonic-gate (void) strcpy(newlink, stage_link); 3675*7c478bd9Sstevel@tonic-gate } else { 3676*7c478bd9Sstevel@tonic-gate (void) strcpy(newlink, dev_dir); 3677*7c478bd9Sstevel@tonic-gate (void) strcat(newlink, "/"); 3678*7c478bd9Sstevel@tonic-gate (void) strcat(newlink, 3679*7c478bd9Sstevel@tonic-gate &contents[strlen(DEV) + strlen("/")]); 3680*7c478bd9Sstevel@tonic-gate } 3681*7c478bd9Sstevel@tonic-gate 3682*7c478bd9Sstevel@tonic-gate } else { 3683*7c478bd9Sstevel@tonic-gate newlink[0] = '\0'; 3684*7c478bd9Sstevel@tonic-gate } 3685*7c478bd9Sstevel@tonic-gate } while (newlink[0] != '\0'); 3686*7c478bd9Sstevel@tonic-gate 3687*7c478bd9Sstevel@tonic-gate if (strncmp(devlink, dev_dir, strlen(dev_dir)) != 0) { 3688*7c478bd9Sstevel@tonic-gate vprint(BUILDCACHE_MID, "%sinvalid link: %s\n", fcn, devlink); 3689*7c478bd9Sstevel@tonic-gate return; 3690*7c478bd9Sstevel@tonic-gate } 3691*7c478bd9Sstevel@tonic-gate 3692*7c478bd9Sstevel@tonic-gate r_devlink = devlink + strlen(dev_dir); 3693*7c478bd9Sstevel@tonic-gate 3694*7c478bd9Sstevel@tonic-gate if (r_devlink[0] != '/') 3695*7c478bd9Sstevel@tonic-gate return; 3696*7c478bd9Sstevel@tonic-gate 3697*7c478bd9Sstevel@tonic-gate link = s_malloc(sizeof (link_t)); 3698*7c478bd9Sstevel@tonic-gate 3699*7c478bd9Sstevel@tonic-gate /* don't store the '/' after rootdir/dev */ 3700*7c478bd9Sstevel@tonic-gate r_devlink += 1; 3701*7c478bd9Sstevel@tonic-gate 3702*7c478bd9Sstevel@tonic-gate vprint(BUILDCACHE_MID, "%scaching link: %s\n", fcn, r_devlink); 3703*7c478bd9Sstevel@tonic-gate link->devlink = s_strdup(r_devlink); 3704*7c478bd9Sstevel@tonic-gate 3705*7c478bd9Sstevel@tonic-gate link->contents = s_strdup(r_contents); 3706*7c478bd9Sstevel@tonic-gate 3707*7c478bd9Sstevel@tonic-gate link->next = linkhead->link; 3708*7c478bd9Sstevel@tonic-gate linkhead->link = link; 3709*7c478bd9Sstevel@tonic-gate } 3710*7c478bd9Sstevel@tonic-gate 3711*7c478bd9Sstevel@tonic-gate /* 3712*7c478bd9Sstevel@tonic-gate * to be consistent, devlink must not begin with / and must be 3713*7c478bd9Sstevel@tonic-gate * relative to /dev/, whereas physpath must contain / and be 3714*7c478bd9Sstevel@tonic-gate * relative to /devices. 3715*7c478bd9Sstevel@tonic-gate */ 3716*7c478bd9Sstevel@tonic-gate static void 3717*7c478bd9Sstevel@tonic-gate add_link_to_cache(char *devlink, char *physpath) 3718*7c478bd9Sstevel@tonic-gate { 3719*7c478bd9Sstevel@tonic-gate linkhead_t *linkhead; 3720*7c478bd9Sstevel@tonic-gate link_t *link; 3721*7c478bd9Sstevel@tonic-gate int added = 0; 3722*7c478bd9Sstevel@tonic-gate 3723*7c478bd9Sstevel@tonic-gate if (file_mods == FALSE) { 3724*7c478bd9Sstevel@tonic-gate return; 3725*7c478bd9Sstevel@tonic-gate } 3726*7c478bd9Sstevel@tonic-gate 3727*7c478bd9Sstevel@tonic-gate vprint(CACHE_MID, "add_link_to_cache: %s -> %s ", 3728*7c478bd9Sstevel@tonic-gate devlink, physpath); 3729*7c478bd9Sstevel@tonic-gate 3730*7c478bd9Sstevel@tonic-gate for (linkhead = headlinkhead; linkhead != NULL; 3731*7c478bd9Sstevel@tonic-gate linkhead = linkhead->nexthead) { 3732*7c478bd9Sstevel@tonic-gate if (regexec(&(linkhead->dir_re_compiled), devlink, 0, NULL, 3733*7c478bd9Sstevel@tonic-gate 0) == 0) { 3734*7c478bd9Sstevel@tonic-gate added++; 3735*7c478bd9Sstevel@tonic-gate link = s_malloc(sizeof (link_t)); 3736*7c478bd9Sstevel@tonic-gate link->devlink = s_strdup(devlink); 3737*7c478bd9Sstevel@tonic-gate link->contents = s_strdup(physpath); 3738*7c478bd9Sstevel@tonic-gate link->next = linkhead->link; 3739*7c478bd9Sstevel@tonic-gate linkhead->link = link; 3740*7c478bd9Sstevel@tonic-gate } 3741*7c478bd9Sstevel@tonic-gate } 3742*7c478bd9Sstevel@tonic-gate 3743*7c478bd9Sstevel@tonic-gate vprint(CACHE_MID, 3744*7c478bd9Sstevel@tonic-gate " %d %s\n", added, added == 0 ? "NOT ADDED" : "ADDED"); 3745*7c478bd9Sstevel@tonic-gate } 3746*7c478bd9Sstevel@tonic-gate 3747*7c478bd9Sstevel@tonic-gate /* 3748*7c478bd9Sstevel@tonic-gate * Remove devlink from cache. Devlink must be relative to /dev/ and not start 3749*7c478bd9Sstevel@tonic-gate * with /. 3750*7c478bd9Sstevel@tonic-gate */ 3751*7c478bd9Sstevel@tonic-gate static void 3752*7c478bd9Sstevel@tonic-gate rm_link_from_cache(char *devlink) 3753*7c478bd9Sstevel@tonic-gate { 3754*7c478bd9Sstevel@tonic-gate linkhead_t *linkhead; 3755*7c478bd9Sstevel@tonic-gate link_t **linkp; 3756*7c478bd9Sstevel@tonic-gate link_t *save; 3757*7c478bd9Sstevel@tonic-gate 3758*7c478bd9Sstevel@tonic-gate vprint(CACHE_MID, "rm_link_from_cache enter: %s\n", devlink); 3759*7c478bd9Sstevel@tonic-gate 3760*7c478bd9Sstevel@tonic-gate for (linkhead = headlinkhead; linkhead != NULL; 3761*7c478bd9Sstevel@tonic-gate linkhead = linkhead->nexthead) { 3762*7c478bd9Sstevel@tonic-gate if (regexec(&(linkhead->dir_re_compiled), devlink, 0, NULL, 3763*7c478bd9Sstevel@tonic-gate 0) == 0) { 3764*7c478bd9Sstevel@tonic-gate 3765*7c478bd9Sstevel@tonic-gate for (linkp = &(linkhead->link); *linkp != NULL; ) { 3766*7c478bd9Sstevel@tonic-gate if ((strcmp((*linkp)->devlink, devlink) == 0)) { 3767*7c478bd9Sstevel@tonic-gate save = *linkp; 3768*7c478bd9Sstevel@tonic-gate *linkp = (*linkp)->next; 3769*7c478bd9Sstevel@tonic-gate /* 3770*7c478bd9Sstevel@tonic-gate * We are removing our caller's 3771*7c478bd9Sstevel@tonic-gate * "next" link. Update the nextlink 3772*7c478bd9Sstevel@tonic-gate * field in the head so that our 3773*7c478bd9Sstevel@tonic-gate * callers accesses the next valid 3774*7c478bd9Sstevel@tonic-gate * link 3775*7c478bd9Sstevel@tonic-gate */ 3776*7c478bd9Sstevel@tonic-gate if (linkhead->nextlink == save) 3777*7c478bd9Sstevel@tonic-gate linkhead->nextlink = *linkp; 3778*7c478bd9Sstevel@tonic-gate free(save->devlink); 3779*7c478bd9Sstevel@tonic-gate free(save->contents); 3780*7c478bd9Sstevel@tonic-gate free(save); 3781*7c478bd9Sstevel@tonic-gate vprint(CACHE_MID, " %s FREED FROM " 3782*7c478bd9Sstevel@tonic-gate "CACHE\n", devlink); 3783*7c478bd9Sstevel@tonic-gate } else { 3784*7c478bd9Sstevel@tonic-gate linkp = &((*linkp)->next); 3785*7c478bd9Sstevel@tonic-gate } 3786*7c478bd9Sstevel@tonic-gate } 3787*7c478bd9Sstevel@tonic-gate } 3788*7c478bd9Sstevel@tonic-gate } 3789*7c478bd9Sstevel@tonic-gate } 3790*7c478bd9Sstevel@tonic-gate 3791*7c478bd9Sstevel@tonic-gate static void 3792*7c478bd9Sstevel@tonic-gate rm_all_links_from_cache() 3793*7c478bd9Sstevel@tonic-gate { 3794*7c478bd9Sstevel@tonic-gate linkhead_t *linkhead; 3795*7c478bd9Sstevel@tonic-gate linkhead_t *nextlinkhead; 3796*7c478bd9Sstevel@tonic-gate link_t *link; 3797*7c478bd9Sstevel@tonic-gate link_t *nextlink; 3798*7c478bd9Sstevel@tonic-gate 3799*7c478bd9Sstevel@tonic-gate vprint(CACHE_MID, "rm_all_links_from_cache\n"); 3800*7c478bd9Sstevel@tonic-gate 3801*7c478bd9Sstevel@tonic-gate for (linkhead = headlinkhead; linkhead != NULL; 3802*7c478bd9Sstevel@tonic-gate linkhead = nextlinkhead) { 3803*7c478bd9Sstevel@tonic-gate 3804*7c478bd9Sstevel@tonic-gate nextlinkhead = linkhead->nexthead; 3805*7c478bd9Sstevel@tonic-gate assert(linkhead->nextlink == NULL); 3806*7c478bd9Sstevel@tonic-gate for (link = linkhead->link; link != NULL; link = nextlink) { 3807*7c478bd9Sstevel@tonic-gate nextlink = link->next; 3808*7c478bd9Sstevel@tonic-gate free(link->devlink); 3809*7c478bd9Sstevel@tonic-gate free(link->contents); 3810*7c478bd9Sstevel@tonic-gate free(link); 3811*7c478bd9Sstevel@tonic-gate } 3812*7c478bd9Sstevel@tonic-gate regfree(&(linkhead->dir_re_compiled)); 3813*7c478bd9Sstevel@tonic-gate free(linkhead->dir_re); 3814*7c478bd9Sstevel@tonic-gate free(linkhead); 3815*7c478bd9Sstevel@tonic-gate } 3816*7c478bd9Sstevel@tonic-gate headlinkhead = NULL; 3817*7c478bd9Sstevel@tonic-gate } 3818*7c478bd9Sstevel@tonic-gate 3819*7c478bd9Sstevel@tonic-gate /* 3820*7c478bd9Sstevel@tonic-gate * Called when the kernel has modified the incore path_to_inst data. This 3821*7c478bd9Sstevel@tonic-gate * function will schedule a flush of the data to the filesystem. 3822*7c478bd9Sstevel@tonic-gate */ 3823*7c478bd9Sstevel@tonic-gate static void 3824*7c478bd9Sstevel@tonic-gate devfs_instance_mod(void) 3825*7c478bd9Sstevel@tonic-gate { 3826*7c478bd9Sstevel@tonic-gate char *fcn = "devfs_instance_mod: "; 3827*7c478bd9Sstevel@tonic-gate vprint(PATH2INST_MID, "%senter\n", fcn); 3828*7c478bd9Sstevel@tonic-gate 3829*7c478bd9Sstevel@tonic-gate /* signal instance thread */ 3830*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&count_lock); 3831*7c478bd9Sstevel@tonic-gate inst_count++; 3832*7c478bd9Sstevel@tonic-gate (void) cond_signal(&cv); 3833*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&count_lock); 3834*7c478bd9Sstevel@tonic-gate } 3835*7c478bd9Sstevel@tonic-gate 3836*7c478bd9Sstevel@tonic-gate static void 3837*7c478bd9Sstevel@tonic-gate instance_flush_thread(void) 3838*7c478bd9Sstevel@tonic-gate { 3839*7c478bd9Sstevel@tonic-gate int i; 3840*7c478bd9Sstevel@tonic-gate int idle; 3841*7c478bd9Sstevel@tonic-gate 3842*7c478bd9Sstevel@tonic-gate for (;;) { 3843*7c478bd9Sstevel@tonic-gate 3844*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&count_lock); 3845*7c478bd9Sstevel@tonic-gate while (inst_count == 0) { 3846*7c478bd9Sstevel@tonic-gate (void) cond_wait(&cv, &count_lock); 3847*7c478bd9Sstevel@tonic-gate } 3848*7c478bd9Sstevel@tonic-gate inst_count = 0; 3849*7c478bd9Sstevel@tonic-gate 3850*7c478bd9Sstevel@tonic-gate vprint(PATH2INST_MID, "signaled to flush path_to_inst." 3851*7c478bd9Sstevel@tonic-gate " Enter delay loop\n"); 3852*7c478bd9Sstevel@tonic-gate /* 3853*7c478bd9Sstevel@tonic-gate * Wait MAX_IDLE_DELAY seconds after getting the last flush 3854*7c478bd9Sstevel@tonic-gate * path_to_inst event before invoking a flush, but never wait 3855*7c478bd9Sstevel@tonic-gate * more than MAX_DELAY seconds after getting the first event. 3856*7c478bd9Sstevel@tonic-gate */ 3857*7c478bd9Sstevel@tonic-gate for (idle = 0, i = 0; i < MAX_DELAY; i++) { 3858*7c478bd9Sstevel@tonic-gate 3859*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&count_lock); 3860*7c478bd9Sstevel@tonic-gate (void) sleep(1); 3861*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&count_lock); 3862*7c478bd9Sstevel@tonic-gate 3863*7c478bd9Sstevel@tonic-gate /* shorten the delay if we are idle */ 3864*7c478bd9Sstevel@tonic-gate if (inst_count == 0) { 3865*7c478bd9Sstevel@tonic-gate idle++; 3866*7c478bd9Sstevel@tonic-gate if (idle > MAX_IDLE_DELAY) { 3867*7c478bd9Sstevel@tonic-gate break; 3868*7c478bd9Sstevel@tonic-gate } 3869*7c478bd9Sstevel@tonic-gate } else { 3870*7c478bd9Sstevel@tonic-gate inst_count = idle = 0; 3871*7c478bd9Sstevel@tonic-gate } 3872*7c478bd9Sstevel@tonic-gate } 3873*7c478bd9Sstevel@tonic-gate 3874*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&count_lock); 3875*7c478bd9Sstevel@tonic-gate 3876*7c478bd9Sstevel@tonic-gate flush_path_to_inst(); 3877*7c478bd9Sstevel@tonic-gate } 3878*7c478bd9Sstevel@tonic-gate } 3879*7c478bd9Sstevel@tonic-gate 3880*7c478bd9Sstevel@tonic-gate /* 3881*7c478bd9Sstevel@tonic-gate * Helper function for flush_path_to_inst() below; this routine calls the 3882*7c478bd9Sstevel@tonic-gate * inst_sync syscall to flush the path_to_inst database to the given file. 3883*7c478bd9Sstevel@tonic-gate */ 3884*7c478bd9Sstevel@tonic-gate static int 3885*7c478bd9Sstevel@tonic-gate do_inst_sync(char *filename) 3886*7c478bd9Sstevel@tonic-gate { 3887*7c478bd9Sstevel@tonic-gate void (*sigsaved)(int); 3888*7c478bd9Sstevel@tonic-gate int err = 0; 3889*7c478bd9Sstevel@tonic-gate 3890*7c478bd9Sstevel@tonic-gate vprint(INSTSYNC_MID, "do_inst_sync: about to flush %s\n", filename); 3891*7c478bd9Sstevel@tonic-gate sigsaved = sigset(SIGSYS, SIG_IGN); 3892*7c478bd9Sstevel@tonic-gate if (inst_sync(filename, 0) == -1) 3893*7c478bd9Sstevel@tonic-gate err = errno; 3894*7c478bd9Sstevel@tonic-gate (void) sigset(SIGSYS, sigsaved); 3895*7c478bd9Sstevel@tonic-gate 3896*7c478bd9Sstevel@tonic-gate switch (err) { 3897*7c478bd9Sstevel@tonic-gate case 0: 3898*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 3899*7c478bd9Sstevel@tonic-gate case EALREADY: /* no-op, path_to_inst already up to date */ 3900*7c478bd9Sstevel@tonic-gate return (EALREADY); 3901*7c478bd9Sstevel@tonic-gate case ENOSYS: 3902*7c478bd9Sstevel@tonic-gate err_print(CANT_LOAD_SYSCALL); 3903*7c478bd9Sstevel@tonic-gate break; 3904*7c478bd9Sstevel@tonic-gate case EPERM: 3905*7c478bd9Sstevel@tonic-gate err_print(SUPER_TO_SYNC); 3906*7c478bd9Sstevel@tonic-gate break; 3907*7c478bd9Sstevel@tonic-gate default: 3908*7c478bd9Sstevel@tonic-gate err_print(INSTSYNC_FAILED, filename, strerror(err)); 3909*7c478bd9Sstevel@tonic-gate break; 3910*7c478bd9Sstevel@tonic-gate } 3911*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 3912*7c478bd9Sstevel@tonic-gate } 3913*7c478bd9Sstevel@tonic-gate 3914*7c478bd9Sstevel@tonic-gate /* 3915*7c478bd9Sstevel@tonic-gate * Flush the kernel's path_to_inst database to /etc/path_to_inst. To do so 3916*7c478bd9Sstevel@tonic-gate * safely, the database is flushed to a temporary file, then moved into place. 3917*7c478bd9Sstevel@tonic-gate * 3918*7c478bd9Sstevel@tonic-gate * The following files are used during this process: 3919*7c478bd9Sstevel@tonic-gate * /etc/path_to_inst: The path_to_inst file 3920*7c478bd9Sstevel@tonic-gate * /etc/path_to_inst.<pid>: Contains data flushed from the kernel 3921*7c478bd9Sstevel@tonic-gate * /etc/path_to_inst.old: The backup file 3922*7c478bd9Sstevel@tonic-gate * /etc/path_to_inst.old.<pid>: Temp file for creating backup 3923*7c478bd9Sstevel@tonic-gate * 3924*7c478bd9Sstevel@tonic-gate */ 3925*7c478bd9Sstevel@tonic-gate static void 3926*7c478bd9Sstevel@tonic-gate flush_path_to_inst(void) 3927*7c478bd9Sstevel@tonic-gate { 3928*7c478bd9Sstevel@tonic-gate char *new_inst_file = NULL; 3929*7c478bd9Sstevel@tonic-gate char *old_inst_file = NULL; 3930*7c478bd9Sstevel@tonic-gate char *old_inst_file_npid = NULL; 3931*7c478bd9Sstevel@tonic-gate FILE *inst_file_fp = NULL; 3932*7c478bd9Sstevel@tonic-gate FILE *old_inst_file_fp = NULL; 3933*7c478bd9Sstevel@tonic-gate struct stat sb; 3934*7c478bd9Sstevel@tonic-gate int err = 0; 3935*7c478bd9Sstevel@tonic-gate int c; 3936*7c478bd9Sstevel@tonic-gate int inst_strlen; 3937*7c478bd9Sstevel@tonic-gate 3938*7c478bd9Sstevel@tonic-gate vprint(PATH2INST_MID, "flush_path_to_inst: %s\n", 3939*7c478bd9Sstevel@tonic-gate (flush_path_to_inst_enable == TRUE) ? "ENABLED" : "DISABLED"); 3940*7c478bd9Sstevel@tonic-gate 3941*7c478bd9Sstevel@tonic-gate if (flush_path_to_inst_enable == FALSE) { 3942*7c478bd9Sstevel@tonic-gate return; 3943*7c478bd9Sstevel@tonic-gate } 3944*7c478bd9Sstevel@tonic-gate 3945*7c478bd9Sstevel@tonic-gate inst_strlen = strlen(inst_file); 3946*7c478bd9Sstevel@tonic-gate new_inst_file = s_malloc(inst_strlen + PID_STR_LEN + 2); 3947*7c478bd9Sstevel@tonic-gate old_inst_file = s_malloc(inst_strlen + PID_STR_LEN + 6); 3948*7c478bd9Sstevel@tonic-gate old_inst_file_npid = s_malloc(inst_strlen + 3949*7c478bd9Sstevel@tonic-gate sizeof (INSTANCE_FILE_SUFFIX)); 3950*7c478bd9Sstevel@tonic-gate 3951*7c478bd9Sstevel@tonic-gate (void) snprintf(new_inst_file, inst_strlen + PID_STR_LEN + 2, 3952*7c478bd9Sstevel@tonic-gate "%s.%ld", inst_file, getpid()); 3953*7c478bd9Sstevel@tonic-gate 3954*7c478bd9Sstevel@tonic-gate if (stat(new_inst_file, &sb) == 0) { 3955*7c478bd9Sstevel@tonic-gate s_unlink(new_inst_file); 3956*7c478bd9Sstevel@tonic-gate } 3957*7c478bd9Sstevel@tonic-gate 3958*7c478bd9Sstevel@tonic-gate if ((err = do_inst_sync(new_inst_file)) != DEVFSADM_SUCCESS) { 3959*7c478bd9Sstevel@tonic-gate goto out; 3960*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3961*7c478bd9Sstevel@tonic-gate } 3962*7c478bd9Sstevel@tonic-gate 3963*7c478bd9Sstevel@tonic-gate /* 3964*7c478bd9Sstevel@tonic-gate * Now we deal with the somewhat tricky updating and renaming 3965*7c478bd9Sstevel@tonic-gate * of this critical piece of kernel state. 3966*7c478bd9Sstevel@tonic-gate */ 3967*7c478bd9Sstevel@tonic-gate 3968*7c478bd9Sstevel@tonic-gate /* 3969*7c478bd9Sstevel@tonic-gate * Copy the current instance file into a temporary file. 3970*7c478bd9Sstevel@tonic-gate * Then rename the temporary file into the backup (.old) 3971*7c478bd9Sstevel@tonic-gate * file and rename the newly flushed kernel data into 3972*7c478bd9Sstevel@tonic-gate * the instance file. 3973*7c478bd9Sstevel@tonic-gate * Of course if 'inst_file' doesn't exist, there's much 3974*7c478bd9Sstevel@tonic-gate * less for us to do .. tee hee. 3975*7c478bd9Sstevel@tonic-gate */ 3976*7c478bd9Sstevel@tonic-gate if ((inst_file_fp = fopen(inst_file, "r")) == NULL) { 3977*7c478bd9Sstevel@tonic-gate /* 3978*7c478bd9Sstevel@tonic-gate * No such file. Rename the new onto the old 3979*7c478bd9Sstevel@tonic-gate */ 3980*7c478bd9Sstevel@tonic-gate if ((err = rename(new_inst_file, inst_file)) != 0) 3981*7c478bd9Sstevel@tonic-gate err_print(RENAME_FAILED, inst_file, strerror(errno)); 3982*7c478bd9Sstevel@tonic-gate goto out; 3983*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3984*7c478bd9Sstevel@tonic-gate } 3985*7c478bd9Sstevel@tonic-gate 3986*7c478bd9Sstevel@tonic-gate (void) snprintf(old_inst_file, inst_strlen + PID_STR_LEN + 6, 3987*7c478bd9Sstevel@tonic-gate "%s.old.%ld", inst_file, getpid()); 3988*7c478bd9Sstevel@tonic-gate 3989*7c478bd9Sstevel@tonic-gate if (stat(old_inst_file, &sb) == 0) { 3990*7c478bd9Sstevel@tonic-gate s_unlink(old_inst_file); 3991*7c478bd9Sstevel@tonic-gate } 3992*7c478bd9Sstevel@tonic-gate 3993*7c478bd9Sstevel@tonic-gate if ((old_inst_file_fp = fopen(old_inst_file, "w")) == NULL) { 3994*7c478bd9Sstevel@tonic-gate /* 3995*7c478bd9Sstevel@tonic-gate * Can't open the 'old_inst_file' file for writing. 3996*7c478bd9Sstevel@tonic-gate * This is somewhat strange given that the syscall 3997*7c478bd9Sstevel@tonic-gate * just succeeded to write a file out.. hmm.. maybe 3998*7c478bd9Sstevel@tonic-gate * the fs just filled up or something nasty. 3999*7c478bd9Sstevel@tonic-gate * 4000*7c478bd9Sstevel@tonic-gate * Anyway, abort what we've done so far. 4001*7c478bd9Sstevel@tonic-gate */ 4002*7c478bd9Sstevel@tonic-gate err_print(CANT_UPDATE, old_inst_file); 4003*7c478bd9Sstevel@tonic-gate err = DEVFSADM_FAILURE; 4004*7c478bd9Sstevel@tonic-gate goto out; 4005*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 4006*7c478bd9Sstevel@tonic-gate } 4007*7c478bd9Sstevel@tonic-gate 4008*7c478bd9Sstevel@tonic-gate /* 4009*7c478bd9Sstevel@tonic-gate * Copy current instance file into the temporary file 4010*7c478bd9Sstevel@tonic-gate */ 4011*7c478bd9Sstevel@tonic-gate err = 0; 4012*7c478bd9Sstevel@tonic-gate while ((c = getc(inst_file_fp)) != EOF) { 4013*7c478bd9Sstevel@tonic-gate if ((err = putc(c, old_inst_file_fp)) == EOF) { 4014*7c478bd9Sstevel@tonic-gate break; 4015*7c478bd9Sstevel@tonic-gate } 4016*7c478bd9Sstevel@tonic-gate } 4017*7c478bd9Sstevel@tonic-gate 4018*7c478bd9Sstevel@tonic-gate if (fclose(old_inst_file_fp) == EOF || err == EOF) { 4019*7c478bd9Sstevel@tonic-gate vprint(INFO_MID, CANT_UPDATE, old_inst_file); 4020*7c478bd9Sstevel@tonic-gate err = DEVFSADM_FAILURE; 4021*7c478bd9Sstevel@tonic-gate goto out; 4022*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4023*7c478bd9Sstevel@tonic-gate } 4024*7c478bd9Sstevel@tonic-gate 4025*7c478bd9Sstevel@tonic-gate /* 4026*7c478bd9Sstevel@tonic-gate * Set permissions to be the same on the backup as 4027*7c478bd9Sstevel@tonic-gate * /etc/path_to_inst. 4028*7c478bd9Sstevel@tonic-gate */ 4029*7c478bd9Sstevel@tonic-gate (void) chmod(old_inst_file, 0444); 4030*7c478bd9Sstevel@tonic-gate 4031*7c478bd9Sstevel@tonic-gate /* 4032*7c478bd9Sstevel@tonic-gate * So far, everything we've done is more or less reversible. 4033*7c478bd9Sstevel@tonic-gate * But now we're going to commit ourselves. 4034*7c478bd9Sstevel@tonic-gate */ 4035*7c478bd9Sstevel@tonic-gate 4036*7c478bd9Sstevel@tonic-gate (void) snprintf(old_inst_file_npid, 4037*7c478bd9Sstevel@tonic-gate inst_strlen + sizeof (INSTANCE_FILE_SUFFIX), 4038*7c478bd9Sstevel@tonic-gate "%s%s", inst_file, INSTANCE_FILE_SUFFIX); 4039*7c478bd9Sstevel@tonic-gate 4040*7c478bd9Sstevel@tonic-gate if ((err = rename(old_inst_file, old_inst_file_npid)) != 0) { 4041*7c478bd9Sstevel@tonic-gate err_print(RENAME_FAILED, old_inst_file_npid, 4042*7c478bd9Sstevel@tonic-gate strerror(errno)); 4043*7c478bd9Sstevel@tonic-gate } else if ((err = rename(new_inst_file, inst_file)) != 0) { 4044*7c478bd9Sstevel@tonic-gate err_print(RENAME_FAILED, inst_file, strerror(errno)); 4045*7c478bd9Sstevel@tonic-gate } 4046*7c478bd9Sstevel@tonic-gate 4047*7c478bd9Sstevel@tonic-gate out: 4048*7c478bd9Sstevel@tonic-gate if (inst_file_fp != NULL) { 4049*7c478bd9Sstevel@tonic-gate if (fclose(inst_file_fp) == EOF) { 4050*7c478bd9Sstevel@tonic-gate err_print(FCLOSE_FAILED, inst_file, strerror(errno)); 4051*7c478bd9Sstevel@tonic-gate } 4052*7c478bd9Sstevel@tonic-gate } 4053*7c478bd9Sstevel@tonic-gate 4054*7c478bd9Sstevel@tonic-gate if (stat(new_inst_file, &sb) == 0) { 4055*7c478bd9Sstevel@tonic-gate s_unlink(new_inst_file); 4056*7c478bd9Sstevel@tonic-gate } 4057*7c478bd9Sstevel@tonic-gate free(new_inst_file); 4058*7c478bd9Sstevel@tonic-gate 4059*7c478bd9Sstevel@tonic-gate if (stat(old_inst_file, &sb) == 0) { 4060*7c478bd9Sstevel@tonic-gate s_unlink(old_inst_file); 4061*7c478bd9Sstevel@tonic-gate } 4062*7c478bd9Sstevel@tonic-gate free(old_inst_file); 4063*7c478bd9Sstevel@tonic-gate 4064*7c478bd9Sstevel@tonic-gate free(old_inst_file_npid); 4065*7c478bd9Sstevel@tonic-gate 4066*7c478bd9Sstevel@tonic-gate if (err != 0 && err != EALREADY) { 4067*7c478bd9Sstevel@tonic-gate err_print(FAILED_TO_UPDATE, inst_file); 4068*7c478bd9Sstevel@tonic-gate } 4069*7c478bd9Sstevel@tonic-gate } 4070*7c478bd9Sstevel@tonic-gate 4071*7c478bd9Sstevel@tonic-gate /* 4072*7c478bd9Sstevel@tonic-gate * detach from tty. For daemon mode. 4073*7c478bd9Sstevel@tonic-gate */ 4074*7c478bd9Sstevel@tonic-gate void 4075*7c478bd9Sstevel@tonic-gate detachfromtty() 4076*7c478bd9Sstevel@tonic-gate { 4077*7c478bd9Sstevel@tonic-gate (void) setsid(); 4078*7c478bd9Sstevel@tonic-gate if (DEVFSADM_DEBUG_ON == TRUE) { 4079*7c478bd9Sstevel@tonic-gate return; 4080*7c478bd9Sstevel@tonic-gate } 4081*7c478bd9Sstevel@tonic-gate 4082*7c478bd9Sstevel@tonic-gate (void) close(0); 4083*7c478bd9Sstevel@tonic-gate (void) close(1); 4084*7c478bd9Sstevel@tonic-gate (void) close(2); 4085*7c478bd9Sstevel@tonic-gate (void) open("/dev/null", O_RDWR, 0); 4086*7c478bd9Sstevel@tonic-gate (void) dup(0); 4087*7c478bd9Sstevel@tonic-gate (void) dup(0); 4088*7c478bd9Sstevel@tonic-gate openlog(DEVFSADMD, LOG_PID, LOG_DAEMON); 4089*7c478bd9Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_INFO)); 4090*7c478bd9Sstevel@tonic-gate logflag = TRUE; 4091*7c478bd9Sstevel@tonic-gate } 4092*7c478bd9Sstevel@tonic-gate 4093*7c478bd9Sstevel@tonic-gate /* 4094*7c478bd9Sstevel@tonic-gate * Use an advisory lock to synchronize updates to /dev. If the lock is 4095*7c478bd9Sstevel@tonic-gate * held by another process, block in the fcntl() system call until that 4096*7c478bd9Sstevel@tonic-gate * process drops the lock or exits. The lock file itself is 4097*7c478bd9Sstevel@tonic-gate * DEV_LOCK_FILE. The process id of the current and last process owning 4098*7c478bd9Sstevel@tonic-gate * the lock is kept in the lock file. After acquiring the lock, read the 4099*7c478bd9Sstevel@tonic-gate * process id and return it. It is the process ID which last owned the 4100*7c478bd9Sstevel@tonic-gate * lock, and will be used to determine if caches need to be flushed. 4101*7c478bd9Sstevel@tonic-gate * 4102*7c478bd9Sstevel@tonic-gate * NOTE: if the devlink database is held open by the caller, it may 4103*7c478bd9Sstevel@tonic-gate * be closed by this routine. This is to enforce the following lock ordering: 4104*7c478bd9Sstevel@tonic-gate * 1) /dev lock 2) database open 4105*7c478bd9Sstevel@tonic-gate */ 4106*7c478bd9Sstevel@tonic-gate pid_t 4107*7c478bd9Sstevel@tonic-gate enter_dev_lock() 4108*7c478bd9Sstevel@tonic-gate { 4109*7c478bd9Sstevel@tonic-gate struct flock lock; 4110*7c478bd9Sstevel@tonic-gate int n; 4111*7c478bd9Sstevel@tonic-gate pid_t pid; 4112*7c478bd9Sstevel@tonic-gate pid_t last_owner_pid; 4113*7c478bd9Sstevel@tonic-gate 4114*7c478bd9Sstevel@tonic-gate if (file_mods == FALSE) { 4115*7c478bd9Sstevel@tonic-gate return (0); 4116*7c478bd9Sstevel@tonic-gate } 4117*7c478bd9Sstevel@tonic-gate 4118*7c478bd9Sstevel@tonic-gate s_mkdirp(dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); 4119*7c478bd9Sstevel@tonic-gate (void) snprintf(dev_lockfile, sizeof (dev_lockfile), 4120*7c478bd9Sstevel@tonic-gate "%s/%s", dev_dir, DEV_LOCK_FILE); 4121*7c478bd9Sstevel@tonic-gate 4122*7c478bd9Sstevel@tonic-gate vprint(LOCK_MID, "enter_dev_lock: lock file %s\n", dev_lockfile); 4123*7c478bd9Sstevel@tonic-gate 4124*7c478bd9Sstevel@tonic-gate dev_lock_fd = open(dev_lockfile, O_CREAT|O_RDWR, 0644); 4125*7c478bd9Sstevel@tonic-gate if (dev_lock_fd < 0) { 4126*7c478bd9Sstevel@tonic-gate err_print(OPEN_FAILED, dev_lockfile, strerror(errno)); 4127*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4128*7c478bd9Sstevel@tonic-gate } 4129*7c478bd9Sstevel@tonic-gate 4130*7c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 4131*7c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 4132*7c478bd9Sstevel@tonic-gate lock.l_start = 0; 4133*7c478bd9Sstevel@tonic-gate lock.l_len = 0; 4134*7c478bd9Sstevel@tonic-gate 4135*7c478bd9Sstevel@tonic-gate /* try for the lock, but don't wait */ 4136*7c478bd9Sstevel@tonic-gate if (fcntl(dev_lock_fd, F_SETLK, &lock) == -1) { 4137*7c478bd9Sstevel@tonic-gate if ((errno == EACCES) || (errno == EAGAIN)) { 4138*7c478bd9Sstevel@tonic-gate pid = 0; 4139*7c478bd9Sstevel@tonic-gate n = read(dev_lock_fd, &pid, sizeof (pid_t)); 4140*7c478bd9Sstevel@tonic-gate vprint(LOCK_MID, "waiting for PID %d to complete\n", 4141*7c478bd9Sstevel@tonic-gate (int)pid); 4142*7c478bd9Sstevel@tonic-gate if (lseek(dev_lock_fd, 0, SEEK_SET) == (off_t)-1) { 4143*7c478bd9Sstevel@tonic-gate err_print(LSEEK_FAILED, dev_lockfile, 4144*7c478bd9Sstevel@tonic-gate strerror(errno)); 4145*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4146*7c478bd9Sstevel@tonic-gate } 4147*7c478bd9Sstevel@tonic-gate /* 4148*7c478bd9Sstevel@tonic-gate * wait for the dev lock. If we have the database open, 4149*7c478bd9Sstevel@tonic-gate * close it first - the order of lock acquisition should 4150*7c478bd9Sstevel@tonic-gate * always be: 1) dev_lock 2) database 4151*7c478bd9Sstevel@tonic-gate * This is to prevent deadlocks with any locks the 4152*7c478bd9Sstevel@tonic-gate * database code may hold. 4153*7c478bd9Sstevel@tonic-gate */ 4154*7c478bd9Sstevel@tonic-gate (void) di_devlink_close(&devlink_cache, 0); 4155*7c478bd9Sstevel@tonic-gate if (fcntl(dev_lock_fd, F_SETLKW, &lock) == -1) { 4156*7c478bd9Sstevel@tonic-gate err_print(LOCK_FAILED, dev_lockfile, 4157*7c478bd9Sstevel@tonic-gate strerror(errno)); 4158*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4159*7c478bd9Sstevel@tonic-gate } 4160*7c478bd9Sstevel@tonic-gate } 4161*7c478bd9Sstevel@tonic-gate } 4162*7c478bd9Sstevel@tonic-gate 4163*7c478bd9Sstevel@tonic-gate hold_dev_lock = TRUE; 4164*7c478bd9Sstevel@tonic-gate pid = 0; 4165*7c478bd9Sstevel@tonic-gate n = read(dev_lock_fd, &pid, sizeof (pid_t)); 4166*7c478bd9Sstevel@tonic-gate if (n == sizeof (pid_t) && pid == getpid()) { 4167*7c478bd9Sstevel@tonic-gate return (pid); 4168*7c478bd9Sstevel@tonic-gate } 4169*7c478bd9Sstevel@tonic-gate 4170*7c478bd9Sstevel@tonic-gate last_owner_pid = pid; 4171*7c478bd9Sstevel@tonic-gate 4172*7c478bd9Sstevel@tonic-gate if (lseek(dev_lock_fd, 0, SEEK_SET) == (off_t)-1) { 4173*7c478bd9Sstevel@tonic-gate err_print(LSEEK_FAILED, dev_lockfile, strerror(errno)); 4174*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4175*7c478bd9Sstevel@tonic-gate } 4176*7c478bd9Sstevel@tonic-gate pid = getpid(); 4177*7c478bd9Sstevel@tonic-gate n = write(dev_lock_fd, &pid, sizeof (pid_t)); 4178*7c478bd9Sstevel@tonic-gate if (n != sizeof (pid_t)) { 4179*7c478bd9Sstevel@tonic-gate err_print(WRITE_FAILED, dev_lockfile, strerror(errno)); 4180*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4181*7c478bd9Sstevel@tonic-gate } 4182*7c478bd9Sstevel@tonic-gate 4183*7c478bd9Sstevel@tonic-gate return (last_owner_pid); 4184*7c478bd9Sstevel@tonic-gate } 4185*7c478bd9Sstevel@tonic-gate 4186*7c478bd9Sstevel@tonic-gate /* 4187*7c478bd9Sstevel@tonic-gate * Drop the advisory /dev lock, close lock file. Close and re-open the 4188*7c478bd9Sstevel@tonic-gate * file every time so to ensure a resync if for some reason the lock file 4189*7c478bd9Sstevel@tonic-gate * gets removed. 4190*7c478bd9Sstevel@tonic-gate */ 4191*7c478bd9Sstevel@tonic-gate void 4192*7c478bd9Sstevel@tonic-gate exit_dev_lock() 4193*7c478bd9Sstevel@tonic-gate { 4194*7c478bd9Sstevel@tonic-gate struct flock unlock; 4195*7c478bd9Sstevel@tonic-gate 4196*7c478bd9Sstevel@tonic-gate if (hold_dev_lock == FALSE) { 4197*7c478bd9Sstevel@tonic-gate return; 4198*7c478bd9Sstevel@tonic-gate } 4199*7c478bd9Sstevel@tonic-gate 4200*7c478bd9Sstevel@tonic-gate vprint(LOCK_MID, "exit_dev_lock: lock file %s\n", dev_lockfile); 4201*7c478bd9Sstevel@tonic-gate 4202*7c478bd9Sstevel@tonic-gate unlock.l_type = F_UNLCK; 4203*7c478bd9Sstevel@tonic-gate unlock.l_whence = SEEK_SET; 4204*7c478bd9Sstevel@tonic-gate unlock.l_start = 0; 4205*7c478bd9Sstevel@tonic-gate unlock.l_len = 0; 4206*7c478bd9Sstevel@tonic-gate 4207*7c478bd9Sstevel@tonic-gate if (fcntl(dev_lock_fd, F_SETLK, &unlock) == -1) { 4208*7c478bd9Sstevel@tonic-gate err_print(UNLOCK_FAILED, dev_lockfile, strerror(errno)); 4209*7c478bd9Sstevel@tonic-gate } 4210*7c478bd9Sstevel@tonic-gate 4211*7c478bd9Sstevel@tonic-gate hold_dev_lock = FALSE; 4212*7c478bd9Sstevel@tonic-gate 4213*7c478bd9Sstevel@tonic-gate if (close(dev_lock_fd) == -1) { 4214*7c478bd9Sstevel@tonic-gate err_print(CLOSE_FAILED, dev_lockfile, strerror(errno)); 4215*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4216*7c478bd9Sstevel@tonic-gate } 4217*7c478bd9Sstevel@tonic-gate } 4218*7c478bd9Sstevel@tonic-gate 4219*7c478bd9Sstevel@tonic-gate /* 4220*7c478bd9Sstevel@tonic-gate * 4221*7c478bd9Sstevel@tonic-gate * Use an advisory lock to ensure that only one daemon process is active 4222*7c478bd9Sstevel@tonic-gate * in the system at any point in time. If the lock is held by another 4223*7c478bd9Sstevel@tonic-gate * process, do not block but return the pid owner of the lock to the 4224*7c478bd9Sstevel@tonic-gate * caller immediately. The lock is cleared if the holding daemon process 4225*7c478bd9Sstevel@tonic-gate * exits for any reason even if the lock file remains, so the daemon can 4226*7c478bd9Sstevel@tonic-gate * be restarted if necessary. The lock file is DAEMON_LOCK_FILE. 4227*7c478bd9Sstevel@tonic-gate */ 4228*7c478bd9Sstevel@tonic-gate pid_t 4229*7c478bd9Sstevel@tonic-gate enter_daemon_lock(void) 4230*7c478bd9Sstevel@tonic-gate { 4231*7c478bd9Sstevel@tonic-gate struct flock lock; 4232*7c478bd9Sstevel@tonic-gate 4233*7c478bd9Sstevel@tonic-gate s_mkdirp(dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); 4234*7c478bd9Sstevel@tonic-gate (void) snprintf(daemon_lockfile, sizeof (daemon_lockfile), 4235*7c478bd9Sstevel@tonic-gate "%s/%s", dev_dir, DAEMON_LOCK_FILE); 4236*7c478bd9Sstevel@tonic-gate 4237*7c478bd9Sstevel@tonic-gate vprint(LOCK_MID, "enter_daemon_lock: lock file %s\n", daemon_lockfile); 4238*7c478bd9Sstevel@tonic-gate 4239*7c478bd9Sstevel@tonic-gate daemon_lock_fd = open(daemon_lockfile, O_CREAT|O_RDWR, 0644); 4240*7c478bd9Sstevel@tonic-gate if (daemon_lock_fd < 0) { 4241*7c478bd9Sstevel@tonic-gate err_print(OPEN_FAILED, daemon_lockfile, strerror(errno)); 4242*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4243*7c478bd9Sstevel@tonic-gate } 4244*7c478bd9Sstevel@tonic-gate 4245*7c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 4246*7c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 4247*7c478bd9Sstevel@tonic-gate lock.l_start = 0; 4248*7c478bd9Sstevel@tonic-gate lock.l_len = 0; 4249*7c478bd9Sstevel@tonic-gate 4250*7c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 4251*7c478bd9Sstevel@tonic-gate 4252*7c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EDEADLK) { 4253*7c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) { 4254*7c478bd9Sstevel@tonic-gate err_print(LOCK_FAILED, daemon_lockfile, 4255*7c478bd9Sstevel@tonic-gate strerror(errno)); 4256*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4257*7c478bd9Sstevel@tonic-gate } 4258*7c478bd9Sstevel@tonic-gate return (lock.l_pid); 4259*7c478bd9Sstevel@tonic-gate } 4260*7c478bd9Sstevel@tonic-gate } 4261*7c478bd9Sstevel@tonic-gate hold_daemon_lock = TRUE; 4262*7c478bd9Sstevel@tonic-gate return (getpid()); 4263*7c478bd9Sstevel@tonic-gate } 4264*7c478bd9Sstevel@tonic-gate 4265*7c478bd9Sstevel@tonic-gate /* 4266*7c478bd9Sstevel@tonic-gate * Drop the advisory daemon lock, close lock file 4267*7c478bd9Sstevel@tonic-gate */ 4268*7c478bd9Sstevel@tonic-gate void 4269*7c478bd9Sstevel@tonic-gate exit_daemon_lock(void) 4270*7c478bd9Sstevel@tonic-gate { 4271*7c478bd9Sstevel@tonic-gate struct flock lock; 4272*7c478bd9Sstevel@tonic-gate 4273*7c478bd9Sstevel@tonic-gate if (hold_daemon_lock == FALSE) { 4274*7c478bd9Sstevel@tonic-gate return; 4275*7c478bd9Sstevel@tonic-gate } 4276*7c478bd9Sstevel@tonic-gate 4277*7c478bd9Sstevel@tonic-gate vprint(LOCK_MID, "exit_daemon_lock: lock file %s\n", daemon_lockfile); 4278*7c478bd9Sstevel@tonic-gate 4279*7c478bd9Sstevel@tonic-gate lock.l_type = F_UNLCK; 4280*7c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 4281*7c478bd9Sstevel@tonic-gate lock.l_start = 0; 4282*7c478bd9Sstevel@tonic-gate lock.l_len = 0; 4283*7c478bd9Sstevel@tonic-gate 4284*7c478bd9Sstevel@tonic-gate if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 4285*7c478bd9Sstevel@tonic-gate err_print(UNLOCK_FAILED, daemon_lockfile, strerror(errno)); 4286*7c478bd9Sstevel@tonic-gate } 4287*7c478bd9Sstevel@tonic-gate 4288*7c478bd9Sstevel@tonic-gate if (close(daemon_lock_fd) == -1) { 4289*7c478bd9Sstevel@tonic-gate err_print(CLOSE_FAILED, daemon_lockfile, strerror(errno)); 4290*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 4291*7c478bd9Sstevel@tonic-gate } 4292*7c478bd9Sstevel@tonic-gate } 4293*7c478bd9Sstevel@tonic-gate 4294*7c478bd9Sstevel@tonic-gate /* 4295*7c478bd9Sstevel@tonic-gate * Called to removed danging nodes in two different modes: RM_PRE, RM_POST. 4296*7c478bd9Sstevel@tonic-gate * RM_PRE mode is called before processing the entire devinfo tree, and RM_POST 4297*7c478bd9Sstevel@tonic-gate * is called after processing the entire devinfo tree. 4298*7c478bd9Sstevel@tonic-gate */ 4299*7c478bd9Sstevel@tonic-gate static void 4300*7c478bd9Sstevel@tonic-gate pre_and_post_cleanup(int flags) 4301*7c478bd9Sstevel@tonic-gate { 4302*7c478bd9Sstevel@tonic-gate remove_list_t *rm; 4303*7c478bd9Sstevel@tonic-gate recurse_dev_t rd; 4304*7c478bd9Sstevel@tonic-gate cleanup_data_t cleanup_data; 4305*7c478bd9Sstevel@tonic-gate char *fcn = "pre_and_post_cleanup: "; 4306*7c478bd9Sstevel@tonic-gate 4307*7c478bd9Sstevel@tonic-gate if (build_dev == FALSE) 4308*7c478bd9Sstevel@tonic-gate return; 4309*7c478bd9Sstevel@tonic-gate 4310*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "attempting %s-cleanup\n", 4311*7c478bd9Sstevel@tonic-gate flags == RM_PRE ? "pre" : "post"); 4312*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%sflags = %d\n", fcn, flags); 4313*7c478bd9Sstevel@tonic-gate 4314*7c478bd9Sstevel@tonic-gate /* 4315*7c478bd9Sstevel@tonic-gate * the generic function recurse_dev_re is shared among different 4316*7c478bd9Sstevel@tonic-gate * functions, so set the method and data that it should use for 4317*7c478bd9Sstevel@tonic-gate * matches. 4318*7c478bd9Sstevel@tonic-gate */ 4319*7c478bd9Sstevel@tonic-gate rd.fcn = matching_dev; 4320*7c478bd9Sstevel@tonic-gate rd.data = (void *)&cleanup_data; 4321*7c478bd9Sstevel@tonic-gate cleanup_data.flags = flags; 4322*7c478bd9Sstevel@tonic-gate 4323*7c478bd9Sstevel@tonic-gate for (rm = remove_head; rm != NULL; rm = rm->next) { 4324*7c478bd9Sstevel@tonic-gate if ((flags & rm->remove->flags) == flags) { 4325*7c478bd9Sstevel@tonic-gate cleanup_data.rm = rm; 4326*7c478bd9Sstevel@tonic-gate /* 4327*7c478bd9Sstevel@tonic-gate * If reached this point, RM_PRE or RM_POST cleanup is 4328*7c478bd9Sstevel@tonic-gate * desired. clean_ok() decides whether to clean 4329*7c478bd9Sstevel@tonic-gate * under the given circumstances. 4330*7c478bd9Sstevel@tonic-gate */ 4331*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%scleanup: PRE or POST\n", fcn); 4332*7c478bd9Sstevel@tonic-gate if (clean_ok(rm->remove) == DEVFSADM_SUCCESS) { 4333*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "cleanup: cleanup OK\n"); 4334*7c478bd9Sstevel@tonic-gate recurse_dev_re(dev_dir, rm->remove-> 4335*7c478bd9Sstevel@tonic-gate dev_dirs_re, &rd); 4336*7c478bd9Sstevel@tonic-gate } 4337*7c478bd9Sstevel@tonic-gate } 4338*7c478bd9Sstevel@tonic-gate } 4339*7c478bd9Sstevel@tonic-gate } 4340*7c478bd9Sstevel@tonic-gate 4341*7c478bd9Sstevel@tonic-gate /* 4342*7c478bd9Sstevel@tonic-gate * clean_ok() determines whether cleanup should be done according 4343*7c478bd9Sstevel@tonic-gate * to the following matrix: 4344*7c478bd9Sstevel@tonic-gate * 4345*7c478bd9Sstevel@tonic-gate * command line arguments RM_PRE RM_POST RM_PRE && RM_POST && 4346*7c478bd9Sstevel@tonic-gate * RM_ALWAYS RM_ALWAYS 4347*7c478bd9Sstevel@tonic-gate * ---------------------- ------ ----- --------- ---------- 4348*7c478bd9Sstevel@tonic-gate * 4349*7c478bd9Sstevel@tonic-gate * <neither -c nor -C> - - pre-clean post-clean 4350*7c478bd9Sstevel@tonic-gate * 4351*7c478bd9Sstevel@tonic-gate * -C pre-clean post-clean pre-clean post-clean 4352*7c478bd9Sstevel@tonic-gate * 4353*7c478bd9Sstevel@tonic-gate * -C -c class pre-clean post-clean pre-clean post-clean 4354*7c478bd9Sstevel@tonic-gate * if class if class if class if class 4355*7c478bd9Sstevel@tonic-gate * matches matches matches matches 4356*7c478bd9Sstevel@tonic-gate * 4357*7c478bd9Sstevel@tonic-gate * -c class - - pre-clean post-clean 4358*7c478bd9Sstevel@tonic-gate * if class if class 4359*7c478bd9Sstevel@tonic-gate * matches matches 4360*7c478bd9Sstevel@tonic-gate * 4361*7c478bd9Sstevel@tonic-gate */ 4362*7c478bd9Sstevel@tonic-gate static int 4363*7c478bd9Sstevel@tonic-gate clean_ok(devfsadm_remove_t *remove) 4364*7c478bd9Sstevel@tonic-gate { 4365*7c478bd9Sstevel@tonic-gate int i; 4366*7c478bd9Sstevel@tonic-gate 4367*7c478bd9Sstevel@tonic-gate if (single_drv == TRUE) { 4368*7c478bd9Sstevel@tonic-gate /* no cleanup at all when using -i option */ 4369*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 4370*7c478bd9Sstevel@tonic-gate } 4371*7c478bd9Sstevel@tonic-gate 4372*7c478bd9Sstevel@tonic-gate /* 4373*7c478bd9Sstevel@tonic-gate * no cleanup if drivers are not loaded. We make an exception 4374*7c478bd9Sstevel@tonic-gate * for the "disks" program however, since disks has a public 4375*7c478bd9Sstevel@tonic-gate * cleanup flag (-C) and disk drivers are usually never 4376*7c478bd9Sstevel@tonic-gate * unloaded. 4377*7c478bd9Sstevel@tonic-gate */ 4378*7c478bd9Sstevel@tonic-gate if (load_attach_drv == FALSE && strcmp(prog, DISKS) != 0) { 4379*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 4380*7c478bd9Sstevel@tonic-gate } 4381*7c478bd9Sstevel@tonic-gate 4382*7c478bd9Sstevel@tonic-gate /* if the cleanup flag was not specified, return false */ 4383*7c478bd9Sstevel@tonic-gate if ((cleanup == FALSE) && ((remove->flags & RM_ALWAYS) == 0)) { 4384*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 4385*7c478bd9Sstevel@tonic-gate } 4386*7c478bd9Sstevel@tonic-gate 4387*7c478bd9Sstevel@tonic-gate if (num_classes == 0) { 4388*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 4389*7c478bd9Sstevel@tonic-gate } 4390*7c478bd9Sstevel@tonic-gate 4391*7c478bd9Sstevel@tonic-gate /* 4392*7c478bd9Sstevel@tonic-gate * if reached this point, check to see if the class in the given 4393*7c478bd9Sstevel@tonic-gate * remove structure matches a class given on the command line 4394*7c478bd9Sstevel@tonic-gate */ 4395*7c478bd9Sstevel@tonic-gate 4396*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_classes; i++) { 4397*7c478bd9Sstevel@tonic-gate if (strcmp(remove->device_class, classes[i]) == 0) { 4398*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 4399*7c478bd9Sstevel@tonic-gate } 4400*7c478bd9Sstevel@tonic-gate } 4401*7c478bd9Sstevel@tonic-gate 4402*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 4403*7c478bd9Sstevel@tonic-gate } 4404*7c478bd9Sstevel@tonic-gate 4405*7c478bd9Sstevel@tonic-gate /* 4406*7c478bd9Sstevel@tonic-gate * Called to remove dangling nodes after receiving a hotplug event 4407*7c478bd9Sstevel@tonic-gate * containing the physical node pathname to be removed. 4408*7c478bd9Sstevel@tonic-gate */ 4409*7c478bd9Sstevel@tonic-gate void 4410*7c478bd9Sstevel@tonic-gate hot_cleanup(char *node_path, char *minor_name, char *ev_subclass, 4411*7c478bd9Sstevel@tonic-gate char *driver_name, int instance) 4412*7c478bd9Sstevel@tonic-gate { 4413*7c478bd9Sstevel@tonic-gate link_t *link; 4414*7c478bd9Sstevel@tonic-gate linkhead_t *head; 4415*7c478bd9Sstevel@tonic-gate remove_list_t *rm; 4416*7c478bd9Sstevel@tonic-gate char *fcn = "hot_cleanup: "; 4417*7c478bd9Sstevel@tonic-gate char path[PATH_MAX + 1]; 4418*7c478bd9Sstevel@tonic-gate int path_len; 4419*7c478bd9Sstevel@tonic-gate char rmlink[PATH_MAX + 1]; 4420*7c478bd9Sstevel@tonic-gate nvlist_t *nvl = NULL; 4421*7c478bd9Sstevel@tonic-gate 4422*7c478bd9Sstevel@tonic-gate /* 4423*7c478bd9Sstevel@tonic-gate * dev links can go away as part of hot cleanup. 4424*7c478bd9Sstevel@tonic-gate * So first build event attributes in order capture dev links. 4425*7c478bd9Sstevel@tonic-gate */ 4426*7c478bd9Sstevel@tonic-gate if (ev_subclass != NULL) 4427*7c478bd9Sstevel@tonic-gate nvl = build_event_attributes(EC_DEV_REMOVE, ev_subclass, 4428*7c478bd9Sstevel@tonic-gate node_path, DI_NODE_NIL, driver_name, instance); 4429*7c478bd9Sstevel@tonic-gate 4430*7c478bd9Sstevel@tonic-gate (void) strcpy(path, node_path); 4431*7c478bd9Sstevel@tonic-gate (void) strcat(path, ":"); 4432*7c478bd9Sstevel@tonic-gate (void) strcat(path, minor_name == NULL ? "" : minor_name); 4433*7c478bd9Sstevel@tonic-gate 4434*7c478bd9Sstevel@tonic-gate path_len = strlen(path); 4435*7c478bd9Sstevel@tonic-gate 4436*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%spath=%s\n", fcn, path); 4437*7c478bd9Sstevel@tonic-gate 4438*7c478bd9Sstevel@tonic-gate for (rm = remove_head; rm != NULL; rm = rm->next) { 4439*7c478bd9Sstevel@tonic-gate if ((RM_HOT & rm->remove->flags) == RM_HOT) { 4440*7c478bd9Sstevel@tonic-gate head = get_cached_links(rm->remove->dev_dirs_re); 4441*7c478bd9Sstevel@tonic-gate assert(head->nextlink == NULL); 4442*7c478bd9Sstevel@tonic-gate for (link = head->link; 4443*7c478bd9Sstevel@tonic-gate link != NULL; link = head->nextlink) { 4444*7c478bd9Sstevel@tonic-gate /* 4445*7c478bd9Sstevel@tonic-gate * The remove callback below may remove 4446*7c478bd9Sstevel@tonic-gate * the current and/or any or all of the 4447*7c478bd9Sstevel@tonic-gate * subsequent links in the list. 4448*7c478bd9Sstevel@tonic-gate * Save the next link in the head. If 4449*7c478bd9Sstevel@tonic-gate * the callback removes the next link 4450*7c478bd9Sstevel@tonic-gate * the saved pointer in the head will be 4451*7c478bd9Sstevel@tonic-gate * updated by the callback to point at 4452*7c478bd9Sstevel@tonic-gate * the next valid link. 4453*7c478bd9Sstevel@tonic-gate */ 4454*7c478bd9Sstevel@tonic-gate head->nextlink = link->next; 4455*7c478bd9Sstevel@tonic-gate if (strncmp(link->contents, path, 4456*7c478bd9Sstevel@tonic-gate path_len) == 0) { 4457*7c478bd9Sstevel@tonic-gate 4458*7c478bd9Sstevel@tonic-gate if (call_minor_init(rm->modptr) == 4459*7c478bd9Sstevel@tonic-gate DEVFSADM_FAILURE) 4460*7c478bd9Sstevel@tonic-gate continue; 4461*7c478bd9Sstevel@tonic-gate 4462*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, 4463*7c478bd9Sstevel@tonic-gate "%sremoving %s -> %s\n", fcn, 4464*7c478bd9Sstevel@tonic-gate link->devlink, link->contents); 4465*7c478bd9Sstevel@tonic-gate /* 4466*7c478bd9Sstevel@tonic-gate * Use a copy of the cached link name 4467*7c478bd9Sstevel@tonic-gate * as the cache entry will go away 4468*7c478bd9Sstevel@tonic-gate * during link removal 4469*7c478bd9Sstevel@tonic-gate */ 4470*7c478bd9Sstevel@tonic-gate (void) snprintf(rmlink, sizeof (rmlink), 4471*7c478bd9Sstevel@tonic-gate "%s", link->devlink); 4472*7c478bd9Sstevel@tonic-gate (*(rm->remove->callback_fcn))(rmlink); 4473*7c478bd9Sstevel@tonic-gate } 4474*7c478bd9Sstevel@tonic-gate } 4475*7c478bd9Sstevel@tonic-gate } 4476*7c478bd9Sstevel@tonic-gate } 4477*7c478bd9Sstevel@tonic-gate 4478*7c478bd9Sstevel@tonic-gate /* now log an event */ 4479*7c478bd9Sstevel@tonic-gate if (nvl) { 4480*7c478bd9Sstevel@tonic-gate log_event(EC_DEV_REMOVE, ev_subclass, nvl); 4481*7c478bd9Sstevel@tonic-gate free(nvl); 4482*7c478bd9Sstevel@tonic-gate } 4483*7c478bd9Sstevel@tonic-gate } 4484*7c478bd9Sstevel@tonic-gate 4485*7c478bd9Sstevel@tonic-gate /* 4486*7c478bd9Sstevel@tonic-gate * Open the dir current_dir. For every file which matches the first dir 4487*7c478bd9Sstevel@tonic-gate * component of path_re, recurse. If there are no more *dir* path 4488*7c478bd9Sstevel@tonic-gate * components left in path_re (ie no more /), then call function rd->fcn. 4489*7c478bd9Sstevel@tonic-gate */ 4490*7c478bd9Sstevel@tonic-gate static void 4491*7c478bd9Sstevel@tonic-gate recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd) 4492*7c478bd9Sstevel@tonic-gate { 4493*7c478bd9Sstevel@tonic-gate regex_t re1; 4494*7c478bd9Sstevel@tonic-gate char *slash; 4495*7c478bd9Sstevel@tonic-gate char new_path[PATH_MAX + 1]; 4496*7c478bd9Sstevel@tonic-gate char *anchored_path_re; 4497*7c478bd9Sstevel@tonic-gate struct dirent *entp; 4498*7c478bd9Sstevel@tonic-gate struct dirent *retp; 4499*7c478bd9Sstevel@tonic-gate DIR *dp; 4500*7c478bd9Sstevel@tonic-gate size_t len; 4501*7c478bd9Sstevel@tonic-gate 4502*7c478bd9Sstevel@tonic-gate vprint(RECURSEDEV_MID, "recurse_dev_re: curr = %s path=%s\n", 4503*7c478bd9Sstevel@tonic-gate current_dir, path_re); 4504*7c478bd9Sstevel@tonic-gate 4505*7c478bd9Sstevel@tonic-gate if ((dp = opendir(current_dir)) == NULL) { 4506*7c478bd9Sstevel@tonic-gate return; 4507*7c478bd9Sstevel@tonic-gate } 4508*7c478bd9Sstevel@tonic-gate 4509*7c478bd9Sstevel@tonic-gate len = strlen(path_re); 4510*7c478bd9Sstevel@tonic-gate if ((slash = strchr(path_re, '/')) != NULL) { 4511*7c478bd9Sstevel@tonic-gate len = (slash - path_re); 4512*7c478bd9Sstevel@tonic-gate } 4513*7c478bd9Sstevel@tonic-gate 4514*7c478bd9Sstevel@tonic-gate entp = s_malloc(PATH_MAX + 1 + sizeof (struct dirent)); 4515*7c478bd9Sstevel@tonic-gate 4516*7c478bd9Sstevel@tonic-gate anchored_path_re = s_malloc(len + 3); 4517*7c478bd9Sstevel@tonic-gate (void) sprintf(anchored_path_re, "^%.*s$", len, path_re); 4518*7c478bd9Sstevel@tonic-gate 4519*7c478bd9Sstevel@tonic-gate if (regcomp(&re1, anchored_path_re, REG_EXTENDED) != 0) { 4520*7c478bd9Sstevel@tonic-gate free(anchored_path_re); 4521*7c478bd9Sstevel@tonic-gate goto out; 4522*7c478bd9Sstevel@tonic-gate } 4523*7c478bd9Sstevel@tonic-gate 4524*7c478bd9Sstevel@tonic-gate free(anchored_path_re); 4525*7c478bd9Sstevel@tonic-gate 4526*7c478bd9Sstevel@tonic-gate while (readdir_r(dp, entp, &retp) == 0) { 4527*7c478bd9Sstevel@tonic-gate 4528*7c478bd9Sstevel@tonic-gate /* See 4062296 to understand readdir_r semantics */ 4529*7c478bd9Sstevel@tonic-gate if (retp == NULL) { 4530*7c478bd9Sstevel@tonic-gate break; 4531*7c478bd9Sstevel@tonic-gate } 4532*7c478bd9Sstevel@tonic-gate 4533*7c478bd9Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 || 4534*7c478bd9Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0) { 4535*7c478bd9Sstevel@tonic-gate continue; 4536*7c478bd9Sstevel@tonic-gate } 4537*7c478bd9Sstevel@tonic-gate 4538*7c478bd9Sstevel@tonic-gate if (regexec(&re1, entp->d_name, 0, NULL, 0) == 0) { 4539*7c478bd9Sstevel@tonic-gate /* match */ 4540*7c478bd9Sstevel@tonic-gate (void) strcpy(new_path, current_dir); 4541*7c478bd9Sstevel@tonic-gate (void) strcat(new_path, "/"); 4542*7c478bd9Sstevel@tonic-gate (void) strcat(new_path, entp->d_name); 4543*7c478bd9Sstevel@tonic-gate 4544*7c478bd9Sstevel@tonic-gate vprint(RECURSEDEV_MID, "recurse_dev_re: match, new " 4545*7c478bd9Sstevel@tonic-gate "path = %s\n", new_path); 4546*7c478bd9Sstevel@tonic-gate 4547*7c478bd9Sstevel@tonic-gate if (slash != NULL) { 4548*7c478bd9Sstevel@tonic-gate recurse_dev_re(new_path, slash + 1, rd); 4549*7c478bd9Sstevel@tonic-gate } else { 4550*7c478bd9Sstevel@tonic-gate /* reached the leaf component of path_re */ 4551*7c478bd9Sstevel@tonic-gate vprint(RECURSEDEV_MID, 4552*7c478bd9Sstevel@tonic-gate "recurse_dev_re: calling fcn\n"); 4553*7c478bd9Sstevel@tonic-gate (*(rd->fcn))(new_path, rd->data); 4554*7c478bd9Sstevel@tonic-gate } 4555*7c478bd9Sstevel@tonic-gate } 4556*7c478bd9Sstevel@tonic-gate } 4557*7c478bd9Sstevel@tonic-gate 4558*7c478bd9Sstevel@tonic-gate regfree(&re1); 4559*7c478bd9Sstevel@tonic-gate 4560*7c478bd9Sstevel@tonic-gate out: 4561*7c478bd9Sstevel@tonic-gate free(entp); 4562*7c478bd9Sstevel@tonic-gate s_closedir(dp); 4563*7c478bd9Sstevel@tonic-gate } 4564*7c478bd9Sstevel@tonic-gate 4565*7c478bd9Sstevel@tonic-gate /* 4566*7c478bd9Sstevel@tonic-gate * Found a devpath which matches a RE in the remove structure. 4567*7c478bd9Sstevel@tonic-gate * Now check to see if it is dangling. 4568*7c478bd9Sstevel@tonic-gate */ 4569*7c478bd9Sstevel@tonic-gate static void 4570*7c478bd9Sstevel@tonic-gate matching_dev(char *devpath, void *data) 4571*7c478bd9Sstevel@tonic-gate { 4572*7c478bd9Sstevel@tonic-gate cleanup_data_t *cleanup_data = data; 4573*7c478bd9Sstevel@tonic-gate char *fcn = "matching_dev: "; 4574*7c478bd9Sstevel@tonic-gate 4575*7c478bd9Sstevel@tonic-gate vprint(RECURSEDEV_MID, "%sexamining devpath = '%s'\n", fcn, 4576*7c478bd9Sstevel@tonic-gate devpath); 4577*7c478bd9Sstevel@tonic-gate 4578*7c478bd9Sstevel@tonic-gate if (resolve_link(devpath, NULL, NULL, NULL, 1) == TRUE) { 4579*7c478bd9Sstevel@tonic-gate if (call_minor_init(cleanup_data->rm->modptr) == 4580*7c478bd9Sstevel@tonic-gate DEVFSADM_FAILURE) { 4581*7c478bd9Sstevel@tonic-gate return; 4582*7c478bd9Sstevel@tonic-gate } 4583*7c478bd9Sstevel@tonic-gate 4584*7c478bd9Sstevel@tonic-gate devpath += strlen(dev_dir) + strlen("/"); 4585*7c478bd9Sstevel@tonic-gate 4586*7c478bd9Sstevel@tonic-gate vprint(RECURSEDEV_MID, "%scalling" 4587*7c478bd9Sstevel@tonic-gate " callback %s\n", fcn, devpath); 4588*7c478bd9Sstevel@tonic-gate (*(cleanup_data->rm->remove->callback_fcn))(devpath); 4589*7c478bd9Sstevel@tonic-gate } 4590*7c478bd9Sstevel@tonic-gate } 4591*7c478bd9Sstevel@tonic-gate 4592*7c478bd9Sstevel@tonic-gate int 4593*7c478bd9Sstevel@tonic-gate devfsadm_read_link(char *link, char **devfs_path) 4594*7c478bd9Sstevel@tonic-gate { 4595*7c478bd9Sstevel@tonic-gate char devlink[PATH_MAX]; 4596*7c478bd9Sstevel@tonic-gate 4597*7c478bd9Sstevel@tonic-gate *devfs_path = NULL; 4598*7c478bd9Sstevel@tonic-gate 4599*7c478bd9Sstevel@tonic-gate /* prepend link with dev_dir contents */ 4600*7c478bd9Sstevel@tonic-gate (void) strcpy(devlink, dev_dir); 4601*7c478bd9Sstevel@tonic-gate (void) strcat(devlink, "/"); 4602*7c478bd9Sstevel@tonic-gate (void) strcat(devlink, link); 4603*7c478bd9Sstevel@tonic-gate 4604*7c478bd9Sstevel@tonic-gate /* We *don't* want a stat of the /devices node */ 4605*7c478bd9Sstevel@tonic-gate (void) resolve_link(devlink, NULL, NULL, devfs_path, 0); 4606*7c478bd9Sstevel@tonic-gate 4607*7c478bd9Sstevel@tonic-gate return (*devfs_path ? DEVFSADM_SUCCESS : DEVFSADM_FAILURE); 4608*7c478bd9Sstevel@tonic-gate } 4609*7c478bd9Sstevel@tonic-gate 4610*7c478bd9Sstevel@tonic-gate int 4611*7c478bd9Sstevel@tonic-gate devfsadm_link_valid(char *link) 4612*7c478bd9Sstevel@tonic-gate { 4613*7c478bd9Sstevel@tonic-gate struct stat sb; 4614*7c478bd9Sstevel@tonic-gate char devlink[PATH_MAX + 1], *contents; 4615*7c478bd9Sstevel@tonic-gate int rv, type; 4616*7c478bd9Sstevel@tonic-gate 4617*7c478bd9Sstevel@tonic-gate /* prepend link with dev_dir contents */ 4618*7c478bd9Sstevel@tonic-gate (void) strcpy(devlink, dev_dir); 4619*7c478bd9Sstevel@tonic-gate (void) strcat(devlink, "/"); 4620*7c478bd9Sstevel@tonic-gate (void) strcat(devlink, link); 4621*7c478bd9Sstevel@tonic-gate 4622*7c478bd9Sstevel@tonic-gate if (lstat(devlink, &sb) != 0) { 4623*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FALSE); 4624*7c478bd9Sstevel@tonic-gate } 4625*7c478bd9Sstevel@tonic-gate 4626*7c478bd9Sstevel@tonic-gate contents = NULL; 4627*7c478bd9Sstevel@tonic-gate type = 0; 4628*7c478bd9Sstevel@tonic-gate if (resolve_link(devlink, &contents, &type, NULL, 1) == TRUE) { 4629*7c478bd9Sstevel@tonic-gate rv = DEVFSADM_FALSE; 4630*7c478bd9Sstevel@tonic-gate } else { 4631*7c478bd9Sstevel@tonic-gate rv = DEVFSADM_TRUE; 4632*7c478bd9Sstevel@tonic-gate } 4633*7c478bd9Sstevel@tonic-gate 4634*7c478bd9Sstevel@tonic-gate /* 4635*7c478bd9Sstevel@tonic-gate * The link exists. Add it to the database 4636*7c478bd9Sstevel@tonic-gate */ 4637*7c478bd9Sstevel@tonic-gate (void) di_devlink_add_link(devlink_cache, link, contents, type); 4638*7c478bd9Sstevel@tonic-gate free(contents); 4639*7c478bd9Sstevel@tonic-gate 4640*7c478bd9Sstevel@tonic-gate return (rv); 4641*7c478bd9Sstevel@tonic-gate } 4642*7c478bd9Sstevel@tonic-gate 4643*7c478bd9Sstevel@tonic-gate /* 4644*7c478bd9Sstevel@tonic-gate * devpath: Absolute path to /dev link 4645*7c478bd9Sstevel@tonic-gate * content_p: Returns malloced string (link content) 4646*7c478bd9Sstevel@tonic-gate * type_p: Returns link type: primary or secondary 4647*7c478bd9Sstevel@tonic-gate * devfs_path: Returns malloced string: /devices path w/out "/devices" 4648*7c478bd9Sstevel@tonic-gate * dangle: if set, check if link is dangling 4649*7c478bd9Sstevel@tonic-gate * Returns: 4650*7c478bd9Sstevel@tonic-gate * TRUE if dangling 4651*7c478bd9Sstevel@tonic-gate * FALSE if not or if caller doesn't care 4652*7c478bd9Sstevel@tonic-gate * Caller is assumed to have initialized pointer contents to NULL 4653*7c478bd9Sstevel@tonic-gate */ 4654*7c478bd9Sstevel@tonic-gate static int 4655*7c478bd9Sstevel@tonic-gate resolve_link(char *devpath, char **content_p, int *type_p, char **devfs_path, 4656*7c478bd9Sstevel@tonic-gate int dangle) 4657*7c478bd9Sstevel@tonic-gate { 4658*7c478bd9Sstevel@tonic-gate char contents[PATH_MAX + 1]; 4659*7c478bd9Sstevel@tonic-gate char stage_link[PATH_MAX + 1]; 4660*7c478bd9Sstevel@tonic-gate char *fcn = "resolve_link: "; 4661*7c478bd9Sstevel@tonic-gate char *ptr; 4662*7c478bd9Sstevel@tonic-gate int linksize; 4663*7c478bd9Sstevel@tonic-gate int rv = TRUE; 4664*7c478bd9Sstevel@tonic-gate struct stat sb; 4665*7c478bd9Sstevel@tonic-gate 4666*7c478bd9Sstevel@tonic-gate linksize = readlink(devpath, contents, PATH_MAX); 4667*7c478bd9Sstevel@tonic-gate 4668*7c478bd9Sstevel@tonic-gate if (linksize <= 0) { 4669*7c478bd9Sstevel@tonic-gate return (FALSE); 4670*7c478bd9Sstevel@tonic-gate } else { 4671*7c478bd9Sstevel@tonic-gate contents[linksize] = '\0'; 4672*7c478bd9Sstevel@tonic-gate } 4673*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%s %s -> %s\n", fcn, devpath, contents); 4674*7c478bd9Sstevel@tonic-gate 4675*7c478bd9Sstevel@tonic-gate if (content_p) { 4676*7c478bd9Sstevel@tonic-gate *content_p = s_strdup(contents); 4677*7c478bd9Sstevel@tonic-gate } 4678*7c478bd9Sstevel@tonic-gate 4679*7c478bd9Sstevel@tonic-gate /* 4680*7c478bd9Sstevel@tonic-gate * Check to see if this is a link pointing to another link in /dev. The 4681*7c478bd9Sstevel@tonic-gate * cheap way to do this is to look for a lack of ../devices/. 4682*7c478bd9Sstevel@tonic-gate */ 4683*7c478bd9Sstevel@tonic-gate 4684*7c478bd9Sstevel@tonic-gate if (is_minor_node(contents, &ptr) == DEVFSADM_FALSE) { 4685*7c478bd9Sstevel@tonic-gate 4686*7c478bd9Sstevel@tonic-gate if (type_p) { 4687*7c478bd9Sstevel@tonic-gate *type_p = DI_SECONDARY_LINK; 4688*7c478bd9Sstevel@tonic-gate } 4689*7c478bd9Sstevel@tonic-gate 4690*7c478bd9Sstevel@tonic-gate /* 4691*7c478bd9Sstevel@tonic-gate * assume that linkcontents is really a pointer to another 4692*7c478bd9Sstevel@tonic-gate * link, and if so recurse and read its link contents. 4693*7c478bd9Sstevel@tonic-gate */ 4694*7c478bd9Sstevel@tonic-gate if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { 4695*7c478bd9Sstevel@tonic-gate (void) strcpy(stage_link, dev_dir); 4696*7c478bd9Sstevel@tonic-gate (void) strcat(stage_link, "/"); 4697*7c478bd9Sstevel@tonic-gate (void) strcpy(stage_link, 4698*7c478bd9Sstevel@tonic-gate &contents[strlen(DEV) + strlen("/")]); 4699*7c478bd9Sstevel@tonic-gate } else { 4700*7c478bd9Sstevel@tonic-gate if ((ptr = strrchr(devpath, '/')) == NULL) { 4701*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%s%s -> %s invalid link. " 4702*7c478bd9Sstevel@tonic-gate "missing '/'\n", fcn, devpath, 4703*7c478bd9Sstevel@tonic-gate contents); 4704*7c478bd9Sstevel@tonic-gate return (TRUE); 4705*7c478bd9Sstevel@tonic-gate } 4706*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 4707*7c478bd9Sstevel@tonic-gate (void) strcpy(stage_link, devpath); 4708*7c478bd9Sstevel@tonic-gate *ptr = '/'; 4709*7c478bd9Sstevel@tonic-gate (void) strcat(stage_link, "/"); 4710*7c478bd9Sstevel@tonic-gate (void) strcat(stage_link, contents); 4711*7c478bd9Sstevel@tonic-gate } 4712*7c478bd9Sstevel@tonic-gate return (resolve_link(stage_link, NULL, NULL, devfs_path, 4713*7c478bd9Sstevel@tonic-gate dangle)); 4714*7c478bd9Sstevel@tonic-gate } 4715*7c478bd9Sstevel@tonic-gate 4716*7c478bd9Sstevel@tonic-gate /* Current link points at a /devices minor node */ 4717*7c478bd9Sstevel@tonic-gate if (type_p) { 4718*7c478bd9Sstevel@tonic-gate *type_p = DI_PRIMARY_LINK; 4719*7c478bd9Sstevel@tonic-gate } 4720*7c478bd9Sstevel@tonic-gate 4721*7c478bd9Sstevel@tonic-gate if (devfs_path) 4722*7c478bd9Sstevel@tonic-gate *devfs_path = s_strdup(ptr); 4723*7c478bd9Sstevel@tonic-gate 4724*7c478bd9Sstevel@tonic-gate rv = FALSE; 4725*7c478bd9Sstevel@tonic-gate if (dangle) 4726*7c478bd9Sstevel@tonic-gate rv = (stat(ptr - strlen(DEVICES), &sb) == -1); 4727*7c478bd9Sstevel@tonic-gate 4728*7c478bd9Sstevel@tonic-gate vprint(REMOVE_MID, "%slink=%s, returning %s\n", fcn, 4729*7c478bd9Sstevel@tonic-gate devpath, ((rv == TRUE) ? "TRUE" : "FALSE")); 4730*7c478bd9Sstevel@tonic-gate 4731*7c478bd9Sstevel@tonic-gate return (rv); 4732*7c478bd9Sstevel@tonic-gate } 4733*7c478bd9Sstevel@tonic-gate 4734*7c478bd9Sstevel@tonic-gate /* 4735*7c478bd9Sstevel@tonic-gate * Returns the substring of interest, given a path. 4736*7c478bd9Sstevel@tonic-gate */ 4737*7c478bd9Sstevel@tonic-gate static char * 4738*7c478bd9Sstevel@tonic-gate alloc_cmp_str(const char *path, devfsadm_enumerate_t *dep) 4739*7c478bd9Sstevel@tonic-gate { 4740*7c478bd9Sstevel@tonic-gate uint_t match; 4741*7c478bd9Sstevel@tonic-gate char *np, *ap, *mp; 4742*7c478bd9Sstevel@tonic-gate char *cmp_str = NULL; 4743*7c478bd9Sstevel@tonic-gate char at[] = "@"; 4744*7c478bd9Sstevel@tonic-gate char *fcn = "alloc_cmp_str"; 4745*7c478bd9Sstevel@tonic-gate 4746*7c478bd9Sstevel@tonic-gate np = ap = mp = NULL; 4747*7c478bd9Sstevel@tonic-gate 4748*7c478bd9Sstevel@tonic-gate /* 4749*7c478bd9Sstevel@tonic-gate * extract match flags from the flags argument. 4750*7c478bd9Sstevel@tonic-gate */ 4751*7c478bd9Sstevel@tonic-gate match = (dep->flags & MATCH_MASK); 4752*7c478bd9Sstevel@tonic-gate 4753*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: enumeration match type: 0x%x" 4754*7c478bd9Sstevel@tonic-gate " path: %s\n", fcn, match, path); 4755*7c478bd9Sstevel@tonic-gate 4756*7c478bd9Sstevel@tonic-gate /* 4757*7c478bd9Sstevel@tonic-gate * MATCH_CALLBACK and MATCH_ALL are the only flags 4758*7c478bd9Sstevel@tonic-gate * which may be used if "path" is a /dev path 4759*7c478bd9Sstevel@tonic-gate */ 4760*7c478bd9Sstevel@tonic-gate if (match == MATCH_CALLBACK) { 4761*7c478bd9Sstevel@tonic-gate if (dep->sel_fcn == NULL) { 4762*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid enumerate" 4763*7c478bd9Sstevel@tonic-gate " callback: path: %s\n", fcn, path); 4764*7c478bd9Sstevel@tonic-gate return (NULL); 4765*7c478bd9Sstevel@tonic-gate } 4766*7c478bd9Sstevel@tonic-gate cmp_str = dep->sel_fcn(path, dep->cb_arg); 4767*7c478bd9Sstevel@tonic-gate return (cmp_str); 4768*7c478bd9Sstevel@tonic-gate } 4769*7c478bd9Sstevel@tonic-gate 4770*7c478bd9Sstevel@tonic-gate cmp_str = s_strdup(path); 4771*7c478bd9Sstevel@tonic-gate 4772*7c478bd9Sstevel@tonic-gate if (match == MATCH_ALL) { 4773*7c478bd9Sstevel@tonic-gate return (cmp_str); 4774*7c478bd9Sstevel@tonic-gate } 4775*7c478bd9Sstevel@tonic-gate 4776*7c478bd9Sstevel@tonic-gate /* 4777*7c478bd9Sstevel@tonic-gate * The remaining flags make sense only for /devices 4778*7c478bd9Sstevel@tonic-gate * paths 4779*7c478bd9Sstevel@tonic-gate */ 4780*7c478bd9Sstevel@tonic-gate if ((mp = strrchr(cmp_str, ':')) == NULL) { 4781*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid path: %s\n", 4782*7c478bd9Sstevel@tonic-gate fcn, path); 4783*7c478bd9Sstevel@tonic-gate goto err; 4784*7c478bd9Sstevel@tonic-gate } 4785*7c478bd9Sstevel@tonic-gate 4786*7c478bd9Sstevel@tonic-gate if (match == MATCH_MINOR) { 4787*7c478bd9Sstevel@tonic-gate /* A NULL "match_arg" values implies entire minor */ 4788*7c478bd9Sstevel@tonic-gate if (get_component(mp + 1, dep->match_arg) == NULL) { 4789*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid minor component:" 4790*7c478bd9Sstevel@tonic-gate " path: %s\n", fcn, path); 4791*7c478bd9Sstevel@tonic-gate goto err; 4792*7c478bd9Sstevel@tonic-gate } 4793*7c478bd9Sstevel@tonic-gate return (cmp_str); 4794*7c478bd9Sstevel@tonic-gate } 4795*7c478bd9Sstevel@tonic-gate 4796*7c478bd9Sstevel@tonic-gate if ((np = strrchr(cmp_str, '/')) == NULL) { 4797*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid path: %s\n", fcn, path); 4798*7c478bd9Sstevel@tonic-gate goto err; 4799*7c478bd9Sstevel@tonic-gate } 4800*7c478bd9Sstevel@tonic-gate 4801*7c478bd9Sstevel@tonic-gate if (match == MATCH_PARENT) { 4802*7c478bd9Sstevel@tonic-gate if (strcmp(cmp_str, "/") == 0) { 4803*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid path: %s\n", 4804*7c478bd9Sstevel@tonic-gate fcn, path); 4805*7c478bd9Sstevel@tonic-gate goto err; 4806*7c478bd9Sstevel@tonic-gate } 4807*7c478bd9Sstevel@tonic-gate 4808*7c478bd9Sstevel@tonic-gate if (np == cmp_str) { 4809*7c478bd9Sstevel@tonic-gate *(np + 1) = '\0'; 4810*7c478bd9Sstevel@tonic-gate } else { 4811*7c478bd9Sstevel@tonic-gate *np = '\0'; 4812*7c478bd9Sstevel@tonic-gate } 4813*7c478bd9Sstevel@tonic-gate return (cmp_str); 4814*7c478bd9Sstevel@tonic-gate } 4815*7c478bd9Sstevel@tonic-gate 4816*7c478bd9Sstevel@tonic-gate /* ap can be NULL - Leaf address may not exist or be empty string */ 4817*7c478bd9Sstevel@tonic-gate ap = strchr(np+1, '@'); 4818*7c478bd9Sstevel@tonic-gate 4819*7c478bd9Sstevel@tonic-gate /* minor is no longer of interest */ 4820*7c478bd9Sstevel@tonic-gate *mp = '\0'; 4821*7c478bd9Sstevel@tonic-gate 4822*7c478bd9Sstevel@tonic-gate if (match == MATCH_NODE) { 4823*7c478bd9Sstevel@tonic-gate if (ap) 4824*7c478bd9Sstevel@tonic-gate *ap = '\0'; 4825*7c478bd9Sstevel@tonic-gate return (cmp_str); 4826*7c478bd9Sstevel@tonic-gate } else if (match == MATCH_ADDR) { 4827*7c478bd9Sstevel@tonic-gate /* 4828*7c478bd9Sstevel@tonic-gate * The empty string is a valid address. The only MATCH_ADDR 4829*7c478bd9Sstevel@tonic-gate * allowed in this case is against the whole address or 4830*7c478bd9Sstevel@tonic-gate * the first component of the address (match_arg=NULL/"0"/"1") 4831*7c478bd9Sstevel@tonic-gate * Note that in this case, the path won't have an "@" 4832*7c478bd9Sstevel@tonic-gate * As a result ap will be NULL. We fake up an ap = @'\0' 4833*7c478bd9Sstevel@tonic-gate * so that get_component() will work correctly. 4834*7c478bd9Sstevel@tonic-gate */ 4835*7c478bd9Sstevel@tonic-gate if (ap == NULL) { 4836*7c478bd9Sstevel@tonic-gate ap = at; 4837*7c478bd9Sstevel@tonic-gate } 4838*7c478bd9Sstevel@tonic-gate 4839*7c478bd9Sstevel@tonic-gate if (get_component(ap + 1, dep->match_arg) == NULL) { 4840*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid leaf addr. component:" 4841*7c478bd9Sstevel@tonic-gate " path: %s\n", fcn, path); 4842*7c478bd9Sstevel@tonic-gate goto err; 4843*7c478bd9Sstevel@tonic-gate } 4844*7c478bd9Sstevel@tonic-gate return (cmp_str); 4845*7c478bd9Sstevel@tonic-gate } 4846*7c478bd9Sstevel@tonic-gate 4847*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid enumeration flags: 0x%x" 4848*7c478bd9Sstevel@tonic-gate " path: %s\n", fcn, dep->flags, path); 4849*7c478bd9Sstevel@tonic-gate 4850*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 4851*7c478bd9Sstevel@tonic-gate err: 4852*7c478bd9Sstevel@tonic-gate free(cmp_str); 4853*7c478bd9Sstevel@tonic-gate return (NULL); 4854*7c478bd9Sstevel@tonic-gate } 4855*7c478bd9Sstevel@tonic-gate 4856*7c478bd9Sstevel@tonic-gate 4857*7c478bd9Sstevel@tonic-gate /* 4858*7c478bd9Sstevel@tonic-gate * "str" is expected to be a string with components separated by ',' 4859*7c478bd9Sstevel@tonic-gate * The terminating null char is considered a separator. 4860*7c478bd9Sstevel@tonic-gate * get_component() will remove the portion of the string beyond 4861*7c478bd9Sstevel@tonic-gate * the component indicated. 4862*7c478bd9Sstevel@tonic-gate * If comp_str is NULL, the entire "str" is returned. 4863*7c478bd9Sstevel@tonic-gate */ 4864*7c478bd9Sstevel@tonic-gate static char * 4865*7c478bd9Sstevel@tonic-gate get_component(char *str, const char *comp_str) 4866*7c478bd9Sstevel@tonic-gate { 4867*7c478bd9Sstevel@tonic-gate long comp; 4868*7c478bd9Sstevel@tonic-gate char *cp; 4869*7c478bd9Sstevel@tonic-gate 4870*7c478bd9Sstevel@tonic-gate if (str == NULL) { 4871*7c478bd9Sstevel@tonic-gate return (NULL); 4872*7c478bd9Sstevel@tonic-gate } 4873*7c478bd9Sstevel@tonic-gate 4874*7c478bd9Sstevel@tonic-gate if (comp_str == NULL) { 4875*7c478bd9Sstevel@tonic-gate return (str); 4876*7c478bd9Sstevel@tonic-gate } 4877*7c478bd9Sstevel@tonic-gate 4878*7c478bd9Sstevel@tonic-gate errno = 0; 4879*7c478bd9Sstevel@tonic-gate comp = strtol(comp_str, &cp, 10); 4880*7c478bd9Sstevel@tonic-gate if (errno != 0 || *cp != '\0' || comp < 0) { 4881*7c478bd9Sstevel@tonic-gate return (NULL); 4882*7c478bd9Sstevel@tonic-gate } 4883*7c478bd9Sstevel@tonic-gate 4884*7c478bd9Sstevel@tonic-gate if (comp == 0) 4885*7c478bd9Sstevel@tonic-gate return (str); 4886*7c478bd9Sstevel@tonic-gate 4887*7c478bd9Sstevel@tonic-gate for (cp = str; ; cp++) { 4888*7c478bd9Sstevel@tonic-gate if (*cp == ',' || *cp == '\0') 4889*7c478bd9Sstevel@tonic-gate comp--; 4890*7c478bd9Sstevel@tonic-gate if (*cp == '\0' || comp <= 0) { 4891*7c478bd9Sstevel@tonic-gate break; 4892*7c478bd9Sstevel@tonic-gate } 4893*7c478bd9Sstevel@tonic-gate } 4894*7c478bd9Sstevel@tonic-gate 4895*7c478bd9Sstevel@tonic-gate if (comp == 0) { 4896*7c478bd9Sstevel@tonic-gate *cp = '\0'; 4897*7c478bd9Sstevel@tonic-gate } else { 4898*7c478bd9Sstevel@tonic-gate str = NULL; 4899*7c478bd9Sstevel@tonic-gate } 4900*7c478bd9Sstevel@tonic-gate 4901*7c478bd9Sstevel@tonic-gate return (str); 4902*7c478bd9Sstevel@tonic-gate } 4903*7c478bd9Sstevel@tonic-gate 4904*7c478bd9Sstevel@tonic-gate 4905*7c478bd9Sstevel@tonic-gate /* 4906*7c478bd9Sstevel@tonic-gate * Enumerate serves as a generic counter as well as a means to determine 4907*7c478bd9Sstevel@tonic-gate * logical unit/controller numbers for such items as disk and tape 4908*7c478bd9Sstevel@tonic-gate * drives. 4909*7c478bd9Sstevel@tonic-gate * 4910*7c478bd9Sstevel@tonic-gate * rules[] is an array of devfsadm_enumerate_t structures which defines 4911*7c478bd9Sstevel@tonic-gate * the enumeration rules to be used for a specified set of links in /dev. 4912*7c478bd9Sstevel@tonic-gate * The set of links is specified through regular expressions (of the flavor 4913*7c478bd9Sstevel@tonic-gate * described in regex(5)). These regular expressions are used to determine 4914*7c478bd9Sstevel@tonic-gate * the set of links in /dev to examine. The last path component in these 4915*7c478bd9Sstevel@tonic-gate * regular expressions MUST contain a parenthesized subexpression surrounding 4916*7c478bd9Sstevel@tonic-gate * the RE which is to be considered the enumerating component. The subexp 4917*7c478bd9Sstevel@tonic-gate * member in a rule is the subexpression number of the enumerating 4918*7c478bd9Sstevel@tonic-gate * component. Subexpressions in the last path component are numbered starting 4919*7c478bd9Sstevel@tonic-gate * from 1. 4920*7c478bd9Sstevel@tonic-gate * 4921*7c478bd9Sstevel@tonic-gate * A cache of current id assignments is built up from existing symlinks and 4922*7c478bd9Sstevel@tonic-gate * new assignments use the lowest unused id. Assignments are based on a 4923*7c478bd9Sstevel@tonic-gate * match of a specified substring of a symlink's contents. If the specified 4924*7c478bd9Sstevel@tonic-gate * component for the devfs_path argument matches the corresponding substring 4925*7c478bd9Sstevel@tonic-gate * for a existing symlink's contents, the cached id is returned. Else, a new 4926*7c478bd9Sstevel@tonic-gate * id is created and returned in *buf. *buf must be freed by the caller. 4927*7c478bd9Sstevel@tonic-gate * 4928*7c478bd9Sstevel@tonic-gate * An id assignment may be governed by a combination of rules, each rule 4929*7c478bd9Sstevel@tonic-gate * applicable to a different subset of links in /dev. For example, controller 4930*7c478bd9Sstevel@tonic-gate * numbers may be determined by a combination of disk symlinks in /dev/[r]dsk 4931*7c478bd9Sstevel@tonic-gate * and controller symlinks in /dev/cfg, with the two sets requiring different 4932*7c478bd9Sstevel@tonic-gate * rules to derive the "substring of interest". In such cases, the rules 4933*7c478bd9Sstevel@tonic-gate * array will have more than one element. 4934*7c478bd9Sstevel@tonic-gate */ 4935*7c478bd9Sstevel@tonic-gate int 4936*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_int(char *devfs_path, int index, char **buf, 4937*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int nrules) 4938*7c478bd9Sstevel@tonic-gate { 4939*7c478bd9Sstevel@tonic-gate return (find_enum_id(rules, nrules, 4940*7c478bd9Sstevel@tonic-gate devfs_path, index, "0", INTEGER, buf, 0)); 4941*7c478bd9Sstevel@tonic-gate } 4942*7c478bd9Sstevel@tonic-gate 4943*7c478bd9Sstevel@tonic-gate int 4944*7c478bd9Sstevel@tonic-gate disk_enumerate_int(char *devfs_path, int index, char **buf, 4945*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int nrules) 4946*7c478bd9Sstevel@tonic-gate { 4947*7c478bd9Sstevel@tonic-gate return (find_enum_id(rules, nrules, 4948*7c478bd9Sstevel@tonic-gate devfs_path, index, "0", INTEGER, buf, 1)); 4949*7c478bd9Sstevel@tonic-gate } 4950*7c478bd9Sstevel@tonic-gate 4951*7c478bd9Sstevel@tonic-gate /* 4952*7c478bd9Sstevel@tonic-gate * Same as above, but allows a starting value to be specified. 4953*7c478bd9Sstevel@tonic-gate * Private to devfsadm.... used by devlinks. 4954*7c478bd9Sstevel@tonic-gate */ 4955*7c478bd9Sstevel@tonic-gate static int 4956*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_int_start(char *devfs_path, int index, char **buf, 4957*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int nrules, char *start) 4958*7c478bd9Sstevel@tonic-gate { 4959*7c478bd9Sstevel@tonic-gate return (find_enum_id(rules, nrules, 4960*7c478bd9Sstevel@tonic-gate devfs_path, index, start, INTEGER, buf, 0)); 4961*7c478bd9Sstevel@tonic-gate } 4962*7c478bd9Sstevel@tonic-gate 4963*7c478bd9Sstevel@tonic-gate /* 4964*7c478bd9Sstevel@tonic-gate * devfsadm_enumerate_char serves as a generic counter returning 4965*7c478bd9Sstevel@tonic-gate * a single letter. 4966*7c478bd9Sstevel@tonic-gate */ 4967*7c478bd9Sstevel@tonic-gate int 4968*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_char(char *devfs_path, int index, char **buf, 4969*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int nrules) 4970*7c478bd9Sstevel@tonic-gate { 4971*7c478bd9Sstevel@tonic-gate return (find_enum_id(rules, nrules, 4972*7c478bd9Sstevel@tonic-gate devfs_path, index, "a", LETTER, buf, 0)); 4973*7c478bd9Sstevel@tonic-gate } 4974*7c478bd9Sstevel@tonic-gate 4975*7c478bd9Sstevel@tonic-gate /* 4976*7c478bd9Sstevel@tonic-gate * Same as above, but allows a starting char to be specified. 4977*7c478bd9Sstevel@tonic-gate * Private to devfsadm - used by ports module (port_link.c) 4978*7c478bd9Sstevel@tonic-gate */ 4979*7c478bd9Sstevel@tonic-gate int 4980*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_char_start(char *devfs_path, int index, char **buf, 4981*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int nrules, char *start) 4982*7c478bd9Sstevel@tonic-gate { 4983*7c478bd9Sstevel@tonic-gate return (find_enum_id(rules, nrules, 4984*7c478bd9Sstevel@tonic-gate devfs_path, index, start, LETTER, buf, 0)); 4985*7c478bd9Sstevel@tonic-gate } 4986*7c478bd9Sstevel@tonic-gate 4987*7c478bd9Sstevel@tonic-gate 4988*7c478bd9Sstevel@tonic-gate /* 4989*7c478bd9Sstevel@tonic-gate * For a given numeral_set (see get_cached_set for desc of numeral_set), 4990*7c478bd9Sstevel@tonic-gate * search all cached entries looking for matches on a specified substring 4991*7c478bd9Sstevel@tonic-gate * of devfs_path. The substring is derived from devfs_path based on the 4992*7c478bd9Sstevel@tonic-gate * rule specified by "index". If a match is found on a cached entry, 4993*7c478bd9Sstevel@tonic-gate * return the enumerated id in buf. Otherwise, create a new id by calling 4994*7c478bd9Sstevel@tonic-gate * new_id, then cache and return that entry. 4995*7c478bd9Sstevel@tonic-gate */ 4996*7c478bd9Sstevel@tonic-gate static int 4997*7c478bd9Sstevel@tonic-gate find_enum_id(devfsadm_enumerate_t rules[], int nrules, 4998*7c478bd9Sstevel@tonic-gate char *devfs_path, int index, char *min, int type, char **buf, 4999*7c478bd9Sstevel@tonic-gate int multiple) 5000*7c478bd9Sstevel@tonic-gate { 5001*7c478bd9Sstevel@tonic-gate numeral_t *matchnp; 5002*7c478bd9Sstevel@tonic-gate numeral_t *numeral; 5003*7c478bd9Sstevel@tonic-gate int matchcount = 0; 5004*7c478bd9Sstevel@tonic-gate char *cmp_str; 5005*7c478bd9Sstevel@tonic-gate char *fcn = "find_enum_id"; 5006*7c478bd9Sstevel@tonic-gate numeral_set_t *set; 5007*7c478bd9Sstevel@tonic-gate 5008*7c478bd9Sstevel@tonic-gate if (rules == NULL) { 5009*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: no rules. path: %s\n", 5010*7c478bd9Sstevel@tonic-gate fcn, devfs_path ? devfs_path : "<NULL path>"); 5011*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5012*7c478bd9Sstevel@tonic-gate } 5013*7c478bd9Sstevel@tonic-gate 5014*7c478bd9Sstevel@tonic-gate if (devfs_path == NULL) { 5015*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: NULL path\n", fcn); 5016*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5017*7c478bd9Sstevel@tonic-gate } 5018*7c478bd9Sstevel@tonic-gate 5019*7c478bd9Sstevel@tonic-gate if (nrules <= 0 || index < 0 || index >= nrules || buf == NULL) { 5020*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid arguments. path: %s\n", 5021*7c478bd9Sstevel@tonic-gate fcn, devfs_path); 5022*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5023*7c478bd9Sstevel@tonic-gate } 5024*7c478bd9Sstevel@tonic-gate 5025*7c478bd9Sstevel@tonic-gate *buf = NULL; 5026*7c478bd9Sstevel@tonic-gate 5027*7c478bd9Sstevel@tonic-gate 5028*7c478bd9Sstevel@tonic-gate cmp_str = alloc_cmp_str(devfs_path, &rules[index]); 5029*7c478bd9Sstevel@tonic-gate if (cmp_str == NULL) { 5030*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5031*7c478bd9Sstevel@tonic-gate } 5032*7c478bd9Sstevel@tonic-gate 5033*7c478bd9Sstevel@tonic-gate if ((set = get_enum_cache(rules, nrules)) == NULL) { 5034*7c478bd9Sstevel@tonic-gate free(cmp_str); 5035*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5036*7c478bd9Sstevel@tonic-gate } 5037*7c478bd9Sstevel@tonic-gate 5038*7c478bd9Sstevel@tonic-gate assert(nrules == set->re_count); 5039*7c478bd9Sstevel@tonic-gate 5040*7c478bd9Sstevel@tonic-gate /* 5041*7c478bd9Sstevel@tonic-gate * Check and see if a matching entry is already cached. 5042*7c478bd9Sstevel@tonic-gate */ 5043*7c478bd9Sstevel@tonic-gate matchcount = lookup_enum_cache(set, cmp_str, rules, index, 5044*7c478bd9Sstevel@tonic-gate &matchnp); 5045*7c478bd9Sstevel@tonic-gate 5046*7c478bd9Sstevel@tonic-gate if (matchcount < 0 || matchcount > 1) { 5047*7c478bd9Sstevel@tonic-gate free(cmp_str); 5048*7c478bd9Sstevel@tonic-gate if (multiple && matchcount > 1) 5049*7c478bd9Sstevel@tonic-gate return (DEVFSADM_MULTIPLE); 5050*7c478bd9Sstevel@tonic-gate else 5051*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5052*7c478bd9Sstevel@tonic-gate } 5053*7c478bd9Sstevel@tonic-gate 5054*7c478bd9Sstevel@tonic-gate /* if matching entry already cached, return it */ 5055*7c478bd9Sstevel@tonic-gate if (matchcount == 1) { 5056*7c478bd9Sstevel@tonic-gate *buf = s_strdup(matchnp->id); 5057*7c478bd9Sstevel@tonic-gate free(cmp_str); 5058*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5059*7c478bd9Sstevel@tonic-gate } 5060*7c478bd9Sstevel@tonic-gate 5061*7c478bd9Sstevel@tonic-gate /* 5062*7c478bd9Sstevel@tonic-gate * no cached entry, initialize a numeral struct 5063*7c478bd9Sstevel@tonic-gate * by calling new_id() and cache onto the numeral_set 5064*7c478bd9Sstevel@tonic-gate */ 5065*7c478bd9Sstevel@tonic-gate numeral = s_malloc(sizeof (numeral_t)); 5066*7c478bd9Sstevel@tonic-gate numeral->id = new_id(set->headnumeral, type, min); 5067*7c478bd9Sstevel@tonic-gate numeral->full_path = s_strdup(devfs_path); 5068*7c478bd9Sstevel@tonic-gate numeral->rule_index = index; 5069*7c478bd9Sstevel@tonic-gate numeral->cmp_str = cmp_str; 5070*7c478bd9Sstevel@tonic-gate cmp_str = NULL; 5071*7c478bd9Sstevel@tonic-gate 5072*7c478bd9Sstevel@tonic-gate /* insert to head of list for fast lookups */ 5073*7c478bd9Sstevel@tonic-gate numeral->next = set->headnumeral; 5074*7c478bd9Sstevel@tonic-gate set->headnumeral = numeral; 5075*7c478bd9Sstevel@tonic-gate 5076*7c478bd9Sstevel@tonic-gate *buf = s_strdup(numeral->id); 5077*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5078*7c478bd9Sstevel@tonic-gate } 5079*7c478bd9Sstevel@tonic-gate 5080*7c478bd9Sstevel@tonic-gate 5081*7c478bd9Sstevel@tonic-gate /* 5082*7c478bd9Sstevel@tonic-gate * Looks up the specified cache for a match with a specified string 5083*7c478bd9Sstevel@tonic-gate * Returns: 5084*7c478bd9Sstevel@tonic-gate * -1 : on error. 5085*7c478bd9Sstevel@tonic-gate * 0/1/2 : Number of matches. 5086*7c478bd9Sstevel@tonic-gate * Returns the matching element only if there is a single match. 5087*7c478bd9Sstevel@tonic-gate * If the "uncached" flag is set, derives the "cmp_str" afresh 5088*7c478bd9Sstevel@tonic-gate * for the match instead of using cached values. 5089*7c478bd9Sstevel@tonic-gate */ 5090*7c478bd9Sstevel@tonic-gate static int 5091*7c478bd9Sstevel@tonic-gate lookup_enum_cache(numeral_set_t *set, char *cmp_str, 5092*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int index, numeral_t **matchnpp) 5093*7c478bd9Sstevel@tonic-gate { 5094*7c478bd9Sstevel@tonic-gate int matchcount = 0, rv = -1; 5095*7c478bd9Sstevel@tonic-gate int uncached; 5096*7c478bd9Sstevel@tonic-gate numeral_t *np; 5097*7c478bd9Sstevel@tonic-gate char *fcn = "lookup_enum_cache"; 5098*7c478bd9Sstevel@tonic-gate char *cp; 5099*7c478bd9Sstevel@tonic-gate 5100*7c478bd9Sstevel@tonic-gate *matchnpp = NULL; 5101*7c478bd9Sstevel@tonic-gate 5102*7c478bd9Sstevel@tonic-gate assert(index < set->re_count); 5103*7c478bd9Sstevel@tonic-gate 5104*7c478bd9Sstevel@tonic-gate if (cmp_str == NULL) { 5105*7c478bd9Sstevel@tonic-gate return (-1); 5106*7c478bd9Sstevel@tonic-gate } 5107*7c478bd9Sstevel@tonic-gate 5108*7c478bd9Sstevel@tonic-gate uncached = 0; 5109*7c478bd9Sstevel@tonic-gate if ((rules[index].flags & MATCH_UNCACHED) == MATCH_UNCACHED) { 5110*7c478bd9Sstevel@tonic-gate uncached = 1; 5111*7c478bd9Sstevel@tonic-gate } 5112*7c478bd9Sstevel@tonic-gate 5113*7c478bd9Sstevel@tonic-gate /* 5114*7c478bd9Sstevel@tonic-gate * Check and see if a matching entry is already cached. 5115*7c478bd9Sstevel@tonic-gate */ 5116*7c478bd9Sstevel@tonic-gate for (np = set->headnumeral; np != NULL; np = np->next) { 5117*7c478bd9Sstevel@tonic-gate if (np->cmp_str == NULL) { 5118*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid entry in enumerate" 5119*7c478bd9Sstevel@tonic-gate " cache. path: %s\n", fcn, np->full_path); 5120*7c478bd9Sstevel@tonic-gate return (-1); 5121*7c478bd9Sstevel@tonic-gate } 5122*7c478bd9Sstevel@tonic-gate 5123*7c478bd9Sstevel@tonic-gate if (uncached) { 5124*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%s: bypassing enumerate cache." 5125*7c478bd9Sstevel@tonic-gate " path: %s\n", fcn, cmp_str); 5126*7c478bd9Sstevel@tonic-gate cp = alloc_cmp_str(np->full_path, 5127*7c478bd9Sstevel@tonic-gate &rules[np->rule_index]); 5128*7c478bd9Sstevel@tonic-gate if (cp == NULL) 5129*7c478bd9Sstevel@tonic-gate return (-1); 5130*7c478bd9Sstevel@tonic-gate rv = strcmp(cmp_str, cp); 5131*7c478bd9Sstevel@tonic-gate free(cp); 5132*7c478bd9Sstevel@tonic-gate } else { 5133*7c478bd9Sstevel@tonic-gate rv = strcmp(cmp_str, np->cmp_str); 5134*7c478bd9Sstevel@tonic-gate } 5135*7c478bd9Sstevel@tonic-gate 5136*7c478bd9Sstevel@tonic-gate if (rv == 0) { 5137*7c478bd9Sstevel@tonic-gate if (matchcount++ != 0) { 5138*7c478bd9Sstevel@tonic-gate break; /* more than 1 match. */ 5139*7c478bd9Sstevel@tonic-gate } 5140*7c478bd9Sstevel@tonic-gate *matchnpp = np; 5141*7c478bd9Sstevel@tonic-gate } 5142*7c478bd9Sstevel@tonic-gate } 5143*7c478bd9Sstevel@tonic-gate 5144*7c478bd9Sstevel@tonic-gate return (matchcount); 5145*7c478bd9Sstevel@tonic-gate } 5146*7c478bd9Sstevel@tonic-gate 5147*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 5148*7c478bd9Sstevel@tonic-gate static void 5149*7c478bd9Sstevel@tonic-gate dump_enum_cache(numeral_set_t *setp) 5150*7c478bd9Sstevel@tonic-gate { 5151*7c478bd9Sstevel@tonic-gate int i; 5152*7c478bd9Sstevel@tonic-gate numeral_t *np; 5153*7c478bd9Sstevel@tonic-gate char *fcn = "dump_enum_cache"; 5154*7c478bd9Sstevel@tonic-gate 5155*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: re_count = %d\n", fcn, setp->re_count); 5156*7c478bd9Sstevel@tonic-gate for (i = 0; i < setp->re_count; i++) { 5157*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: re[%d] = %s\n", fcn, i, setp->re[i]); 5158*7c478bd9Sstevel@tonic-gate } 5159*7c478bd9Sstevel@tonic-gate 5160*7c478bd9Sstevel@tonic-gate for (np = setp->headnumeral; np != NULL; np = np->next) { 5161*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: id: %s\n", fcn, np->id); 5162*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: full_path: %s\n", fcn, np->full_path); 5163*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: rule_index: %d\n", fcn, np->rule_index); 5164*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: cmp_str: %s\n", fcn, np->cmp_str); 5165*7c478bd9Sstevel@tonic-gate } 5166*7c478bd9Sstevel@tonic-gate } 5167*7c478bd9Sstevel@tonic-gate #endif 5168*7c478bd9Sstevel@tonic-gate 5169*7c478bd9Sstevel@tonic-gate /* 5170*7c478bd9Sstevel@tonic-gate * For a given set of regular expressions in rules[], this function returns 5171*7c478bd9Sstevel@tonic-gate * either a previously cached struct numeral_set or it will create and 5172*7c478bd9Sstevel@tonic-gate * cache a new struct numeral_set. There is only one struct numeral_set 5173*7c478bd9Sstevel@tonic-gate * for the combination of REs present in rules[]. Each numeral_set contains 5174*7c478bd9Sstevel@tonic-gate * the regular expressions in rules[] used for cache selection AND a linked 5175*7c478bd9Sstevel@tonic-gate * list of struct numerals, ONE FOR EACH *UNIQUE* numeral or character ID 5176*7c478bd9Sstevel@tonic-gate * selected by the grouping parenthesized subexpression found in the last 5177*7c478bd9Sstevel@tonic-gate * path component of each rules[].re. For example, the RE: "rmt/([0-9]+)" 5178*7c478bd9Sstevel@tonic-gate * selects all the logical nodes of the correct form in dev/rmt/. 5179*7c478bd9Sstevel@tonic-gate * Each rmt/X will store a *single* struct numeral... ie 0, 1, 2 each get a 5180*7c478bd9Sstevel@tonic-gate * single struct numeral. There is no need to store more than a single logical 5181*7c478bd9Sstevel@tonic-gate * node matching X since the information desired in the devfspath would be 5182*7c478bd9Sstevel@tonic-gate * identical for the portion of the devfspath of interest. (the part up to, 5183*7c478bd9Sstevel@tonic-gate * but not including the minor name in this example.) 5184*7c478bd9Sstevel@tonic-gate * 5185*7c478bd9Sstevel@tonic-gate * If the given numeral_set is not yet cached, call enumerate_recurse to 5186*7c478bd9Sstevel@tonic-gate * create it. 5187*7c478bd9Sstevel@tonic-gate */ 5188*7c478bd9Sstevel@tonic-gate static numeral_set_t * 5189*7c478bd9Sstevel@tonic-gate get_enum_cache(devfsadm_enumerate_t rules[], int nrules) 5190*7c478bd9Sstevel@tonic-gate { 5191*7c478bd9Sstevel@tonic-gate /* linked list of numeral sets */ 5192*7c478bd9Sstevel@tonic-gate numeral_set_t *setp; 5193*7c478bd9Sstevel@tonic-gate int i; 5194*7c478bd9Sstevel@tonic-gate char *path_left; 5195*7c478bd9Sstevel@tonic-gate char *fcn = "get_enum_cache"; 5196*7c478bd9Sstevel@tonic-gate 5197*7c478bd9Sstevel@tonic-gate /* 5198*7c478bd9Sstevel@tonic-gate * See if we've already cached this numeral set. 5199*7c478bd9Sstevel@tonic-gate */ 5200*7c478bd9Sstevel@tonic-gate for (setp = head_numeral_set; setp != NULL; setp = setp->next) { 5201*7c478bd9Sstevel@tonic-gate /* 5202*7c478bd9Sstevel@tonic-gate * check all regexp's passed in function against 5203*7c478bd9Sstevel@tonic-gate * those in cached set. 5204*7c478bd9Sstevel@tonic-gate */ 5205*7c478bd9Sstevel@tonic-gate if (nrules != setp->re_count) { 5206*7c478bd9Sstevel@tonic-gate continue; 5207*7c478bd9Sstevel@tonic-gate } 5208*7c478bd9Sstevel@tonic-gate 5209*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrules; i++) { 5210*7c478bd9Sstevel@tonic-gate if (strcmp(setp->re[i], rules[i].re) != 0) { 5211*7c478bd9Sstevel@tonic-gate break; 5212*7c478bd9Sstevel@tonic-gate } 5213*7c478bd9Sstevel@tonic-gate } 5214*7c478bd9Sstevel@tonic-gate 5215*7c478bd9Sstevel@tonic-gate if (i == nrules) { 5216*7c478bd9Sstevel@tonic-gate return (setp); 5217*7c478bd9Sstevel@tonic-gate } 5218*7c478bd9Sstevel@tonic-gate } 5219*7c478bd9Sstevel@tonic-gate 5220*7c478bd9Sstevel@tonic-gate /* 5221*7c478bd9Sstevel@tonic-gate * If the MATCH_UNCACHED flag is set, we should not be here. 5222*7c478bd9Sstevel@tonic-gate */ 5223*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrules; i++) { 5224*7c478bd9Sstevel@tonic-gate if ((rules[i].flags & MATCH_UNCACHED) == MATCH_UNCACHED) { 5225*7c478bd9Sstevel@tonic-gate vprint(ENUM_MID, "%s: invalid enumeration flags: " 5226*7c478bd9Sstevel@tonic-gate "0x%x\n", fcn, rules[i].flags); 5227*7c478bd9Sstevel@tonic-gate return (NULL); 5228*7c478bd9Sstevel@tonic-gate } 5229*7c478bd9Sstevel@tonic-gate } 5230*7c478bd9Sstevel@tonic-gate 5231*7c478bd9Sstevel@tonic-gate /* 5232*7c478bd9Sstevel@tonic-gate * Since we made it here, we have not yet cached the given set of 5233*7c478bd9Sstevel@tonic-gate * logical nodes matching the passed re. Create a cached entry 5234*7c478bd9Sstevel@tonic-gate * struct numeral_set and populate it with a minimal set of 5235*7c478bd9Sstevel@tonic-gate * logical nodes from /dev. 5236*7c478bd9Sstevel@tonic-gate */ 5237*7c478bd9Sstevel@tonic-gate 5238*7c478bd9Sstevel@tonic-gate setp = s_malloc(sizeof (numeral_set_t)); 5239*7c478bd9Sstevel@tonic-gate setp->re = s_malloc(sizeof (char *) * nrules); 5240*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrules; i++) { 5241*7c478bd9Sstevel@tonic-gate setp->re[i] = s_strdup(rules[i].re); 5242*7c478bd9Sstevel@tonic-gate } 5243*7c478bd9Sstevel@tonic-gate setp->re_count = nrules; 5244*7c478bd9Sstevel@tonic-gate setp->headnumeral = NULL; 5245*7c478bd9Sstevel@tonic-gate 5246*7c478bd9Sstevel@tonic-gate /* put this new cached set on the cached set list */ 5247*7c478bd9Sstevel@tonic-gate setp->next = head_numeral_set; 5248*7c478bd9Sstevel@tonic-gate head_numeral_set = setp; 5249*7c478bd9Sstevel@tonic-gate 5250*7c478bd9Sstevel@tonic-gate /* 5251*7c478bd9Sstevel@tonic-gate * For each RE, search disk and cache any matches on the 5252*7c478bd9Sstevel@tonic-gate * numeral list. We are careful to use global_dev_dir here since 5253*7c478bd9Sstevel@tonic-gate * for zones, we want to use the global zone's enumeration as the 5254*7c478bd9Sstevel@tonic-gate * source for enumeration within the zone. Otherwise, for example, 5255*7c478bd9Sstevel@tonic-gate * controller numbering would be wrong within the zone. 5256*7c478bd9Sstevel@tonic-gate */ 5257*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrules; i++) { 5258*7c478bd9Sstevel@tonic-gate path_left = s_strdup(setp->re[i]); 5259*7c478bd9Sstevel@tonic-gate enumerate_recurse(global_dev_dir, path_left, setp, rules, i); 5260*7c478bd9Sstevel@tonic-gate free(path_left); 5261*7c478bd9Sstevel@tonic-gate } 5262*7c478bd9Sstevel@tonic-gate 5263*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 5264*7c478bd9Sstevel@tonic-gate dump_enum_cache(setp); 5265*7c478bd9Sstevel@tonic-gate #endif 5266*7c478bd9Sstevel@tonic-gate 5267*7c478bd9Sstevel@tonic-gate return (setp); 5268*7c478bd9Sstevel@tonic-gate } 5269*7c478bd9Sstevel@tonic-gate 5270*7c478bd9Sstevel@tonic-gate 5271*7c478bd9Sstevel@tonic-gate /* 5272*7c478bd9Sstevel@tonic-gate * This function stats the pathname namebuf. If this is a directory 5273*7c478bd9Sstevel@tonic-gate * entry, we recurse down dname/fname until we find the first symbolic 5274*7c478bd9Sstevel@tonic-gate * link, and then stat and return it. This is valid for the same reason 5275*7c478bd9Sstevel@tonic-gate * that we only need to read a single pathname for multiple matching 5276*7c478bd9Sstevel@tonic-gate * logical ID's... ie, all the logical nodes should contain identical 5277*7c478bd9Sstevel@tonic-gate * physical paths for the parts we are interested. 5278*7c478bd9Sstevel@tonic-gate */ 5279*7c478bd9Sstevel@tonic-gate int 5280*7c478bd9Sstevel@tonic-gate get_stat_info(char *namebuf, struct stat *sb) 5281*7c478bd9Sstevel@tonic-gate { 5282*7c478bd9Sstevel@tonic-gate struct dirent *entp; 5283*7c478bd9Sstevel@tonic-gate struct dirent *retp; 5284*7c478bd9Sstevel@tonic-gate DIR *dp; 5285*7c478bd9Sstevel@tonic-gate char *cp; 5286*7c478bd9Sstevel@tonic-gate 5287*7c478bd9Sstevel@tonic-gate if (lstat(namebuf, sb) < 0) { 5288*7c478bd9Sstevel@tonic-gate (void) err_print(LSTAT_FAILED, namebuf, strerror(errno)); 5289*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5290*7c478bd9Sstevel@tonic-gate } 5291*7c478bd9Sstevel@tonic-gate 5292*7c478bd9Sstevel@tonic-gate if ((sb->st_mode & S_IFMT) == S_IFLNK) { 5293*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5294*7c478bd9Sstevel@tonic-gate } 5295*7c478bd9Sstevel@tonic-gate 5296*7c478bd9Sstevel@tonic-gate /* 5297*7c478bd9Sstevel@tonic-gate * If it is a dir, recurse down until we find a link and 5298*7c478bd9Sstevel@tonic-gate * then use the link. 5299*7c478bd9Sstevel@tonic-gate */ 5300*7c478bd9Sstevel@tonic-gate if ((sb->st_mode & S_IFMT) == S_IFDIR) { 5301*7c478bd9Sstevel@tonic-gate 5302*7c478bd9Sstevel@tonic-gate if ((dp = opendir(namebuf)) == NULL) { 5303*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5304*7c478bd9Sstevel@tonic-gate } 5305*7c478bd9Sstevel@tonic-gate 5306*7c478bd9Sstevel@tonic-gate entp = s_malloc(PATH_MAX + 1 + sizeof (struct dirent)); 5307*7c478bd9Sstevel@tonic-gate 5308*7c478bd9Sstevel@tonic-gate /* 5309*7c478bd9Sstevel@tonic-gate * Search each dir entry looking for a symlink. Return 5310*7c478bd9Sstevel@tonic-gate * the first symlink found in namebuf. Recurse dirs. 5311*7c478bd9Sstevel@tonic-gate */ 5312*7c478bd9Sstevel@tonic-gate while (readdir_r(dp, entp, &retp) == 0) { 5313*7c478bd9Sstevel@tonic-gate if (retp == NULL) { 5314*7c478bd9Sstevel@tonic-gate break; 5315*7c478bd9Sstevel@tonic-gate } 5316*7c478bd9Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 || 5317*7c478bd9Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0) { 5318*7c478bd9Sstevel@tonic-gate continue; 5319*7c478bd9Sstevel@tonic-gate } 5320*7c478bd9Sstevel@tonic-gate 5321*7c478bd9Sstevel@tonic-gate cp = namebuf + strlen(namebuf); 5322*7c478bd9Sstevel@tonic-gate (void) strcat(namebuf, "/"); 5323*7c478bd9Sstevel@tonic-gate (void) strcat(namebuf, entp->d_name); 5324*7c478bd9Sstevel@tonic-gate if (get_stat_info(namebuf, sb) == DEVFSADM_SUCCESS) { 5325*7c478bd9Sstevel@tonic-gate free(entp); 5326*7c478bd9Sstevel@tonic-gate s_closedir(dp); 5327*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5328*7c478bd9Sstevel@tonic-gate } 5329*7c478bd9Sstevel@tonic-gate *cp = '\0'; 5330*7c478bd9Sstevel@tonic-gate } 5331*7c478bd9Sstevel@tonic-gate free(entp); 5332*7c478bd9Sstevel@tonic-gate s_closedir(dp); 5333*7c478bd9Sstevel@tonic-gate } 5334*7c478bd9Sstevel@tonic-gate 5335*7c478bd9Sstevel@tonic-gate /* no symlink found, so return error */ 5336*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5337*7c478bd9Sstevel@tonic-gate } 5338*7c478bd9Sstevel@tonic-gate 5339*7c478bd9Sstevel@tonic-gate /* 5340*7c478bd9Sstevel@tonic-gate * An existing matching ID was not found, so this function is called to 5341*7c478bd9Sstevel@tonic-gate * create the next lowest ID. In the INTEGER case, return the next 5342*7c478bd9Sstevel@tonic-gate * lowest unused integer. In the case of LETTER, return the next lowest 5343*7c478bd9Sstevel@tonic-gate * unused letter. Return empty string if all 26 are used. 5344*7c478bd9Sstevel@tonic-gate * Only IDs >= min will be returned. 5345*7c478bd9Sstevel@tonic-gate */ 5346*7c478bd9Sstevel@tonic-gate char * 5347*7c478bd9Sstevel@tonic-gate new_id(numeral_t *numeral, int type, char *min) 5348*7c478bd9Sstevel@tonic-gate { 5349*7c478bd9Sstevel@tonic-gate int imin; 5350*7c478bd9Sstevel@tonic-gate temp_t *temp; 5351*7c478bd9Sstevel@tonic-gate temp_t *ptr; 5352*7c478bd9Sstevel@tonic-gate temp_t **previous; 5353*7c478bd9Sstevel@tonic-gate temp_t *head = NULL; 5354*7c478bd9Sstevel@tonic-gate char *retval; 5355*7c478bd9Sstevel@tonic-gate static char tempbuff[8]; 5356*7c478bd9Sstevel@tonic-gate numeral_t *np; 5357*7c478bd9Sstevel@tonic-gate 5358*7c478bd9Sstevel@tonic-gate if (type == LETTER) { 5359*7c478bd9Sstevel@tonic-gate 5360*7c478bd9Sstevel@tonic-gate char letter[26], i; 5361*7c478bd9Sstevel@tonic-gate 5362*7c478bd9Sstevel@tonic-gate if (numeral == NULL) { 5363*7c478bd9Sstevel@tonic-gate return (s_strdup(min)); 5364*7c478bd9Sstevel@tonic-gate } 5365*7c478bd9Sstevel@tonic-gate 5366*7c478bd9Sstevel@tonic-gate for (i = 0; i < 26; i++) { 5367*7c478bd9Sstevel@tonic-gate letter[i] = 0; 5368*7c478bd9Sstevel@tonic-gate } 5369*7c478bd9Sstevel@tonic-gate 5370*7c478bd9Sstevel@tonic-gate for (np = numeral; np != NULL; np = np->next) { 5371*7c478bd9Sstevel@tonic-gate letter[*np->id - 'a']++; 5372*7c478bd9Sstevel@tonic-gate } 5373*7c478bd9Sstevel@tonic-gate 5374*7c478bd9Sstevel@tonic-gate imin = *min - 'a'; 5375*7c478bd9Sstevel@tonic-gate 5376*7c478bd9Sstevel@tonic-gate for (i = imin; i < 26; i++) { 5377*7c478bd9Sstevel@tonic-gate if (letter[i] == 0) { 5378*7c478bd9Sstevel@tonic-gate retval = s_malloc(2); 5379*7c478bd9Sstevel@tonic-gate retval[0] = 'a' + i; 5380*7c478bd9Sstevel@tonic-gate retval[1] = '\0'; 5381*7c478bd9Sstevel@tonic-gate return (retval); 5382*7c478bd9Sstevel@tonic-gate } 5383*7c478bd9Sstevel@tonic-gate } 5384*7c478bd9Sstevel@tonic-gate 5385*7c478bd9Sstevel@tonic-gate return (s_strdup("")); 5386*7c478bd9Sstevel@tonic-gate } 5387*7c478bd9Sstevel@tonic-gate 5388*7c478bd9Sstevel@tonic-gate if (type == INTEGER) { 5389*7c478bd9Sstevel@tonic-gate 5390*7c478bd9Sstevel@tonic-gate if (numeral == NULL) { 5391*7c478bd9Sstevel@tonic-gate return (s_strdup(min)); 5392*7c478bd9Sstevel@tonic-gate } 5393*7c478bd9Sstevel@tonic-gate 5394*7c478bd9Sstevel@tonic-gate imin = atoi(min); 5395*7c478bd9Sstevel@tonic-gate 5396*7c478bd9Sstevel@tonic-gate /* sort list */ 5397*7c478bd9Sstevel@tonic-gate for (np = numeral; np != NULL; np = np->next) { 5398*7c478bd9Sstevel@tonic-gate temp = s_malloc(sizeof (temp_t)); 5399*7c478bd9Sstevel@tonic-gate temp->integer = atoi(np->id); 5400*7c478bd9Sstevel@tonic-gate temp->next = NULL; 5401*7c478bd9Sstevel@tonic-gate 5402*7c478bd9Sstevel@tonic-gate previous = &head; 5403*7c478bd9Sstevel@tonic-gate for (ptr = head; ptr != NULL; ptr = ptr->next) { 5404*7c478bd9Sstevel@tonic-gate if (temp->integer < ptr->integer) { 5405*7c478bd9Sstevel@tonic-gate temp->next = ptr; 5406*7c478bd9Sstevel@tonic-gate *previous = temp; 5407*7c478bd9Sstevel@tonic-gate break; 5408*7c478bd9Sstevel@tonic-gate } 5409*7c478bd9Sstevel@tonic-gate previous = &(ptr->next); 5410*7c478bd9Sstevel@tonic-gate } 5411*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 5412*7c478bd9Sstevel@tonic-gate *previous = temp; 5413*7c478bd9Sstevel@tonic-gate } 5414*7c478bd9Sstevel@tonic-gate } 5415*7c478bd9Sstevel@tonic-gate 5416*7c478bd9Sstevel@tonic-gate /* now search sorted list for first hole >= imin */ 5417*7c478bd9Sstevel@tonic-gate for (ptr = head; ptr != NULL; ptr = ptr->next) { 5418*7c478bd9Sstevel@tonic-gate if (imin == ptr->integer) { 5419*7c478bd9Sstevel@tonic-gate imin++; 5420*7c478bd9Sstevel@tonic-gate } else { 5421*7c478bd9Sstevel@tonic-gate if (imin < ptr->integer) { 5422*7c478bd9Sstevel@tonic-gate break; 5423*7c478bd9Sstevel@tonic-gate } 5424*7c478bd9Sstevel@tonic-gate } 5425*7c478bd9Sstevel@tonic-gate 5426*7c478bd9Sstevel@tonic-gate } 5427*7c478bd9Sstevel@tonic-gate 5428*7c478bd9Sstevel@tonic-gate /* free temp list */ 5429*7c478bd9Sstevel@tonic-gate for (ptr = head; ptr != NULL; ) { 5430*7c478bd9Sstevel@tonic-gate temp = ptr; 5431*7c478bd9Sstevel@tonic-gate ptr = ptr->next; 5432*7c478bd9Sstevel@tonic-gate free(temp); 5433*7c478bd9Sstevel@tonic-gate } 5434*7c478bd9Sstevel@tonic-gate 5435*7c478bd9Sstevel@tonic-gate (void) sprintf(tempbuff, "%d", imin); 5436*7c478bd9Sstevel@tonic-gate return (s_strdup(tempbuff)); 5437*7c478bd9Sstevel@tonic-gate } 5438*7c478bd9Sstevel@tonic-gate 5439*7c478bd9Sstevel@tonic-gate return (s_strdup("")); 5440*7c478bd9Sstevel@tonic-gate } 5441*7c478bd9Sstevel@tonic-gate 5442*7c478bd9Sstevel@tonic-gate /* 5443*7c478bd9Sstevel@tonic-gate * Search current_dir for all files which match the first path component 5444*7c478bd9Sstevel@tonic-gate * of path_left, which is an RE. If a match is found, but there are more 5445*7c478bd9Sstevel@tonic-gate * components of path_left, then recurse, otherwise, if we have reached 5446*7c478bd9Sstevel@tonic-gate * the last component of path_left, call create_cached_numerals for each 5447*7c478bd9Sstevel@tonic-gate * file. At some point, recurse_dev_re() should be rewritten so that this 5448*7c478bd9Sstevel@tonic-gate * function can be eliminated. 5449*7c478bd9Sstevel@tonic-gate */ 5450*7c478bd9Sstevel@tonic-gate static void 5451*7c478bd9Sstevel@tonic-gate enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, 5452*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int index) 5453*7c478bd9Sstevel@tonic-gate { 5454*7c478bd9Sstevel@tonic-gate char *slash; 5455*7c478bd9Sstevel@tonic-gate char *new_path; 5456*7c478bd9Sstevel@tonic-gate char *numeral_id; 5457*7c478bd9Sstevel@tonic-gate struct dirent *entp; 5458*7c478bd9Sstevel@tonic-gate struct dirent *retp; 5459*7c478bd9Sstevel@tonic-gate DIR *dp; 5460*7c478bd9Sstevel@tonic-gate 5461*7c478bd9Sstevel@tonic-gate if ((dp = opendir(current_dir)) == NULL) { 5462*7c478bd9Sstevel@tonic-gate return; 5463*7c478bd9Sstevel@tonic-gate } 5464*7c478bd9Sstevel@tonic-gate 5465*7c478bd9Sstevel@tonic-gate /* get rid of any extra '/' */ 5466*7c478bd9Sstevel@tonic-gate while (*path_left == '/') { 5467*7c478bd9Sstevel@tonic-gate path_left++; 5468*7c478bd9Sstevel@tonic-gate } 5469*7c478bd9Sstevel@tonic-gate 5470*7c478bd9Sstevel@tonic-gate if (slash = strchr(path_left, '/')) { 5471*7c478bd9Sstevel@tonic-gate *slash = '\0'; 5472*7c478bd9Sstevel@tonic-gate } 5473*7c478bd9Sstevel@tonic-gate 5474*7c478bd9Sstevel@tonic-gate entp = s_malloc(PATH_MAX + 1 + sizeof (struct dirent)); 5475*7c478bd9Sstevel@tonic-gate 5476*7c478bd9Sstevel@tonic-gate while (readdir_r(dp, entp, &retp) == 0) { 5477*7c478bd9Sstevel@tonic-gate 5478*7c478bd9Sstevel@tonic-gate if (retp == NULL) { 5479*7c478bd9Sstevel@tonic-gate break; 5480*7c478bd9Sstevel@tonic-gate } 5481*7c478bd9Sstevel@tonic-gate 5482*7c478bd9Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 || 5483*7c478bd9Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0) { 5484*7c478bd9Sstevel@tonic-gate continue; 5485*7c478bd9Sstevel@tonic-gate } 5486*7c478bd9Sstevel@tonic-gate 5487*7c478bd9Sstevel@tonic-gate /* 5488*7c478bd9Sstevel@tonic-gate * Returns true if path_left matches entp->d_name 5489*7c478bd9Sstevel@tonic-gate * If it is the last path component, pass subexp 5490*7c478bd9Sstevel@tonic-gate * so that it will return the corresponding ID in 5491*7c478bd9Sstevel@tonic-gate * numeral_id. 5492*7c478bd9Sstevel@tonic-gate */ 5493*7c478bd9Sstevel@tonic-gate numeral_id = NULL; 5494*7c478bd9Sstevel@tonic-gate if (match_path_component(path_left, entp->d_name, &numeral_id, 5495*7c478bd9Sstevel@tonic-gate slash ? 0 : rules[index].subexp)) { 5496*7c478bd9Sstevel@tonic-gate 5497*7c478bd9Sstevel@tonic-gate new_path = s_malloc(strlen(current_dir) + 5498*7c478bd9Sstevel@tonic-gate strlen(entp->d_name) + 2); 5499*7c478bd9Sstevel@tonic-gate 5500*7c478bd9Sstevel@tonic-gate (void) strcpy(new_path, current_dir); 5501*7c478bd9Sstevel@tonic-gate (void) strcat(new_path, "/"); 5502*7c478bd9Sstevel@tonic-gate (void) strcat(new_path, entp->d_name); 5503*7c478bd9Sstevel@tonic-gate 5504*7c478bd9Sstevel@tonic-gate if (slash != NULL) { 5505*7c478bd9Sstevel@tonic-gate enumerate_recurse(new_path, slash + 1, 5506*7c478bd9Sstevel@tonic-gate setp, rules, index); 5507*7c478bd9Sstevel@tonic-gate } else { 5508*7c478bd9Sstevel@tonic-gate create_cached_numeral(new_path, setp, 5509*7c478bd9Sstevel@tonic-gate numeral_id, rules, index); 5510*7c478bd9Sstevel@tonic-gate if (numeral_id != NULL) { 5511*7c478bd9Sstevel@tonic-gate free(numeral_id); 5512*7c478bd9Sstevel@tonic-gate } 5513*7c478bd9Sstevel@tonic-gate } 5514*7c478bd9Sstevel@tonic-gate free(new_path); 5515*7c478bd9Sstevel@tonic-gate } 5516*7c478bd9Sstevel@tonic-gate } 5517*7c478bd9Sstevel@tonic-gate 5518*7c478bd9Sstevel@tonic-gate if (slash != NULL) { 5519*7c478bd9Sstevel@tonic-gate *slash = '/'; 5520*7c478bd9Sstevel@tonic-gate } 5521*7c478bd9Sstevel@tonic-gate free(entp); 5522*7c478bd9Sstevel@tonic-gate s_closedir(dp); 5523*7c478bd9Sstevel@tonic-gate } 5524*7c478bd9Sstevel@tonic-gate 5525*7c478bd9Sstevel@tonic-gate 5526*7c478bd9Sstevel@tonic-gate /* 5527*7c478bd9Sstevel@tonic-gate * Returns true if file matches file_re. If subexp is non-zero, it means 5528*7c478bd9Sstevel@tonic-gate * we are searching the last path component and need to return the 5529*7c478bd9Sstevel@tonic-gate * parenthesized subexpression subexp in id. 5530*7c478bd9Sstevel@tonic-gate * 5531*7c478bd9Sstevel@tonic-gate */ 5532*7c478bd9Sstevel@tonic-gate static int 5533*7c478bd9Sstevel@tonic-gate match_path_component(char *file_re, char *file, char **id, int subexp) 5534*7c478bd9Sstevel@tonic-gate { 5535*7c478bd9Sstevel@tonic-gate regex_t re1; 5536*7c478bd9Sstevel@tonic-gate int match = 0; 5537*7c478bd9Sstevel@tonic-gate int nelements; 5538*7c478bd9Sstevel@tonic-gate regmatch_t *pmatch; 5539*7c478bd9Sstevel@tonic-gate 5540*7c478bd9Sstevel@tonic-gate if (subexp != 0) { 5541*7c478bd9Sstevel@tonic-gate nelements = subexp + 1; 5542*7c478bd9Sstevel@tonic-gate pmatch = (regmatch_t *) 5543*7c478bd9Sstevel@tonic-gate s_malloc(sizeof (regmatch_t) * nelements); 5544*7c478bd9Sstevel@tonic-gate } else { 5545*7c478bd9Sstevel@tonic-gate pmatch = NULL; 5546*7c478bd9Sstevel@tonic-gate nelements = 0; 5547*7c478bd9Sstevel@tonic-gate } 5548*7c478bd9Sstevel@tonic-gate 5549*7c478bd9Sstevel@tonic-gate if (regcomp(&re1, file_re, REG_EXTENDED) != 0) { 5550*7c478bd9Sstevel@tonic-gate if (pmatch != NULL) { 5551*7c478bd9Sstevel@tonic-gate free(pmatch); 5552*7c478bd9Sstevel@tonic-gate } 5553*7c478bd9Sstevel@tonic-gate return (0); 5554*7c478bd9Sstevel@tonic-gate } 5555*7c478bd9Sstevel@tonic-gate 5556*7c478bd9Sstevel@tonic-gate if (regexec(&re1, file, nelements, pmatch, 0) == 0) { 5557*7c478bd9Sstevel@tonic-gate match = 1; 5558*7c478bd9Sstevel@tonic-gate } 5559*7c478bd9Sstevel@tonic-gate 5560*7c478bd9Sstevel@tonic-gate if ((match != 0) && (subexp != 0)) { 5561*7c478bd9Sstevel@tonic-gate int size = pmatch[subexp].rm_eo - pmatch[subexp].rm_so; 5562*7c478bd9Sstevel@tonic-gate *id = s_malloc(size + 1); 5563*7c478bd9Sstevel@tonic-gate (void) strncpy(*id, &file[pmatch[subexp].rm_so], size); 5564*7c478bd9Sstevel@tonic-gate (*id)[size] = '\0'; 5565*7c478bd9Sstevel@tonic-gate } 5566*7c478bd9Sstevel@tonic-gate 5567*7c478bd9Sstevel@tonic-gate if (pmatch != NULL) { 5568*7c478bd9Sstevel@tonic-gate free(pmatch); 5569*7c478bd9Sstevel@tonic-gate } 5570*7c478bd9Sstevel@tonic-gate regfree(&re1); 5571*7c478bd9Sstevel@tonic-gate return (match); 5572*7c478bd9Sstevel@tonic-gate } 5573*7c478bd9Sstevel@tonic-gate 5574*7c478bd9Sstevel@tonic-gate /* 5575*7c478bd9Sstevel@tonic-gate * This function is called for every file which matched the leaf 5576*7c478bd9Sstevel@tonic-gate * component of the RE. If the "numeral_id" is not already on the 5577*7c478bd9Sstevel@tonic-gate * numeral set's numeral list, add it and its physical path. 5578*7c478bd9Sstevel@tonic-gate */ 5579*7c478bd9Sstevel@tonic-gate static void 5580*7c478bd9Sstevel@tonic-gate create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, 5581*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[], int index) 5582*7c478bd9Sstevel@tonic-gate { 5583*7c478bd9Sstevel@tonic-gate char linkbuf[PATH_MAX + 1]; 5584*7c478bd9Sstevel@tonic-gate char lpath[PATH_MAX + 1]; 5585*7c478bd9Sstevel@tonic-gate char *linkptr, *cmp_str; 5586*7c478bd9Sstevel@tonic-gate numeral_t *np; 5587*7c478bd9Sstevel@tonic-gate int linksize; 5588*7c478bd9Sstevel@tonic-gate struct stat sb; 5589*7c478bd9Sstevel@tonic-gate const char *fcn = "create_cached_numeral"; 5590*7c478bd9Sstevel@tonic-gate 5591*7c478bd9Sstevel@tonic-gate assert(index >= 0 && index < setp->re_count); 5592*7c478bd9Sstevel@tonic-gate assert(strcmp(rules[index].re, setp->re[index]) == 0); 5593*7c478bd9Sstevel@tonic-gate 5594*7c478bd9Sstevel@tonic-gate /* 5595*7c478bd9Sstevel@tonic-gate * We found a numeral_id from an entry in /dev which matched 5596*7c478bd9Sstevel@tonic-gate * the re passed in from devfsadm_enumerate. We only need to make sure 5597*7c478bd9Sstevel@tonic-gate * ONE copy of numeral_id exists on the numeral list. We only need 5598*7c478bd9Sstevel@tonic-gate * to store /dev/dsk/cNtod0s0 and no other entries hanging off 5599*7c478bd9Sstevel@tonic-gate * of controller N. 5600*7c478bd9Sstevel@tonic-gate */ 5601*7c478bd9Sstevel@tonic-gate for (np = setp->headnumeral; np != NULL; np = np->next) { 5602*7c478bd9Sstevel@tonic-gate if (strcmp(numeral_id, np->id) == 0) { 5603*7c478bd9Sstevel@tonic-gate return; 5604*7c478bd9Sstevel@tonic-gate } 5605*7c478bd9Sstevel@tonic-gate } 5606*7c478bd9Sstevel@tonic-gate 5607*7c478bd9Sstevel@tonic-gate /* NOT on list, so add it */ 5608*7c478bd9Sstevel@tonic-gate 5609*7c478bd9Sstevel@tonic-gate (void) strcpy(lpath, path); 5610*7c478bd9Sstevel@tonic-gate /* 5611*7c478bd9Sstevel@tonic-gate * If path is a dir, it is changed to the first symbolic link it find 5612*7c478bd9Sstevel@tonic-gate * if it finds one. 5613*7c478bd9Sstevel@tonic-gate */ 5614*7c478bd9Sstevel@tonic-gate if (get_stat_info(lpath, &sb) == DEVFSADM_FAILURE) { 5615*7c478bd9Sstevel@tonic-gate return; 5616*7c478bd9Sstevel@tonic-gate } 5617*7c478bd9Sstevel@tonic-gate 5618*7c478bd9Sstevel@tonic-gate /* If we get here, we found a symlink */ 5619*7c478bd9Sstevel@tonic-gate linksize = readlink(lpath, linkbuf, PATH_MAX); 5620*7c478bd9Sstevel@tonic-gate 5621*7c478bd9Sstevel@tonic-gate if (linksize <= 0) { 5622*7c478bd9Sstevel@tonic-gate err_print(READLINK_FAILED, fcn, lpath, strerror(errno)); 5623*7c478bd9Sstevel@tonic-gate return; 5624*7c478bd9Sstevel@tonic-gate } 5625*7c478bd9Sstevel@tonic-gate 5626*7c478bd9Sstevel@tonic-gate linkbuf[linksize] = '\0'; 5627*7c478bd9Sstevel@tonic-gate 5628*7c478bd9Sstevel@tonic-gate /* 5629*7c478bd9Sstevel@tonic-gate * the following just points linkptr to the root of the /devices 5630*7c478bd9Sstevel@tonic-gate * node if it is a minor node, otherwise, to the first char of 5631*7c478bd9Sstevel@tonic-gate * linkbuf if it is a link. 5632*7c478bd9Sstevel@tonic-gate */ 5633*7c478bd9Sstevel@tonic-gate (void) is_minor_node(linkbuf, &linkptr); 5634*7c478bd9Sstevel@tonic-gate 5635*7c478bd9Sstevel@tonic-gate cmp_str = alloc_cmp_str(linkptr, &rules[index]); 5636*7c478bd9Sstevel@tonic-gate if (cmp_str == NULL) { 5637*7c478bd9Sstevel@tonic-gate return; 5638*7c478bd9Sstevel@tonic-gate } 5639*7c478bd9Sstevel@tonic-gate 5640*7c478bd9Sstevel@tonic-gate np = s_malloc(sizeof (numeral_t)); 5641*7c478bd9Sstevel@tonic-gate 5642*7c478bd9Sstevel@tonic-gate np->id = s_strdup(numeral_id); 5643*7c478bd9Sstevel@tonic-gate np->full_path = s_strdup(linkptr); 5644*7c478bd9Sstevel@tonic-gate np->rule_index = index; 5645*7c478bd9Sstevel@tonic-gate np->cmp_str = cmp_str; 5646*7c478bd9Sstevel@tonic-gate 5647*7c478bd9Sstevel@tonic-gate np->next = setp->headnumeral; 5648*7c478bd9Sstevel@tonic-gate setp->headnumeral = np; 5649*7c478bd9Sstevel@tonic-gate } 5650*7c478bd9Sstevel@tonic-gate 5651*7c478bd9Sstevel@tonic-gate 5652*7c478bd9Sstevel@tonic-gate /* 5653*7c478bd9Sstevel@tonic-gate * This should be called either before or after granting access to a 5654*7c478bd9Sstevel@tonic-gate * command line version of devfsadm running, since it may have changed 5655*7c478bd9Sstevel@tonic-gate * the state of /dev. It forces future enumerate calls to re-build 5656*7c478bd9Sstevel@tonic-gate * cached information from /dev. 5657*7c478bd9Sstevel@tonic-gate */ 5658*7c478bd9Sstevel@tonic-gate void 5659*7c478bd9Sstevel@tonic-gate invalidate_enumerate_cache(void) 5660*7c478bd9Sstevel@tonic-gate { 5661*7c478bd9Sstevel@tonic-gate numeral_set_t *setp; 5662*7c478bd9Sstevel@tonic-gate numeral_set_t *savedsetp; 5663*7c478bd9Sstevel@tonic-gate numeral_t *savednumset; 5664*7c478bd9Sstevel@tonic-gate numeral_t *numset; 5665*7c478bd9Sstevel@tonic-gate int i; 5666*7c478bd9Sstevel@tonic-gate 5667*7c478bd9Sstevel@tonic-gate for (setp = head_numeral_set; setp != NULL; ) { 5668*7c478bd9Sstevel@tonic-gate /* 5669*7c478bd9Sstevel@tonic-gate * check all regexp's passed in function against 5670*7c478bd9Sstevel@tonic-gate * those in cached set. 5671*7c478bd9Sstevel@tonic-gate */ 5672*7c478bd9Sstevel@tonic-gate 5673*7c478bd9Sstevel@tonic-gate savedsetp = setp; 5674*7c478bd9Sstevel@tonic-gate setp = setp->next; 5675*7c478bd9Sstevel@tonic-gate 5676*7c478bd9Sstevel@tonic-gate for (i = 0; i < savedsetp->re_count; i++) { 5677*7c478bd9Sstevel@tonic-gate free(savedsetp->re[i]); 5678*7c478bd9Sstevel@tonic-gate } 5679*7c478bd9Sstevel@tonic-gate free(savedsetp->re); 5680*7c478bd9Sstevel@tonic-gate 5681*7c478bd9Sstevel@tonic-gate for (numset = savedsetp->headnumeral; numset != NULL; ) { 5682*7c478bd9Sstevel@tonic-gate savednumset = numset; 5683*7c478bd9Sstevel@tonic-gate numset = numset->next; 5684*7c478bd9Sstevel@tonic-gate assert(savednumset->rule_index < savedsetp->re_count); 5685*7c478bd9Sstevel@tonic-gate free(savednumset->id); 5686*7c478bd9Sstevel@tonic-gate free(savednumset->full_path); 5687*7c478bd9Sstevel@tonic-gate free(savednumset->cmp_str); 5688*7c478bd9Sstevel@tonic-gate free(savednumset); 5689*7c478bd9Sstevel@tonic-gate } 5690*7c478bd9Sstevel@tonic-gate free(savedsetp); 5691*7c478bd9Sstevel@tonic-gate } 5692*7c478bd9Sstevel@tonic-gate head_numeral_set = NULL; 5693*7c478bd9Sstevel@tonic-gate } 5694*7c478bd9Sstevel@tonic-gate 5695*7c478bd9Sstevel@tonic-gate /* 5696*7c478bd9Sstevel@tonic-gate * Copies over links from /dev to <root>/dev and device special files in 5697*7c478bd9Sstevel@tonic-gate * /devices to <root>/devices, preserving the existing file modes. If 5698*7c478bd9Sstevel@tonic-gate * the link or special file already exists on <root>, skip the copy. (it 5699*7c478bd9Sstevel@tonic-gate * would exist only if a package hard coded it there, so assume package 5700*7c478bd9Sstevel@tonic-gate * knows best?). Use /etc/name_to_major and <root>/etc/name_to_major to 5701*7c478bd9Sstevel@tonic-gate * make translations for major numbers on device special files. No need to 5702*7c478bd9Sstevel@tonic-gate * make a translation on minor_perm since if the file was created in the 5703*7c478bd9Sstevel@tonic-gate * miniroot then it would presumably have the same minor_perm entry in 5704*7c478bd9Sstevel@tonic-gate * <root>/etc/minor_perm. To be used only by install. 5705*7c478bd9Sstevel@tonic-gate */ 5706*7c478bd9Sstevel@tonic-gate int 5707*7c478bd9Sstevel@tonic-gate devfsadm_copy(void) 5708*7c478bd9Sstevel@tonic-gate { 5709*7c478bd9Sstevel@tonic-gate char filename[PATH_MAX + 1]; 5710*7c478bd9Sstevel@tonic-gate 5711*7c478bd9Sstevel@tonic-gate /* load the installed root's name_to_major for translations */ 5712*7c478bd9Sstevel@tonic-gate (void) snprintf(filename, sizeof (filename), "%s%s", root_dir, 5713*7c478bd9Sstevel@tonic-gate NAME_TO_MAJOR); 5714*7c478bd9Sstevel@tonic-gate if (load_n2m_table(filename) == DEVFSADM_FAILURE) { 5715*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5716*7c478bd9Sstevel@tonic-gate } 5717*7c478bd9Sstevel@tonic-gate 5718*7c478bd9Sstevel@tonic-gate /* Copy /dev to target disk. No need to copy /devices with devfs */ 5719*7c478bd9Sstevel@tonic-gate (void) nftw(DEV, devfsadm_copy_file, 20, FTW_PHYS); 5720*7c478bd9Sstevel@tonic-gate 5721*7c478bd9Sstevel@tonic-gate /* Let install handle copying over path_to_inst */ 5722*7c478bd9Sstevel@tonic-gate 5723*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5724*7c478bd9Sstevel@tonic-gate } 5725*7c478bd9Sstevel@tonic-gate 5726*7c478bd9Sstevel@tonic-gate /* 5727*7c478bd9Sstevel@tonic-gate * This function copies links, dirs, and device special files. 5728*7c478bd9Sstevel@tonic-gate * Note that it always returns DEVFSADM_SUCCESS, so that nftw doesn't 5729*7c478bd9Sstevel@tonic-gate * abort. 5730*7c478bd9Sstevel@tonic-gate */ 5731*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5732*7c478bd9Sstevel@tonic-gate static int 5733*7c478bd9Sstevel@tonic-gate devfsadm_copy_file(const char *file, const struct stat *stat, 5734*7c478bd9Sstevel@tonic-gate int flags, struct FTW *ftw) 5735*7c478bd9Sstevel@tonic-gate { 5736*7c478bd9Sstevel@tonic-gate struct stat sp; 5737*7c478bd9Sstevel@tonic-gate dev_t newdev; 5738*7c478bd9Sstevel@tonic-gate char newfile[PATH_MAX + 1]; 5739*7c478bd9Sstevel@tonic-gate char linkcontents[PATH_MAX + 1]; 5740*7c478bd9Sstevel@tonic-gate int bytes; 5741*7c478bd9Sstevel@tonic-gate const char *fcn = "devfsadm_copy_file"; 5742*7c478bd9Sstevel@tonic-gate 5743*7c478bd9Sstevel@tonic-gate (void) strcpy(newfile, root_dir); 5744*7c478bd9Sstevel@tonic-gate (void) strcat(newfile, "/"); 5745*7c478bd9Sstevel@tonic-gate (void) strcat(newfile, file); 5746*7c478bd9Sstevel@tonic-gate 5747*7c478bd9Sstevel@tonic-gate if (lstat(newfile, &sp) == 0) { 5748*7c478bd9Sstevel@tonic-gate /* newfile already exists, so no need to continue */ 5749*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5750*7c478bd9Sstevel@tonic-gate } 5751*7c478bd9Sstevel@tonic-gate 5752*7c478bd9Sstevel@tonic-gate if (((stat->st_mode & S_IFMT) == S_IFBLK) || 5753*7c478bd9Sstevel@tonic-gate ((stat->st_mode & S_IFMT) == S_IFCHR)) { 5754*7c478bd9Sstevel@tonic-gate if (translate_major(stat->st_rdev, &newdev) == 5755*7c478bd9Sstevel@tonic-gate DEVFSADM_FAILURE) { 5756*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5757*7c478bd9Sstevel@tonic-gate } 5758*7c478bd9Sstevel@tonic-gate if (mknod(newfile, stat->st_mode, newdev) == -1) { 5759*7c478bd9Sstevel@tonic-gate err_print(MKNOD_FAILED, newfile, strerror(errno)); 5760*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5761*7c478bd9Sstevel@tonic-gate } 5762*7c478bd9Sstevel@tonic-gate } else if ((stat->st_mode & S_IFMT) == S_IFDIR) { 5763*7c478bd9Sstevel@tonic-gate if (mknod(newfile, stat->st_mode, 0) == -1) { 5764*7c478bd9Sstevel@tonic-gate err_print(MKNOD_FAILED, newfile, strerror(errno)); 5765*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5766*7c478bd9Sstevel@tonic-gate } 5767*7c478bd9Sstevel@tonic-gate } else if ((stat->st_mode & S_IFMT) == S_IFLNK) { 5768*7c478bd9Sstevel@tonic-gate if ((bytes = readlink(file, linkcontents, PATH_MAX)) == -1) { 5769*7c478bd9Sstevel@tonic-gate err_print(READLINK_FAILED, fcn, file, strerror(errno)); 5770*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5771*7c478bd9Sstevel@tonic-gate } 5772*7c478bd9Sstevel@tonic-gate linkcontents[bytes] = '\0'; 5773*7c478bd9Sstevel@tonic-gate if (symlink(linkcontents, newfile) == -1) { 5774*7c478bd9Sstevel@tonic-gate err_print(SYMLINK_FAILED, newfile, newfile, 5775*7c478bd9Sstevel@tonic-gate strerror(errno)); 5776*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5777*7c478bd9Sstevel@tonic-gate } 5778*7c478bd9Sstevel@tonic-gate } 5779*7c478bd9Sstevel@tonic-gate 5780*7c478bd9Sstevel@tonic-gate (void) lchown(newfile, stat->st_uid, stat->st_gid); 5781*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5782*7c478bd9Sstevel@tonic-gate } 5783*7c478bd9Sstevel@tonic-gate 5784*7c478bd9Sstevel@tonic-gate /* 5785*7c478bd9Sstevel@tonic-gate * Given a dev_t from the running kernel, return the new_dev_t 5786*7c478bd9Sstevel@tonic-gate * by translating to the major number found on the installed 5787*7c478bd9Sstevel@tonic-gate * target's root name_to_major file. 5788*7c478bd9Sstevel@tonic-gate */ 5789*7c478bd9Sstevel@tonic-gate static int 5790*7c478bd9Sstevel@tonic-gate translate_major(dev_t old_dev, dev_t *new_dev) 5791*7c478bd9Sstevel@tonic-gate { 5792*7c478bd9Sstevel@tonic-gate major_t oldmajor; 5793*7c478bd9Sstevel@tonic-gate major_t newmajor; 5794*7c478bd9Sstevel@tonic-gate minor_t oldminor; 5795*7c478bd9Sstevel@tonic-gate minor_t newminor; 5796*7c478bd9Sstevel@tonic-gate char cdriver[FILENAME_MAX + 1]; 5797*7c478bd9Sstevel@tonic-gate char driver[FILENAME_MAX + 1]; 5798*7c478bd9Sstevel@tonic-gate char *fcn = "translate_major: "; 5799*7c478bd9Sstevel@tonic-gate 5800*7c478bd9Sstevel@tonic-gate oldmajor = major(old_dev); 5801*7c478bd9Sstevel@tonic-gate if (modctl(MODGETNAME, driver, sizeof (driver), 5802*7c478bd9Sstevel@tonic-gate &oldmajor) != 0) { 5803*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5804*7c478bd9Sstevel@tonic-gate } 5805*7c478bd9Sstevel@tonic-gate 5806*7c478bd9Sstevel@tonic-gate if (strcmp(driver, "clone") != 0) { 5807*7c478bd9Sstevel@tonic-gate /* non-clone case */ 5808*7c478bd9Sstevel@tonic-gate 5809*7c478bd9Sstevel@tonic-gate /* look up major number is target's name2major */ 5810*7c478bd9Sstevel@tonic-gate if (get_major_no(driver, &newmajor) == DEVFSADM_FAILURE) { 5811*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5812*7c478bd9Sstevel@tonic-gate } 5813*7c478bd9Sstevel@tonic-gate 5814*7c478bd9Sstevel@tonic-gate *new_dev = makedev(newmajor, minor(old_dev)); 5815*7c478bd9Sstevel@tonic-gate if (old_dev != *new_dev) { 5816*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%sdriver: %s old: %lu,%lu " 5817*7c478bd9Sstevel@tonic-gate "new: %lu,%lu\n", fcn, driver, major(old_dev), 5818*7c478bd9Sstevel@tonic-gate minor(old_dev), major(*new_dev), 5819*7c478bd9Sstevel@tonic-gate minor(*new_dev)); 5820*7c478bd9Sstevel@tonic-gate } 5821*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5822*7c478bd9Sstevel@tonic-gate } else { 5823*7c478bd9Sstevel@tonic-gate /* 5824*7c478bd9Sstevel@tonic-gate * The clone is a special case. Look at its minor 5825*7c478bd9Sstevel@tonic-gate * number since it is the major number of the real driver. 5826*7c478bd9Sstevel@tonic-gate */ 5827*7c478bd9Sstevel@tonic-gate if (get_major_no(driver, &newmajor) == DEVFSADM_FAILURE) { 5828*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5829*7c478bd9Sstevel@tonic-gate } 5830*7c478bd9Sstevel@tonic-gate 5831*7c478bd9Sstevel@tonic-gate oldminor = minor(old_dev); 5832*7c478bd9Sstevel@tonic-gate if (modctl(MODGETNAME, cdriver, sizeof (cdriver), 5833*7c478bd9Sstevel@tonic-gate &oldminor) != 0) { 5834*7c478bd9Sstevel@tonic-gate err_print(MODGETNAME_FAILED, oldminor); 5835*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5836*7c478bd9Sstevel@tonic-gate } 5837*7c478bd9Sstevel@tonic-gate 5838*7c478bd9Sstevel@tonic-gate if (get_major_no(cdriver, &newminor) == DEVFSADM_FAILURE) { 5839*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5840*7c478bd9Sstevel@tonic-gate } 5841*7c478bd9Sstevel@tonic-gate 5842*7c478bd9Sstevel@tonic-gate *new_dev = makedev(newmajor, newminor); 5843*7c478bd9Sstevel@tonic-gate if (old_dev != *new_dev) { 5844*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "%sdriver: %s old: " 5845*7c478bd9Sstevel@tonic-gate "%lu,%lu new: %lu,%lu\n", fcn, driver, 5846*7c478bd9Sstevel@tonic-gate major(old_dev), minor(old_dev), 5847*7c478bd9Sstevel@tonic-gate major(*new_dev), minor(*new_dev)); 5848*7c478bd9Sstevel@tonic-gate } 5849*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5850*7c478bd9Sstevel@tonic-gate } 5851*7c478bd9Sstevel@tonic-gate } 5852*7c478bd9Sstevel@tonic-gate 5853*7c478bd9Sstevel@tonic-gate /* 5854*7c478bd9Sstevel@tonic-gate * 5855*7c478bd9Sstevel@tonic-gate * Find the major number for driver, searching the n2m_list that was 5856*7c478bd9Sstevel@tonic-gate * built in load_n2m_table(). 5857*7c478bd9Sstevel@tonic-gate */ 5858*7c478bd9Sstevel@tonic-gate static int 5859*7c478bd9Sstevel@tonic-gate get_major_no(char *driver, major_t *major) 5860*7c478bd9Sstevel@tonic-gate { 5861*7c478bd9Sstevel@tonic-gate n2m_t *ptr; 5862*7c478bd9Sstevel@tonic-gate 5863*7c478bd9Sstevel@tonic-gate for (ptr = n2m_list; ptr != NULL; ptr = ptr->next) { 5864*7c478bd9Sstevel@tonic-gate if (strcmp(ptr->driver, driver) == 0) { 5865*7c478bd9Sstevel@tonic-gate *major = ptr->major; 5866*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5867*7c478bd9Sstevel@tonic-gate } 5868*7c478bd9Sstevel@tonic-gate } 5869*7c478bd9Sstevel@tonic-gate err_print(FIND_MAJOR_FAILED, driver); 5870*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5871*7c478bd9Sstevel@tonic-gate } 5872*7c478bd9Sstevel@tonic-gate 5873*7c478bd9Sstevel@tonic-gate /* 5874*7c478bd9Sstevel@tonic-gate * Loads a name_to_major table into memory. Used only for suninstall's 5875*7c478bd9Sstevel@tonic-gate * private -R option to devfsadm, to translate major numbers from the 5876*7c478bd9Sstevel@tonic-gate * running to the installed target disk. 5877*7c478bd9Sstevel@tonic-gate */ 5878*7c478bd9Sstevel@tonic-gate static int 5879*7c478bd9Sstevel@tonic-gate load_n2m_table(char *file) 5880*7c478bd9Sstevel@tonic-gate { 5881*7c478bd9Sstevel@tonic-gate FILE *fp; 5882*7c478bd9Sstevel@tonic-gate char line[1024]; 5883*7c478bd9Sstevel@tonic-gate char driver[PATH_MAX + 1]; 5884*7c478bd9Sstevel@tonic-gate major_t major; 5885*7c478bd9Sstevel@tonic-gate n2m_t *ptr; 5886*7c478bd9Sstevel@tonic-gate int ln = 0; 5887*7c478bd9Sstevel@tonic-gate 5888*7c478bd9Sstevel@tonic-gate if ((fp = fopen(file, "r")) == NULL) { 5889*7c478bd9Sstevel@tonic-gate err_print(FOPEN_FAILED, file, strerror(errno)); 5890*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 5891*7c478bd9Sstevel@tonic-gate } 5892*7c478bd9Sstevel@tonic-gate 5893*7c478bd9Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) { 5894*7c478bd9Sstevel@tonic-gate ln++; 5895*7c478bd9Sstevel@tonic-gate if (line[0] == '#') { 5896*7c478bd9Sstevel@tonic-gate continue; 5897*7c478bd9Sstevel@tonic-gate } 5898*7c478bd9Sstevel@tonic-gate if (sscanf(line, "%1024s%lu", driver, &major) != 2) { 5899*7c478bd9Sstevel@tonic-gate err_print(IGNORING_LINE_IN, ln, file); 5900*7c478bd9Sstevel@tonic-gate continue; 5901*7c478bd9Sstevel@tonic-gate } 5902*7c478bd9Sstevel@tonic-gate ptr = (n2m_t *)s_malloc(sizeof (n2m_t)); 5903*7c478bd9Sstevel@tonic-gate ptr->major = major; 5904*7c478bd9Sstevel@tonic-gate ptr->driver = s_strdup(driver); 5905*7c478bd9Sstevel@tonic-gate ptr->next = n2m_list; 5906*7c478bd9Sstevel@tonic-gate n2m_list = ptr; 5907*7c478bd9Sstevel@tonic-gate } 5908*7c478bd9Sstevel@tonic-gate if (fclose(fp) == EOF) { 5909*7c478bd9Sstevel@tonic-gate err_print(FCLOSE_FAILED, file, strerror(errno)); 5910*7c478bd9Sstevel@tonic-gate } 5911*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 5912*7c478bd9Sstevel@tonic-gate } 5913*7c478bd9Sstevel@tonic-gate 5914*7c478bd9Sstevel@tonic-gate /* 5915*7c478bd9Sstevel@tonic-gate * Called at devfsadm startup to read in the devlink.tab file. Creates 5916*7c478bd9Sstevel@tonic-gate * a linked list of devlinktab_list structures which will be 5917*7c478bd9Sstevel@tonic-gate * searched for every minor node. 5918*7c478bd9Sstevel@tonic-gate */ 5919*7c478bd9Sstevel@tonic-gate static void 5920*7c478bd9Sstevel@tonic-gate read_devlinktab_file(void) 5921*7c478bd9Sstevel@tonic-gate { 5922*7c478bd9Sstevel@tonic-gate devlinktab_list_t *headp = NULL; 5923*7c478bd9Sstevel@tonic-gate devlinktab_list_t *entryp; 5924*7c478bd9Sstevel@tonic-gate devlinktab_list_t **previous; 5925*7c478bd9Sstevel@tonic-gate devlinktab_list_t *save; 5926*7c478bd9Sstevel@tonic-gate char line[MAX_DEVLINK_LINE]; 5927*7c478bd9Sstevel@tonic-gate char *selector; 5928*7c478bd9Sstevel@tonic-gate char *p_link; 5929*7c478bd9Sstevel@tonic-gate char *s_link; 5930*7c478bd9Sstevel@tonic-gate FILE *fp; 5931*7c478bd9Sstevel@tonic-gate int i; 5932*7c478bd9Sstevel@tonic-gate static struct stat cached_sb; 5933*7c478bd9Sstevel@tonic-gate struct stat current_sb; 5934*7c478bd9Sstevel@tonic-gate static int cached = FALSE; 5935*7c478bd9Sstevel@tonic-gate 5936*7c478bd9Sstevel@tonic-gate if (devlinktab_file == NULL) { 5937*7c478bd9Sstevel@tonic-gate return; 5938*7c478bd9Sstevel@tonic-gate } 5939*7c478bd9Sstevel@tonic-gate 5940*7c478bd9Sstevel@tonic-gate (void) stat(devlinktab_file, ¤t_sb); 5941*7c478bd9Sstevel@tonic-gate 5942*7c478bd9Sstevel@tonic-gate /* if already cached, check to see if it is still valid */ 5943*7c478bd9Sstevel@tonic-gate if (cached == TRUE) { 5944*7c478bd9Sstevel@tonic-gate 5945*7c478bd9Sstevel@tonic-gate if (current_sb.st_mtime == cached_sb.st_mtime) { 5946*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "%s cache valid\n", devlinktab_file); 5947*7c478bd9Sstevel@tonic-gate return; 5948*7c478bd9Sstevel@tonic-gate } 5949*7c478bd9Sstevel@tonic-gate 5950*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "invalidating %s cache\n", devlinktab_file); 5951*7c478bd9Sstevel@tonic-gate 5952*7c478bd9Sstevel@tonic-gate while (devlinktab_list != NULL) { 5953*7c478bd9Sstevel@tonic-gate free_link_list(devlinktab_list->p_link); 5954*7c478bd9Sstevel@tonic-gate free_link_list(devlinktab_list->s_link); 5955*7c478bd9Sstevel@tonic-gate free_selector_list(devlinktab_list->selector); 5956*7c478bd9Sstevel@tonic-gate free(devlinktab_list->selector_pattern); 5957*7c478bd9Sstevel@tonic-gate free(devlinktab_list->p_link_pattern); 5958*7c478bd9Sstevel@tonic-gate if (devlinktab_list->s_link_pattern != NULL) { 5959*7c478bd9Sstevel@tonic-gate free(devlinktab_list->s_link_pattern); 5960*7c478bd9Sstevel@tonic-gate } 5961*7c478bd9Sstevel@tonic-gate save = devlinktab_list; 5962*7c478bd9Sstevel@tonic-gate devlinktab_list = devlinktab_list->next; 5963*7c478bd9Sstevel@tonic-gate free(save); 5964*7c478bd9Sstevel@tonic-gate } 5965*7c478bd9Sstevel@tonic-gate } else { 5966*7c478bd9Sstevel@tonic-gate cached = TRUE; 5967*7c478bd9Sstevel@tonic-gate } 5968*7c478bd9Sstevel@tonic-gate 5969*7c478bd9Sstevel@tonic-gate (void) stat(devlinktab_file, &cached_sb); 5970*7c478bd9Sstevel@tonic-gate 5971*7c478bd9Sstevel@tonic-gate if ((fp = fopen(devlinktab_file, "r")) == NULL) { 5972*7c478bd9Sstevel@tonic-gate err_print(FOPEN_FAILED, devlinktab_file, strerror(errno)); 5973*7c478bd9Sstevel@tonic-gate return; 5974*7c478bd9Sstevel@tonic-gate } 5975*7c478bd9Sstevel@tonic-gate 5976*7c478bd9Sstevel@tonic-gate previous = &headp; 5977*7c478bd9Sstevel@tonic-gate 5978*7c478bd9Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) { 5979*7c478bd9Sstevel@tonic-gate devlinktab_line++; 5980*7c478bd9Sstevel@tonic-gate i = strlen(line); 5981*7c478bd9Sstevel@tonic-gate if (line[i-1] == NEWLINE) { 5982*7c478bd9Sstevel@tonic-gate line[i-1] = '\0'; 5983*7c478bd9Sstevel@tonic-gate } else if (i == sizeof (line-1)) { 5984*7c478bd9Sstevel@tonic-gate err_print(LINE_TOO_LONG, devlinktab_line, 5985*7c478bd9Sstevel@tonic-gate devlinktab_file, sizeof (line)-1); 5986*7c478bd9Sstevel@tonic-gate while (((i = getc(fp)) != '\n') && (i != EOF)); 5987*7c478bd9Sstevel@tonic-gate continue; 5988*7c478bd9Sstevel@tonic-gate } 5989*7c478bd9Sstevel@tonic-gate 5990*7c478bd9Sstevel@tonic-gate if ((line[0] == '#') || (line[0] == '\0')) { 5991*7c478bd9Sstevel@tonic-gate /* Ignore comments and blank lines */ 5992*7c478bd9Sstevel@tonic-gate continue; 5993*7c478bd9Sstevel@tonic-gate } 5994*7c478bd9Sstevel@tonic-gate 5995*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "table: %s line %d: '%s'\n", 5996*7c478bd9Sstevel@tonic-gate devlinktab_file, devlinktab_line, line); 5997*7c478bd9Sstevel@tonic-gate 5998*7c478bd9Sstevel@tonic-gate /* break each entry into fields. s_link may be NULL */ 5999*7c478bd9Sstevel@tonic-gate if (split_devlinktab_entry(line, &selector, &p_link, 6000*7c478bd9Sstevel@tonic-gate &s_link) == DEVFSADM_FAILURE) { 6001*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "split_entry returns failure\n"); 6002*7c478bd9Sstevel@tonic-gate continue; 6003*7c478bd9Sstevel@tonic-gate } else { 6004*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "split_entry selector='%s' " 6005*7c478bd9Sstevel@tonic-gate "p_link='%s' s_link='%s'\n\n", selector, 6006*7c478bd9Sstevel@tonic-gate p_link, (s_link == NULL) ? "" : s_link); 6007*7c478bd9Sstevel@tonic-gate } 6008*7c478bd9Sstevel@tonic-gate 6009*7c478bd9Sstevel@tonic-gate entryp = (devlinktab_list_t *) 6010*7c478bd9Sstevel@tonic-gate s_malloc(sizeof (devlinktab_list_t)); 6011*7c478bd9Sstevel@tonic-gate 6012*7c478bd9Sstevel@tonic-gate entryp->line_number = devlinktab_line; 6013*7c478bd9Sstevel@tonic-gate 6014*7c478bd9Sstevel@tonic-gate if ((entryp->selector = 6015*7c478bd9Sstevel@tonic-gate create_selector_list(selector)) == NULL) { 6016*7c478bd9Sstevel@tonic-gate free(entryp); 6017*7c478bd9Sstevel@tonic-gate continue; 6018*7c478bd9Sstevel@tonic-gate } 6019*7c478bd9Sstevel@tonic-gate entryp->selector_pattern = s_strdup(selector); 6020*7c478bd9Sstevel@tonic-gate 6021*7c478bd9Sstevel@tonic-gate if ((entryp->p_link = create_link_list(p_link)) == NULL) { 6022*7c478bd9Sstevel@tonic-gate free_selector_list(entryp->selector); 6023*7c478bd9Sstevel@tonic-gate free(entryp->selector_pattern); 6024*7c478bd9Sstevel@tonic-gate free(entryp); 6025*7c478bd9Sstevel@tonic-gate continue; 6026*7c478bd9Sstevel@tonic-gate } 6027*7c478bd9Sstevel@tonic-gate 6028*7c478bd9Sstevel@tonic-gate entryp->p_link_pattern = s_strdup(p_link); 6029*7c478bd9Sstevel@tonic-gate 6030*7c478bd9Sstevel@tonic-gate if (s_link != NULL) { 6031*7c478bd9Sstevel@tonic-gate if ((entryp->s_link = 6032*7c478bd9Sstevel@tonic-gate create_link_list(s_link)) == NULL) { 6033*7c478bd9Sstevel@tonic-gate free_selector_list(entryp->selector); 6034*7c478bd9Sstevel@tonic-gate free_link_list(entryp->p_link); 6035*7c478bd9Sstevel@tonic-gate free(entryp->selector_pattern); 6036*7c478bd9Sstevel@tonic-gate free(entryp->p_link_pattern); 6037*7c478bd9Sstevel@tonic-gate free(entryp); 6038*7c478bd9Sstevel@tonic-gate continue; 6039*7c478bd9Sstevel@tonic-gate } 6040*7c478bd9Sstevel@tonic-gate entryp->s_link_pattern = s_strdup(s_link); 6041*7c478bd9Sstevel@tonic-gate } else { 6042*7c478bd9Sstevel@tonic-gate entryp->s_link = NULL; 6043*7c478bd9Sstevel@tonic-gate entryp->s_link_pattern = NULL; 6044*7c478bd9Sstevel@tonic-gate 6045*7c478bd9Sstevel@tonic-gate } 6046*7c478bd9Sstevel@tonic-gate 6047*7c478bd9Sstevel@tonic-gate /* append to end of list */ 6048*7c478bd9Sstevel@tonic-gate 6049*7c478bd9Sstevel@tonic-gate entryp->next = NULL; 6050*7c478bd9Sstevel@tonic-gate *previous = entryp; 6051*7c478bd9Sstevel@tonic-gate previous = &(entryp->next); 6052*7c478bd9Sstevel@tonic-gate } 6053*7c478bd9Sstevel@tonic-gate if (fclose(fp) == EOF) { 6054*7c478bd9Sstevel@tonic-gate err_print(FCLOSE_FAILED, devlinktab_file, strerror(errno)); 6055*7c478bd9Sstevel@tonic-gate } 6056*7c478bd9Sstevel@tonic-gate devlinktab_list = headp; 6057*7c478bd9Sstevel@tonic-gate } 6058*7c478bd9Sstevel@tonic-gate 6059*7c478bd9Sstevel@tonic-gate /* 6060*7c478bd9Sstevel@tonic-gate * 6061*7c478bd9Sstevel@tonic-gate * For a single line entry in devlink.tab, split the line into fields 6062*7c478bd9Sstevel@tonic-gate * selector, p_link, and an optionally s_link. If s_link field is not 6063*7c478bd9Sstevel@tonic-gate * present, then return NULL in s_link (not NULL string). 6064*7c478bd9Sstevel@tonic-gate */ 6065*7c478bd9Sstevel@tonic-gate static int 6066*7c478bd9Sstevel@tonic-gate split_devlinktab_entry(char *entry, char **selector, char **p_link, 6067*7c478bd9Sstevel@tonic-gate char **s_link) 6068*7c478bd9Sstevel@tonic-gate { 6069*7c478bd9Sstevel@tonic-gate char *tab; 6070*7c478bd9Sstevel@tonic-gate 6071*7c478bd9Sstevel@tonic-gate *selector = entry; 6072*7c478bd9Sstevel@tonic-gate 6073*7c478bd9Sstevel@tonic-gate if ((tab = strchr(entry, TAB)) != NULL) { 6074*7c478bd9Sstevel@tonic-gate *tab = '\0'; 6075*7c478bd9Sstevel@tonic-gate *p_link = ++tab; 6076*7c478bd9Sstevel@tonic-gate } else { 6077*7c478bd9Sstevel@tonic-gate err_print(MISSING_TAB, devlinktab_line, devlinktab_file); 6078*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6079*7c478bd9Sstevel@tonic-gate } 6080*7c478bd9Sstevel@tonic-gate 6081*7c478bd9Sstevel@tonic-gate if (*p_link == '\0') { 6082*7c478bd9Sstevel@tonic-gate err_print(MISSING_DEVNAME, devlinktab_line, devlinktab_file); 6083*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6084*7c478bd9Sstevel@tonic-gate } 6085*7c478bd9Sstevel@tonic-gate 6086*7c478bd9Sstevel@tonic-gate if ((tab = strchr(*p_link, TAB)) != NULL) { 6087*7c478bd9Sstevel@tonic-gate *tab = '\0'; 6088*7c478bd9Sstevel@tonic-gate *s_link = ++tab; 6089*7c478bd9Sstevel@tonic-gate if (strchr(*s_link, TAB) != NULL) { 6090*7c478bd9Sstevel@tonic-gate err_print(TOO_MANY_FIELDS, devlinktab_line, 6091*7c478bd9Sstevel@tonic-gate devlinktab_file); 6092*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6093*7c478bd9Sstevel@tonic-gate } 6094*7c478bd9Sstevel@tonic-gate } else { 6095*7c478bd9Sstevel@tonic-gate *s_link = NULL; 6096*7c478bd9Sstevel@tonic-gate } 6097*7c478bd9Sstevel@tonic-gate 6098*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6099*7c478bd9Sstevel@tonic-gate } 6100*7c478bd9Sstevel@tonic-gate 6101*7c478bd9Sstevel@tonic-gate /* 6102*7c478bd9Sstevel@tonic-gate * For a given devfs_spec field, for each element in the field, add it to 6103*7c478bd9Sstevel@tonic-gate * a linked list of devfs_spec structures. Return the linked list in 6104*7c478bd9Sstevel@tonic-gate * devfs_spec_list. 6105*7c478bd9Sstevel@tonic-gate */ 6106*7c478bd9Sstevel@tonic-gate static selector_list_t * 6107*7c478bd9Sstevel@tonic-gate create_selector_list(char *selector) 6108*7c478bd9Sstevel@tonic-gate { 6109*7c478bd9Sstevel@tonic-gate char *key; 6110*7c478bd9Sstevel@tonic-gate char *val; 6111*7c478bd9Sstevel@tonic-gate int error = FALSE; 6112*7c478bd9Sstevel@tonic-gate selector_list_t *head_selector_list = NULL; 6113*7c478bd9Sstevel@tonic-gate selector_list_t *selector_list; 6114*7c478bd9Sstevel@tonic-gate 6115*7c478bd9Sstevel@tonic-gate /* parse_devfs_spec splits the next field into keyword & value */ 6116*7c478bd9Sstevel@tonic-gate while ((*selector != NULL) && (error == FALSE)) { 6117*7c478bd9Sstevel@tonic-gate if (parse_selector(&selector, &key, 6118*7c478bd9Sstevel@tonic-gate &val) == DEVFSADM_FAILURE) { 6119*7c478bd9Sstevel@tonic-gate error = TRUE; 6120*7c478bd9Sstevel@tonic-gate break; 6121*7c478bd9Sstevel@tonic-gate } else { 6122*7c478bd9Sstevel@tonic-gate selector_list = (selector_list_t *) 6123*7c478bd9Sstevel@tonic-gate s_malloc(sizeof (selector_list_t)); 6124*7c478bd9Sstevel@tonic-gate if (strcmp(NAME_S, key) == 0) { 6125*7c478bd9Sstevel@tonic-gate selector_list->key = NAME; 6126*7c478bd9Sstevel@tonic-gate } else if (strcmp(TYPE_S, key) == 0) { 6127*7c478bd9Sstevel@tonic-gate selector_list->key = TYPE; 6128*7c478bd9Sstevel@tonic-gate } else if (strncmp(ADDR_S, key, ADDR_S_LEN) == 0) { 6129*7c478bd9Sstevel@tonic-gate selector_list->key = ADDR; 6130*7c478bd9Sstevel@tonic-gate if (key[ADDR_S_LEN] == '\0') { 6131*7c478bd9Sstevel@tonic-gate selector_list->arg = 0; 6132*7c478bd9Sstevel@tonic-gate } else if (isdigit(key[ADDR_S_LEN]) != 6133*7c478bd9Sstevel@tonic-gate FALSE) { 6134*7c478bd9Sstevel@tonic-gate selector_list->arg = 6135*7c478bd9Sstevel@tonic-gate atoi(&key[ADDR_S_LEN]); 6136*7c478bd9Sstevel@tonic-gate } else { 6137*7c478bd9Sstevel@tonic-gate error = TRUE; 6138*7c478bd9Sstevel@tonic-gate free(selector_list); 6139*7c478bd9Sstevel@tonic-gate err_print(BADKEYWORD, key, 6140*7c478bd9Sstevel@tonic-gate devlinktab_line, 6141*7c478bd9Sstevel@tonic-gate devlinktab_file); 6142*7c478bd9Sstevel@tonic-gate break; 6143*7c478bd9Sstevel@tonic-gate } 6144*7c478bd9Sstevel@tonic-gate } else if (strncmp(MINOR_S, key, 6145*7c478bd9Sstevel@tonic-gate MINOR_S_LEN) == 0) { 6146*7c478bd9Sstevel@tonic-gate selector_list->key = MINOR; 6147*7c478bd9Sstevel@tonic-gate if (key[MINOR_S_LEN] == '\0') { 6148*7c478bd9Sstevel@tonic-gate selector_list->arg = 0; 6149*7c478bd9Sstevel@tonic-gate } else if (isdigit(key[MINOR_S_LEN]) != 6150*7c478bd9Sstevel@tonic-gate FALSE) { 6151*7c478bd9Sstevel@tonic-gate selector_list->arg = 6152*7c478bd9Sstevel@tonic-gate atoi(&key[MINOR_S_LEN]); 6153*7c478bd9Sstevel@tonic-gate } else { 6154*7c478bd9Sstevel@tonic-gate error = TRUE; 6155*7c478bd9Sstevel@tonic-gate free(selector_list); 6156*7c478bd9Sstevel@tonic-gate err_print(BADKEYWORD, key, 6157*7c478bd9Sstevel@tonic-gate devlinktab_line, 6158*7c478bd9Sstevel@tonic-gate devlinktab_file); 6159*7c478bd9Sstevel@tonic-gate break; 6160*7c478bd9Sstevel@tonic-gate } 6161*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "MINOR = %s\n", val); 6162*7c478bd9Sstevel@tonic-gate } else { 6163*7c478bd9Sstevel@tonic-gate err_print(UNRECOGNIZED_KEY, key, 6164*7c478bd9Sstevel@tonic-gate devlinktab_line, devlinktab_file); 6165*7c478bd9Sstevel@tonic-gate error = TRUE; 6166*7c478bd9Sstevel@tonic-gate free(selector_list); 6167*7c478bd9Sstevel@tonic-gate break; 6168*7c478bd9Sstevel@tonic-gate } 6169*7c478bd9Sstevel@tonic-gate selector_list->val = s_strdup(val); 6170*7c478bd9Sstevel@tonic-gate selector_list->next = head_selector_list; 6171*7c478bd9Sstevel@tonic-gate head_selector_list = selector_list; 6172*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "key='%s' val='%s' arg=%d\n", 6173*7c478bd9Sstevel@tonic-gate key, val, selector_list->arg); 6174*7c478bd9Sstevel@tonic-gate } 6175*7c478bd9Sstevel@tonic-gate } 6176*7c478bd9Sstevel@tonic-gate 6177*7c478bd9Sstevel@tonic-gate if ((error == FALSE) && (head_selector_list != NULL)) { 6178*7c478bd9Sstevel@tonic-gate return (head_selector_list); 6179*7c478bd9Sstevel@tonic-gate } else { 6180*7c478bd9Sstevel@tonic-gate /* parse failed. Free any allocated structs */ 6181*7c478bd9Sstevel@tonic-gate free_selector_list(head_selector_list); 6182*7c478bd9Sstevel@tonic-gate return (NULL); 6183*7c478bd9Sstevel@tonic-gate } 6184*7c478bd9Sstevel@tonic-gate } 6185*7c478bd9Sstevel@tonic-gate 6186*7c478bd9Sstevel@tonic-gate /* 6187*7c478bd9Sstevel@tonic-gate * Takes a semicolon separated list of selector elements and breaks up 6188*7c478bd9Sstevel@tonic-gate * into a keyword-value pair. semicolon and equal characters are 6189*7c478bd9Sstevel@tonic-gate * replaced with NULL's. On success, selector is updated to point to the 6190*7c478bd9Sstevel@tonic-gate * terminating NULL character terminating the keyword-value pair, and the 6191*7c478bd9Sstevel@tonic-gate * function returns DEVFSADM_SUCCESS. If there is a syntax error, 6192*7c478bd9Sstevel@tonic-gate * devfs_spec is not modified and function returns DEVFSADM_FAILURE. 6193*7c478bd9Sstevel@tonic-gate */ 6194*7c478bd9Sstevel@tonic-gate static int 6195*7c478bd9Sstevel@tonic-gate parse_selector(char **selector, char **key, char **val) 6196*7c478bd9Sstevel@tonic-gate { 6197*7c478bd9Sstevel@tonic-gate char *equal; 6198*7c478bd9Sstevel@tonic-gate char *semi_colon; 6199*7c478bd9Sstevel@tonic-gate 6200*7c478bd9Sstevel@tonic-gate *key = *selector; 6201*7c478bd9Sstevel@tonic-gate 6202*7c478bd9Sstevel@tonic-gate if ((equal = strchr(*key, '=')) != NULL) { 6203*7c478bd9Sstevel@tonic-gate *equal = '\0'; 6204*7c478bd9Sstevel@tonic-gate } else { 6205*7c478bd9Sstevel@tonic-gate err_print(MISSING_EQUAL, devlinktab_line, devlinktab_file); 6206*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6207*7c478bd9Sstevel@tonic-gate } 6208*7c478bd9Sstevel@tonic-gate 6209*7c478bd9Sstevel@tonic-gate *val = ++equal; 6210*7c478bd9Sstevel@tonic-gate if ((semi_colon = strchr(equal, ';')) != NULL) { 6211*7c478bd9Sstevel@tonic-gate *semi_colon = '\0'; 6212*7c478bd9Sstevel@tonic-gate *selector = semi_colon + 1; 6213*7c478bd9Sstevel@tonic-gate } else { 6214*7c478bd9Sstevel@tonic-gate *selector = equal + strlen(equal); 6215*7c478bd9Sstevel@tonic-gate } 6216*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6217*7c478bd9Sstevel@tonic-gate } 6218*7c478bd9Sstevel@tonic-gate 6219*7c478bd9Sstevel@tonic-gate /* 6220*7c478bd9Sstevel@tonic-gate * link is either the second or third field of devlink.tab. Parse link 6221*7c478bd9Sstevel@tonic-gate * into a linked list of devlink structures and return ptr to list. Each 6222*7c478bd9Sstevel@tonic-gate * list element is either a constant string, or one of the following 6223*7c478bd9Sstevel@tonic-gate * escape sequences: \M, \A, \N, or \D. The first three escape sequences 6224*7c478bd9Sstevel@tonic-gate * take a numerical argument. 6225*7c478bd9Sstevel@tonic-gate */ 6226*7c478bd9Sstevel@tonic-gate static link_list_t * 6227*7c478bd9Sstevel@tonic-gate create_link_list(char *link) 6228*7c478bd9Sstevel@tonic-gate { 6229*7c478bd9Sstevel@tonic-gate int x = 0; 6230*7c478bd9Sstevel@tonic-gate int error = FALSE; 6231*7c478bd9Sstevel@tonic-gate int counter_found = FALSE; 6232*7c478bd9Sstevel@tonic-gate link_list_t *head = NULL; 6233*7c478bd9Sstevel@tonic-gate link_list_t **ptr; 6234*7c478bd9Sstevel@tonic-gate link_list_t *link_list; 6235*7c478bd9Sstevel@tonic-gate char constant[MAX_DEVLINK_LINE]; 6236*7c478bd9Sstevel@tonic-gate char *error_str; 6237*7c478bd9Sstevel@tonic-gate 6238*7c478bd9Sstevel@tonic-gate if (link == NULL) { 6239*7c478bd9Sstevel@tonic-gate return (NULL); 6240*7c478bd9Sstevel@tonic-gate } 6241*7c478bd9Sstevel@tonic-gate 6242*7c478bd9Sstevel@tonic-gate while ((*link != '\0') && (error == FALSE)) { 6243*7c478bd9Sstevel@tonic-gate link_list = (link_list_t *)s_malloc(sizeof (link_list_t)); 6244*7c478bd9Sstevel@tonic-gate link_list->next = NULL; 6245*7c478bd9Sstevel@tonic-gate 6246*7c478bd9Sstevel@tonic-gate while ((*link != '\0') && (*link != '\\')) { 6247*7c478bd9Sstevel@tonic-gate /* a non-escaped string */ 6248*7c478bd9Sstevel@tonic-gate constant[x++] = *(link++); 6249*7c478bd9Sstevel@tonic-gate } 6250*7c478bd9Sstevel@tonic-gate if (x != 0) { 6251*7c478bd9Sstevel@tonic-gate constant[x] = '\0'; 6252*7c478bd9Sstevel@tonic-gate link_list->type = CONSTANT; 6253*7c478bd9Sstevel@tonic-gate link_list->constant = s_strdup(constant); 6254*7c478bd9Sstevel@tonic-gate x = 0; 6255*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "CONSTANT FOUND %s\n", constant); 6256*7c478bd9Sstevel@tonic-gate } else { 6257*7c478bd9Sstevel@tonic-gate switch (*(++link)) { 6258*7c478bd9Sstevel@tonic-gate case 'M': 6259*7c478bd9Sstevel@tonic-gate link_list->type = MINOR; 6260*7c478bd9Sstevel@tonic-gate break; 6261*7c478bd9Sstevel@tonic-gate case 'A': 6262*7c478bd9Sstevel@tonic-gate link_list->type = ADDR; 6263*7c478bd9Sstevel@tonic-gate break; 6264*7c478bd9Sstevel@tonic-gate case 'N': 6265*7c478bd9Sstevel@tonic-gate if (counter_found == TRUE) { 6266*7c478bd9Sstevel@tonic-gate error = TRUE; 6267*7c478bd9Sstevel@tonic-gate error_str = "multiple counters " 6268*7c478bd9Sstevel@tonic-gate "not permitted"; 6269*7c478bd9Sstevel@tonic-gate free(link_list); 6270*7c478bd9Sstevel@tonic-gate } else { 6271*7c478bd9Sstevel@tonic-gate counter_found = TRUE; 6272*7c478bd9Sstevel@tonic-gate link_list->type = COUNTER; 6273*7c478bd9Sstevel@tonic-gate } 6274*7c478bd9Sstevel@tonic-gate break; 6275*7c478bd9Sstevel@tonic-gate case 'D': 6276*7c478bd9Sstevel@tonic-gate link_list->type = NAME; 6277*7c478bd9Sstevel@tonic-gate break; 6278*7c478bd9Sstevel@tonic-gate default: 6279*7c478bd9Sstevel@tonic-gate error = TRUE; 6280*7c478bd9Sstevel@tonic-gate free(link_list); 6281*7c478bd9Sstevel@tonic-gate error_str = "unrecognized escape sequence"; 6282*7c478bd9Sstevel@tonic-gate break; 6283*7c478bd9Sstevel@tonic-gate } 6284*7c478bd9Sstevel@tonic-gate if (*(link++) != 'D') { 6285*7c478bd9Sstevel@tonic-gate if (isdigit(*link) == FALSE) { 6286*7c478bd9Sstevel@tonic-gate error_str = "escape sequence must be " 6287*7c478bd9Sstevel@tonic-gate "followed by a digit\n"; 6288*7c478bd9Sstevel@tonic-gate error = TRUE; 6289*7c478bd9Sstevel@tonic-gate free(link_list); 6290*7c478bd9Sstevel@tonic-gate } else { 6291*7c478bd9Sstevel@tonic-gate link_list->arg = 6292*7c478bd9Sstevel@tonic-gate (int)strtoul(link, &link, 10); 6293*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "link_list->arg = " 6294*7c478bd9Sstevel@tonic-gate "%d\n", link_list->arg); 6295*7c478bd9Sstevel@tonic-gate } 6296*7c478bd9Sstevel@tonic-gate } 6297*7c478bd9Sstevel@tonic-gate } 6298*7c478bd9Sstevel@tonic-gate /* append link_list struct to end of list */ 6299*7c478bd9Sstevel@tonic-gate if (error == FALSE) { 6300*7c478bd9Sstevel@tonic-gate for (ptr = &head; *ptr != NULL; ptr = &((*ptr)->next)); 6301*7c478bd9Sstevel@tonic-gate *ptr = link_list; 6302*7c478bd9Sstevel@tonic-gate } 6303*7c478bd9Sstevel@tonic-gate } 6304*7c478bd9Sstevel@tonic-gate 6305*7c478bd9Sstevel@tonic-gate if (error == FALSE) { 6306*7c478bd9Sstevel@tonic-gate return (head); 6307*7c478bd9Sstevel@tonic-gate } else { 6308*7c478bd9Sstevel@tonic-gate err_print(CONFIG_INCORRECT, devlinktab_line, devlinktab_file, 6309*7c478bd9Sstevel@tonic-gate error_str); 6310*7c478bd9Sstevel@tonic-gate free_link_list(head); 6311*7c478bd9Sstevel@tonic-gate return (NULL); 6312*7c478bd9Sstevel@tonic-gate } 6313*7c478bd9Sstevel@tonic-gate } 6314*7c478bd9Sstevel@tonic-gate 6315*7c478bd9Sstevel@tonic-gate /* 6316*7c478bd9Sstevel@tonic-gate * Called for each minor node devfsadm processes; for each minor node, 6317*7c478bd9Sstevel@tonic-gate * look for matches in the devlinktab_list list which was created on 6318*7c478bd9Sstevel@tonic-gate * startup read_devlinktab_file(). If there is a match, call build_links() 6319*7c478bd9Sstevel@tonic-gate * to build a logical devlink and a possible extra devlink. 6320*7c478bd9Sstevel@tonic-gate */ 6321*7c478bd9Sstevel@tonic-gate static int 6322*7c478bd9Sstevel@tonic-gate process_devlink_compat(di_minor_t minor, di_node_t node) 6323*7c478bd9Sstevel@tonic-gate { 6324*7c478bd9Sstevel@tonic-gate int link_built = FALSE; 6325*7c478bd9Sstevel@tonic-gate devlinktab_list_t *entry; 6326*7c478bd9Sstevel@tonic-gate char *nodetype; 6327*7c478bd9Sstevel@tonic-gate char *dev_path; 6328*7c478bd9Sstevel@tonic-gate 6329*7c478bd9Sstevel@tonic-gate if (devlinks_debug == TRUE) { 6330*7c478bd9Sstevel@tonic-gate nodetype = di_minor_nodetype(minor); 6331*7c478bd9Sstevel@tonic-gate assert(nodetype != NULL); 6332*7c478bd9Sstevel@tonic-gate if ((dev_path = di_devfs_path(node)) != NULL) { 6333*7c478bd9Sstevel@tonic-gate vprint(INFO_MID, "'%s' entry: %s:%s\n", nodetype, 6334*7c478bd9Sstevel@tonic-gate dev_path, 6335*7c478bd9Sstevel@tonic-gate di_minor_name(minor) ? di_minor_name(minor) : 6336*7c478bd9Sstevel@tonic-gate ""); 6337*7c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path); 6338*7c478bd9Sstevel@tonic-gate } 6339*7c478bd9Sstevel@tonic-gate 6340*7c478bd9Sstevel@tonic-gate } 6341*7c478bd9Sstevel@tonic-gate 6342*7c478bd9Sstevel@tonic-gate 6343*7c478bd9Sstevel@tonic-gate /* don't process devlink.tab if devfsadm invoked with -c <class> */ 6344*7c478bd9Sstevel@tonic-gate if (num_classes > 0) { 6345*7c478bd9Sstevel@tonic-gate return (FALSE); 6346*7c478bd9Sstevel@tonic-gate } 6347*7c478bd9Sstevel@tonic-gate 6348*7c478bd9Sstevel@tonic-gate for (entry = devlinktab_list; entry != NULL; entry = entry->next) { 6349*7c478bd9Sstevel@tonic-gate if (devlink_matches(entry, minor, node) == DEVFSADM_SUCCESS) { 6350*7c478bd9Sstevel@tonic-gate link_built = TRUE; 6351*7c478bd9Sstevel@tonic-gate (void) build_links(entry, minor, node); 6352*7c478bd9Sstevel@tonic-gate } 6353*7c478bd9Sstevel@tonic-gate } 6354*7c478bd9Sstevel@tonic-gate return (link_built); 6355*7c478bd9Sstevel@tonic-gate } 6356*7c478bd9Sstevel@tonic-gate 6357*7c478bd9Sstevel@tonic-gate /* 6358*7c478bd9Sstevel@tonic-gate * For a given devlink.tab devlinktab_list entry, see if the selector 6359*7c478bd9Sstevel@tonic-gate * field matches this minor node. If it does, return DEVFSADM_SUCCESS, 6360*7c478bd9Sstevel@tonic-gate * otherwise DEVFSADM_FAILURE. 6361*7c478bd9Sstevel@tonic-gate */ 6362*7c478bd9Sstevel@tonic-gate static int 6363*7c478bd9Sstevel@tonic-gate devlink_matches(devlinktab_list_t *entry, di_minor_t minor, di_node_t node) 6364*7c478bd9Sstevel@tonic-gate { 6365*7c478bd9Sstevel@tonic-gate selector_list_t *selector = entry->selector; 6366*7c478bd9Sstevel@tonic-gate char *addr; 6367*7c478bd9Sstevel@tonic-gate char *minor_name; 6368*7c478bd9Sstevel@tonic-gate char *node_type; 6369*7c478bd9Sstevel@tonic-gate 6370*7c478bd9Sstevel@tonic-gate for (; selector != NULL; selector = selector->next) { 6371*7c478bd9Sstevel@tonic-gate switch (selector->key) { 6372*7c478bd9Sstevel@tonic-gate case NAME: 6373*7c478bd9Sstevel@tonic-gate if (strcmp(di_node_name(node), selector->val) != 0) { 6374*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6375*7c478bd9Sstevel@tonic-gate } 6376*7c478bd9Sstevel@tonic-gate break; 6377*7c478bd9Sstevel@tonic-gate case TYPE: 6378*7c478bd9Sstevel@tonic-gate node_type = di_minor_nodetype(minor); 6379*7c478bd9Sstevel@tonic-gate assert(node_type != NULL); 6380*7c478bd9Sstevel@tonic-gate if (strcmp(node_type, selector->val) != 0) { 6381*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6382*7c478bd9Sstevel@tonic-gate } 6383*7c478bd9Sstevel@tonic-gate break; 6384*7c478bd9Sstevel@tonic-gate case ADDR: 6385*7c478bd9Sstevel@tonic-gate if ((addr = di_bus_addr(node)) == NULL) { 6386*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6387*7c478bd9Sstevel@tonic-gate } 6388*7c478bd9Sstevel@tonic-gate if (selector->arg == 0) { 6389*7c478bd9Sstevel@tonic-gate if (strcmp(addr, selector->val) != 0) { 6390*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6391*7c478bd9Sstevel@tonic-gate } 6392*7c478bd9Sstevel@tonic-gate } else { 6393*7c478bd9Sstevel@tonic-gate if (compare_field(addr, selector->val, 6394*7c478bd9Sstevel@tonic-gate selector->arg) == DEVFSADM_FAILURE) { 6395*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6396*7c478bd9Sstevel@tonic-gate } 6397*7c478bd9Sstevel@tonic-gate } 6398*7c478bd9Sstevel@tonic-gate break; 6399*7c478bd9Sstevel@tonic-gate case MINOR: 6400*7c478bd9Sstevel@tonic-gate if ((minor_name = di_minor_name(minor)) == NULL) { 6401*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6402*7c478bd9Sstevel@tonic-gate } 6403*7c478bd9Sstevel@tonic-gate if (selector->arg == 0) { 6404*7c478bd9Sstevel@tonic-gate if (strcmp(minor_name, selector->val) != 0) { 6405*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6406*7c478bd9Sstevel@tonic-gate } 6407*7c478bd9Sstevel@tonic-gate } else { 6408*7c478bd9Sstevel@tonic-gate if (compare_field(minor_name, selector->val, 6409*7c478bd9Sstevel@tonic-gate selector->arg) == DEVFSADM_FAILURE) { 6410*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6411*7c478bd9Sstevel@tonic-gate } 6412*7c478bd9Sstevel@tonic-gate } 6413*7c478bd9Sstevel@tonic-gate break; 6414*7c478bd9Sstevel@tonic-gate default: 6415*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6416*7c478bd9Sstevel@tonic-gate } 6417*7c478bd9Sstevel@tonic-gate } 6418*7c478bd9Sstevel@tonic-gate 6419*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6420*7c478bd9Sstevel@tonic-gate } 6421*7c478bd9Sstevel@tonic-gate 6422*7c478bd9Sstevel@tonic-gate /* 6423*7c478bd9Sstevel@tonic-gate * For the given minor node and devlinktab_list entry from devlink.tab, 6424*7c478bd9Sstevel@tonic-gate * build a logical dev link and a possible extra devlink. 6425*7c478bd9Sstevel@tonic-gate * Return DEVFSADM_SUCCESS if link is created, otherwise DEVFSADM_FAILURE. 6426*7c478bd9Sstevel@tonic-gate */ 6427*7c478bd9Sstevel@tonic-gate static int 6428*7c478bd9Sstevel@tonic-gate build_links(devlinktab_list_t *entry, di_minor_t minor, di_node_t node) 6429*7c478bd9Sstevel@tonic-gate { 6430*7c478bd9Sstevel@tonic-gate char secondary_link[PATH_MAX + 1]; 6431*7c478bd9Sstevel@tonic-gate char primary_link[PATH_MAX + 1]; 6432*7c478bd9Sstevel@tonic-gate char contents[PATH_MAX + 1]; 6433*7c478bd9Sstevel@tonic-gate char *dev_path; 6434*7c478bd9Sstevel@tonic-gate 6435*7c478bd9Sstevel@tonic-gate if ((dev_path = di_devfs_path(node)) == NULL) { 6436*7c478bd9Sstevel@tonic-gate err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 6437*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 6438*7c478bd9Sstevel@tonic-gate } 6439*7c478bd9Sstevel@tonic-gate (void) strcpy(contents, dev_path); 6440*7c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path); 6441*7c478bd9Sstevel@tonic-gate 6442*7c478bd9Sstevel@tonic-gate (void) strcat(contents, ":"); 6443*7c478bd9Sstevel@tonic-gate (void) strcat(contents, di_minor_name(minor)); 6444*7c478bd9Sstevel@tonic-gate 6445*7c478bd9Sstevel@tonic-gate if (construct_devlink(primary_link, entry->p_link, contents, 6446*7c478bd9Sstevel@tonic-gate minor, node, 6447*7c478bd9Sstevel@tonic-gate entry->p_link_pattern) == DEVFSADM_FAILURE) { 6448*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6449*7c478bd9Sstevel@tonic-gate } 6450*7c478bd9Sstevel@tonic-gate (void) devfsadm_mklink(primary_link, node, minor, 0); 6451*7c478bd9Sstevel@tonic-gate 6452*7c478bd9Sstevel@tonic-gate if (entry->s_link == NULL) { 6453*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6454*7c478bd9Sstevel@tonic-gate } 6455*7c478bd9Sstevel@tonic-gate 6456*7c478bd9Sstevel@tonic-gate if (construct_devlink(secondary_link, entry->s_link, 6457*7c478bd9Sstevel@tonic-gate primary_link, minor, node, 6458*7c478bd9Sstevel@tonic-gate entry->s_link_pattern) == DEVFSADM_FAILURE) { 6459*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6460*7c478bd9Sstevel@tonic-gate } 6461*7c478bd9Sstevel@tonic-gate 6462*7c478bd9Sstevel@tonic-gate (void) devfsadm_secondary_link(secondary_link, primary_link, 0); 6463*7c478bd9Sstevel@tonic-gate 6464*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6465*7c478bd9Sstevel@tonic-gate } 6466*7c478bd9Sstevel@tonic-gate 6467*7c478bd9Sstevel@tonic-gate /* 6468*7c478bd9Sstevel@tonic-gate * The counter rule for devlink.tab entries is implemented via 6469*7c478bd9Sstevel@tonic-gate * devfsadm_enumerate_int_start(). One of the arguments to this function 6470*7c478bd9Sstevel@tonic-gate * is a path, where each path component is treated as a regular expression. 6471*7c478bd9Sstevel@tonic-gate * For devlink.tab entries, this path regular expression is derived from 6472*7c478bd9Sstevel@tonic-gate * the devlink spec. get_anchored_re() accepts path regular expressions derived 6473*7c478bd9Sstevel@tonic-gate * from devlink.tab entries and inserts the anchors '^' and '$' at the beginning 6474*7c478bd9Sstevel@tonic-gate * and end respectively of each path component. This is done to prevent 6475*7c478bd9Sstevel@tonic-gate * false matches. For example, without anchors, "a/([0-9]+)" will match "ab/c9" 6476*7c478bd9Sstevel@tonic-gate * and incorrect links will be generated. 6477*7c478bd9Sstevel@tonic-gate */ 6478*7c478bd9Sstevel@tonic-gate static int 6479*7c478bd9Sstevel@tonic-gate get_anchored_re(char *link, char *anchored_re, char *pattern) 6480*7c478bd9Sstevel@tonic-gate { 6481*7c478bd9Sstevel@tonic-gate if (*link == '/' || *link == '\0') { 6482*7c478bd9Sstevel@tonic-gate err_print(INVALID_DEVLINK_SPEC, pattern); 6483*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6484*7c478bd9Sstevel@tonic-gate } 6485*7c478bd9Sstevel@tonic-gate 6486*7c478bd9Sstevel@tonic-gate *anchored_re++ = '^'; 6487*7c478bd9Sstevel@tonic-gate for (; *link != '\0'; ) { 6488*7c478bd9Sstevel@tonic-gate if (*link == '/') { 6489*7c478bd9Sstevel@tonic-gate while (*link == '/') 6490*7c478bd9Sstevel@tonic-gate link++; 6491*7c478bd9Sstevel@tonic-gate *anchored_re++ = '$'; 6492*7c478bd9Sstevel@tonic-gate *anchored_re++ = '/'; 6493*7c478bd9Sstevel@tonic-gate if (*link != '\0') { 6494*7c478bd9Sstevel@tonic-gate *anchored_re++ = '^'; 6495*7c478bd9Sstevel@tonic-gate } 6496*7c478bd9Sstevel@tonic-gate } else { 6497*7c478bd9Sstevel@tonic-gate *anchored_re++ = *link++; 6498*7c478bd9Sstevel@tonic-gate if (*link == '\0') { 6499*7c478bd9Sstevel@tonic-gate *anchored_re++ = '$'; 6500*7c478bd9Sstevel@tonic-gate } 6501*7c478bd9Sstevel@tonic-gate } 6502*7c478bd9Sstevel@tonic-gate } 6503*7c478bd9Sstevel@tonic-gate *anchored_re = '\0'; 6504*7c478bd9Sstevel@tonic-gate 6505*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6506*7c478bd9Sstevel@tonic-gate } 6507*7c478bd9Sstevel@tonic-gate 6508*7c478bd9Sstevel@tonic-gate static int 6509*7c478bd9Sstevel@tonic-gate construct_devlink(char *link, link_list_t *link_build, char *contents, 6510*7c478bd9Sstevel@tonic-gate di_minor_t minor, di_node_t node, char *pattern) 6511*7c478bd9Sstevel@tonic-gate { 6512*7c478bd9Sstevel@tonic-gate int counter_offset = -1; 6513*7c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[1] = {NULL}; 6514*7c478bd9Sstevel@tonic-gate char templink[PATH_MAX + 1]; 6515*7c478bd9Sstevel@tonic-gate char *buff; 6516*7c478bd9Sstevel@tonic-gate char start[10]; 6517*7c478bd9Sstevel@tonic-gate char *node_path; 6518*7c478bd9Sstevel@tonic-gate char anchored_re[PATH_MAX + 1]; 6519*7c478bd9Sstevel@tonic-gate 6520*7c478bd9Sstevel@tonic-gate link[0] = '\0'; 6521*7c478bd9Sstevel@tonic-gate 6522*7c478bd9Sstevel@tonic-gate for (; link_build != NULL; link_build = link_build->next) { 6523*7c478bd9Sstevel@tonic-gate switch (link_build->type) { 6524*7c478bd9Sstevel@tonic-gate case NAME: 6525*7c478bd9Sstevel@tonic-gate (void) strcat(link, di_node_name(node)); 6526*7c478bd9Sstevel@tonic-gate break; 6527*7c478bd9Sstevel@tonic-gate case CONSTANT: 6528*7c478bd9Sstevel@tonic-gate (void) strcat(link, link_build->constant); 6529*7c478bd9Sstevel@tonic-gate break; 6530*7c478bd9Sstevel@tonic-gate case ADDR: 6531*7c478bd9Sstevel@tonic-gate if (component_cat(link, di_bus_addr(node), 6532*7c478bd9Sstevel@tonic-gate link_build->arg) == DEVFSADM_FAILURE) { 6533*7c478bd9Sstevel@tonic-gate node_path = di_devfs_path(node); 6534*7c478bd9Sstevel@tonic-gate err_print(CANNOT_BE_USED, pattern, node_path, 6535*7c478bd9Sstevel@tonic-gate di_minor_name(minor)); 6536*7c478bd9Sstevel@tonic-gate di_devfs_path_free(node_path); 6537*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6538*7c478bd9Sstevel@tonic-gate } 6539*7c478bd9Sstevel@tonic-gate break; 6540*7c478bd9Sstevel@tonic-gate case MINOR: 6541*7c478bd9Sstevel@tonic-gate if (component_cat(link, di_minor_name(minor), 6542*7c478bd9Sstevel@tonic-gate link_build->arg) == DEVFSADM_FAILURE) { 6543*7c478bd9Sstevel@tonic-gate node_path = di_devfs_path(node); 6544*7c478bd9Sstevel@tonic-gate err_print(CANNOT_BE_USED, pattern, node_path, 6545*7c478bd9Sstevel@tonic-gate di_minor_name(minor)); 6546*7c478bd9Sstevel@tonic-gate di_devfs_path_free(node_path); 6547*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6548*7c478bd9Sstevel@tonic-gate } 6549*7c478bd9Sstevel@tonic-gate break; 6550*7c478bd9Sstevel@tonic-gate case COUNTER: 6551*7c478bd9Sstevel@tonic-gate counter_offset = strlen(link); 6552*7c478bd9Sstevel@tonic-gate (void) strcat(link, "([0-9]+)"); 6553*7c478bd9Sstevel@tonic-gate (void) sprintf(start, "%d", link_build->arg); 6554*7c478bd9Sstevel@tonic-gate break; 6555*7c478bd9Sstevel@tonic-gate default: 6556*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6557*7c478bd9Sstevel@tonic-gate } 6558*7c478bd9Sstevel@tonic-gate } 6559*7c478bd9Sstevel@tonic-gate 6560*7c478bd9Sstevel@tonic-gate if (counter_offset != -1) { 6561*7c478bd9Sstevel@tonic-gate /* 6562*7c478bd9Sstevel@tonic-gate * copy anything appended after "([0-9]+)" into 6563*7c478bd9Sstevel@tonic-gate * templink 6564*7c478bd9Sstevel@tonic-gate */ 6565*7c478bd9Sstevel@tonic-gate 6566*7c478bd9Sstevel@tonic-gate (void) strcpy(templink, 6567*7c478bd9Sstevel@tonic-gate &link[counter_offset + strlen("([0-9]+)")]); 6568*7c478bd9Sstevel@tonic-gate if (get_anchored_re(link, anchored_re, pattern) 6569*7c478bd9Sstevel@tonic-gate != DEVFSADM_SUCCESS) { 6570*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6571*7c478bd9Sstevel@tonic-gate } 6572*7c478bd9Sstevel@tonic-gate rules[0].re = anchored_re; 6573*7c478bd9Sstevel@tonic-gate rules[0].subexp = 1; 6574*7c478bd9Sstevel@tonic-gate rules[0].flags = MATCH_ALL; 6575*7c478bd9Sstevel@tonic-gate if (devfsadm_enumerate_int_start(contents, 0, &buff, 6576*7c478bd9Sstevel@tonic-gate rules, 1, start) == DEVFSADM_FAILURE) { 6577*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6578*7c478bd9Sstevel@tonic-gate } 6579*7c478bd9Sstevel@tonic-gate (void) strcpy(&link[counter_offset], buff); 6580*7c478bd9Sstevel@tonic-gate free(buff); 6581*7c478bd9Sstevel@tonic-gate (void) strcat(link, templink); 6582*7c478bd9Sstevel@tonic-gate vprint(DEVLINK_MID, "COUNTER is %s\n", link); 6583*7c478bd9Sstevel@tonic-gate } 6584*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6585*7c478bd9Sstevel@tonic-gate } 6586*7c478bd9Sstevel@tonic-gate 6587*7c478bd9Sstevel@tonic-gate /* 6588*7c478bd9Sstevel@tonic-gate * Compares "field" number of the comma separated list "full_name" with 6589*7c478bd9Sstevel@tonic-gate * field_item. Returns DEVFSADM_SUCCESS for match, 6590*7c478bd9Sstevel@tonic-gate * DEVFSADM_FAILURE for no match. 6591*7c478bd9Sstevel@tonic-gate */ 6592*7c478bd9Sstevel@tonic-gate static int 6593*7c478bd9Sstevel@tonic-gate compare_field(char *full_name, char *field_item, int field) 6594*7c478bd9Sstevel@tonic-gate { 6595*7c478bd9Sstevel@tonic-gate --field; 6596*7c478bd9Sstevel@tonic-gate while ((*full_name != '\0') && (field != 0)) { 6597*7c478bd9Sstevel@tonic-gate if (*(full_name++) == ',') { 6598*7c478bd9Sstevel@tonic-gate field--; 6599*7c478bd9Sstevel@tonic-gate } 6600*7c478bd9Sstevel@tonic-gate } 6601*7c478bd9Sstevel@tonic-gate 6602*7c478bd9Sstevel@tonic-gate if (field != 0) { 6603*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6604*7c478bd9Sstevel@tonic-gate } 6605*7c478bd9Sstevel@tonic-gate 6606*7c478bd9Sstevel@tonic-gate while ((*full_name != '\0') && (*field_item != '\0') && 6607*7c478bd9Sstevel@tonic-gate (*full_name != ',')) { 6608*7c478bd9Sstevel@tonic-gate if (*(full_name++) != *(field_item++)) { 6609*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6610*7c478bd9Sstevel@tonic-gate } 6611*7c478bd9Sstevel@tonic-gate } 6612*7c478bd9Sstevel@tonic-gate 6613*7c478bd9Sstevel@tonic-gate if (*field_item != '\0') { 6614*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6615*7c478bd9Sstevel@tonic-gate } 6616*7c478bd9Sstevel@tonic-gate 6617*7c478bd9Sstevel@tonic-gate if ((*full_name == '\0') || (*full_name == ',')) 6618*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6619*7c478bd9Sstevel@tonic-gate 6620*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6621*7c478bd9Sstevel@tonic-gate } 6622*7c478bd9Sstevel@tonic-gate 6623*7c478bd9Sstevel@tonic-gate /* 6624*7c478bd9Sstevel@tonic-gate * strcat() field # "field" of comma separated list "name" to "link". 6625*7c478bd9Sstevel@tonic-gate * Field 0 is the entire name. 6626*7c478bd9Sstevel@tonic-gate * Return DEVFSADM_SUCCESS or DEVFSADM_FAILURE. 6627*7c478bd9Sstevel@tonic-gate */ 6628*7c478bd9Sstevel@tonic-gate static int 6629*7c478bd9Sstevel@tonic-gate component_cat(char *link, char *name, int field) 6630*7c478bd9Sstevel@tonic-gate { 6631*7c478bd9Sstevel@tonic-gate 6632*7c478bd9Sstevel@tonic-gate if (name == NULL) { 6633*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6634*7c478bd9Sstevel@tonic-gate } 6635*7c478bd9Sstevel@tonic-gate 6636*7c478bd9Sstevel@tonic-gate if (field == 0) { 6637*7c478bd9Sstevel@tonic-gate (void) strcat(link, name); 6638*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6639*7c478bd9Sstevel@tonic-gate } 6640*7c478bd9Sstevel@tonic-gate 6641*7c478bd9Sstevel@tonic-gate while (*link != '\0') { 6642*7c478bd9Sstevel@tonic-gate link++; 6643*7c478bd9Sstevel@tonic-gate } 6644*7c478bd9Sstevel@tonic-gate 6645*7c478bd9Sstevel@tonic-gate --field; 6646*7c478bd9Sstevel@tonic-gate while ((*name != '\0') && (field != 0)) { 6647*7c478bd9Sstevel@tonic-gate if (*(name++) == ',') { 6648*7c478bd9Sstevel@tonic-gate --field; 6649*7c478bd9Sstevel@tonic-gate } 6650*7c478bd9Sstevel@tonic-gate } 6651*7c478bd9Sstevel@tonic-gate 6652*7c478bd9Sstevel@tonic-gate if (field != 0) { 6653*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 6654*7c478bd9Sstevel@tonic-gate } 6655*7c478bd9Sstevel@tonic-gate 6656*7c478bd9Sstevel@tonic-gate while ((*name != '\0') && (*name != ',')) { 6657*7c478bd9Sstevel@tonic-gate *(link++) = *(name++); 6658*7c478bd9Sstevel@tonic-gate } 6659*7c478bd9Sstevel@tonic-gate 6660*7c478bd9Sstevel@tonic-gate *link = '\0'; 6661*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 6662*7c478bd9Sstevel@tonic-gate } 6663*7c478bd9Sstevel@tonic-gate 6664*7c478bd9Sstevel@tonic-gate static void 6665*7c478bd9Sstevel@tonic-gate free_selector_list(selector_list_t *head) 6666*7c478bd9Sstevel@tonic-gate { 6667*7c478bd9Sstevel@tonic-gate selector_list_t *temp; 6668*7c478bd9Sstevel@tonic-gate 6669*7c478bd9Sstevel@tonic-gate while (head != NULL) { 6670*7c478bd9Sstevel@tonic-gate temp = head; 6671*7c478bd9Sstevel@tonic-gate head = head->next; 6672*7c478bd9Sstevel@tonic-gate free(temp->val); 6673*7c478bd9Sstevel@tonic-gate free(temp); 6674*7c478bd9Sstevel@tonic-gate } 6675*7c478bd9Sstevel@tonic-gate } 6676*7c478bd9Sstevel@tonic-gate 6677*7c478bd9Sstevel@tonic-gate static void 6678*7c478bd9Sstevel@tonic-gate free_link_list(link_list_t *head) 6679*7c478bd9Sstevel@tonic-gate { 6680*7c478bd9Sstevel@tonic-gate link_list_t *temp; 6681*7c478bd9Sstevel@tonic-gate 6682*7c478bd9Sstevel@tonic-gate while (head != NULL) { 6683*7c478bd9Sstevel@tonic-gate temp = head; 6684*7c478bd9Sstevel@tonic-gate head = head->next; 6685*7c478bd9Sstevel@tonic-gate if (temp->type == CONSTANT) { 6686*7c478bd9Sstevel@tonic-gate free(temp->constant); 6687*7c478bd9Sstevel@tonic-gate } 6688*7c478bd9Sstevel@tonic-gate free(temp); 6689*7c478bd9Sstevel@tonic-gate } 6690*7c478bd9Sstevel@tonic-gate } 6691*7c478bd9Sstevel@tonic-gate 6692*7c478bd9Sstevel@tonic-gate /* 6693*7c478bd9Sstevel@tonic-gate * Prints only if level matches one of the debug levels 6694*7c478bd9Sstevel@tonic-gate * given on command line. INFO_MID is always printed. 6695*7c478bd9Sstevel@tonic-gate * 6696*7c478bd9Sstevel@tonic-gate * See devfsadm.h for a listing of globally defined levels and 6697*7c478bd9Sstevel@tonic-gate * meanings. Modules should prefix the level with their 6698*7c478bd9Sstevel@tonic-gate * module name to prevent collisions. 6699*7c478bd9Sstevel@tonic-gate */ 6700*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 6701*7c478bd9Sstevel@tonic-gate void 6702*7c478bd9Sstevel@tonic-gate devfsadm_print(char *msgid, char *message, ...) 6703*7c478bd9Sstevel@tonic-gate { 6704*7c478bd9Sstevel@tonic-gate va_list ap; 6705*7c478bd9Sstevel@tonic-gate static int newline = TRUE; 6706*7c478bd9Sstevel@tonic-gate int x; 6707*7c478bd9Sstevel@tonic-gate 6708*7c478bd9Sstevel@tonic-gate if (msgid != NULL) { 6709*7c478bd9Sstevel@tonic-gate for (x = 0; x < num_verbose; x++) { 6710*7c478bd9Sstevel@tonic-gate if (strcmp(verbose[x], msgid) == 0) { 6711*7c478bd9Sstevel@tonic-gate break; 6712*7c478bd9Sstevel@tonic-gate } 6713*7c478bd9Sstevel@tonic-gate if (strcmp(verbose[x], ALL_MID) == 0) { 6714*7c478bd9Sstevel@tonic-gate break; 6715*7c478bd9Sstevel@tonic-gate } 6716*7c478bd9Sstevel@tonic-gate } 6717*7c478bd9Sstevel@tonic-gate if (x == num_verbose) { 6718*7c478bd9Sstevel@tonic-gate return; 6719*7c478bd9Sstevel@tonic-gate } 6720*7c478bd9Sstevel@tonic-gate } 6721*7c478bd9Sstevel@tonic-gate 6722*7c478bd9Sstevel@tonic-gate va_start(ap, message); 6723*7c478bd9Sstevel@tonic-gate 6724*7c478bd9Sstevel@tonic-gate if (msgid == NULL) { 6725*7c478bd9Sstevel@tonic-gate if (logflag == TRUE) { 6726*7c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_NOTICE, message, ap); 6727*7c478bd9Sstevel@tonic-gate } else { 6728*7c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, message, ap); 6729*7c478bd9Sstevel@tonic-gate } 6730*7c478bd9Sstevel@tonic-gate 6731*7c478bd9Sstevel@tonic-gate } else { 6732*7c478bd9Sstevel@tonic-gate if (logflag == TRUE) { 6733*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_DEBUG, "%s[%ld]: %s: ", 6734*7c478bd9Sstevel@tonic-gate prog, getpid(), msgid); 6735*7c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_DEBUG, message, ap); 6736*7c478bd9Sstevel@tonic-gate } else { 6737*7c478bd9Sstevel@tonic-gate if (newline == TRUE) { 6738*7c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s[%ld]: %s: ", 6739*7c478bd9Sstevel@tonic-gate prog, getpid(), msgid); 6740*7c478bd9Sstevel@tonic-gate } 6741*7c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, message, ap); 6742*7c478bd9Sstevel@tonic-gate } 6743*7c478bd9Sstevel@tonic-gate } 6744*7c478bd9Sstevel@tonic-gate 6745*7c478bd9Sstevel@tonic-gate if (message[strlen(message) - 1] == '\n') { 6746*7c478bd9Sstevel@tonic-gate newline = TRUE; 6747*7c478bd9Sstevel@tonic-gate } else { 6748*7c478bd9Sstevel@tonic-gate newline = FALSE; 6749*7c478bd9Sstevel@tonic-gate } 6750*7c478bd9Sstevel@tonic-gate va_end(ap); 6751*7c478bd9Sstevel@tonic-gate } 6752*7c478bd9Sstevel@tonic-gate 6753*7c478bd9Sstevel@tonic-gate /* 6754*7c478bd9Sstevel@tonic-gate * print error messages to the terminal or to syslog 6755*7c478bd9Sstevel@tonic-gate */ 6756*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 6757*7c478bd9Sstevel@tonic-gate void 6758*7c478bd9Sstevel@tonic-gate devfsadm_errprint(char *message, ...) 6759*7c478bd9Sstevel@tonic-gate { 6760*7c478bd9Sstevel@tonic-gate va_list ap; 6761*7c478bd9Sstevel@tonic-gate 6762*7c478bd9Sstevel@tonic-gate va_start(ap, message); 6763*7c478bd9Sstevel@tonic-gate 6764*7c478bd9Sstevel@tonic-gate if (logflag == TRUE) { 6765*7c478bd9Sstevel@tonic-gate (void) vsyslog(LOG_ERR, message, ap); 6766*7c478bd9Sstevel@tonic-gate } else { 6767*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog); 6768*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, message, ap); 6769*7c478bd9Sstevel@tonic-gate } 6770*7c478bd9Sstevel@tonic-gate va_end(ap); 6771*7c478bd9Sstevel@tonic-gate } 6772*7c478bd9Sstevel@tonic-gate 6773*7c478bd9Sstevel@tonic-gate /* 6774*7c478bd9Sstevel@tonic-gate * return noupdate state (-s) 6775*7c478bd9Sstevel@tonic-gate */ 6776*7c478bd9Sstevel@tonic-gate int 6777*7c478bd9Sstevel@tonic-gate devfsadm_noupdate(void) 6778*7c478bd9Sstevel@tonic-gate { 6779*7c478bd9Sstevel@tonic-gate return (file_mods == TRUE ? DEVFSADM_TRUE : DEVFSADM_FALSE); 6780*7c478bd9Sstevel@tonic-gate } 6781*7c478bd9Sstevel@tonic-gate 6782*7c478bd9Sstevel@tonic-gate /* 6783*7c478bd9Sstevel@tonic-gate * return current root update path (-r) 6784*7c478bd9Sstevel@tonic-gate */ 6785*7c478bd9Sstevel@tonic-gate const char * 6786*7c478bd9Sstevel@tonic-gate devfsadm_root_path(void) 6787*7c478bd9Sstevel@tonic-gate { 6788*7c478bd9Sstevel@tonic-gate if (root_dir[0] == '\0') { 6789*7c478bd9Sstevel@tonic-gate return ("/"); 6790*7c478bd9Sstevel@tonic-gate } else { 6791*7c478bd9Sstevel@tonic-gate return ((const char *)root_dir); 6792*7c478bd9Sstevel@tonic-gate } 6793*7c478bd9Sstevel@tonic-gate } 6794*7c478bd9Sstevel@tonic-gate 6795*7c478bd9Sstevel@tonic-gate /* common exit function which ensures releasing locks */ 6796*7c478bd9Sstevel@tonic-gate static void 6797*7c478bd9Sstevel@tonic-gate devfsadm_exit(int status) 6798*7c478bd9Sstevel@tonic-gate { 6799*7c478bd9Sstevel@tonic-gate if (DEVFSADM_DEBUG_ON) { 6800*7c478bd9Sstevel@tonic-gate vprint(INFO_MID, "exit status = %d\n", status); 6801*7c478bd9Sstevel@tonic-gate } 6802*7c478bd9Sstevel@tonic-gate 6803*7c478bd9Sstevel@tonic-gate if (rcm_hdl) { 6804*7c478bd9Sstevel@tonic-gate if (thr_self() != process_rcm_events_tid) { 6805*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&rcm_eventq_lock); 6806*7c478bd9Sstevel@tonic-gate need_to_exit_rcm_event_thread = 1; 6807*7c478bd9Sstevel@tonic-gate (void) cond_broadcast(&rcm_eventq_cv); 6808*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_eventq_lock); 6809*7c478bd9Sstevel@tonic-gate 6810*7c478bd9Sstevel@tonic-gate /* wait until process_rcm_events() thread exits */ 6811*7c478bd9Sstevel@tonic-gate (void) thr_join(process_rcm_events_tid, NULL, NULL); 6812*7c478bd9Sstevel@tonic-gate } 6813*7c478bd9Sstevel@tonic-gate librcm_free_handle(rcm_hdl); 6814*7c478bd9Sstevel@tonic-gate (void) dlclose(librcm_hdl); 6815*7c478bd9Sstevel@tonic-gate } 6816*7c478bd9Sstevel@tonic-gate 6817*7c478bd9Sstevel@tonic-gate zlist_deleteall_unlocked(); /* dispose of all zones */ 6818*7c478bd9Sstevel@tonic-gate 6819*7c478bd9Sstevel@tonic-gate exit_dev_lock(); 6820*7c478bd9Sstevel@tonic-gate exit_daemon_lock(); 6821*7c478bd9Sstevel@tonic-gate 6822*7c478bd9Sstevel@tonic-gate if (logflag == TRUE) { 6823*7c478bd9Sstevel@tonic-gate closelog(); 6824*7c478bd9Sstevel@tonic-gate } 6825*7c478bd9Sstevel@tonic-gate 6826*7c478bd9Sstevel@tonic-gate exit(status); 6827*7c478bd9Sstevel@tonic-gate } 6828*7c478bd9Sstevel@tonic-gate 6829*7c478bd9Sstevel@tonic-gate /* 6830*7c478bd9Sstevel@tonic-gate * set root_dir, devices_dir, dev_dir using optarg. zone_mode determines 6831*7c478bd9Sstevel@tonic-gate * whether we're operating on behalf of a zone; in this case, we need to 6832*7c478bd9Sstevel@tonic-gate * reference some things from the global zone. Note that zone mode and 6833*7c478bd9Sstevel@tonic-gate * -R don't get along, but that should be OK since zone mode is not 6834*7c478bd9Sstevel@tonic-gate * a public interface. 6835*7c478bd9Sstevel@tonic-gate */ 6836*7c478bd9Sstevel@tonic-gate static void 6837*7c478bd9Sstevel@tonic-gate set_root_devices_dev_dir(char *dir, int zone_mode) 6838*7c478bd9Sstevel@tonic-gate { 6839*7c478bd9Sstevel@tonic-gate size_t len; 6840*7c478bd9Sstevel@tonic-gate 6841*7c478bd9Sstevel@tonic-gate root_dir = s_strdup(dir); 6842*7c478bd9Sstevel@tonic-gate len = strlen(dir) + strlen(DEVICES) + 1; 6843*7c478bd9Sstevel@tonic-gate devices_dir = s_malloc(len); 6844*7c478bd9Sstevel@tonic-gate (void) snprintf(devices_dir, len, "%s%s", root_dir, DEVICES); 6845*7c478bd9Sstevel@tonic-gate len = strlen(root_dir) + strlen(DEV) + 1; 6846*7c478bd9Sstevel@tonic-gate dev_dir = s_malloc(len); 6847*7c478bd9Sstevel@tonic-gate (void) snprintf(dev_dir, len, "%s%s", root_dir, DEV); 6848*7c478bd9Sstevel@tonic-gate if (zone_mode) { 6849*7c478bd9Sstevel@tonic-gate len = strlen(DEV) + 1; 6850*7c478bd9Sstevel@tonic-gate global_dev_dir = s_malloc(len); 6851*7c478bd9Sstevel@tonic-gate (void) snprintf(global_dev_dir, len, "%s", DEV); 6852*7c478bd9Sstevel@tonic-gate } else { 6853*7c478bd9Sstevel@tonic-gate global_dev_dir = s_malloc(len); 6854*7c478bd9Sstevel@tonic-gate (void) snprintf(global_dev_dir, len, "%s%s", root_dir, DEV); 6855*7c478bd9Sstevel@tonic-gate } 6856*7c478bd9Sstevel@tonic-gate } 6857*7c478bd9Sstevel@tonic-gate 6858*7c478bd9Sstevel@tonic-gate /* 6859*7c478bd9Sstevel@tonic-gate * Removes quotes. 6860*7c478bd9Sstevel@tonic-gate */ 6861*7c478bd9Sstevel@tonic-gate static char * 6862*7c478bd9Sstevel@tonic-gate dequote(char *src) 6863*7c478bd9Sstevel@tonic-gate { 6864*7c478bd9Sstevel@tonic-gate char *dst; 6865*7c478bd9Sstevel@tonic-gate int len; 6866*7c478bd9Sstevel@tonic-gate 6867*7c478bd9Sstevel@tonic-gate len = strlen(src); 6868*7c478bd9Sstevel@tonic-gate dst = s_malloc(len + 1); 6869*7c478bd9Sstevel@tonic-gate if (src[0] == '\"' && src[len - 1] == '\"') { 6870*7c478bd9Sstevel@tonic-gate len -= 2; 6871*7c478bd9Sstevel@tonic-gate (void) strncpy(dst, &src[1], len); 6872*7c478bd9Sstevel@tonic-gate dst[len] = '\0'; 6873*7c478bd9Sstevel@tonic-gate } else { 6874*7c478bd9Sstevel@tonic-gate (void) strcpy(dst, src); 6875*7c478bd9Sstevel@tonic-gate } 6876*7c478bd9Sstevel@tonic-gate return (dst); 6877*7c478bd9Sstevel@tonic-gate } 6878*7c478bd9Sstevel@tonic-gate 6879*7c478bd9Sstevel@tonic-gate /* 6880*7c478bd9Sstevel@tonic-gate * For a given physical device pathname and spectype, return the 6881*7c478bd9Sstevel@tonic-gate * ownership and permissions attributes by looking in data from 6882*7c478bd9Sstevel@tonic-gate * /etc/minor_perm. If currently in installation mode, check for 6883*7c478bd9Sstevel@tonic-gate * possible major number translations from the miniroot to the installed 6884*7c478bd9Sstevel@tonic-gate * root's name_to_major table. Note that there can be multiple matches, 6885*7c478bd9Sstevel@tonic-gate * but the last match takes effect. pts seems to rely on this 6886*7c478bd9Sstevel@tonic-gate * implementation behavior. 6887*7c478bd9Sstevel@tonic-gate */ 6888*7c478bd9Sstevel@tonic-gate static void 6889*7c478bd9Sstevel@tonic-gate getattr(char *phy_path, char *aminor, int spectype, dev_t dev, mode_t *mode, 6890*7c478bd9Sstevel@tonic-gate uid_t *uid, gid_t *gid) 6891*7c478bd9Sstevel@tonic-gate { 6892*7c478bd9Sstevel@tonic-gate char devname[PATH_MAX + 1]; 6893*7c478bd9Sstevel@tonic-gate char *node_name; 6894*7c478bd9Sstevel@tonic-gate char *minor_name; 6895*7c478bd9Sstevel@tonic-gate int match = FALSE; 6896*7c478bd9Sstevel@tonic-gate int is_clone; 6897*7c478bd9Sstevel@tonic-gate int mp_drvname_matches_node_name; 6898*7c478bd9Sstevel@tonic-gate int mp_drvname_matches_minor_name; 6899*7c478bd9Sstevel@tonic-gate int mp_drvname_is_clone; 6900*7c478bd9Sstevel@tonic-gate int mp_drvname_matches_drvname; 6901*7c478bd9Sstevel@tonic-gate struct mperm *mp; 6902*7c478bd9Sstevel@tonic-gate major_t major_no; 6903*7c478bd9Sstevel@tonic-gate char driver[PATH_MAX + 1]; 6904*7c478bd9Sstevel@tonic-gate 6905*7c478bd9Sstevel@tonic-gate /* 6906*7c478bd9Sstevel@tonic-gate * Get the driver name based on the major number since the name 6907*7c478bd9Sstevel@tonic-gate * in /devices may be generic. Could be running with more major 6908*7c478bd9Sstevel@tonic-gate * numbers than are in /etc/name_to_major, so get it from the kernel 6909*7c478bd9Sstevel@tonic-gate */ 6910*7c478bd9Sstevel@tonic-gate major_no = major(dev); 6911*7c478bd9Sstevel@tonic-gate 6912*7c478bd9Sstevel@tonic-gate if (modctl(MODGETNAME, driver, sizeof (driver), &major_no) != 0) { 6913*7c478bd9Sstevel@tonic-gate /* return default values */ 6914*7c478bd9Sstevel@tonic-gate goto use_defaults; 6915*7c478bd9Sstevel@tonic-gate } 6916*7c478bd9Sstevel@tonic-gate 6917*7c478bd9Sstevel@tonic-gate (void) strcpy(devname, phy_path); 6918*7c478bd9Sstevel@tonic-gate 6919*7c478bd9Sstevel@tonic-gate node_name = strrchr(devname, '/'); /* node name is the last */ 6920*7c478bd9Sstevel@tonic-gate /* component */ 6921*7c478bd9Sstevel@tonic-gate if (node_name == NULL) { 6922*7c478bd9Sstevel@tonic-gate err_print(NO_NODE, devname); 6923*7c478bd9Sstevel@tonic-gate goto use_defaults; 6924*7c478bd9Sstevel@tonic-gate } 6925*7c478bd9Sstevel@tonic-gate 6926*7c478bd9Sstevel@tonic-gate minor_name = strchr(++node_name, '@'); /* see if it has address part */ 6927*7c478bd9Sstevel@tonic-gate 6928*7c478bd9Sstevel@tonic-gate if (minor_name != NULL) { 6929*7c478bd9Sstevel@tonic-gate *minor_name++ = '\0'; 6930*7c478bd9Sstevel@tonic-gate } else { 6931*7c478bd9Sstevel@tonic-gate minor_name = node_name; 6932*7c478bd9Sstevel@tonic-gate } 6933*7c478bd9Sstevel@tonic-gate 6934*7c478bd9Sstevel@tonic-gate minor_name = strchr(minor_name, ':'); /* look for minor name */ 6935*7c478bd9Sstevel@tonic-gate 6936*7c478bd9Sstevel@tonic-gate if (minor_name == NULL) { 6937*7c478bd9Sstevel@tonic-gate err_print(NO_MINOR, devname); 6938*7c478bd9Sstevel@tonic-gate goto use_defaults; 6939*7c478bd9Sstevel@tonic-gate } 6940*7c478bd9Sstevel@tonic-gate *minor_name++ = '\0'; 6941*7c478bd9Sstevel@tonic-gate 6942*7c478bd9Sstevel@tonic-gate /* 6943*7c478bd9Sstevel@tonic-gate * mp->mp_drvname = device name from minor_perm 6944*7c478bd9Sstevel@tonic-gate * mp->mp_minorname = minor part of device name from 6945*7c478bd9Sstevel@tonic-gate * minor_perm 6946*7c478bd9Sstevel@tonic-gate * drvname = name of driver for this device 6947*7c478bd9Sstevel@tonic-gate */ 6948*7c478bd9Sstevel@tonic-gate 6949*7c478bd9Sstevel@tonic-gate is_clone = (strcmp(node_name, "clone") == 0 ? TRUE : FALSE); 6950*7c478bd9Sstevel@tonic-gate for (mp = minor_perms; mp != NULL; mp = mp->mp_next) { 6951*7c478bd9Sstevel@tonic-gate mp_drvname_matches_node_name = 6952*7c478bd9Sstevel@tonic-gate (strcmp(mp->mp_drvname, node_name) == 0 ? TRUE : FALSE); 6953*7c478bd9Sstevel@tonic-gate mp_drvname_matches_minor_name = 6954*7c478bd9Sstevel@tonic-gate (strcmp(mp->mp_drvname, minor_name) == 0 ? TRUE:FALSE); 6955*7c478bd9Sstevel@tonic-gate mp_drvname_is_clone = 6956*7c478bd9Sstevel@tonic-gate (strcmp(mp->mp_drvname, "clone") == 0 ? TRUE : FALSE); 6957*7c478bd9Sstevel@tonic-gate mp_drvname_matches_drvname = 6958*7c478bd9Sstevel@tonic-gate (strcmp(mp->mp_drvname, driver) == 0 ? TRUE : FALSE); 6959*7c478bd9Sstevel@tonic-gate 6960*7c478bd9Sstevel@tonic-gate /* 6961*7c478bd9Sstevel@tonic-gate * If one of the following cases is true, then we try to change 6962*7c478bd9Sstevel@tonic-gate * the permissions if a "shell global pattern match" of 6963*7c478bd9Sstevel@tonic-gate * mp_>mp_minorname matches minor_name. 6964*7c478bd9Sstevel@tonic-gate * 6965*7c478bd9Sstevel@tonic-gate * 1. mp->mp_drvname matches driver. 6966*7c478bd9Sstevel@tonic-gate * 6967*7c478bd9Sstevel@tonic-gate * OR 6968*7c478bd9Sstevel@tonic-gate * 6969*7c478bd9Sstevel@tonic-gate * 2. mp->mp_drvname matches node_name and this 6970*7c478bd9Sstevel@tonic-gate * name is an alias of the driver name 6971*7c478bd9Sstevel@tonic-gate * 6972*7c478bd9Sstevel@tonic-gate * OR 6973*7c478bd9Sstevel@tonic-gate * 6974*7c478bd9Sstevel@tonic-gate * 3. /devices entry is the clone device and either 6975*7c478bd9Sstevel@tonic-gate * minor_perm entry is the clone device or matches 6976*7c478bd9Sstevel@tonic-gate * the minor part of the clone device. 6977*7c478bd9Sstevel@tonic-gate */ 6978*7c478bd9Sstevel@tonic-gate 6979*7c478bd9Sstevel@tonic-gate if ((mp_drvname_matches_drvname == TRUE)|| 6980*7c478bd9Sstevel@tonic-gate ((mp_drvname_matches_node_name == TRUE) && 6981*7c478bd9Sstevel@tonic-gate (alias(driver, node_name) == TRUE)) || 6982*7c478bd9Sstevel@tonic-gate ((is_clone == TRUE) && 6983*7c478bd9Sstevel@tonic-gate ((mp_drvname_is_clone == TRUE) || 6984*7c478bd9Sstevel@tonic-gate (mp_drvname_matches_minor_name == TRUE)))) { 6985*7c478bd9Sstevel@tonic-gate /* 6986*7c478bd9Sstevel@tonic-gate * Check that the minor part of the 6987*7c478bd9Sstevel@tonic-gate * device name from the minor_perm 6988*7c478bd9Sstevel@tonic-gate * entry matches and if so, set the 6989*7c478bd9Sstevel@tonic-gate * permissions. 6990*7c478bd9Sstevel@tonic-gate * 6991*7c478bd9Sstevel@tonic-gate * Under real devfs, clone minor name is changed 6992*7c478bd9Sstevel@tonic-gate * to match the driver name, but minor_perm may 6993*7c478bd9Sstevel@tonic-gate * not match. We reconcile it here. 6994*7c478bd9Sstevel@tonic-gate */ 6995*7c478bd9Sstevel@tonic-gate if (aminor != NULL) 6996*7c478bd9Sstevel@tonic-gate minor_name = aminor; 6997*7c478bd9Sstevel@tonic-gate 6998*7c478bd9Sstevel@tonic-gate if (gmatch(minor_name, mp->mp_minorname) != 0) { 6999*7c478bd9Sstevel@tonic-gate *uid = mp->mp_uid; 7000*7c478bd9Sstevel@tonic-gate *gid = mp->mp_gid; 7001*7c478bd9Sstevel@tonic-gate *mode = spectype | mp->mp_mode; 7002*7c478bd9Sstevel@tonic-gate match = TRUE; 7003*7c478bd9Sstevel@tonic-gate } 7004*7c478bd9Sstevel@tonic-gate } 7005*7c478bd9Sstevel@tonic-gate } 7006*7c478bd9Sstevel@tonic-gate 7007*7c478bd9Sstevel@tonic-gate if (match == TRUE) { 7008*7c478bd9Sstevel@tonic-gate return; 7009*7c478bd9Sstevel@tonic-gate } 7010*7c478bd9Sstevel@tonic-gate 7011*7c478bd9Sstevel@tonic-gate use_defaults: 7012*7c478bd9Sstevel@tonic-gate /* not found in minor_perm, so just use default values */ 7013*7c478bd9Sstevel@tonic-gate *uid = root_uid; 7014*7c478bd9Sstevel@tonic-gate *gid = sys_gid; 7015*7c478bd9Sstevel@tonic-gate *mode = (spectype | 0600); 7016*7c478bd9Sstevel@tonic-gate } 7017*7c478bd9Sstevel@tonic-gate 7018*7c478bd9Sstevel@tonic-gate /* 7019*7c478bd9Sstevel@tonic-gate * Called by devfs_read_minor_perm() to report errors 7020*7c478bd9Sstevel@tonic-gate * key is: 7021*7c478bd9Sstevel@tonic-gate * line number: ignoring line number error 7022*7c478bd9Sstevel@tonic-gate * errno: open/close errors 7023*7c478bd9Sstevel@tonic-gate * size: alloc errors 7024*7c478bd9Sstevel@tonic-gate */ 7025*7c478bd9Sstevel@tonic-gate static void 7026*7c478bd9Sstevel@tonic-gate minorperm_err_cb(minorperm_err_t mp_err, int key) 7027*7c478bd9Sstevel@tonic-gate { 7028*7c478bd9Sstevel@tonic-gate switch (mp_err) { 7029*7c478bd9Sstevel@tonic-gate case MP_FOPEN_ERR: 7030*7c478bd9Sstevel@tonic-gate err_print(FOPEN_FAILED, MINOR_PERM_FILE, strerror(key)); 7031*7c478bd9Sstevel@tonic-gate break; 7032*7c478bd9Sstevel@tonic-gate case MP_FCLOSE_ERR: 7033*7c478bd9Sstevel@tonic-gate err_print(FCLOSE_FAILED, MINOR_PERM_FILE, strerror(key)); 7034*7c478bd9Sstevel@tonic-gate break; 7035*7c478bd9Sstevel@tonic-gate case MP_IGNORING_LINE_ERR: 7036*7c478bd9Sstevel@tonic-gate err_print(IGNORING_LINE_IN, key, MINOR_PERM_FILE); 7037*7c478bd9Sstevel@tonic-gate break; 7038*7c478bd9Sstevel@tonic-gate case MP_ALLOC_ERR: 7039*7c478bd9Sstevel@tonic-gate err_print(MALLOC_FAILED, key); 7040*7c478bd9Sstevel@tonic-gate break; 7041*7c478bd9Sstevel@tonic-gate case MP_NVLIST_ERR: 7042*7c478bd9Sstevel@tonic-gate err_print(NVLIST_ERROR, MINOR_PERM_FILE, strerror(key)); 7043*7c478bd9Sstevel@tonic-gate break; 7044*7c478bd9Sstevel@tonic-gate case MP_CANT_FIND_USER_ERR: 7045*7c478bd9Sstevel@tonic-gate err_print(CANT_FIND_USER, DEFAULT_DEV_USER); 7046*7c478bd9Sstevel@tonic-gate break; 7047*7c478bd9Sstevel@tonic-gate case MP_CANT_FIND_GROUP_ERR: 7048*7c478bd9Sstevel@tonic-gate err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP); 7049*7c478bd9Sstevel@tonic-gate break; 7050*7c478bd9Sstevel@tonic-gate } 7051*7c478bd9Sstevel@tonic-gate } 7052*7c478bd9Sstevel@tonic-gate 7053*7c478bd9Sstevel@tonic-gate static void 7054*7c478bd9Sstevel@tonic-gate read_minor_perm_file(void) 7055*7c478bd9Sstevel@tonic-gate { 7056*7c478bd9Sstevel@tonic-gate static int cached = FALSE; 7057*7c478bd9Sstevel@tonic-gate static struct stat cached_sb; 7058*7c478bd9Sstevel@tonic-gate struct stat current_sb; 7059*7c478bd9Sstevel@tonic-gate 7060*7c478bd9Sstevel@tonic-gate (void) stat(MINOR_PERM_FILE, ¤t_sb); 7061*7c478bd9Sstevel@tonic-gate 7062*7c478bd9Sstevel@tonic-gate /* If already cached, check to see if it is still valid */ 7063*7c478bd9Sstevel@tonic-gate if (cached == TRUE) { 7064*7c478bd9Sstevel@tonic-gate 7065*7c478bd9Sstevel@tonic-gate if (current_sb.st_mtime == cached_sb.st_mtime) { 7066*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "%s cache valid\n", MINOR_PERM_FILE); 7067*7c478bd9Sstevel@tonic-gate return; 7068*7c478bd9Sstevel@tonic-gate } 7069*7c478bd9Sstevel@tonic-gate devfs_free_minor_perm(minor_perms); 7070*7c478bd9Sstevel@tonic-gate minor_perms = NULL; 7071*7c478bd9Sstevel@tonic-gate } else { 7072*7c478bd9Sstevel@tonic-gate cached = TRUE; 7073*7c478bd9Sstevel@tonic-gate } 7074*7c478bd9Sstevel@tonic-gate 7075*7c478bd9Sstevel@tonic-gate (void) stat(MINOR_PERM_FILE, &cached_sb); 7076*7c478bd9Sstevel@tonic-gate 7077*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "loading binding file: %s\n", MINOR_PERM_FILE); 7078*7c478bd9Sstevel@tonic-gate 7079*7c478bd9Sstevel@tonic-gate minor_perms = devfs_read_minor_perm(minorperm_err_cb); 7080*7c478bd9Sstevel@tonic-gate } 7081*7c478bd9Sstevel@tonic-gate 7082*7c478bd9Sstevel@tonic-gate static void 7083*7c478bd9Sstevel@tonic-gate load_minor_perm_file(void) 7084*7c478bd9Sstevel@tonic-gate { 7085*7c478bd9Sstevel@tonic-gate read_minor_perm_file(); 7086*7c478bd9Sstevel@tonic-gate if (devfs_load_minor_perm(minor_perms, minorperm_err_cb) != 0) 7087*7c478bd9Sstevel@tonic-gate err_print(gettext("minor_perm load failed\n")); 7088*7c478bd9Sstevel@tonic-gate } 7089*7c478bd9Sstevel@tonic-gate 7090*7c478bd9Sstevel@tonic-gate static char * 7091*7c478bd9Sstevel@tonic-gate convert_to_re(char *dev) 7092*7c478bd9Sstevel@tonic-gate { 7093*7c478bd9Sstevel@tonic-gate char *p, *l, *out; 7094*7c478bd9Sstevel@tonic-gate int i; 7095*7c478bd9Sstevel@tonic-gate 7096*7c478bd9Sstevel@tonic-gate out = s_malloc(PATH_MAX); 7097*7c478bd9Sstevel@tonic-gate 7098*7c478bd9Sstevel@tonic-gate for (l = p = dev, i = 0; (*p != '\0') && (i < (PATH_MAX - 1)); 7099*7c478bd9Sstevel@tonic-gate ++p, i++) { 7100*7c478bd9Sstevel@tonic-gate if ((*p == '*') && ((l != p) && (*l == '/'))) { 7101*7c478bd9Sstevel@tonic-gate out[i++] = '.'; 7102*7c478bd9Sstevel@tonic-gate out[i] = '+'; 7103*7c478bd9Sstevel@tonic-gate } else { 7104*7c478bd9Sstevel@tonic-gate out[i] = *p; 7105*7c478bd9Sstevel@tonic-gate } 7106*7c478bd9Sstevel@tonic-gate l = p; 7107*7c478bd9Sstevel@tonic-gate } 7108*7c478bd9Sstevel@tonic-gate out[i] = '\0'; 7109*7c478bd9Sstevel@tonic-gate p = (char *)s_malloc(strlen(out) + 1); 7110*7c478bd9Sstevel@tonic-gate (void) strlcpy(p, out, strlen(out) + 1); 7111*7c478bd9Sstevel@tonic-gate free(out); 7112*7c478bd9Sstevel@tonic-gate 7113*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "converted %s -> %s\n", dev, p); 7114*7c478bd9Sstevel@tonic-gate 7115*7c478bd9Sstevel@tonic-gate return (p); 7116*7c478bd9Sstevel@tonic-gate } 7117*7c478bd9Sstevel@tonic-gate 7118*7c478bd9Sstevel@tonic-gate static void 7119*7c478bd9Sstevel@tonic-gate read_logindevperm_file(void) 7120*7c478bd9Sstevel@tonic-gate { 7121*7c478bd9Sstevel@tonic-gate static int cached = FALSE; 7122*7c478bd9Sstevel@tonic-gate static struct stat cached_sb; 7123*7c478bd9Sstevel@tonic-gate struct stat current_sb; 7124*7c478bd9Sstevel@tonic-gate struct login_dev *ldev; 7125*7c478bd9Sstevel@tonic-gate FILE *fp; 7126*7c478bd9Sstevel@tonic-gate char line[MAX_LDEV_LINE]; 7127*7c478bd9Sstevel@tonic-gate int ln, perm, rv; 7128*7c478bd9Sstevel@tonic-gate char *cp, *console, *devlist, *dev; 7129*7c478bd9Sstevel@tonic-gate char *lasts, *devlasts, *permstr, *drv; 7130*7c478bd9Sstevel@tonic-gate struct driver_list *list, *next; 7131*7c478bd9Sstevel@tonic-gate 7132*7c478bd9Sstevel@tonic-gate /* Read logindevperm only when enabled */ 7133*7c478bd9Sstevel@tonic-gate if (login_dev_enable != TRUE) 7134*7c478bd9Sstevel@tonic-gate return; 7135*7c478bd9Sstevel@tonic-gate 7136*7c478bd9Sstevel@tonic-gate if (cached == TRUE) { 7137*7c478bd9Sstevel@tonic-gate if (stat(LDEV_FILE, ¤t_sb) == 0 && 7138*7c478bd9Sstevel@tonic-gate current_sb.st_mtime == cached_sb.st_mtime) { 7139*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "%s cache valid\n", LDEV_FILE); 7140*7c478bd9Sstevel@tonic-gate return; 7141*7c478bd9Sstevel@tonic-gate } 7142*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "invalidating %s cache\n", LDEV_FILE); 7143*7c478bd9Sstevel@tonic-gate while (login_dev_cache != NULL) { 7144*7c478bd9Sstevel@tonic-gate 7145*7c478bd9Sstevel@tonic-gate ldev = login_dev_cache; 7146*7c478bd9Sstevel@tonic-gate login_dev_cache = ldev->ldev_next; 7147*7c478bd9Sstevel@tonic-gate free(ldev->ldev_console); 7148*7c478bd9Sstevel@tonic-gate free(ldev->ldev_device); 7149*7c478bd9Sstevel@tonic-gate regfree(&ldev->ldev_device_regex); 7150*7c478bd9Sstevel@tonic-gate list = ldev->ldev_driver_list; 7151*7c478bd9Sstevel@tonic-gate while (list) { 7152*7c478bd9Sstevel@tonic-gate next = list->next; 7153*7c478bd9Sstevel@tonic-gate free(list); 7154*7c478bd9Sstevel@tonic-gate list = next; 7155*7c478bd9Sstevel@tonic-gate } 7156*7c478bd9Sstevel@tonic-gate free(ldev); 7157*7c478bd9Sstevel@tonic-gate } 7158*7c478bd9Sstevel@tonic-gate } else { 7159*7c478bd9Sstevel@tonic-gate cached = TRUE; 7160*7c478bd9Sstevel@tonic-gate } 7161*7c478bd9Sstevel@tonic-gate 7162*7c478bd9Sstevel@tonic-gate assert(login_dev_cache == NULL); 7163*7c478bd9Sstevel@tonic-gate 7164*7c478bd9Sstevel@tonic-gate if (stat(LDEV_FILE, &cached_sb) != 0) { 7165*7c478bd9Sstevel@tonic-gate cached = FALSE; 7166*7c478bd9Sstevel@tonic-gate return; 7167*7c478bd9Sstevel@tonic-gate } 7168*7c478bd9Sstevel@tonic-gate 7169*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "loading file: %s\n", LDEV_FILE); 7170*7c478bd9Sstevel@tonic-gate 7171*7c478bd9Sstevel@tonic-gate if ((fp = fopen(LDEV_FILE, "r")) == NULL) { 7172*7c478bd9Sstevel@tonic-gate /* Not fatal to devfsadm */ 7173*7c478bd9Sstevel@tonic-gate cached = FALSE; 7174*7c478bd9Sstevel@tonic-gate err_print(FOPEN_FAILED, LDEV_FILE, strerror(errno)); 7175*7c478bd9Sstevel@tonic-gate return; 7176*7c478bd9Sstevel@tonic-gate } 7177*7c478bd9Sstevel@tonic-gate 7178*7c478bd9Sstevel@tonic-gate ln = 0; 7179*7c478bd9Sstevel@tonic-gate while (fgets(line, MAX_LDEV_LINE, fp) != NULL) { 7180*7c478bd9Sstevel@tonic-gate ln++; 7181*7c478bd9Sstevel@tonic-gate 7182*7c478bd9Sstevel@tonic-gate /* Remove comments */ 7183*7c478bd9Sstevel@tonic-gate if ((cp = strchr(line, '#')) != NULL) 7184*7c478bd9Sstevel@tonic-gate *cp = '\0'; 7185*7c478bd9Sstevel@tonic-gate 7186*7c478bd9Sstevel@tonic-gate if ((console = strtok_r(line, LDEV_DELIMS, &lasts)) == NULL) 7187*7c478bd9Sstevel@tonic-gate continue; /* Blank line */ 7188*7c478bd9Sstevel@tonic-gate 7189*7c478bd9Sstevel@tonic-gate if ((permstr = strtok_r(NULL, LDEV_DELIMS, &lasts)) == NULL) { 7190*7c478bd9Sstevel@tonic-gate err_print(IGNORING_LINE_IN, ln, LDEV_FILE); 7191*7c478bd9Sstevel@tonic-gate continue; /* Malformed line */ 7192*7c478bd9Sstevel@tonic-gate } 7193*7c478bd9Sstevel@tonic-gate 7194*7c478bd9Sstevel@tonic-gate /* 7195*7c478bd9Sstevel@tonic-gate * permstr is string in octal format. Convert to int 7196*7c478bd9Sstevel@tonic-gate */ 7197*7c478bd9Sstevel@tonic-gate cp = NULL; 7198*7c478bd9Sstevel@tonic-gate errno = 0; 7199*7c478bd9Sstevel@tonic-gate perm = strtol(permstr, &cp, 8); 7200*7c478bd9Sstevel@tonic-gate if (errno || perm < 0 || perm > 0777 || *cp != '\0') { 7201*7c478bd9Sstevel@tonic-gate err_print(IGNORING_LINE_IN, ln, LDEV_FILE); 7202*7c478bd9Sstevel@tonic-gate continue; 7203*7c478bd9Sstevel@tonic-gate } 7204*7c478bd9Sstevel@tonic-gate 7205*7c478bd9Sstevel@tonic-gate if ((devlist = strtok_r(NULL, LDEV_DELIMS, &lasts)) == NULL) { 7206*7c478bd9Sstevel@tonic-gate err_print(IGNORING_LINE_IN, ln, LDEV_FILE); 7207*7c478bd9Sstevel@tonic-gate continue; 7208*7c478bd9Sstevel@tonic-gate } 7209*7c478bd9Sstevel@tonic-gate 7210*7c478bd9Sstevel@tonic-gate dev = strtok_r(devlist, LDEV_DEV_DELIM, &devlasts); 7211*7c478bd9Sstevel@tonic-gate while (dev) { 7212*7c478bd9Sstevel@tonic-gate 7213*7c478bd9Sstevel@tonic-gate ldev = (struct login_dev *)s_zalloc( 7214*7c478bd9Sstevel@tonic-gate sizeof (struct login_dev)); 7215*7c478bd9Sstevel@tonic-gate ldev->ldev_console = s_strdup(console); 7216*7c478bd9Sstevel@tonic-gate ldev->ldev_perms = perm; 7217*7c478bd9Sstevel@tonic-gate 7218*7c478bd9Sstevel@tonic-gate /* 7219*7c478bd9Sstevel@tonic-gate * the logical device name may contain '*' which 7220*7c478bd9Sstevel@tonic-gate * we convert to a regular expression 7221*7c478bd9Sstevel@tonic-gate */ 7222*7c478bd9Sstevel@tonic-gate ldev->ldev_device = convert_to_re(dev); 7223*7c478bd9Sstevel@tonic-gate if (ldev->ldev_device && 7224*7c478bd9Sstevel@tonic-gate (rv = regcomp(&ldev->ldev_device_regex, 7225*7c478bd9Sstevel@tonic-gate ldev->ldev_device, REG_EXTENDED))) { 7226*7c478bd9Sstevel@tonic-gate bzero(&ldev->ldev_device_regex, 7227*7c478bd9Sstevel@tonic-gate sizeof (ldev->ldev_device_regex)); 7228*7c478bd9Sstevel@tonic-gate err_print(REGCOMP_FAILED, 7229*7c478bd9Sstevel@tonic-gate ldev->ldev_device, rv); 7230*7c478bd9Sstevel@tonic-gate } 7231*7c478bd9Sstevel@tonic-gate ldev->ldev_next = login_dev_cache; 7232*7c478bd9Sstevel@tonic-gate login_dev_cache = ldev; 7233*7c478bd9Sstevel@tonic-gate dev = strtok_r(NULL, LDEV_DEV_DELIM, &devlasts); 7234*7c478bd9Sstevel@tonic-gate } 7235*7c478bd9Sstevel@tonic-gate 7236*7c478bd9Sstevel@tonic-gate drv = strtok_r(NULL, LDEV_DRVLIST_DELIMS, &lasts); 7237*7c478bd9Sstevel@tonic-gate if (drv) { 7238*7c478bd9Sstevel@tonic-gate if (strcmp(drv, LDEV_DRVLIST_NAME) == 0) { 7239*7c478bd9Sstevel@tonic-gate 7240*7c478bd9Sstevel@tonic-gate drv = strtok_r(NULL, LDEV_DRV_DELIMS, 7241*7c478bd9Sstevel@tonic-gate &lasts); 7242*7c478bd9Sstevel@tonic-gate 7243*7c478bd9Sstevel@tonic-gate while (drv) { 7244*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, 7245*7c478bd9Sstevel@tonic-gate "logindevperm driver=%s\n", 7246*7c478bd9Sstevel@tonic-gate drv); 7247*7c478bd9Sstevel@tonic-gate 7248*7c478bd9Sstevel@tonic-gate /* 7249*7c478bd9Sstevel@tonic-gate * create a linked list of driver 7250*7c478bd9Sstevel@tonic-gate * names 7251*7c478bd9Sstevel@tonic-gate */ 7252*7c478bd9Sstevel@tonic-gate list = (struct driver_list *) 7253*7c478bd9Sstevel@tonic-gate s_zalloc( 7254*7c478bd9Sstevel@tonic-gate sizeof (struct driver_list)); 7255*7c478bd9Sstevel@tonic-gate (void) strlcpy(list->driver_name, drv, 7256*7c478bd9Sstevel@tonic-gate sizeof (list->driver_name)); 7257*7c478bd9Sstevel@tonic-gate list->next = ldev->ldev_driver_list; 7258*7c478bd9Sstevel@tonic-gate ldev->ldev_driver_list = list; 7259*7c478bd9Sstevel@tonic-gate drv = strtok_r(NULL, LDEV_DRV_DELIMS, 7260*7c478bd9Sstevel@tonic-gate &lasts); 7261*7c478bd9Sstevel@tonic-gate } 7262*7c478bd9Sstevel@tonic-gate } 7263*7c478bd9Sstevel@tonic-gate } 7264*7c478bd9Sstevel@tonic-gate } 7265*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 7266*7c478bd9Sstevel@tonic-gate } 7267*7c478bd9Sstevel@tonic-gate 7268*7c478bd9Sstevel@tonic-gate /* 7269*7c478bd9Sstevel@tonic-gate * Tokens are separated by ' ', '\t', ':', '=', '&', '|', ';', '\n', or '\0' 7270*7c478bd9Sstevel@tonic-gate * 7271*7c478bd9Sstevel@tonic-gate * Returns DEVFSADM_SUCCESS if token found, DEVFSADM_FAILURE otherwise. 7272*7c478bd9Sstevel@tonic-gate */ 7273*7c478bd9Sstevel@tonic-gate static int 7274*7c478bd9Sstevel@tonic-gate getnexttoken(char *next, char **nextp, char **tokenpp, char *tchar) 7275*7c478bd9Sstevel@tonic-gate { 7276*7c478bd9Sstevel@tonic-gate char *cp; 7277*7c478bd9Sstevel@tonic-gate char *cp1; 7278*7c478bd9Sstevel@tonic-gate char *tokenp; 7279*7c478bd9Sstevel@tonic-gate 7280*7c478bd9Sstevel@tonic-gate cp = next; 7281*7c478bd9Sstevel@tonic-gate while (*cp == ' ' || *cp == '\t') { 7282*7c478bd9Sstevel@tonic-gate cp++; /* skip leading spaces */ 7283*7c478bd9Sstevel@tonic-gate } 7284*7c478bd9Sstevel@tonic-gate tokenp = cp; /* start of token */ 7285*7c478bd9Sstevel@tonic-gate while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t' && 7286*7c478bd9Sstevel@tonic-gate *cp != ':' && *cp != '=' && *cp != '&' && 7287*7c478bd9Sstevel@tonic-gate *cp != '|' && *cp != ';') { 7288*7c478bd9Sstevel@tonic-gate cp++; /* point to next character */ 7289*7c478bd9Sstevel@tonic-gate } 7290*7c478bd9Sstevel@tonic-gate /* 7291*7c478bd9Sstevel@tonic-gate * If terminating character is a space or tab, look ahead to see if 7292*7c478bd9Sstevel@tonic-gate * there's another terminator that's not a space or a tab. 7293*7c478bd9Sstevel@tonic-gate * (This code handles trailing spaces.) 7294*7c478bd9Sstevel@tonic-gate */ 7295*7c478bd9Sstevel@tonic-gate if (*cp == ' ' || *cp == '\t') { 7296*7c478bd9Sstevel@tonic-gate cp1 = cp; 7297*7c478bd9Sstevel@tonic-gate while (*++cp1 == ' ' || *cp1 == '\t') 7298*7c478bd9Sstevel@tonic-gate ; 7299*7c478bd9Sstevel@tonic-gate if (*cp1 == '=' || *cp1 == ':' || *cp1 == '&' || *cp1 == '|' || 7300*7c478bd9Sstevel@tonic-gate *cp1 == ';' || *cp1 == '\n' || *cp1 == '\0') { 7301*7c478bd9Sstevel@tonic-gate *cp = NULL; /* terminate token */ 7302*7c478bd9Sstevel@tonic-gate cp = cp1; 7303*7c478bd9Sstevel@tonic-gate } 7304*7c478bd9Sstevel@tonic-gate } 7305*7c478bd9Sstevel@tonic-gate if (tchar != NULL) { 7306*7c478bd9Sstevel@tonic-gate *tchar = *cp; /* save terminating character */ 7307*7c478bd9Sstevel@tonic-gate if (*tchar == '\0') { 7308*7c478bd9Sstevel@tonic-gate *tchar = '\n'; 7309*7c478bd9Sstevel@tonic-gate } 7310*7c478bd9Sstevel@tonic-gate } 7311*7c478bd9Sstevel@tonic-gate *cp++ = '\0'; /* terminate token, point to next */ 7312*7c478bd9Sstevel@tonic-gate *nextp = cp; /* set pointer to next character */ 7313*7c478bd9Sstevel@tonic-gate if (cp - tokenp - 1 == 0) { 7314*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FAILURE); 7315*7c478bd9Sstevel@tonic-gate } 7316*7c478bd9Sstevel@tonic-gate *tokenpp = tokenp; 7317*7c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 7318*7c478bd9Sstevel@tonic-gate } 7319*7c478bd9Sstevel@tonic-gate 7320*7c478bd9Sstevel@tonic-gate /* 7321*7c478bd9Sstevel@tonic-gate * read or reread the driver aliases file 7322*7c478bd9Sstevel@tonic-gate */ 7323*7c478bd9Sstevel@tonic-gate static void 7324*7c478bd9Sstevel@tonic-gate read_driver_aliases_file(void) 7325*7c478bd9Sstevel@tonic-gate { 7326*7c478bd9Sstevel@tonic-gate 7327*7c478bd9Sstevel@tonic-gate driver_alias_t *save; 7328*7c478bd9Sstevel@tonic-gate driver_alias_t *lst_tail; 7329*7c478bd9Sstevel@tonic-gate driver_alias_t *ap; 7330*7c478bd9Sstevel@tonic-gate static int cached = FALSE; 7331*7c478bd9Sstevel@tonic-gate FILE *afd; 7332*7c478bd9Sstevel@tonic-gate char line[256]; 7333*7c478bd9Sstevel@tonic-gate char *cp; 7334*7c478bd9Sstevel@tonic-gate char *p; 7335*7c478bd9Sstevel@tonic-gate char t; 7336*7c478bd9Sstevel@tonic-gate int ln = 0; 7337*7c478bd9Sstevel@tonic-gate static struct stat cached_sb; 7338*7c478bd9Sstevel@tonic-gate struct stat current_sb; 7339*7c478bd9Sstevel@tonic-gate 7340*7c478bd9Sstevel@tonic-gate (void) stat(ALIASFILE, ¤t_sb); 7341*7c478bd9Sstevel@tonic-gate 7342*7c478bd9Sstevel@tonic-gate /* If already cached, check to see if it is still valid */ 7343*7c478bd9Sstevel@tonic-gate if (cached == TRUE) { 7344*7c478bd9Sstevel@tonic-gate 7345*7c478bd9Sstevel@tonic-gate if (current_sb.st_mtime == cached_sb.st_mtime) { 7346*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "%s cache valid\n", ALIASFILE); 7347*7c478bd9Sstevel@tonic-gate return; 7348*7c478bd9Sstevel@tonic-gate } 7349*7c478bd9Sstevel@tonic-gate 7350*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "invalidating %s cache\n", ALIASFILE); 7351*7c478bd9Sstevel@tonic-gate while (driver_aliases != NULL) { 7352*7c478bd9Sstevel@tonic-gate free(driver_aliases->alias_name); 7353*7c478bd9Sstevel@tonic-gate free(driver_aliases->driver_name); 7354*7c478bd9Sstevel@tonic-gate save = driver_aliases; 7355*7c478bd9Sstevel@tonic-gate driver_aliases = driver_aliases->next; 7356*7c478bd9Sstevel@tonic-gate free(save); 7357*7c478bd9Sstevel@tonic-gate } 7358*7c478bd9Sstevel@tonic-gate } else { 7359*7c478bd9Sstevel@tonic-gate cached = TRUE; 7360*7c478bd9Sstevel@tonic-gate } 7361*7c478bd9Sstevel@tonic-gate 7362*7c478bd9Sstevel@tonic-gate (void) stat(ALIASFILE, &cached_sb); 7363*7c478bd9Sstevel@tonic-gate 7364*7c478bd9Sstevel@tonic-gate vprint(FILES_MID, "loading binding file: %s\n", ALIASFILE); 7365*7c478bd9Sstevel@tonic-gate 7366*7c478bd9Sstevel@tonic-gate if ((afd = fopen(ALIASFILE, "r")) == NULL) { 7367*7c478bd9Sstevel@tonic-gate err_print(FOPEN_FAILED, ALIASFILE, strerror(errno)); 7368*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 7369*7c478bd9Sstevel@tonic-gate } 7370*7c478bd9Sstevel@tonic-gate 7371*7c478bd9Sstevel@tonic-gate while (fgets(line, sizeof (line) - 1, afd) != NULL) { 7372*7c478bd9Sstevel@tonic-gate ln++; 7373*7c478bd9Sstevel@tonic-gate cp = line; 7374*7c478bd9Sstevel@tonic-gate if (getnexttoken(cp, &cp, &p, &t) == DEVFSADM_FAILURE) { 7375*7c478bd9Sstevel@tonic-gate err_print(IGNORING_LINE_IN, ln, ALIASFILE); 7376*7c478bd9Sstevel@tonic-gate continue; 7377*7c478bd9Sstevel@tonic-gate } 7378*7c478bd9Sstevel@tonic-gate if (t == '\n' || t == '\0') { 7379*7c478bd9Sstevel@tonic-gate err_print(DRV_BUT_NO_ALIAS, ln, ALIASFILE); 7380*7c478bd9Sstevel@tonic-gate continue; 7381*7c478bd9Sstevel@tonic-gate } 7382*7c478bd9Sstevel@tonic-gate ap = (struct driver_alias *) 7383*7c478bd9Sstevel@tonic-gate s_zalloc(sizeof (struct driver_alias)); 7384*7c478bd9Sstevel@tonic-gate ap->driver_name = s_strdup(p); 7385*7c478bd9Sstevel@tonic-gate if (getnexttoken(cp, &cp, &p, &t) == DEVFSADM_FAILURE) { 7386*7c478bd9Sstevel@tonic-gate err_print(DRV_BUT_NO_ALIAS, ln, ALIASFILE); 7387*7c478bd9Sstevel@tonic-gate free(ap->driver_name); 7388*7c478bd9Sstevel@tonic-gate free(ap); 7389*7c478bd9Sstevel@tonic-gate continue; 7390*7c478bd9Sstevel@tonic-gate } 7391*7c478bd9Sstevel@tonic-gate if (*p == '"') { 7392*7c478bd9Sstevel@tonic-gate if (p[strlen(p) - 1] == '"') { 7393*7c478bd9Sstevel@tonic-gate p[strlen(p) - 1] = '\0'; 7394*7c478bd9Sstevel@tonic-gate p++; 7395*7c478bd9Sstevel@tonic-gate } 7396*7c478bd9Sstevel@tonic-gate } 7397*7c478bd9Sstevel@tonic-gate ap->alias_name = s_strdup(p); 7398*7c478bd9Sstevel@tonic-gate if (driver_aliases == NULL) { 7399*7c478bd9Sstevel@tonic-gate driver_aliases = ap; 7400*7c478bd9Sstevel@tonic-gate lst_tail = ap; 7401*7c478bd9Sstevel@tonic-gate } else { 7402*7c478bd9Sstevel@tonic-gate lst_tail->next = ap; 7403*7c478bd9Sstevel@tonic-gate lst_tail = ap; 7404*7c478bd9Sstevel@tonic-gate } 7405*7c478bd9Sstevel@tonic-gate } 7406*7c478bd9Sstevel@tonic-gate if (fclose(afd) == EOF) { 7407*7c478bd9Sstevel@tonic-gate err_print(FCLOSE_FAILED, ALIASFILE, strerror(errno)); 7408*7c478bd9Sstevel@tonic-gate } 7409*7c478bd9Sstevel@tonic-gate } 7410*7c478bd9Sstevel@tonic-gate 7411*7c478bd9Sstevel@tonic-gate /* 7412*7c478bd9Sstevel@tonic-gate * return TRUE if alias_name is an alias for driver_name, otherwise 7413*7c478bd9Sstevel@tonic-gate * return FALSE. 7414*7c478bd9Sstevel@tonic-gate */ 7415*7c478bd9Sstevel@tonic-gate static int 7416*7c478bd9Sstevel@tonic-gate alias(char *driver_name, char *alias_name) 7417*7c478bd9Sstevel@tonic-gate { 7418*7c478bd9Sstevel@tonic-gate driver_alias_t *alias; 7419*7c478bd9Sstevel@tonic-gate 7420*7c478bd9Sstevel@tonic-gate /* 7421*7c478bd9Sstevel@tonic-gate * check for a match 7422*7c478bd9Sstevel@tonic-gate */ 7423*7c478bd9Sstevel@tonic-gate for (alias = driver_aliases; alias != NULL; alias = alias->next) { 7424*7c478bd9Sstevel@tonic-gate if ((strcmp(alias->driver_name, driver_name) == 0) && 7425*7c478bd9Sstevel@tonic-gate (strcmp(alias->alias_name, alias_name) == 0)) { 7426*7c478bd9Sstevel@tonic-gate return (TRUE); 7427*7c478bd9Sstevel@tonic-gate } 7428*7c478bd9Sstevel@tonic-gate } 7429*7c478bd9Sstevel@tonic-gate return (FALSE); 7430*7c478bd9Sstevel@tonic-gate } 7431*7c478bd9Sstevel@tonic-gate 7432*7c478bd9Sstevel@tonic-gate /* 7433*7c478bd9Sstevel@tonic-gate * convenience functions 7434*7c478bd9Sstevel@tonic-gate */ 7435*7c478bd9Sstevel@tonic-gate static void * 7436*7c478bd9Sstevel@tonic-gate s_malloc(const size_t size) 7437*7c478bd9Sstevel@tonic-gate { 7438*7c478bd9Sstevel@tonic-gate void *rp; 7439*7c478bd9Sstevel@tonic-gate 7440*7c478bd9Sstevel@tonic-gate rp = malloc(size); 7441*7c478bd9Sstevel@tonic-gate if (rp == NULL) { 7442*7c478bd9Sstevel@tonic-gate err_print(MALLOC_FAILED, size); 7443*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 7444*7c478bd9Sstevel@tonic-gate } 7445*7c478bd9Sstevel@tonic-gate return (rp); 7446*7c478bd9Sstevel@tonic-gate } 7447*7c478bd9Sstevel@tonic-gate 7448*7c478bd9Sstevel@tonic-gate /* 7449*7c478bd9Sstevel@tonic-gate * convenience functions 7450*7c478bd9Sstevel@tonic-gate */ 7451*7c478bd9Sstevel@tonic-gate static void * 7452*7c478bd9Sstevel@tonic-gate s_realloc(void *ptr, const size_t size) 7453*7c478bd9Sstevel@tonic-gate { 7454*7c478bd9Sstevel@tonic-gate ptr = realloc(ptr, size); 7455*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 7456*7c478bd9Sstevel@tonic-gate err_print(REALLOC_FAILED, size); 7457*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 7458*7c478bd9Sstevel@tonic-gate } 7459*7c478bd9Sstevel@tonic-gate return (ptr); 7460*7c478bd9Sstevel@tonic-gate } 7461*7c478bd9Sstevel@tonic-gate 7462*7c478bd9Sstevel@tonic-gate static void * 7463*7c478bd9Sstevel@tonic-gate s_zalloc(const size_t size) 7464*7c478bd9Sstevel@tonic-gate { 7465*7c478bd9Sstevel@tonic-gate void *rp; 7466*7c478bd9Sstevel@tonic-gate 7467*7c478bd9Sstevel@tonic-gate rp = calloc(1, size); 7468*7c478bd9Sstevel@tonic-gate if (rp == NULL) { 7469*7c478bd9Sstevel@tonic-gate err_print(CALLOC_FAILED, size); 7470*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 7471*7c478bd9Sstevel@tonic-gate } 7472*7c478bd9Sstevel@tonic-gate return (rp); 7473*7c478bd9Sstevel@tonic-gate } 7474*7c478bd9Sstevel@tonic-gate 7475*7c478bd9Sstevel@tonic-gate char * 7476*7c478bd9Sstevel@tonic-gate s_strdup(const char *ptr) 7477*7c478bd9Sstevel@tonic-gate { 7478*7c478bd9Sstevel@tonic-gate void *rp; 7479*7c478bd9Sstevel@tonic-gate 7480*7c478bd9Sstevel@tonic-gate rp = strdup(ptr); 7481*7c478bd9Sstevel@tonic-gate if (rp == NULL) { 7482*7c478bd9Sstevel@tonic-gate err_print(STRDUP_FAILED, ptr); 7483*7c478bd9Sstevel@tonic-gate devfsadm_exit(1); 7484*7c478bd9Sstevel@tonic-gate } 7485*7c478bd9Sstevel@tonic-gate return (rp); 7486*7c478bd9Sstevel@tonic-gate } 7487*7c478bd9Sstevel@tonic-gate 7488*7c478bd9Sstevel@tonic-gate static void 7489*7c478bd9Sstevel@tonic-gate s_closedir(DIR *dirp) 7490*7c478bd9Sstevel@tonic-gate { 7491*7c478bd9Sstevel@tonic-gate retry: 7492*7c478bd9Sstevel@tonic-gate if (closedir(dirp) != 0) { 7493*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 7494*7c478bd9Sstevel@tonic-gate goto retry; 7495*7c478bd9Sstevel@tonic-gate err_print(CLOSEDIR_FAILED, strerror(errno)); 7496*7c478bd9Sstevel@tonic-gate } 7497*7c478bd9Sstevel@tonic-gate } 7498*7c478bd9Sstevel@tonic-gate 7499*7c478bd9Sstevel@tonic-gate static void 7500*7c478bd9Sstevel@tonic-gate s_mkdirp(const char *path, const mode_t mode) 7501*7c478bd9Sstevel@tonic-gate { 7502*7c478bd9Sstevel@tonic-gate vprint(CHATTY_MID, "mkdirp(%s, 0x%lx)\n", path, mode); 7503*7c478bd9Sstevel@tonic-gate if (mkdirp(path, mode) == -1) { 7504*7c478bd9Sstevel@tonic-gate if (errno != EEXIST) { 7505*7c478bd9Sstevel@tonic-gate err_print(MKDIR_FAILED, path, mode, strerror(errno)); 7506*7c478bd9Sstevel@tonic-gate } 7507*7c478bd9Sstevel@tonic-gate } 7508*7c478bd9Sstevel@tonic-gate } 7509*7c478bd9Sstevel@tonic-gate 7510*7c478bd9Sstevel@tonic-gate static void 7511*7c478bd9Sstevel@tonic-gate s_unlink(const char *file) 7512*7c478bd9Sstevel@tonic-gate { 7513*7c478bd9Sstevel@tonic-gate retry: 7514*7c478bd9Sstevel@tonic-gate if (unlink(file) == -1) { 7515*7c478bd9Sstevel@tonic-gate if (errno == EINTR || errno == EAGAIN) 7516*7c478bd9Sstevel@tonic-gate goto retry; 7517*7c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 7518*7c478bd9Sstevel@tonic-gate err_print(UNLINK_FAILED, file, strerror(errno)); 7519*7c478bd9Sstevel@tonic-gate } 7520*7c478bd9Sstevel@tonic-gate } 7521*7c478bd9Sstevel@tonic-gate } 7522*7c478bd9Sstevel@tonic-gate 7523*7c478bd9Sstevel@tonic-gate static void 7524*7c478bd9Sstevel@tonic-gate add_verbose_id(char *mid) 7525*7c478bd9Sstevel@tonic-gate { 7526*7c478bd9Sstevel@tonic-gate num_verbose++; 7527*7c478bd9Sstevel@tonic-gate verbose = s_realloc(verbose, num_verbose * sizeof (char *)); 7528*7c478bd9Sstevel@tonic-gate verbose[num_verbose - 1] = mid; 7529*7c478bd9Sstevel@tonic-gate } 7530*7c478bd9Sstevel@tonic-gate 7531*7c478bd9Sstevel@tonic-gate /* 7532*7c478bd9Sstevel@tonic-gate * returns DEVFSADM_TRUE if contents is a minor node in /devices. 7533*7c478bd9Sstevel@tonic-gate * If mn_root is not NULL, mn_root is set to: 7534*7c478bd9Sstevel@tonic-gate * if contents is a /dev node, mn_root = contents 7535*7c478bd9Sstevel@tonic-gate * OR 7536*7c478bd9Sstevel@tonic-gate * if contents is a /devices node, mn_root set to the '/' 7537*7c478bd9Sstevel@tonic-gate * following /devices. 7538*7c478bd9Sstevel@tonic-gate */ 7539*7c478bd9Sstevel@tonic-gate static int 7540*7c478bd9Sstevel@tonic-gate is_minor_node(char *contents, char **mn_root) 7541*7c478bd9Sstevel@tonic-gate { 7542*7c478bd9Sstevel@tonic-gate char *ptr; 7543*7c478bd9Sstevel@tonic-gate char device_prefix[100]; 7544*7c478bd9Sstevel@tonic-gate 7545*7c478bd9Sstevel@tonic-gate (void) snprintf(device_prefix, sizeof (device_prefix), "../devices/"); 7546*7c478bd9Sstevel@tonic-gate 7547*7c478bd9Sstevel@tonic-gate if ((ptr = strstr(contents, device_prefix)) != NULL) { 7548*7c478bd9Sstevel@tonic-gate if (mn_root != NULL) { 7549*7c478bd9Sstevel@tonic-gate /* mn_root should point to the / following /devices */ 7550*7c478bd9Sstevel@tonic-gate *mn_root = ptr += strlen(device_prefix) - 1; 7551*7c478bd9Sstevel@tonic-gate } 7552*7c478bd9Sstevel@tonic-gate return (DEVFSADM_TRUE); 7553*7c478bd9Sstevel@tonic-gate } 7554*7c478bd9Sstevel@tonic-gate 7555*7c478bd9Sstevel@tonic-gate (void) snprintf(device_prefix, sizeof (device_prefix), "/devices/"); 7556*7c478bd9Sstevel@tonic-gate 7557*7c478bd9Sstevel@tonic-gate if (strncmp(contents, device_prefix, strlen(device_prefix)) == 0) { 7558*7c478bd9Sstevel@tonic-gate if (mn_root != NULL) { 7559*7c478bd9Sstevel@tonic-gate /* mn_root should point to the / following /devices */ 7560*7c478bd9Sstevel@tonic-gate *mn_root = contents + strlen(device_prefix) - 1; 7561*7c478bd9Sstevel@tonic-gate } 7562*7c478bd9Sstevel@tonic-gate return (DEVFSADM_TRUE); 7563*7c478bd9Sstevel@tonic-gate } 7564*7c478bd9Sstevel@tonic-gate 7565*7c478bd9Sstevel@tonic-gate if (mn_root != NULL) { 7566*7c478bd9Sstevel@tonic-gate *mn_root = contents; 7567*7c478bd9Sstevel@tonic-gate } 7568*7c478bd9Sstevel@tonic-gate return (DEVFSADM_FALSE); 7569*7c478bd9Sstevel@tonic-gate } 7570*7c478bd9Sstevel@tonic-gate 7571*7c478bd9Sstevel@tonic-gate /* 7572*7c478bd9Sstevel@tonic-gate * Lookup nvpair corresponding to the given name and type: 7573*7c478bd9Sstevel@tonic-gate * 7574*7c478bd9Sstevel@tonic-gate * The standard nvlist_lookup functions in libnvpair don't work as our 7575*7c478bd9Sstevel@tonic-gate * nvlist is not allocated with NV_UNIQUE_NAME or NV_UNIQUE_NAME_TYPE. 7576*7c478bd9Sstevel@tonic-gate */ 7577*7c478bd9Sstevel@tonic-gate static nvpair_t * 7578*7c478bd9Sstevel@tonic-gate lookup_nvpair(nvlist_t *nvl, char *name, data_type_t type) 7579*7c478bd9Sstevel@tonic-gate { 7580*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 7581*7c478bd9Sstevel@tonic-gate 7582*7c478bd9Sstevel@tonic-gate for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 7583*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, nvp)) { 7584*7c478bd9Sstevel@tonic-gate if (strcmp(name, nvpair_name(nvp)) == 0 && 7585*7c478bd9Sstevel@tonic-gate nvpair_type(nvp) == type) 7586*7c478bd9Sstevel@tonic-gate return (nvp); 7587*7c478bd9Sstevel@tonic-gate } 7588*7c478bd9Sstevel@tonic-gate 7589*7c478bd9Sstevel@tonic-gate return (NULL); 7590*7c478bd9Sstevel@tonic-gate } 7591*7c478bd9Sstevel@tonic-gate 7592*7c478bd9Sstevel@tonic-gate /* 7593*7c478bd9Sstevel@tonic-gate * Send the specified event to RCM if the given nvlist contains a minor 7594*7c478bd9Sstevel@tonic-gate * node of the specified type. 7595*7c478bd9Sstevel@tonic-gate */ 7596*7c478bd9Sstevel@tonic-gate static void 7597*7c478bd9Sstevel@tonic-gate notify_event(nvlist_t *nvl, char *minor_node_type, char *event) 7598*7c478bd9Sstevel@tonic-gate { 7599*7c478bd9Sstevel@tonic-gate nvpair_t *nvp, *mnvp; 7600*7c478bd9Sstevel@tonic-gate char *path, *driver, *type; 7601*7c478bd9Sstevel@tonic-gate int instance; 7602*7c478bd9Sstevel@tonic-gate int err; 7603*7c478bd9Sstevel@tonic-gate boolean_t do_notify = B_FALSE; 7604*7c478bd9Sstevel@tonic-gate uint_t nminor; 7605*7c478bd9Sstevel@tonic-gate char *minor_byte_array; 7606*7c478bd9Sstevel@tonic-gate nvlist_t *mnvl; 7607*7c478bd9Sstevel@tonic-gate 7608*7c478bd9Sstevel@tonic-gate nvp = NULL; 7609*7c478bd9Sstevel@tonic-gate while (!do_notify && ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL)) { 7610*7c478bd9Sstevel@tonic-gate if (strcmp(nvpair_name(nvp), RCM_NV_MINOR_DATA) != 0) 7611*7c478bd9Sstevel@tonic-gate continue; 7612*7c478bd9Sstevel@tonic-gate if (nvpair_value_byte_array(nvp, 7613*7c478bd9Sstevel@tonic-gate (uchar_t **)&minor_byte_array, &nminor) != 0) 7614*7c478bd9Sstevel@tonic-gate goto error; 7615*7c478bd9Sstevel@tonic-gate if (nvlist_unpack(minor_byte_array, 7616*7c478bd9Sstevel@tonic-gate nminor, &mnvl, 0) != 0) 7617*7c478bd9Sstevel@tonic-gate goto error; 7618*7c478bd9Sstevel@tonic-gate 7619*7c478bd9Sstevel@tonic-gate mnvp = NULL; 7620*7c478bd9Sstevel@tonic-gate while (!do_notify && 7621*7c478bd9Sstevel@tonic-gate ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) != NULL)) { 7622*7c478bd9Sstevel@tonic-gate if (strcmp(nvpair_name(mnvp), 7623*7c478bd9Sstevel@tonic-gate RCM_NV_MINOR_NODE_TYPE) == 0) { 7624*7c478bd9Sstevel@tonic-gate if (nvpair_value_string(mnvp, &type) != 0) { 7625*7c478bd9Sstevel@tonic-gate nvlist_free(mnvl); 7626*7c478bd9Sstevel@tonic-gate goto error; 7627*7c478bd9Sstevel@tonic-gate } 7628*7c478bd9Sstevel@tonic-gate do_notify = (strcmp(type, 7629*7c478bd9Sstevel@tonic-gate minor_node_type) == 0); 7630*7c478bd9Sstevel@tonic-gate } 7631*7c478bd9Sstevel@tonic-gate } 7632*7c478bd9Sstevel@tonic-gate 7633*7c478bd9Sstevel@tonic-gate nvlist_free(mnvl); 7634*7c478bd9Sstevel@tonic-gate } 7635*7c478bd9Sstevel@tonic-gate 7636*7c478bd9Sstevel@tonic-gate if (!do_notify) 7637*7c478bd9Sstevel@tonic-gate return; 7638*7c478bd9Sstevel@tonic-gate 7639*7c478bd9Sstevel@tonic-gate if (librcm_notify_event(rcm_hdl, event, 0, nvl, NULL) == RCM_SUCCESS) 7640*7c478bd9Sstevel@tonic-gate return; 7641*7c478bd9Sstevel@tonic-gate 7642*7c478bd9Sstevel@tonic-gate error: 7643*7c478bd9Sstevel@tonic-gate err = errno; 7644*7c478bd9Sstevel@tonic-gate 7645*7c478bd9Sstevel@tonic-gate if (((nvp = lookup_nvpair(nvl, 7646*7c478bd9Sstevel@tonic-gate RCM_NV_DEVFS_PATH, DATA_TYPE_STRING)) == NULL) || 7647*7c478bd9Sstevel@tonic-gate (nvpair_value_string(nvp, &path) != 0)) 7648*7c478bd9Sstevel@tonic-gate path = "unknown"; 7649*7c478bd9Sstevel@tonic-gate 7650*7c478bd9Sstevel@tonic-gate if (((nvp = lookup_nvpair(nvl, 7651*7c478bd9Sstevel@tonic-gate RCM_NV_DRIVER_NAME, DATA_TYPE_STRING)) == NULL) || 7652*7c478bd9Sstevel@tonic-gate (nvpair_value_string(nvp, &driver) != 0)) 7653*7c478bd9Sstevel@tonic-gate driver = "unknown"; 7654*7c478bd9Sstevel@tonic-gate 7655*7c478bd9Sstevel@tonic-gate if (((nvp = lookup_nvpair(nvl, 7656*7c478bd9Sstevel@tonic-gate RCM_NV_INSTANCE, DATA_TYPE_INT32)) == NULL) || 7657*7c478bd9Sstevel@tonic-gate (nvpair_value_int32(nvp, &instance) != 0)) 7658*7c478bd9Sstevel@tonic-gate instance = -1; 7659*7c478bd9Sstevel@tonic-gate 7660*7c478bd9Sstevel@tonic-gate err_print(RCM_NOTIFY_FAILED, path, driver, 7661*7c478bd9Sstevel@tonic-gate instance, strerror(err)); 7662*7c478bd9Sstevel@tonic-gate } 7663*7c478bd9Sstevel@tonic-gate 7664*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7665*7c478bd9Sstevel@tonic-gate static void 7666*7c478bd9Sstevel@tonic-gate process_rcm_events(void *arg) 7667*7c478bd9Sstevel@tonic-gate { 7668*7c478bd9Sstevel@tonic-gate struct rcm_eventq *ev, *ev_next; 7669*7c478bd9Sstevel@tonic-gate int need_to_exit; 7670*7c478bd9Sstevel@tonic-gate 7671*7c478bd9Sstevel@tonic-gate for (;;) { 7672*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&rcm_eventq_lock); 7673*7c478bd9Sstevel@tonic-gate while (rcm_eventq_head == NULL && 7674*7c478bd9Sstevel@tonic-gate need_to_exit_rcm_event_thread == 0) 7675*7c478bd9Sstevel@tonic-gate (void) cond_wait(&rcm_eventq_cv, &rcm_eventq_lock); 7676*7c478bd9Sstevel@tonic-gate 7677*7c478bd9Sstevel@tonic-gate need_to_exit = need_to_exit_rcm_event_thread; 7678*7c478bd9Sstevel@tonic-gate ev = rcm_eventq_head; 7679*7c478bd9Sstevel@tonic-gate rcm_eventq_head = rcm_eventq_tail = NULL; 7680*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_eventq_lock); 7681*7c478bd9Sstevel@tonic-gate 7682*7c478bd9Sstevel@tonic-gate for (; ev != NULL; ev = ev_next) { 7683*7c478bd9Sstevel@tonic-gate /* 7684*7c478bd9Sstevel@tonic-gate * Private notification interface to RCM: 7685*7c478bd9Sstevel@tonic-gate * Do not retry the RCM notification on an error since 7686*7c478bd9Sstevel@tonic-gate * we do not know whether the failure occurred in 7687*7c478bd9Sstevel@tonic-gate * librcm, rcm_daemon or rcm modules or scripts. 7688*7c478bd9Sstevel@tonic-gate */ 7689*7c478bd9Sstevel@tonic-gate 7690*7c478bd9Sstevel@tonic-gate notify_event(ev->nvl, DDI_NT_NET, 7691*7c478bd9Sstevel@tonic-gate RCM_RESOURCE_NETWORK_NEW); 7692*7c478bd9Sstevel@tonic-gate 7693*7c478bd9Sstevel@tonic-gate notify_event(ev->nvl, DDI_NT_MAC, 7694*7c478bd9Sstevel@tonic-gate RCM_RESOURCE_MAC_NEW); 7695*7c478bd9Sstevel@tonic-gate 7696*7c478bd9Sstevel@tonic-gate ev_next = ev->next; 7697*7c478bd9Sstevel@tonic-gate nvlist_free(ev->nvl); 7698*7c478bd9Sstevel@tonic-gate free(ev); 7699*7c478bd9Sstevel@tonic-gate } 7700*7c478bd9Sstevel@tonic-gate 7701*7c478bd9Sstevel@tonic-gate if (need_to_exit) 7702*7c478bd9Sstevel@tonic-gate return; 7703*7c478bd9Sstevel@tonic-gate } 7704*7c478bd9Sstevel@tonic-gate } 7705*7c478bd9Sstevel@tonic-gate 7706*7c478bd9Sstevel@tonic-gate /* 7707*7c478bd9Sstevel@tonic-gate * Initialize rcm related handles and function pointers. 7708*7c478bd9Sstevel@tonic-gate * Since RCM need not present in miniroot, we dlopen librcm. 7709*7c478bd9Sstevel@tonic-gate */ 7710*7c478bd9Sstevel@tonic-gate static int 7711*7c478bd9Sstevel@tonic-gate rcm_init(void) 7712*7c478bd9Sstevel@tonic-gate { 7713*7c478bd9Sstevel@tonic-gate #define LIBRCM_PATH "/usr/lib/librcm.so" 7714*7c478bd9Sstevel@tonic-gate rcm_handle_t *hdl = NULL; 7715*7c478bd9Sstevel@tonic-gate int err; 7716*7c478bd9Sstevel@tonic-gate 7717*7c478bd9Sstevel@tonic-gate if ((librcm_hdl = dlopen(LIBRCM_PATH, RTLD_LAZY)) == NULL) { 7718*7c478bd9Sstevel@tonic-gate /* 7719*7c478bd9Sstevel@tonic-gate * don't log an error here, since librcm may not be present 7720*7c478bd9Sstevel@tonic-gate * in miniroot. 7721*7c478bd9Sstevel@tonic-gate */ 7722*7c478bd9Sstevel@tonic-gate return (-1); 7723*7c478bd9Sstevel@tonic-gate } 7724*7c478bd9Sstevel@tonic-gate 7725*7c478bd9Sstevel@tonic-gate librcm_alloc_handle = (int (*)())dlsym(librcm_hdl, "rcm_alloc_handle"); 7726*7c478bd9Sstevel@tonic-gate librcm_free_handle = (void (*)())dlsym(librcm_hdl, "rcm_free_handle"); 7727*7c478bd9Sstevel@tonic-gate librcm_notify_event = (int (*)())dlsym(librcm_hdl, "rcm_notify_event"); 7728*7c478bd9Sstevel@tonic-gate 7729*7c478bd9Sstevel@tonic-gate if (librcm_alloc_handle == NULL || librcm_notify_event == NULL || 7730*7c478bd9Sstevel@tonic-gate librcm_free_handle == NULL) { 7731*7c478bd9Sstevel@tonic-gate err_print(MISSING_SYMBOLS, LIBRCM_PATH); 7732*7c478bd9Sstevel@tonic-gate goto out; 7733*7c478bd9Sstevel@tonic-gate } 7734*7c478bd9Sstevel@tonic-gate 7735*7c478bd9Sstevel@tonic-gate /* Initialize the rcm handle */ 7736*7c478bd9Sstevel@tonic-gate if (librcm_alloc_handle(NULL, 0, NULL, &hdl) != RCM_SUCCESS) { 7737*7c478bd9Sstevel@tonic-gate err_print(RCM_ALLOC_HANDLE_ERROR); 7738*7c478bd9Sstevel@tonic-gate goto out; 7739*7c478bd9Sstevel@tonic-gate } 7740*7c478bd9Sstevel@tonic-gate 7741*7c478bd9Sstevel@tonic-gate (void) cond_init(&rcm_eventq_cv, USYNC_THREAD, 0); 7742*7c478bd9Sstevel@tonic-gate (void) mutex_init(&rcm_eventq_lock, USYNC_THREAD, 0); 7743*7c478bd9Sstevel@tonic-gate 7744*7c478bd9Sstevel@tonic-gate /* create a thread to notify RCM of events */ 7745*7c478bd9Sstevel@tonic-gate if ((err = thr_create(NULL, 0, (void *(*)(void *))process_rcm_events, 7746*7c478bd9Sstevel@tonic-gate NULL, 0, &process_rcm_events_tid)) != 0) { 7747*7c478bd9Sstevel@tonic-gate err_print(CANT_CREATE_THREAD, "process_rcm_events", 7748*7c478bd9Sstevel@tonic-gate strerror(err)); 7749*7c478bd9Sstevel@tonic-gate goto out; 7750*7c478bd9Sstevel@tonic-gate } 7751*7c478bd9Sstevel@tonic-gate 7752*7c478bd9Sstevel@tonic-gate rcm_hdl = hdl; 7753*7c478bd9Sstevel@tonic-gate return (0); 7754*7c478bd9Sstevel@tonic-gate 7755*7c478bd9Sstevel@tonic-gate out: 7756*7c478bd9Sstevel@tonic-gate if (hdl) 7757*7c478bd9Sstevel@tonic-gate librcm_free_handle(hdl); 7758*7c478bd9Sstevel@tonic-gate (void) dlclose(librcm_hdl); 7759*7c478bd9Sstevel@tonic-gate return (-1); 7760*7c478bd9Sstevel@tonic-gate } 7761*7c478bd9Sstevel@tonic-gate 7762*7c478bd9Sstevel@tonic-gate /* 7763*7c478bd9Sstevel@tonic-gate * Build an nvlist using the minor data. Pack it and add the packed nvlist 7764*7c478bd9Sstevel@tonic-gate * as a byte array to nv_list parameter. 7765*7c478bd9Sstevel@tonic-gate * Return 0 on success, errno on failure. 7766*7c478bd9Sstevel@tonic-gate */ 7767*7c478bd9Sstevel@tonic-gate static int 7768*7c478bd9Sstevel@tonic-gate add_minor_data_to_nvl(nvlist_t *nv_list, di_minor_t minor) 7769*7c478bd9Sstevel@tonic-gate { 7770*7c478bd9Sstevel@tonic-gate nvlist_t *nvl = NULL; 7771*7c478bd9Sstevel@tonic-gate int32_t minor_type; 7772*7c478bd9Sstevel@tonic-gate char *minor_name, *minor_node_type; 7773*7c478bd9Sstevel@tonic-gate int err; 7774*7c478bd9Sstevel@tonic-gate char *buf = NULL; 7775*7c478bd9Sstevel@tonic-gate size_t buflen = 0; 7776*7c478bd9Sstevel@tonic-gate 7777*7c478bd9Sstevel@tonic-gate if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) 7778*7c478bd9Sstevel@tonic-gate return (err); 7779*7c478bd9Sstevel@tonic-gate 7780*7c478bd9Sstevel@tonic-gate minor_type = (int32_t)di_minor_type(minor); 7781*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_int32(nvl, RCM_NV_MINOR_TYPE, minor_type)) != 0) 7782*7c478bd9Sstevel@tonic-gate goto error; 7783*7c478bd9Sstevel@tonic-gate 7784*7c478bd9Sstevel@tonic-gate minor_name = di_minor_name(minor); 7785*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, RCM_NV_MINOR_NAME, minor_name)) != 0) 7786*7c478bd9Sstevel@tonic-gate goto error; 7787*7c478bd9Sstevel@tonic-gate 7788*7c478bd9Sstevel@tonic-gate if ((minor_node_type = di_minor_nodetype(minor)) == NULL) 7789*7c478bd9Sstevel@tonic-gate minor_node_type = ""; 7790*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, RCM_NV_MINOR_NODE_TYPE, 7791*7c478bd9Sstevel@tonic-gate minor_node_type)) != 0) 7792*7c478bd9Sstevel@tonic-gate goto error; 7793*7c478bd9Sstevel@tonic-gate 7794*7c478bd9Sstevel@tonic-gate if ((err = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) != 0) 7795*7c478bd9Sstevel@tonic-gate goto error; 7796*7c478bd9Sstevel@tonic-gate 7797*7c478bd9Sstevel@tonic-gate err = nvlist_add_byte_array(nv_list, RCM_NV_MINOR_DATA, 7798*7c478bd9Sstevel@tonic-gate (uchar_t *)(buf), (uint_t)(buflen)); 7799*7c478bd9Sstevel@tonic-gate 7800*7c478bd9Sstevel@tonic-gate error: 7801*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 7802*7c478bd9Sstevel@tonic-gate if (buf) 7803*7c478bd9Sstevel@tonic-gate free(buf); 7804*7c478bd9Sstevel@tonic-gate return (err); 7805*7c478bd9Sstevel@tonic-gate } 7806*7c478bd9Sstevel@tonic-gate 7807*7c478bd9Sstevel@tonic-gate static void 7808*7c478bd9Sstevel@tonic-gate enqueue_rcm_event(nvlist_t *nvl) 7809*7c478bd9Sstevel@tonic-gate { 7810*7c478bd9Sstevel@tonic-gate struct rcm_eventq *ev; 7811*7c478bd9Sstevel@tonic-gate 7812*7c478bd9Sstevel@tonic-gate ev = (struct rcm_eventq *)s_zalloc(sizeof (struct rcm_eventq)); 7813*7c478bd9Sstevel@tonic-gate ev->nvl = nvl; 7814*7c478bd9Sstevel@tonic-gate 7815*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&rcm_eventq_lock); 7816*7c478bd9Sstevel@tonic-gate if (rcm_eventq_head == NULL) 7817*7c478bd9Sstevel@tonic-gate rcm_eventq_head = ev; 7818*7c478bd9Sstevel@tonic-gate else 7819*7c478bd9Sstevel@tonic-gate rcm_eventq_tail->next = ev; 7820*7c478bd9Sstevel@tonic-gate rcm_eventq_tail = ev; 7821*7c478bd9Sstevel@tonic-gate (void) cond_broadcast(&rcm_eventq_cv); 7822*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_eventq_lock); 7823*7c478bd9Sstevel@tonic-gate } 7824*7c478bd9Sstevel@tonic-gate 7825*7c478bd9Sstevel@tonic-gate /* 7826*7c478bd9Sstevel@tonic-gate * Generate an nvlist using the information given in node and minor_name. 7827*7c478bd9Sstevel@tonic-gate * If minor_name is NULL the nvlist will contain information on 7828*7c478bd9Sstevel@tonic-gate * all minor nodes. Otherwise the nvlist will contain information 7829*7c478bd9Sstevel@tonic-gate * only on the given minor_name. Notify RCM passing the nvlist. 7830*7c478bd9Sstevel@tonic-gate * 7831*7c478bd9Sstevel@tonic-gate * Return 0 upon successfully notifying RCM, errno on failure. 7832*7c478bd9Sstevel@tonic-gate */ 7833*7c478bd9Sstevel@tonic-gate static int 7834*7c478bd9Sstevel@tonic-gate notify_rcm(di_node_t node, char *minor_name) 7835*7c478bd9Sstevel@tonic-gate { 7836*7c478bd9Sstevel@tonic-gate nvlist_t *nvl = NULL; 7837*7c478bd9Sstevel@tonic-gate char *path, *driver_name; 7838*7c478bd9Sstevel@tonic-gate char *node_name; 7839*7c478bd9Sstevel@tonic-gate int err; 7840*7c478bd9Sstevel@tonic-gate int32_t instance; 7841*7c478bd9Sstevel@tonic-gate di_minor_t minor; 7842*7c478bd9Sstevel@tonic-gate 7843*7c478bd9Sstevel@tonic-gate if ((driver_name = di_driver_name(node)) == NULL) 7844*7c478bd9Sstevel@tonic-gate driver_name = ""; 7845*7c478bd9Sstevel@tonic-gate 7846*7c478bd9Sstevel@tonic-gate instance = (int32_t)di_instance(node); 7847*7c478bd9Sstevel@tonic-gate 7848*7c478bd9Sstevel@tonic-gate if ((path = di_devfs_path(node)) == NULL) { 7849*7c478bd9Sstevel@tonic-gate err = errno; 7850*7c478bd9Sstevel@tonic-gate goto error; 7851*7c478bd9Sstevel@tonic-gate } 7852*7c478bd9Sstevel@tonic-gate 7853*7c478bd9Sstevel@tonic-gate if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) 7854*7c478bd9Sstevel@tonic-gate goto error; 7855*7c478bd9Sstevel@tonic-gate 7856*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, RCM_NV_DRIVER_NAME, driver_name)) 7857*7c478bd9Sstevel@tonic-gate != 0) 7858*7c478bd9Sstevel@tonic-gate goto error; 7859*7c478bd9Sstevel@tonic-gate 7860*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_int32(nvl, RCM_NV_INSTANCE, instance)) != 0) 7861*7c478bd9Sstevel@tonic-gate goto error; 7862*7c478bd9Sstevel@tonic-gate 7863*7c478bd9Sstevel@tonic-gate if ((node_name = di_node_name(node)) == NULL) 7864*7c478bd9Sstevel@tonic-gate node_name = ""; 7865*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, RCM_NV_NODE_NAME, node_name)) != 0) 7866*7c478bd9Sstevel@tonic-gate goto error; 7867*7c478bd9Sstevel@tonic-gate 7868*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, RCM_NV_DEVFS_PATH, path)) != 0) 7869*7c478bd9Sstevel@tonic-gate goto error; 7870*7c478bd9Sstevel@tonic-gate 7871*7c478bd9Sstevel@tonic-gate minor = di_minor_next(node, DI_MINOR_NIL); 7872*7c478bd9Sstevel@tonic-gate while (minor != DI_MINOR_NIL) { 7873*7c478bd9Sstevel@tonic-gate if ((minor_name == NULL) || 7874*7c478bd9Sstevel@tonic-gate (strcmp(minor_name, di_minor_name(minor)) == 0)) { 7875*7c478bd9Sstevel@tonic-gate if ((err = add_minor_data_to_nvl(nvl, minor)) != 0) 7876*7c478bd9Sstevel@tonic-gate goto error; 7877*7c478bd9Sstevel@tonic-gate } 7878*7c478bd9Sstevel@tonic-gate minor = di_minor_next(node, minor); 7879*7c478bd9Sstevel@tonic-gate } 7880*7c478bd9Sstevel@tonic-gate 7881*7c478bd9Sstevel@tonic-gate enqueue_rcm_event(nvl); 7882*7c478bd9Sstevel@tonic-gate di_devfs_path_free(path); 7883*7c478bd9Sstevel@tonic-gate return (0); 7884*7c478bd9Sstevel@tonic-gate 7885*7c478bd9Sstevel@tonic-gate error: 7886*7c478bd9Sstevel@tonic-gate err_print(RCM_NVLIST_BUILD_ERROR, ((path != NULL) ? path : "unknown"), 7887*7c478bd9Sstevel@tonic-gate driver_name, instance, strerror(err)); 7888*7c478bd9Sstevel@tonic-gate 7889*7c478bd9Sstevel@tonic-gate if (path) 7890*7c478bd9Sstevel@tonic-gate di_devfs_path_free(path); 7891*7c478bd9Sstevel@tonic-gate if (nvl) 7892*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 7893*7c478bd9Sstevel@tonic-gate return (err); 7894*7c478bd9Sstevel@tonic-gate } 7895*7c478bd9Sstevel@tonic-gate 7896*7c478bd9Sstevel@tonic-gate /* 7897*7c478bd9Sstevel@tonic-gate * Add the specified property to nvl. 7898*7c478bd9Sstevel@tonic-gate * Returns: 7899*7c478bd9Sstevel@tonic-gate * 0 successfully added 7900*7c478bd9Sstevel@tonic-gate * -1 an error occurred 7901*7c478bd9Sstevel@tonic-gate * 1 could not add the property for reasons not due to errors. 7902*7c478bd9Sstevel@tonic-gate */ 7903*7c478bd9Sstevel@tonic-gate static int 7904*7c478bd9Sstevel@tonic-gate add_property(nvlist_t *nvl, di_prop_t prop) 7905*7c478bd9Sstevel@tonic-gate { 7906*7c478bd9Sstevel@tonic-gate char *name; 7907*7c478bd9Sstevel@tonic-gate char *attr_name; 7908*7c478bd9Sstevel@tonic-gate int n, len; 7909*7c478bd9Sstevel@tonic-gate int32_t *int32p; 7910*7c478bd9Sstevel@tonic-gate int64_t *int64p; 7911*7c478bd9Sstevel@tonic-gate char *str; 7912*7c478bd9Sstevel@tonic-gate char **strarray; 7913*7c478bd9Sstevel@tonic-gate uchar_t *bytep; 7914*7c478bd9Sstevel@tonic-gate int rv = 0; 7915*7c478bd9Sstevel@tonic-gate int i; 7916*7c478bd9Sstevel@tonic-gate 7917*7c478bd9Sstevel@tonic-gate if ((name = di_prop_name(prop)) == NULL) 7918*7c478bd9Sstevel@tonic-gate return (-1); 7919*7c478bd9Sstevel@tonic-gate 7920*7c478bd9Sstevel@tonic-gate len = sizeof (DEV_PROP_PREFIX) + strlen(name); 7921*7c478bd9Sstevel@tonic-gate if ((attr_name = malloc(len)) == NULL) 7922*7c478bd9Sstevel@tonic-gate return (-1); 7923*7c478bd9Sstevel@tonic-gate 7924*7c478bd9Sstevel@tonic-gate (void) strlcpy(attr_name, DEV_PROP_PREFIX, len); 7925*7c478bd9Sstevel@tonic-gate (void) strlcat(attr_name, name, len); 7926*7c478bd9Sstevel@tonic-gate 7927*7c478bd9Sstevel@tonic-gate switch (di_prop_type(prop)) { 7928*7c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_BOOLEAN: 7929*7c478bd9Sstevel@tonic-gate if (nvlist_add_boolean(nvl, attr_name) != 0) 7930*7c478bd9Sstevel@tonic-gate goto out; 7931*7c478bd9Sstevel@tonic-gate break; 7932*7c478bd9Sstevel@tonic-gate 7933*7c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT: 7934*7c478bd9Sstevel@tonic-gate if ((n = di_prop_ints(prop, &int32p)) < 1) 7935*7c478bd9Sstevel@tonic-gate goto out; 7936*7c478bd9Sstevel@tonic-gate 7937*7c478bd9Sstevel@tonic-gate if (n <= (PROP_LEN_LIMIT / sizeof (int32_t))) { 7938*7c478bd9Sstevel@tonic-gate if (nvlist_add_int32_array(nvl, attr_name, int32p, 7939*7c478bd9Sstevel@tonic-gate n) != 0) 7940*7c478bd9Sstevel@tonic-gate goto out; 7941*7c478bd9Sstevel@tonic-gate } else 7942*7c478bd9Sstevel@tonic-gate rv = 1; 7943*7c478bd9Sstevel@tonic-gate break; 7944*7c478bd9Sstevel@tonic-gate 7945*7c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT64: 7946*7c478bd9Sstevel@tonic-gate if ((n = di_prop_int64(prop, &int64p)) < 1) 7947*7c478bd9Sstevel@tonic-gate goto out; 7948*7c478bd9Sstevel@tonic-gate 7949*7c478bd9Sstevel@tonic-gate if (n <= (PROP_LEN_LIMIT / sizeof (int64_t))) { 7950*7c478bd9Sstevel@tonic-gate if (nvlist_add_int64_array(nvl, attr_name, int64p, 7951*7c478bd9Sstevel@tonic-gate n) != 0) 7952*7c478bd9Sstevel@tonic-gate goto out; 7953*7c478bd9Sstevel@tonic-gate } else 7954*7c478bd9Sstevel@tonic-gate rv = 1; 7955*7c478bd9Sstevel@tonic-gate break; 7956*7c478bd9Sstevel@tonic-gate 7957*7c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_BYTE: 7958*7c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_UNKNOWN: 7959*7c478bd9Sstevel@tonic-gate if ((n = di_prop_bytes(prop, &bytep)) < 1) 7960*7c478bd9Sstevel@tonic-gate goto out; 7961*7c478bd9Sstevel@tonic-gate 7962*7c478bd9Sstevel@tonic-gate if (n <= PROP_LEN_LIMIT) { 7963*7c478bd9Sstevel@tonic-gate if (nvlist_add_byte_array(nvl, attr_name, bytep, n) 7964*7c478bd9Sstevel@tonic-gate != 0) 7965*7c478bd9Sstevel@tonic-gate goto out; 7966*7c478bd9Sstevel@tonic-gate } else 7967*7c478bd9Sstevel@tonic-gate rv = 1; 7968*7c478bd9Sstevel@tonic-gate break; 7969*7c478bd9Sstevel@tonic-gate 7970*7c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_STRING: 7971*7c478bd9Sstevel@tonic-gate if ((n = di_prop_strings(prop, &str)) < 1) 7972*7c478bd9Sstevel@tonic-gate goto out; 7973*7c478bd9Sstevel@tonic-gate 7974*7c478bd9Sstevel@tonic-gate if ((strarray = malloc(n * sizeof (char *))) == NULL) 7975*7c478bd9Sstevel@tonic-gate goto out; 7976*7c478bd9Sstevel@tonic-gate 7977*7c478bd9Sstevel@tonic-gate len = 0; 7978*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 7979*7c478bd9Sstevel@tonic-gate strarray[i] = str + len; 7980*7c478bd9Sstevel@tonic-gate len += strlen(strarray[i]) + 1; 7981*7c478bd9Sstevel@tonic-gate } 7982*7c478bd9Sstevel@tonic-gate 7983*7c478bd9Sstevel@tonic-gate if (len <= PROP_LEN_LIMIT) { 7984*7c478bd9Sstevel@tonic-gate if (nvlist_add_string_array(nvl, attr_name, strarray, 7985*7c478bd9Sstevel@tonic-gate n) != 0) { 7986*7c478bd9Sstevel@tonic-gate free(strarray); 7987*7c478bd9Sstevel@tonic-gate goto out; 7988*7c478bd9Sstevel@tonic-gate } 7989*7c478bd9Sstevel@tonic-gate } else 7990*7c478bd9Sstevel@tonic-gate rv = 1; 7991*7c478bd9Sstevel@tonic-gate free(strarray); 7992*7c478bd9Sstevel@tonic-gate break; 7993*7c478bd9Sstevel@tonic-gate 7994*7c478bd9Sstevel@tonic-gate default: 7995*7c478bd9Sstevel@tonic-gate rv = 1; 7996*7c478bd9Sstevel@tonic-gate break; 7997*7c478bd9Sstevel@tonic-gate } 7998*7c478bd9Sstevel@tonic-gate 7999*7c478bd9Sstevel@tonic-gate free(attr_name); 8000*7c478bd9Sstevel@tonic-gate return (rv); 8001*7c478bd9Sstevel@tonic-gate 8002*7c478bd9Sstevel@tonic-gate out: 8003*7c478bd9Sstevel@tonic-gate free(attr_name); 8004*7c478bd9Sstevel@tonic-gate return (-1); 8005*7c478bd9Sstevel@tonic-gate } 8006*7c478bd9Sstevel@tonic-gate 8007*7c478bd9Sstevel@tonic-gate static void 8008*7c478bd9Sstevel@tonic-gate free_dev_names(struct devlink_cb_arg *x) 8009*7c478bd9Sstevel@tonic-gate { 8010*7c478bd9Sstevel@tonic-gate int i; 8011*7c478bd9Sstevel@tonic-gate 8012*7c478bd9Sstevel@tonic-gate for (i = 0; i < x->count; i++) { 8013*7c478bd9Sstevel@tonic-gate free(x->dev_names[i]); 8014*7c478bd9Sstevel@tonic-gate free(x->link_contents[i]); 8015*7c478bd9Sstevel@tonic-gate } 8016*7c478bd9Sstevel@tonic-gate } 8017*7c478bd9Sstevel@tonic-gate 8018*7c478bd9Sstevel@tonic-gate /* callback function for di_devlink_cache_walk */ 8019*7c478bd9Sstevel@tonic-gate static int 8020*7c478bd9Sstevel@tonic-gate devlink_cb(di_devlink_t dl, void *arg) 8021*7c478bd9Sstevel@tonic-gate { 8022*7c478bd9Sstevel@tonic-gate struct devlink_cb_arg *x = (struct devlink_cb_arg *)arg; 8023*7c478bd9Sstevel@tonic-gate const char *path; 8024*7c478bd9Sstevel@tonic-gate const char *content; 8025*7c478bd9Sstevel@tonic-gate 8026*7c478bd9Sstevel@tonic-gate if ((path = di_devlink_path(dl)) == NULL || 8027*7c478bd9Sstevel@tonic-gate (content = di_devlink_content(dl)) == NULL || 8028*7c478bd9Sstevel@tonic-gate (x->dev_names[x->count] = strdup(path)) == NULL) 8029*7c478bd9Sstevel@tonic-gate goto out; 8030*7c478bd9Sstevel@tonic-gate 8031*7c478bd9Sstevel@tonic-gate if ((x->link_contents[x->count] = strdup(content)) == NULL) { 8032*7c478bd9Sstevel@tonic-gate free(x->dev_names[x->count]); 8033*7c478bd9Sstevel@tonic-gate goto out; 8034*7c478bd9Sstevel@tonic-gate } 8035*7c478bd9Sstevel@tonic-gate 8036*7c478bd9Sstevel@tonic-gate x->count++; 8037*7c478bd9Sstevel@tonic-gate if (x->count >= MAX_DEV_NAME_COUNT) 8038*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8039*7c478bd9Sstevel@tonic-gate 8040*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 8041*7c478bd9Sstevel@tonic-gate 8042*7c478bd9Sstevel@tonic-gate out: 8043*7c478bd9Sstevel@tonic-gate x->rv = -1; 8044*7c478bd9Sstevel@tonic-gate free_dev_names(x); 8045*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8046*7c478bd9Sstevel@tonic-gate } 8047*7c478bd9Sstevel@tonic-gate 8048*7c478bd9Sstevel@tonic-gate /* 8049*7c478bd9Sstevel@tonic-gate * Lookup dev name corresponding to the phys_path. 8050*7c478bd9Sstevel@tonic-gate * phys_path is path to a node or minor node. 8051*7c478bd9Sstevel@tonic-gate * Returns: 8052*7c478bd9Sstevel@tonic-gate * 0 with *dev_name set to the dev name 8053*7c478bd9Sstevel@tonic-gate * Lookup succeeded and dev_name found 8054*7c478bd9Sstevel@tonic-gate * 0 with *dev_name set to NULL 8055*7c478bd9Sstevel@tonic-gate * Lookup encountered no errors but dev name not found 8056*7c478bd9Sstevel@tonic-gate * -1 8057*7c478bd9Sstevel@tonic-gate * Lookup failed 8058*7c478bd9Sstevel@tonic-gate */ 8059*7c478bd9Sstevel@tonic-gate static int 8060*7c478bd9Sstevel@tonic-gate lookup_dev_name(char *phys_path, char **dev_name) 8061*7c478bd9Sstevel@tonic-gate { 8062*7c478bd9Sstevel@tonic-gate struct devlink_cb_arg cb_arg; 8063*7c478bd9Sstevel@tonic-gate 8064*7c478bd9Sstevel@tonic-gate *dev_name = NULL; 8065*7c478bd9Sstevel@tonic-gate 8066*7c478bd9Sstevel@tonic-gate cb_arg.count = 0; 8067*7c478bd9Sstevel@tonic-gate cb_arg.rv = 0; 8068*7c478bd9Sstevel@tonic-gate (void) di_devlink_cache_walk(devlink_cache, NULL, phys_path, 8069*7c478bd9Sstevel@tonic-gate DI_PRIMARY_LINK, &cb_arg, devlink_cb); 8070*7c478bd9Sstevel@tonic-gate 8071*7c478bd9Sstevel@tonic-gate if (cb_arg.rv == -1) 8072*7c478bd9Sstevel@tonic-gate return (-1); 8073*7c478bd9Sstevel@tonic-gate 8074*7c478bd9Sstevel@tonic-gate if (cb_arg.count > 0) { 8075*7c478bd9Sstevel@tonic-gate *dev_name = strdup(cb_arg.dev_names[0]); 8076*7c478bd9Sstevel@tonic-gate free_dev_names(&cb_arg); 8077*7c478bd9Sstevel@tonic-gate if (*dev_name == NULL) 8078*7c478bd9Sstevel@tonic-gate return (-1); 8079*7c478bd9Sstevel@tonic-gate } 8080*7c478bd9Sstevel@tonic-gate 8081*7c478bd9Sstevel@tonic-gate return (0); 8082*7c478bd9Sstevel@tonic-gate } 8083*7c478bd9Sstevel@tonic-gate 8084*7c478bd9Sstevel@tonic-gate static char * 8085*7c478bd9Sstevel@tonic-gate lookup_disk_dev_name(char *node_path) 8086*7c478bd9Sstevel@tonic-gate { 8087*7c478bd9Sstevel@tonic-gate struct devlink_cb_arg cb_arg; 8088*7c478bd9Sstevel@tonic-gate char *dev_name = NULL; 8089*7c478bd9Sstevel@tonic-gate int i; 8090*7c478bd9Sstevel@tonic-gate char *p; 8091*7c478bd9Sstevel@tonic-gate int len1, len2; 8092*7c478bd9Sstevel@tonic-gate 8093*7c478bd9Sstevel@tonic-gate #define DEV_RDSK "/dev/rdsk/" 8094*7c478bd9Sstevel@tonic-gate #define DISK_RAW_MINOR ",raw" 8095*7c478bd9Sstevel@tonic-gate 8096*7c478bd9Sstevel@tonic-gate cb_arg.count = 0; 8097*7c478bd9Sstevel@tonic-gate cb_arg.rv = 0; 8098*7c478bd9Sstevel@tonic-gate (void) di_devlink_cache_walk(devlink_cache, NULL, node_path, 8099*7c478bd9Sstevel@tonic-gate DI_PRIMARY_LINK, &cb_arg, devlink_cb); 8100*7c478bd9Sstevel@tonic-gate 8101*7c478bd9Sstevel@tonic-gate if (cb_arg.rv == -1 || cb_arg.count == 0) 8102*7c478bd9Sstevel@tonic-gate return (NULL); 8103*7c478bd9Sstevel@tonic-gate 8104*7c478bd9Sstevel@tonic-gate /* first try lookup based on /dev/rdsk name */ 8105*7c478bd9Sstevel@tonic-gate for (i = 0; i < cb_arg.count; i++) { 8106*7c478bd9Sstevel@tonic-gate if (strncmp(cb_arg.dev_names[i], DEV_RDSK, 8107*7c478bd9Sstevel@tonic-gate sizeof (DEV_RDSK) - 1) == 0) { 8108*7c478bd9Sstevel@tonic-gate dev_name = strdup(cb_arg.dev_names[i]); 8109*7c478bd9Sstevel@tonic-gate break; 8110*7c478bd9Sstevel@tonic-gate } 8111*7c478bd9Sstevel@tonic-gate } 8112*7c478bd9Sstevel@tonic-gate 8113*7c478bd9Sstevel@tonic-gate if (dev_name == NULL) { 8114*7c478bd9Sstevel@tonic-gate /* now try lookup based on a minor name ending with ",raw" */ 8115*7c478bd9Sstevel@tonic-gate len1 = sizeof (DISK_RAW_MINOR) - 1; 8116*7c478bd9Sstevel@tonic-gate for (i = 0; i < cb_arg.count; i++) { 8117*7c478bd9Sstevel@tonic-gate len2 = strlen(cb_arg.link_contents[i]); 8118*7c478bd9Sstevel@tonic-gate if (len2 >= len1 && 8119*7c478bd9Sstevel@tonic-gate strcmp(cb_arg.link_contents[i] + len2 - len1, 8120*7c478bd9Sstevel@tonic-gate DISK_RAW_MINOR) == 0) { 8121*7c478bd9Sstevel@tonic-gate dev_name = strdup(cb_arg.dev_names[i]); 8122*7c478bd9Sstevel@tonic-gate break; 8123*7c478bd9Sstevel@tonic-gate } 8124*7c478bd9Sstevel@tonic-gate } 8125*7c478bd9Sstevel@tonic-gate } 8126*7c478bd9Sstevel@tonic-gate 8127*7c478bd9Sstevel@tonic-gate free_dev_names(&cb_arg); 8128*7c478bd9Sstevel@tonic-gate 8129*7c478bd9Sstevel@tonic-gate if (strlen(dev_name) == 0) { 8130*7c478bd9Sstevel@tonic-gate free(dev_name); 8131*7c478bd9Sstevel@tonic-gate return (NULL); 8132*7c478bd9Sstevel@tonic-gate } 8133*7c478bd9Sstevel@tonic-gate 8134*7c478bd9Sstevel@tonic-gate /* if the name contains slice or partition number strip it */ 8135*7c478bd9Sstevel@tonic-gate p = dev_name + strlen(dev_name) - 1; 8136*7c478bd9Sstevel@tonic-gate if (isdigit(*p)) { 8137*7c478bd9Sstevel@tonic-gate while (p != dev_name && isdigit(*p)) 8138*7c478bd9Sstevel@tonic-gate p--; 8139*7c478bd9Sstevel@tonic-gate if (*p == 's' || *p == 'p') 8140*7c478bd9Sstevel@tonic-gate *p = '\0'; 8141*7c478bd9Sstevel@tonic-gate } 8142*7c478bd9Sstevel@tonic-gate 8143*7c478bd9Sstevel@tonic-gate return (dev_name); 8144*7c478bd9Sstevel@tonic-gate } 8145*7c478bd9Sstevel@tonic-gate 8146*7c478bd9Sstevel@tonic-gate static char * 8147*7c478bd9Sstevel@tonic-gate lookup_network_dev_name(char *node_path, char *driver_name) 8148*7c478bd9Sstevel@tonic-gate { 8149*7c478bd9Sstevel@tonic-gate char *dev_name = NULL; 8150*7c478bd9Sstevel@tonic-gate char phys_path[MAXPATHLEN]; 8151*7c478bd9Sstevel@tonic-gate 8152*7c478bd9Sstevel@tonic-gate if (lookup_dev_name(node_path, &dev_name) == -1) 8153*7c478bd9Sstevel@tonic-gate return (NULL); 8154*7c478bd9Sstevel@tonic-gate 8155*7c478bd9Sstevel@tonic-gate if (dev_name == NULL) { 8156*7c478bd9Sstevel@tonic-gate /* dlpi style-2 only interface */ 8157*7c478bd9Sstevel@tonic-gate (void) snprintf(phys_path, sizeof (phys_path), 8158*7c478bd9Sstevel@tonic-gate "/pseudo/clone@0:%s", driver_name); 8159*7c478bd9Sstevel@tonic-gate if (lookup_dev_name(phys_path, &dev_name) == -1 || 8160*7c478bd9Sstevel@tonic-gate dev_name == NULL) 8161*7c478bd9Sstevel@tonic-gate return (NULL); 8162*7c478bd9Sstevel@tonic-gate } 8163*7c478bd9Sstevel@tonic-gate 8164*7c478bd9Sstevel@tonic-gate return (dev_name); 8165*7c478bd9Sstevel@tonic-gate } 8166*7c478bd9Sstevel@tonic-gate 8167*7c478bd9Sstevel@tonic-gate /* 8168*7c478bd9Sstevel@tonic-gate * Build an nvlist containing all attributes for devfs events. 8169*7c478bd9Sstevel@tonic-gate * Returns nvlist pointer on success, NULL on failure. 8170*7c478bd9Sstevel@tonic-gate */ 8171*7c478bd9Sstevel@tonic-gate static nvlist_t * 8172*7c478bd9Sstevel@tonic-gate build_event_attributes(char *class, char *subclass, char *node_path, 8173*7c478bd9Sstevel@tonic-gate di_node_t node, char *driver_name, int instance) 8174*7c478bd9Sstevel@tonic-gate { 8175*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 8176*7c478bd9Sstevel@tonic-gate int err = 0; 8177*7c478bd9Sstevel@tonic-gate di_prop_t prop; 8178*7c478bd9Sstevel@tonic-gate int count; 8179*7c478bd9Sstevel@tonic-gate char *prop_name; 8180*7c478bd9Sstevel@tonic-gate int x; 8181*7c478bd9Sstevel@tonic-gate char *dev_name = NULL; 8182*7c478bd9Sstevel@tonic-gate int dev_name_lookup_err = 0; 8183*7c478bd9Sstevel@tonic-gate 8184*7c478bd9Sstevel@tonic-gate if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0) { 8185*7c478bd9Sstevel@tonic-gate nvl = NULL; 8186*7c478bd9Sstevel@tonic-gate goto out; 8187*7c478bd9Sstevel@tonic-gate } 8188*7c478bd9Sstevel@tonic-gate 8189*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_int32(nvl, EV_VERSION, EV_V1)) != 0) 8190*7c478bd9Sstevel@tonic-gate goto out; 8191*7c478bd9Sstevel@tonic-gate 8192*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, DEV_PHYS_PATH, node_path)) != 0) 8193*7c478bd9Sstevel@tonic-gate goto out; 8194*7c478bd9Sstevel@tonic-gate 8195*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_DEV_ADD) != 0 && 8196*7c478bd9Sstevel@tonic-gate strcmp(class, EC_DEV_REMOVE) != 0) 8197*7c478bd9Sstevel@tonic-gate return (nvl); 8198*7c478bd9Sstevel@tonic-gate 8199*7c478bd9Sstevel@tonic-gate if (driver_name == NULL || instance == -1) 8200*7c478bd9Sstevel@tonic-gate goto out; 8201*7c478bd9Sstevel@tonic-gate 8202*7c478bd9Sstevel@tonic-gate if (strcmp(subclass, ESC_DISK) == 0) { 8203*7c478bd9Sstevel@tonic-gate if ((dev_name = lookup_disk_dev_name(node_path)) == NULL) { 8204*7c478bd9Sstevel@tonic-gate dev_name_lookup_err = 1; 8205*7c478bd9Sstevel@tonic-gate goto out; 8206*7c478bd9Sstevel@tonic-gate } 8207*7c478bd9Sstevel@tonic-gate } else if (strcmp(subclass, ESC_NETWORK) == 0) { 8208*7c478bd9Sstevel@tonic-gate if ((dev_name = lookup_network_dev_name(node_path, driver_name)) 8209*7c478bd9Sstevel@tonic-gate == NULL) { 8210*7c478bd9Sstevel@tonic-gate dev_name_lookup_err = 1; 8211*7c478bd9Sstevel@tonic-gate goto out; 8212*7c478bd9Sstevel@tonic-gate } 8213*7c478bd9Sstevel@tonic-gate } 8214*7c478bd9Sstevel@tonic-gate 8215*7c478bd9Sstevel@tonic-gate if (dev_name) { 8216*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, DEV_NAME, dev_name)) != 0) 8217*7c478bd9Sstevel@tonic-gate goto out; 8218*7c478bd9Sstevel@tonic-gate free(dev_name); 8219*7c478bd9Sstevel@tonic-gate dev_name = NULL; 8220*7c478bd9Sstevel@tonic-gate } 8221*7c478bd9Sstevel@tonic-gate 8222*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_string(nvl, DEV_DRIVER_NAME, driver_name)) != 0) 8223*7c478bd9Sstevel@tonic-gate goto out; 8224*7c478bd9Sstevel@tonic-gate 8225*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_int32(nvl, DEV_INSTANCE, instance)) != 0) 8226*7c478bd9Sstevel@tonic-gate goto out; 8227*7c478bd9Sstevel@tonic-gate 8228*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_DEV_ADD) == 0) { 8229*7c478bd9Sstevel@tonic-gate /* add properties */ 8230*7c478bd9Sstevel@tonic-gate count = 0; 8231*7c478bd9Sstevel@tonic-gate for (prop = di_prop_next(node, DI_PROP_NIL); 8232*7c478bd9Sstevel@tonic-gate prop != DI_PROP_NIL && count < MAX_PROP_COUNT; 8233*7c478bd9Sstevel@tonic-gate prop = di_prop_next(node, prop)) { 8234*7c478bd9Sstevel@tonic-gate 8235*7c478bd9Sstevel@tonic-gate if (di_prop_devt(prop) != DDI_DEV_T_NONE) 8236*7c478bd9Sstevel@tonic-gate continue; 8237*7c478bd9Sstevel@tonic-gate 8238*7c478bd9Sstevel@tonic-gate if ((x = add_property(nvl, prop)) == 0) 8239*7c478bd9Sstevel@tonic-gate count++; 8240*7c478bd9Sstevel@tonic-gate else if (x == -1) { 8241*7c478bd9Sstevel@tonic-gate if ((prop_name = di_prop_name(prop)) == NULL) 8242*7c478bd9Sstevel@tonic-gate prop_name = ""; 8243*7c478bd9Sstevel@tonic-gate err_print(PROP_ADD_FAILED, prop_name); 8244*7c478bd9Sstevel@tonic-gate goto out; 8245*7c478bd9Sstevel@tonic-gate } 8246*7c478bd9Sstevel@tonic-gate } 8247*7c478bd9Sstevel@tonic-gate } 8248*7c478bd9Sstevel@tonic-gate 8249*7c478bd9Sstevel@tonic-gate return (nvl); 8250*7c478bd9Sstevel@tonic-gate 8251*7c478bd9Sstevel@tonic-gate out: 8252*7c478bd9Sstevel@tonic-gate if (nvl) 8253*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 8254*7c478bd9Sstevel@tonic-gate 8255*7c478bd9Sstevel@tonic-gate if (dev_name) 8256*7c478bd9Sstevel@tonic-gate free(dev_name); 8257*7c478bd9Sstevel@tonic-gate 8258*7c478bd9Sstevel@tonic-gate if (dev_name_lookup_err) 8259*7c478bd9Sstevel@tonic-gate err_print(DEV_NAME_LOOKUP_FAILED, node_path); 8260*7c478bd9Sstevel@tonic-gate else 8261*7c478bd9Sstevel@tonic-gate err_print(BUILD_EVENT_ATTR_FAILED, (err) ? strerror(err) : ""); 8262*7c478bd9Sstevel@tonic-gate return (NULL); 8263*7c478bd9Sstevel@tonic-gate } 8264*7c478bd9Sstevel@tonic-gate 8265*7c478bd9Sstevel@tonic-gate static void 8266*7c478bd9Sstevel@tonic-gate log_event(char *class, char *subclass, nvlist_t *nvl) 8267*7c478bd9Sstevel@tonic-gate { 8268*7c478bd9Sstevel@tonic-gate sysevent_id_t eid; 8269*7c478bd9Sstevel@tonic-gate 8270*7c478bd9Sstevel@tonic-gate if (sysevent_post_event(class, subclass, "SUNW", DEVFSADMD, 8271*7c478bd9Sstevel@tonic-gate nvl, &eid) != 0) { 8272*7c478bd9Sstevel@tonic-gate err_print(LOG_EVENT_FAILED, strerror(errno)); 8273*7c478bd9Sstevel@tonic-gate } 8274*7c478bd9Sstevel@tonic-gate } 8275*7c478bd9Sstevel@tonic-gate 8276*7c478bd9Sstevel@tonic-gate static void 8277*7c478bd9Sstevel@tonic-gate build_and_log_event(char *class, char *subclass, char *node_path, 8278*7c478bd9Sstevel@tonic-gate di_node_t node) 8279*7c478bd9Sstevel@tonic-gate { 8280*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 8281*7c478bd9Sstevel@tonic-gate 8282*7c478bd9Sstevel@tonic-gate if (node != DI_NODE_NIL) 8283*7c478bd9Sstevel@tonic-gate nvl = build_event_attributes(class, subclass, node_path, node, 8284*7c478bd9Sstevel@tonic-gate di_driver_name(node), di_instance(node)); 8285*7c478bd9Sstevel@tonic-gate else 8286*7c478bd9Sstevel@tonic-gate nvl = build_event_attributes(class, subclass, node_path, node, 8287*7c478bd9Sstevel@tonic-gate NULL, -1); 8288*7c478bd9Sstevel@tonic-gate 8289*7c478bd9Sstevel@tonic-gate if (nvl) { 8290*7c478bd9Sstevel@tonic-gate log_event(class, subclass, nvl); 8291*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 8292*7c478bd9Sstevel@tonic-gate } 8293*7c478bd9Sstevel@tonic-gate } 8294