summaryrefslogtreecommitdiff
path: root/usr/src/cmd/devfsadm/devfsadm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/devfsadm/devfsadm.c')
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.c1183
1 files changed, 494 insertions, 689 deletions
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c
index 67a46fad15..b627bd5255 100644
--- a/usr/src/cmd/devfsadm/devfsadm.c
+++ b/usr/src/cmd/devfsadm/devfsadm.c
@@ -142,8 +142,14 @@ static char *devices_dir = DEVICES;
/* /dev or <rootdir>/dev */
static char *dev_dir = DEV;
-/* /dev for the global zone */
-static char *global_dev_dir = DEV;
+/* /etc/dev or <rootdir>/etc/dev */
+static char *etc_dev_dir = ETCDEV;
+
+/*
+ * writable root (for lock files and doors during install).
+ * This is also root dir for /dev attr dir during install.
+ */
+static char *attr_root = NULL;
/* /etc/path_to_inst unless -p used */
static char *inst_file = INSTANCE_FILE;
@@ -193,7 +199,6 @@ static char lphy_path[PATH_MAX + 1] = {""};
/* Globals used by the link database */
static di_devlink_handle_t devlink_cache;
static int update_database = FALSE;
-static int devlink_door_fd = -1; /* fd of devlink handler door */
/* Globals used to set logindev perms */
static struct login_dev *login_dev_cache = NULL;
@@ -202,11 +207,6 @@ static int login_dev_enable = FALSE;
/* Global to use devinfo snapshot cache */
static int use_snapshot_cache = FALSE;
-/* Zone-related information */
-static int zone_cmd_mode = 0;
-static mutex_t zone_mutex; /* protects zone registration/unregistration ops */
-static struct zone_devinfo *zone_head; /* linked list of zones */
-
/*
* Packaged directories - not removed even when empty.
* The dirs must be listed in canonical form
@@ -225,9 +225,19 @@ static mutex_t rcm_eventq_lock;
static cond_t rcm_eventq_cv;
static volatile int need_to_exit_rcm_event_thread = 0;
+/* Devname globals */
+static int devname_debug_msg = 1;
+static nvlist_t *devname_maps = NULL;
+static int devname_first_call = 1;
+static int load_devname_nsmaps = FALSE;
+static int lookup_door_fd = -1;
+static char *lookup_door_path;
+
static void load_dev_acl(void);
static void update_drvconf(major_t);
-
+static void check_reconfig_state(void);
+static void devname_setup_nsmaps(void);
+static int s_stat(const char *, struct stat *);
int
main(int argc, char *argv[])
@@ -284,6 +294,10 @@ main(int argc, char *argv[])
*/
if (stat(DA_LABEL_CHECK, &tx_stat) == 0)
system_labeled = TRUE;
+ else {
+ /* test hook: see also mkdevalloc.c and allocate.c */
+ system_labeled = is_system_labeled_debug(&tx_stat);
+ }
}
parse_args(argc, argv);
@@ -385,58 +399,53 @@ load_dev_acl()
}
/*
- * set_zone_params sets us up to run against a specific zone. It should
- * only be called from parse_args.
+ * As devfsadm is run early in boot to provide the kernel with
+ * minor_perm info, we might as well check for reconfig at the
+ * same time to avoid running devfsadm twice. This gets invoked
+ * earlier than the env variable RECONFIG_BOOT is set up.
*/
-static int
-set_zone_params(char *zone_name)
+static void
+check_reconfig_state()
{
- char zpath[MAXPATHLEN];
- zone_dochandle_t hdl;
- void *dlhdl;
-
- assert(daemon_mode == FALSE);
+ struct stat sb;
- if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
- err_print(INVALID_ZONE, zone_name);
- return (DEVFSADM_FAILURE);
+ if (s_stat("/reconfigure", &sb) == 0) {
+ (void) modctl(MODDEVNAME, MODDEVNAME_RECONFIG, 0);
}
+}
- if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) {
- err_print(ZONE_LIB_MISSING);
- return (DEVFSADM_FAILURE);
- }
+static void
+modctl_sysavail()
+{
+ /*
+ * Inform /dev that system is available, that
+ * implicit reconfig can now be performed.
+ */
+ (void) modctl(MODDEVNAME, MODDEVNAME_SYSAVAIL, 0);
+}
- if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
- err_print(ZONE_ROOTPATH_FAILED, zone_name, strerror(errno));
- (void) dlclose(dlhdl);
- return (DEVFSADM_FAILURE);
- }
- set_root_devices_dev_dir(zpath, 1);
+static void
+set_lock_root(void)
+{
+ struct stat sb;
+ char *lock_root;
+ size_t len;
- if ((hdl = zonecfg_init_handle()) == NULL) {
- err_print(ZONE_REP_FAILED, zone_name, strerror(errno));
- (void) dlclose(dlhdl);
- return (DEVFSADM_FAILURE);
- }
+ lock_root = attr_root ? attr_root : root_dir;
- if ((zonecfg_get_snapshot_handle(zone_name, hdl)) != Z_OK) {
- err_print(ZONE_REP_FAILED, zone_name, strerror(errno));
- zonecfg_fini_handle(hdl);
- (void) dlclose(dlhdl);
- return (DEVFSADM_FAILURE);
- }
- (void) dlclose(dlhdl);
+ len = strlen(lock_root) + strlen(ETCDEV) + 1;
+ etc_dev_dir = s_malloc(len);
+ (void) snprintf(etc_dev_dir, len, "%s%s", lock_root, ETCDEV);
- zone_head = s_malloc(sizeof (struct zone_devinfo));
- zone_head->zone_path = s_strdup(zpath);
- zone_head->zone_name = s_strdup(zone_name);
- zone_head->zone_dochdl = hdl;
- zone_head->zone_next = NULL;
- zone_cmd_mode = 1;
- return (DEVFSADM_SUCCESS);
+ if (s_stat(etc_dev_dir, &sb) != 0) {
+ s_mkdirp(etc_dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
+ } else if (!S_ISDIR(sb.st_mode)) {
+ err_print(NOT_DIR, etc_dev_dir);
+ devfsadm_exit(1);
+ }
}
+
/*
* Parse arguments for all 6 programs handled from devfsadm.
*/
@@ -489,7 +498,7 @@ parse_args(int argc, char *argv[])
load_attach_drv = FALSE;
break;
case 'r':
- set_root_devices_dev_dir(optarg, 0);
+ set_root_devices_dev_dir(optarg);
if (zone_pathcheck(root_dir) !=
DEVFSADM_SUCCESS)
devfsadm_exit(1);
@@ -636,10 +645,10 @@ parse_args(int argc, char *argv[])
} else if ((strcmp(prog, DEVFSADM) == 0) ||
(strcmp(prog, DEVFSADMD) == 0)) {
char *zonename = NULL;
- enum zreg_op zoneop;
int init_drvconf = 0;
int init_perm = 0;
int public_mode = 0;
+ int init_sysavail = 0;
if (strcmp(prog, DEVFSADMD) == 0) {
daemon_mode = TRUE;
@@ -648,16 +657,19 @@ parse_args(int argc, char *argv[])
devlinktab_file = DEVLINKTAB_FILE;
while ((opt = getopt(argc, argv,
- "Cc:deIi:l:np:PR:r:st:vV:x:z:Z:")) != EOF) {
- if (opt == 'I' || opt == 'P') {
+ "a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) {
+ if (opt == 'I' || opt == 'P' || opt == 'S') {
if (public_mode)
usage();
} else {
- if (init_perm || init_drvconf)
+ if (init_perm || init_drvconf || init_sysavail)
usage();
public_mode = 1;
}
switch (opt) {
+ case 'a':
+ attr_root = s_strdup(optarg);
+ break;
case 'C':
cleanup = TRUE;
break;
@@ -698,6 +710,9 @@ parse_args(int argc, char *argv[])
/* specify an alternate module load path */
module_dirs = s_strdup(optarg);
break;
+ case 'm':
+ load_devname_nsmaps = TRUE;
+ break;
case 'n':
/* prevent driver loading and deferred attach */
load_attach_drv = FALSE;
@@ -721,7 +736,7 @@ parse_args(int argc, char *argv[])
devfsadm_exit(devfsadm_copy());
break;
case 'r':
- set_root_devices_dev_dir(optarg, 0);
+ set_root_devices_dev_dir(optarg);
break;
case 's':
/*
@@ -731,6 +746,11 @@ parse_args(int argc, char *argv[])
file_mods = FALSE;
flush_path_to_inst_enable = FALSE;
break;
+ case 'S':
+ if (daemon_mode == TRUE)
+ usage();
+ init_sysavail = 1;
+ break;
case 't':
devlinktab_file = optarg;
break;
@@ -765,19 +785,10 @@ parse_args(int argc, char *argv[])
usage();
}
break;
- case 'z':
- zonename = optarg;
- zoneop = ZONE_REG;
- break;
- case 'Z':
- zonename = optarg;
- zoneop = ZONE_UNREG;
- break;
default:
usage();
break;
}
-
}
if (optind < argc) {
usage();
@@ -792,44 +803,27 @@ parse_args(int argc, char *argv[])
devfsadm_exit(1);
}
- if (zonename != NULL) {
- /*
- * -z and -Z cannot be used if we're the daemon. The
- * daemon always manages all zones.
- */
- if (daemon_mode == TRUE)
- usage();
-
- /*
- * -z and -Z are private flags, but to be paranoid we
- * check whether they have been combined with -r.
- */
- if (*root_dir != '\0')
- usage();
-
- if (set_zone_params(optarg) != DEVFSADM_SUCCESS)
- devfsadm_exit(1);
-
- call_zone_register(zonename, zoneop);
- if (zoneop == ZONE_UNREG)
- devfsadm_exit(0);
- /*
- * If we are in ZONE_REG mode we plow on, laying out
- * devices for this zone.
- */
- }
- if (init_drvconf || init_perm) {
+ if (init_drvconf || init_perm || init_sysavail) {
/*
* Load minor perm before force-loading drivers
* so the correct permissions are picked up.
*/
- if (init_perm)
+ if (init_perm) {
+ check_reconfig_state();
load_dev_acl();
+ }
if (init_drvconf)
update_drvconf((major_t)-1);
+ if (init_sysavail)
+ modctl_sysavail();
devfsadm_exit(0);
/* NOTREACHED */
}
+
+ if (load_devname_nsmaps == TRUE) {
+ devname_setup_nsmaps();
+ devfsadm_exit(0);
+ }
}
@@ -852,7 +846,7 @@ parse_args(int argc, char *argv[])
load_attach_drv = FALSE;
break;
case 'r':
- set_root_devices_dev_dir(optarg, 0);
+ set_root_devices_dev_dir(optarg);
if (zone_pathcheck(root_dir) !=
DEVFSADM_SUCCESS)
devfsadm_exit(1);
@@ -879,6 +873,7 @@ parse_args(int argc, char *argv[])
usage();
}
}
+ set_lock_root();
}
void
@@ -1089,13 +1084,30 @@ process_devinfo_tree()
static void
print_cache_signal(int signo)
{
-
if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) {
err_print("signal SIGUSR1 failed: %s\n", strerror(errno));
devfsadm_exit(1);
}
}
+static void
+revoke_lookup_door(void)
+{
+ if (lookup_door_fd != -1) {
+ if (door_revoke(lookup_door_fd) == -1) {
+ err_print("door_revoke of %s failed - %s\n",
+ lookup_door_path, strerror(errno));
+ }
+ }
+}
+
+/*ARGSUSED*/
+static void
+catch_exit(int signo)
+{
+ revoke_lookup_door();
+}
+
/*
* Register with eventd for messages. Create doors for synchronous
* link creation.
@@ -1114,9 +1126,14 @@ daemon_update(void)
err_print("signal SIGUSR1 failed: %s\n", strerror(errno));
devfsadm_exit(1);
}
+ if (signal(SIGTERM, catch_exit) == SIG_ERR) {
+ err_print("signal SIGTERM failed: %s\n", strerror(errno));
+ devfsadm_exit(1);
+ }
if (snprintf(door_file, sizeof (door_file),
- "%s%s", root_dir, DEVFSADM_SERVICE_DOOR) >= sizeof (door_file)) {
+ "%s%s", attr_root ? attr_root : root_dir, DEVFSADM_SERVICE_DOOR)
+ >= sizeof (door_file)) {
err_print("update_daemon failed to open sysevent service "
"door\n");
devfsadm_exit(1);
@@ -1142,61 +1159,74 @@ daemon_update(void)
(void) sysevent_close_channel(sysevent_hp);
devfsadm_exit(1);
}
-
- if (snprintf(door_file, sizeof (door_file),
- "%s/%s", dev_dir, ZONE_REG_DOOR) >= sizeof (door_file)) {
- err_print(CANT_CREATE_ZONE_DOOR, door_file,
+ if (snprintf(door_file, sizeof (door_file), "%s/%s",
+ etc_dev_dir, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) {
+ err_print(CANT_CREATE_DOOR, DEVFSADM_SYNCH_DOOR,
strerror(ENAMETOOLONG));
devfsadm_exit(1);
}
+
(void) s_unlink(door_file);
- if ((fd = open(door_file, O_RDWR | O_CREAT, ZONE_DOOR_PERMS)) == -1) {
- err_print(CANT_CREATE_ZONE_DOOR, door_file, strerror(errno));
+ if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) {
+ err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
devfsadm_exit(1);
}
(void) close(fd);
- if ((fd = door_create(zone_reg_handler, NULL,
+
+ if ((fd = door_create(sync_handler, NULL,
DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
- err_print(CANT_CREATE_ZONE_DOOR, door_file, strerror(errno));
+ err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
(void) s_unlink(door_file);
devfsadm_exit(1);
}
+
if (fattach(fd, door_file) == -1) {
- err_print(CANT_CREATE_ZONE_DOOR, door_file, strerror(errno));
+ err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
(void) s_unlink(door_file);
devfsadm_exit(1);
}
- (void) snprintf(door_file, sizeof (door_file), "%s/%s", dev_dir,
- DEVFSADM_SYNCH_DOOR);
+ /*
+ * devname_lookup_door
+ */
+ if (snprintf(door_file, sizeof (door_file), "%s/%s",
+ etc_dev_dir, DEVNAME_LOOKUP_DOOR) >= sizeof (door_file)) {
+ err_print(CANT_CREATE_DOOR, DEVNAME_LOOKUP_DOOR,
+ strerror(ENAMETOOLONG));
+ devfsadm_exit(1);
+ }
(void) s_unlink(door_file);
- if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) {
+ if ((fd = open(door_file, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR)) == -1) {
err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
devfsadm_exit(1);
}
(void) close(fd);
- if ((fd = door_create(sync_handler, NULL,
- DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+ if ((fd = door_create(devname_lookup_handler, NULL,
+ DOOR_REFUSE_DESC)) == -1) {
err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
(void) s_unlink(door_file);
devfsadm_exit(1);
}
+ (void) fdetach(door_file);
+ lookup_door_path = s_strdup(door_file);
+retry:
if (fattach(fd, door_file) == -1) {
+ if (errno == EBUSY)
+ goto retry;
err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
(void) s_unlink(door_file);
devfsadm_exit(1);
}
- devlink_door_fd = fd;
+ lookup_door_fd = fd;
- /*
- * Make sure devfsadm is managing any and all configured system zones.
- */
- if (register_all_zones() != DEVFSADM_SUCCESS) {
- err_print(ZONE_LIST_FAILED, strerror(errno));
- }
+ /* pass down the door name to kernel for door_ki_open */
+ if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0)
+ err_print(DEVNAME_CONTACT_FAILED, strerror(errno));
+ else
+ devname_setup_nsmaps();
vprint(CHATTY_MID, "%spausing\n", fcn);
for (;;) {
@@ -1291,7 +1321,6 @@ lock_dev(void)
if (devlink_cache == NULL)
devlink_cache = di_devlink_open(root_dir, 0);
-
/*
* If modules were unloaded, reload them. Also use module status
* as an indication that we should check to see if other binding
@@ -1349,351 +1378,6 @@ unlock_dev(int flag)
}
/*
- * Contact the daemon to register the identified zone. We do everything with
- * zone names, for simplicity.
- */
-static void
-call_zone_register(char *zone_name, int regop)
-{
- int doorfd, ret, retries = 0;
- door_arg_t arg;
- struct zreg z;
- char path[MAXPATHLEN];
-
- assert(regop == ZONE_REG || regop == ZONE_UNREG);
-
- if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
- err_print(INVALID_ZONE, zone_name);
- return;
- }
-
- z.zreg_error = 0;
- z.zreg_op = regop;
- (void) strlcpy(z.zreg_zonename, zone_name, ZONENAME_MAX);
-
- (void) snprintf(path, sizeof (path), "/dev/%s", ZONE_REG_DOOR);
- if ((doorfd = open(path, O_RDWR)) == -1) {
- return;
- }
-
- bzero(&arg, sizeof (arg));
- arg.data_ptr = (char *)&z;
- arg.data_size = sizeof (z);
- arg.rbuf = (char *)&z;
- arg.rsize = sizeof (z);
-
- /*
- * If the daemon is running, tell it about the zone. If not, it's
- * ok. When it next gets run by the system (because there is
- * device-related work to do), it will load the list of zones from
- * the kernel.
- */
- while (((ret = door_call(doorfd, &arg)) == -1) && retries++ < 3) {
- (void) sleep(retries);
- }
- (void) close(doorfd);
-
- if (ret != 0) {
- return;
- }
-
- switch (z.zreg_error) {
- case ZONE_SUCCESS:
- break;
- case ZONE_ERR_NOZONE:
- err_print(ZONE_REG_FAILED, zone_name, strerror(z.zreg_errno));
- break;
- case ZONE_ERR_DOOR:
- err_print(ZONE_DOOR_MKFAIL, zone_name, strerror(z.zreg_errno));
- break;
- case ZONE_ERR_REPOSITORY:
- err_print(ZONE_REP_FAILED, zone_name, strerror(z.zreg_errno));
- break;
- case ZONE_ERR_NOLIB:
- err_print(ZONE_LIB_MISSING);
- break;
- default:
- err_print(ZONE_REG_FAILED, zone_name, strerror(z.zreg_errno));
- break;
- }
-}
-
-/*
- * The following routines are the daemon-side code for managing the set of
- * currently registered zones.
- *
- * TODO: improve brain-dead list performance--- use libuutil avl tree or hash?
- */
-static void
-zlist_insert(struct zone_devinfo *newzone)
-{
- struct zone_devinfo *z;
- assert(MUTEX_HELD(&zone_mutex));
-
- if (zone_head == NULL) {
- zone_head = newzone;
- return;
- }
- z = zlist_remove(newzone->zone_name);
- if (z != NULL)
- delete_zone(z);
- newzone->zone_next = zone_head;
- zone_head = newzone;
-}
-
-static void
-delete_zone(struct zone_devinfo *z) {
- char door_file[PATH_MAX];
-
- /*
- * Tidy up by withdrawing our door from the zone.
- */
- (void) snprintf(door_file, sizeof (door_file), "%s/dev/%s",
- z->zone_path, DEVFSADM_SYNCH_DOOR);
- (void) s_unlink(door_file);
-
- zonecfg_fini_handle(z->zone_dochdl);
- free(z->zone_path);
- free(z->zone_name);
- free(z);
-}
-
-static struct zone_devinfo *
-zlist_remove(char *zone_name)
-{
- struct zone_devinfo *z, *unlinked = NULL, **prevnextp;
- assert(MUTEX_HELD(&zone_mutex));
-
- prevnextp = &zone_head;
- for (z = zone_head; z != NULL; z = z->zone_next) {
- if (strcmp(zone_name, z->zone_name) == 0) {
- unlinked = z;
- *prevnextp = z->zone_next;
- return (unlinked);
- }
- prevnextp = &(z->zone_next);
- }
- return (NULL);
-}
-
-/*
- * Delete all zones. Note that this should *only* be called in the exit
- * path of the daemon, as it does not take the zone_mutex-- this is because
- * we could wind up calling devfsadm_exit() with that zone_mutex_held.
- */
-static void
-zlist_deleteall_unlocked(void)
-{
- struct zone_devinfo *tofree;
-
- while (zone_head != NULL) {
- tofree = zone_head;
- zone_head = zone_head->zone_next;
- delete_zone(tofree);
- }
- assert(zone_head == NULL);
-}
-
-static int
-zone_register(char *zone_name)
-{
- char door_file[MAXPATHLEN], zpath[MAXPATHLEN];
- int fd;
- int need_unlink = 0, error = ZONE_SUCCESS, myerrno = 0;
- zone_dochandle_t hdl = NULL;
- void *dlhdl = NULL;
- struct zone_devinfo *newzone = NULL;
-
- assert(MUTEX_HELD(&zone_mutex));
-
- if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) {
- error = ZONE_ERR_NOLIB;
- goto bad;
- }
-
- if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
- error = ZONE_ERR_NOZONE;
- myerrno = errno;
- goto bad;
- }
-
- if (snprintf(door_file, sizeof (door_file), "%s/dev/%s",
- zpath, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) {
- myerrno = ENAMETOOLONG; /* synthesize a reasonable errno */
- error = ZONE_ERR_DOOR;
- goto bad;
- }
-
- (void) s_unlink(door_file);
- if ((fd = open(door_file, O_RDWR | O_CREAT, ZONE_DOOR_PERMS)) == -1) {
- myerrno = errno;
- error = ZONE_ERR_DOOR;
- goto bad;
- }
- need_unlink = 1;
- (void) close(fd);
-
- if (fattach(devlink_door_fd, door_file) == -1) {
- error = ZONE_ERR_DOOR;
- myerrno = errno;
- goto bad;
- }
-
- if ((hdl = zonecfg_init_handle()) == NULL) {
- error = ZONE_ERR_REPOSITORY;
- myerrno = errno;
- goto bad;
- }
-
- if ((zonecfg_get_snapshot_handle(zone_name, hdl)) != Z_OK) {
- error = ZONE_ERR_REPOSITORY;
- myerrno = errno;
- goto bad;
- }
-
- newzone = s_malloc(sizeof (struct zone_devinfo));
- newzone->zone_path = s_strdup(zpath);
- newzone->zone_name = s_strdup(zone_name);
- newzone->zone_next = NULL;
- newzone->zone_dochdl = hdl;
- zlist_insert(newzone);
- (void) dlclose(dlhdl);
-
- return (ZONE_SUCCESS);
-
-bad:
- (void) devfsadm_errprint("%s[%ld]: failed to register zone %s: %s",
- prog, getpid(), zone_name, strerror(myerrno));
-
- assert(newzone == NULL);
- if (need_unlink)
- (void) s_unlink(door_file);
- if (hdl)
- zonecfg_fini_handle(hdl);
- if (dlhdl)
- (void) dlclose(dlhdl);
- errno = myerrno;
- return (error);
-}
-
-static int
-zone_unregister(char *zone_name)
-{
- struct zone_devinfo *z;
-
- assert(MUTEX_HELD(&zone_mutex));
-
- if ((z = zlist_remove(zone_name)) == NULL)
- return (ZONE_ERR_NOZONE);
-
- delete_zone(z);
- return (ZONE_SUCCESS);
-}
-
-/*
- * Called by the daemon when it receives a door call to the zone registration
- * door.
- */
-/*ARGSUSED*/
-static void
-zone_reg_handler(void *cookie, char *ap, size_t asize, door_desc_t *dp,
- uint_t ndesc)
-{
- door_cred_t dcred;
- struct zreg *zregp, rzreg;
-
- /*
- * We coarsely lock the whole registration process.
- */
- (void) mutex_lock(&zone_mutex);
-
- /*
- * Must be root to make this call
- * If caller is not root, don't touch its data.
- */
- if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) {
- zregp = &rzreg;
- zregp->zreg_error = ZONE_ERR_REPOSITORY;
- zregp->zreg_errno = EPERM;
- goto out;
- }
-
- assert(ap);
- assert(asize == sizeof (*zregp));
-
- zregp = (struct zreg *)(void *)ap;
-
- /*
- * Kernel must know about this zone; one way of discovering this
- * is by looking up the zone id.
- */
- if (getzoneidbyname(zregp->zreg_zonename) == -1) {
- zregp->zreg_error = ZONE_ERR_REPOSITORY;
- zregp->zreg_errno = errno;
- goto out;
- }
-
- if (zregp->zreg_op == ZONE_REG) {
- zregp->zreg_error = zone_register(zregp->zreg_zonename);
- zregp->zreg_errno = errno;
- } else {
- zregp->zreg_error = zone_unregister(zregp->zreg_zonename);
- zregp->zreg_errno = errno;
- }
-
-out:
- (void) mutex_unlock(&zone_mutex);
- (void) door_return((char *)zregp, sizeof (*zregp), NULL, 0);
-}
-
-static int
-register_all_zones(void)
-{
- zoneid_t *zids = NULL;
- uint_t nzents, nzents_saved;
- int i;
-
- (void) mutex_lock(&zone_mutex);
- if (zone_list(NULL, &nzents) != 0)
- return (DEVFSADM_FAILURE);
-
-again:
- assert(zids == NULL);
- assert(MUTEX_HELD(&zone_mutex));
- if (nzents == 0) {
- (void) mutex_unlock(&zone_mutex);
- return (DEVFSADM_SUCCESS);
- }
- zids = s_zalloc(nzents * sizeof (zoneid_t));
- nzents_saved = nzents;
- if (zone_list(zids, &nzents) != 0) {
- (void) mutex_unlock(&zone_mutex);
- free(zids);
- return (DEVFSADM_FAILURE);
- }
- if (nzents != nzents_saved) {
- /* list changed, try again */
- free(zids);
- zids = NULL;
- goto again;
- }
-
- assert(zids != NULL);
- for (i = 0; i < nzents; i++) {
- char name[ZONENAME_MAX];
-
- if (zids[i] == GLOBAL_ZONEID)
- continue;
- if (getzonenamebyid(zids[i], name, sizeof (name)) >= 0)
- (void) zone_register(name);
- }
-
- (void) mutex_unlock(&zone_mutex);
- free(zids);
- return (DEVFSADM_SUCCESS);
-}
-
-/*
* Check that if -r is set, it is not any part of a zone--- that is, that
* the zonepath is not a substring of the root path.
*/
@@ -1705,7 +1389,7 @@ zone_pathcheck(char *checkpath)
char root[MAXPATHLEN]; /* resolved devfsadm root path */
char zroot[MAXPATHLEN]; /* zone root path */
char rzroot[MAXPATHLEN]; /* resolved zone root path */
- char tmp[MAXPATHLEN];
+ char tmp[MAXPATHLEN];
FILE *cookie;
int err = DEVFSADM_SUCCESS;
@@ -1722,7 +1406,7 @@ zone_pathcheck(char *checkpath)
bzero(root, sizeof (root));
if (resolvepath(checkpath, root, sizeof (root) - 1) == -1) {
/*
- * In this case the user has done 'devfsadm -r' on some path
+ * In this case the user has done "devfsadm -r" on some path
* which does not yet exist, or we got some other misc. error.
* We punt and don't resolve the path in this case.
*/
@@ -1805,6 +1489,10 @@ event_handler(sysevent_t *ev)
vprint(EVENT_MID, "event_handler: %s id:0X%llx\n",
subclass, sysevent_get_seq(ev));
+ if (strcmp(subclass, ESC_DEVFS_START) == 0) {
+ return;
+ }
+
/* Check if event is an instance modification */
if (strcmp(subclass, ESC_DEVFS_INSTANCE_MOD) == 0) {
devfs_instance_mod();
@@ -1891,7 +1579,6 @@ event_handler(sysevent_t *ev)
DI_NODE_NIL);
unlock_dev(CACHE_STATE);
startup_cache_sync_thread();
-
} else
err_print(UNKNOWN_EVENT, subclass);
@@ -2686,129 +2373,13 @@ call_minor_init(module_t *module)
return (DEVFSADM_SUCCESS);
}
-static int
-i_mknod(char *path, int stype, int mode, dev_t dev, uid_t uid, gid_t gid)
-{
- struct stat sbuf;
-
- assert((stype & (S_IFCHR|S_IFBLK)) != 0);
- assert((mode & S_IFMT) == 0);
-
- if (stat(path, &sbuf) == 0) {
- /*
- * the node already exists, check if it's device
- * information is correct
- */
- if (((sbuf.st_mode & S_IFMT) == stype) &&
- (sbuf.st_rdev == dev)) {
- /* the device node is correct, continue */
- return (DEVFSADM_SUCCESS);
- }
- /*
- * the device node already exists but has the wrong
- * mode/dev_t value. we need to delete the current
- * node and re-create it with the correct mode/dev_t
- * value, but we also want to preserve the current
- * owner and permission information.
- */
- uid = sbuf.st_uid;
- gid = sbuf.st_gid;
- mode = sbuf.st_mode & ~S_IFMT;
- s_unlink(path);
- }
-
-top:
- if (mknod(path, stype | mode, dev) == -1) {
- if (errno == ENOENT) {
- /* dirpath to node doesn't exist, create it */
- char *hide = strrchr(path, '/');
- *hide = '\0';
- s_mkdirp(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
- *hide = '/';
- goto top;
- }
- err_print(MKNOD_FAILED, path, strerror(errno));
- return (DEVFSADM_FAILURE);
- } else {
- /*
- * If we successfully made the node, then set its owner
- * and group. Existing nodes will be unaffected.
- */
- (void) chown(path, uid, gid);
- }
- return (DEVFSADM_SUCCESS);
-}
-
-/*ARGSUSED*/
-int
-devfsadm_mklink_zone(struct zone_devinfo *z, char *link, di_node_t node,
- di_minor_t minor, int flags)
-{
- char path[PATH_MAX];
- char phy_path[PATH_MAX];
- char *dev_pathp;
- char *acontents, *aminor = NULL;
- mode_t mode;
- uid_t uid;
- gid_t gid;
- dev_t dev;
- struct zone_devtab out_match;
-
- if (zonecfg_match_dev(z->zone_dochdl, link, &out_match) != Z_OK) {
- return (DEVFSADM_FAILURE);
- }
-
- vprint(ZONE_MID, "zone device match: <device match=\"%s\"> "
- "matches /dev/%s\n", out_match.zone_dev_match, link);
-
- /*
- * In daemon mode, zone_path will be non-empty. In non-daemon mode
- * it will be empty since we've already stuck the zone into dev_dir,
- * etc.
- */
- (void) snprintf(path, sizeof (path), "%s/dev/%s", z->zone_path, link);
- dev = di_minor_devt(minor);
-
- /*
- * If this is an alias node (i.e. a clone node), we have to figure
- * out the minor name.
- */
- if (di_minor_type(minor) == DDM_ALIAS) {
- /* use /pseudo/clone@0:<driver> as the phys path */
- (void) snprintf(phy_path, sizeof (phy_path),
- "/pseudo/clone@0:%s",
- di_driver_name(di_minor_devinfo(minor)));
- aminor = di_minor_name(minor);
- acontents = phy_path;
- } else {
- if ((dev_pathp = di_devfs_path(node)) == NULL) {
- err_print(DI_DEVFS_PATH_FAILED, strerror(errno));
- devfsadm_exit(1);
- }
- (void) snprintf(phy_path, sizeof (phy_path), "%s:%s",
- dev_pathp, di_minor_name(minor));
- di_devfs_path_free(dev_pathp);
- acontents = phy_path;
- }
-
-
- getattr(acontents, aminor, di_minor_spectype(minor), dev,
- &mode, &uid, &gid);
- vprint(ZONE_MID, "zone getattr(%s, %s, %d, %lu, 0%lo, %lu, %lu)\n",
- acontents, aminor ? aminor : "<NULL>", di_minor_spectype(minor),
- dev, mode, uid, gid);
-
- /* Create the node */
- return (i_mknod(path, di_minor_spectype(minor), mode, dev, uid, gid));
-}
-
/*
* Creates a symlink 'link' to the physical path of node:minor.
* Construct link contents, then call create_link_common().
*/
/*ARGSUSED*/
int
-devfsadm_mklink_default(char *link, di_node_t node, di_minor_t minor, int flags)
+devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags)
{
char rcontents[PATH_MAX];
char devlink[PATH_MAX];
@@ -2919,38 +2490,6 @@ devfsadm_mklink_default(char *link, di_node_t node, di_minor_t minor, int flags)
return (rv);
}
-int
-devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags)
-{
- struct zone_devinfo *z;
- int error;
-
- /*
- * If we're in zone mode (also implies !daemon_mode), then the
- * zone devinfo list has only one element, the zone we're configuring,
- * and we can just use zone_head.
- */
- if (zone_cmd_mode)
- return (devfsadm_mklink_zone(zone_head, link, node,
- minor, flags));
- else if (!daemon_mode)
- return (devfsadm_mklink_default(link, node, minor, flags));
-
- /*
- * We're in daemon mode, so we need to make the link in the global
- * zone; then, walk the list of zones, creating the corresponding
- * mknod'd nodes in each.
- */
- error = devfsadm_mklink_default(link, node, minor, flags);
-
- (void) mutex_lock(&zone_mutex);
- for (z = zone_head; z != NULL; z = z->zone_next) {
- (void) devfsadm_mklink_zone(z, link, node, minor, flags);
- }
- (void) mutex_unlock(&zone_mutex);
- return (error);
-}
-
/*
* Creates a symlink link to primary_link. Calculates relative
* directory offsets, then calls link_common().
@@ -3575,6 +3114,8 @@ rm_parent_dir_if_empty(char *pathname)
{
char *ptr, path[PATH_MAX + 1];
char *fcn = "rm_parent_dir_if_empty: ";
+ char *pathlist;
+ int len;
vprint(REMOVE_MID, "%schecking %s if empty\n", fcn, pathname);
@@ -3592,18 +3133,30 @@ rm_parent_dir_if_empty(char *pathname)
*ptr = '\0';
- if (s_rmdir(path) == 0) {
- vprint(REMOVE_MID, "%sremoving empty dir %s\n",
- fcn, path);
- continue;
+ if ((pathlist = dev_readdir(path)) == NULL) {
+ err_print(OPENDIR_FAILED, path, strerror(errno));
+ return;
}
- if (errno == EEXIST) {
+
+ /*
+ * An empty pathlist implies an empty directory
+ */
+ len = strlen(pathlist);
+ free(pathlist);
+ if (len == 0) {
+ if (s_rmdir(path) == 0) {
+ vprint(REMOVE_MID,
+ "%sremoving empty dir %s\n", fcn, path);
+ } else if (errno == EEXIST) {
+ vprint(REMOVE_MID,
+ "%sfailed to remove dir: %s\n", fcn, path);
+ return;
+ }
+ } else {
+ /* some other file is here, so return */
vprint(REMOVE_MID, "%sdir not empty: %s\n", fcn, path);
return;
}
- vprint(REMOVE_MID, "%s can't remove %s: %s\n", fcn, path,
- strerror(errno));
- return;
}
}
@@ -4247,9 +3800,8 @@ enter_dev_lock()
return (0);
}
- s_mkdirp(dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
(void) snprintf(dev_lockfile, sizeof (dev_lockfile),
- "%s/%s", dev_dir, DEV_LOCK_FILE);
+ "%s/%s", etc_dev_dir, DEV_LOCK_FILE);
vprint(LOCK_MID, "enter_dev_lock: lock file %s\n", dev_lockfile);
@@ -4362,9 +3914,8 @@ enter_daemon_lock(void)
{
struct flock lock;
- s_mkdirp(dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
(void) snprintf(daemon_lockfile, sizeof (daemon_lockfile),
- "%s/%s", dev_dir, DAEMON_LOCK_FILE);
+ "%s/%s", etc_dev_dir, DAEMON_LOCK_FILE);
vprint(LOCK_MID, "enter_daemon_lock: lock file %s\n", daemon_lockfile);
@@ -4650,16 +4201,15 @@ recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd)
char *slash;
char new_path[PATH_MAX + 1];
char *anchored_path_re;
- struct dirent *entp;
- DIR *dp;
size_t len;
+ char *pathlist;
+ char *listp;
vprint(RECURSEDEV_MID, "recurse_dev_re: curr = %s path=%s\n",
current_dir, path_re);
- if ((dp = opendir(current_dir)) == NULL) {
+ if ((pathlist = dev_readdir(current_dir)) == NULL)
return;
- }
len = strlen(path_re);
if ((slash = strchr(path_re, '/')) != NULL) {
@@ -4676,18 +4226,13 @@ recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd)
free(anchored_path_re);
- while ((entp = readdir(dp)) != NULL) {
-
- if (strcmp(entp->d_name, ".") == 0 ||
- strcmp(entp->d_name, "..") == 0) {
- continue;
- }
+ for (listp = pathlist; (len = strlen(listp)) > 0; listp += len+1) {
- if (regexec(&re1, entp->d_name, 0, NULL, 0) == 0) {
+ if (regexec(&re1, listp, 0, NULL, 0) == 0) {
/* match */
(void) strcpy(new_path, current_dir);
(void) strcat(new_path, "/");
- (void) strcat(new_path, entp->d_name);
+ (void) strcat(new_path, listp);
vprint(RECURSEDEV_MID, "recurse_dev_re: match, new "
"path = %s\n", new_path);
@@ -4706,7 +4251,7 @@ recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd)
regfree(&re1);
out:
- s_closedir(dp);
+ free(pathlist);
}
/*
@@ -4767,7 +4312,7 @@ devfsadm_link_valid(char *link)
(void) strcat(devlink, "/");
(void) strcat(devlink, link);
- if (lstat(devlink, &sb) != 0) {
+ if (!device_exists(devlink) || lstat(devlink, &sb) != 0) {
return (DEVFSADM_FALSE);
}
@@ -5404,14 +4949,11 @@ get_enum_cache(devfsadm_enumerate_t rules[], int nrules)
/*
* For each RE, search disk and cache any matches on the
- * numeral list. We are careful to use global_dev_dir here since
- * for zones, we want to use the global zone's enumeration as the
- * source for enumeration within the zone. Otherwise, for example,
- * controller numbering would be wrong within the zone.
+ * numeral list.
*/
for (i = 0; i < nrules; i++) {
path_left = s_strdup(setp->re[i]);
- enumerate_recurse(global_dev_dir, path_left, setp, rules, i);
+ enumerate_recurse(dev_dir, path_left, setp, rules, i);
free(path_left);
}
@@ -5434,9 +4976,10 @@ get_enum_cache(devfsadm_enumerate_t rules[], int nrules)
int
get_stat_info(char *namebuf, struct stat *sb)
{
- struct dirent *entp;
- DIR *dp;
char *cp;
+ char *pathlist;
+ char *listp;
+ int len;
if (lstat(namebuf, sb) < 0) {
(void) err_print(LSTAT_FAILED, namebuf, strerror(errno));
@@ -5453,7 +4996,7 @@ get_stat_info(char *namebuf, struct stat *sb)
*/
if ((sb->st_mode & S_IFMT) == S_IFDIR) {
- if ((dp = opendir(namebuf)) == NULL) {
+ if ((pathlist = dev_readdir(namebuf)) == NULL) {
return (DEVFSADM_FAILURE);
}
@@ -5461,22 +5004,21 @@ get_stat_info(char *namebuf, struct stat *sb)
* Search each dir entry looking for a symlink. Return
* the first symlink found in namebuf. Recurse dirs.
*/
- while ((entp = readdir(dp)) != NULL) {
- if (strcmp(entp->d_name, ".") == 0 ||
- strcmp(entp->d_name, "..") == 0) {
- continue;
- }
-
+ for (listp = pathlist;
+ (len = strlen(listp)) > 0; listp += len+1) {
cp = namebuf + strlen(namebuf);
- (void) strcat(namebuf, "/");
- (void) strcat(namebuf, entp->d_name);
+ if ((strlcat(namebuf, "/", PATH_MAX) >= PATH_MAX) ||
+ (strlcat(namebuf, listp, PATH_MAX) >= PATH_MAX)) {
+ *cp = '\0';
+ return (DEVFSADM_FAILURE);
+ }
if (get_stat_info(namebuf, sb) == DEVFSADM_SUCCESS) {
- s_closedir(dp);
+ free(pathlist);
return (DEVFSADM_SUCCESS);
}
*cp = '\0';
}
- s_closedir(dp);
+ free(pathlist);
}
/* no symlink found, so return error */
@@ -5601,10 +5143,11 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp,
char *slash;
char *new_path;
char *numeral_id;
- struct dirent *entp;
- DIR *dp;
+ char *pathlist;
+ char *listp;
+ int len;
- if ((dp = opendir(current_dir)) == NULL) {
+ if ((pathlist = dev_readdir(current_dir)) == NULL) {
return;
}
@@ -5617,29 +5160,24 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp,
*slash = '\0';
}
- while ((entp = readdir(dp)) != NULL) {
-
- if (strcmp(entp->d_name, ".") == 0 ||
- strcmp(entp->d_name, "..") == 0) {
- continue;
- }
+ for (listp = pathlist; (len = strlen(listp)) > 0; listp += len+1) {
/*
- * Returns true if path_left matches entp->d_name
+ * Returns true if path_left matches the list entry.
* If it is the last path component, pass subexp
* so that it will return the corresponding ID in
* numeral_id.
*/
numeral_id = NULL;
- if (match_path_component(path_left, entp->d_name, &numeral_id,
+ if (match_path_component(path_left, listp, &numeral_id,
slash ? 0 : rules[index].subexp)) {
new_path = s_malloc(strlen(current_dir) +
- strlen(entp->d_name) + 2);
+ strlen(listp) + 2);
(void) strcpy(new_path, current_dir);
(void) strcat(new_path, "/");
- (void) strcat(new_path, entp->d_name);
+ (void) strcat(new_path, listp);
if (slash != NULL) {
enumerate_recurse(new_path, slash + 1,
@@ -5658,7 +5196,7 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp,
if (slash != NULL) {
*slash = '/';
}
- s_closedir(dp);
+ free(pathlist);
}
@@ -7007,8 +6545,6 @@ devfsadm_exit(int status)
(void) dlclose(librcm_hdl);
}
- zlist_deleteall_unlocked(); /* dispose of all zones */
-
exit_dev_lock();
exit_daemon_lock();
@@ -7020,14 +6556,10 @@ devfsadm_exit(int status)
}
/*
- * set root_dir, devices_dir, dev_dir using optarg. zone_mode determines
- * whether we're operating on behalf of a zone; in this case, we need to
- * reference some things from the global zone. Note that zone mode and
- * -R don't get along, but that should be OK since zone mode is not
- * a public interface.
+ * set root_dir, devices_dir, dev_dir using optarg.
*/
static void
-set_root_devices_dev_dir(char *dir, int zone_mode)
+set_root_devices_dev_dir(char *dir)
{
size_t len;
@@ -7038,14 +6570,6 @@ set_root_devices_dev_dir(char *dir, int zone_mode)
len = strlen(root_dir) + strlen(DEV) + 1;
dev_dir = s_malloc(len);
(void) snprintf(dev_dir, len, "%s%s", root_dir, DEV);
- if (zone_mode) {
- len = strlen(DEV) + 1;
- global_dev_dir = s_malloc(len);
- (void) snprintf(global_dev_dir, len, "%s", DEV);
- } else {
- global_dev_dir = s_malloc(len);
- (void) snprintf(global_dev_dir, len, "%s%s", root_dir, DEV);
- }
}
/*
@@ -7625,6 +7149,18 @@ alias(char *driver_name, char *alias_name)
/*
* convenience functions
*/
+static int
+s_stat(const char *path, struct stat *sbufp)
+{
+ int rv;
+retry:
+ if ((rv = stat(path, sbufp)) == -1) {
+ if (errno == EINTR)
+ goto retry;
+ }
+ return (rv);
+}
+
static void *
s_malloc(const size_t size)
{
@@ -8478,3 +8014,272 @@ build_and_log_event(char *class, char *subclass, char *node_path,
nvlist_free(nvl);
}
}
+
+static int
+devname_kcall(int subcmd, void *args)
+{
+ int error = 0;
+ char *nvlbuf = NULL;
+ size_t nvlsize;
+
+ switch (subcmd) {
+ case MODDEVNAME_NSMAPS:
+ error = nvlist_pack((nvlist_t *)args, &nvlbuf, &nvlsize, 0, 0);
+ if (error) {
+ err_print("packing MODDEVNAME_NSMAPS failed\n");
+ break;
+ }
+ error = modctl(MODDEVNAME, subcmd, nvlbuf, nvlsize);
+ if (error) {
+ vprint(INFO_MID, "modctl(MODDEVNAME, "
+ "MODDEVNAME_NSMAPS) failed - %s\n",
+ strerror(errno));
+ }
+ free(nvlbuf);
+ nvlist_free(args);
+ break;
+ case MODDEVNAME_LOOKUPDOOR:
+ error = modctl(MODDEVNAME, subcmd, (uintptr_t)args);
+ if (error) {
+ vprint(INFO_MID, "modctl(MODDEVNAME, "
+ "MODDEVNAME_LOOKUPDOOR) failed - %s\n",
+ strerror(errno));
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+static void
+devname_setup_nsmaps(void)
+{
+ int error = 0;
+
+ if (devname_first_call) {
+ devname_first_call = 0;
+ }
+
+ error = di_devname_get_mapinfo(DEVNAME_MASTER_MAP, &devname_maps);
+
+ if (error) {
+ vprint(INFO_MID, "devname_setup_nsmaps: error %d\n", errno);
+ } else {
+#ifdef DEBUG
+ di_devname_print_mapinfo(devname_maps);
+#endif
+ /* pass down the existing map names to kernel */
+ (void) devname_kcall(MODDEVNAME_NSMAPS, (void *)devname_maps);
+ }
+}
+
+static void
+devname_ns_services(uint8_t cmd, char *key, char *map)
+{
+ nvlist_t *nvl = NULL;
+ int32_t error = 0;
+ sdev_door_res_t res;
+
+ vprint(DEVNAME_MID, "devname_ns_services: cmd %d key %s map %s\n",
+ cmd, key, map);
+
+ switch (cmd) {
+ case DEVFSADMD_NS_LOOKUP:
+ vprint(DEVNAME_MID, "calling di_devname_get_mapent\n");
+ error = di_devname_get_mapent(key, map, &nvl);
+ if (nvl == NULL) {
+ error = DEVFSADM_NS_FAILED;
+ goto done;
+ }
+
+ if (error) {
+ nvlist_free(nvl);
+ goto done;
+ }
+
+ if (devname_debug_msg)
+ di_devname_print_mapinfo(nvl);
+
+ vprint(DEVNAME_MID, "calling di_devname_action_on_key for %d\n",
+ cmd);
+ error = di_devname_action_on_key(nvl, cmd, key, (void *)&res);
+ nvlist_free(nvl);
+ break;
+ case DEVFSADMD_NS_READDIR:
+ vprint(DEVNAME_MID, "calling di_devname_get_mapinfo for cmd %d"
+ "\n", cmd);
+ error = di_devname_get_mapinfo(map, &nvl);
+ if (nvl == NULL) {
+ error = DEVFSADM_NS_FAILED;
+ goto done;
+ }
+
+ if (error) {
+ nvlist_free(nvl);
+ goto done;
+ }
+
+ if (devname_debug_msg)
+ di_devname_print_mapinfo(nvl);
+
+ vprint(DEVNAME_MID, "calling di_devname_action_on_key\n");
+ error = di_devname_action_on_key(nvl, cmd, key, (void *)&res);
+ nvlist_free(nvl);
+ break;
+ default:
+ error = DEVFSADM_RUN_NOTSUP;
+ break;
+ }
+
+done:
+ vprint(DEVNAME_MID, "error %d\n", error);
+ res.devfsadm_error = error;
+ (void) door_return((char *)&res, sizeof (struct sdev_door_res),
+ NULL, 0);
+}
+
+/* ARGSUSED */
+static void
+devname_lookup_handler(void *cookie, char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc)
+{
+ int32_t error = 0;
+ door_cred_t dcred;
+ struct dca_impl dci;
+ uint8_t cmd;
+ char *ns_map, *ns_name;
+ sdev_door_res_t res;
+ sdev_door_arg_t *args;
+
+ if (argp == NULL || arg_size == 0) {
+ vprint(DEVNAME_MID, "devname_lookup_handler: argp wrong\n");
+ error = DEVFSADM_RUN_INVALID;
+ goto done;
+ }
+ vprint(DEVNAME_MID, "devname_lookup_handler\n");
+
+ if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) {
+ vprint(DEVNAME_MID, "devname_lookup_handler: cred wrong\n");
+ error = DEVFSADM_RUN_EPERM;
+ goto done;
+ }
+
+ args = (sdev_door_arg_t *)argp;
+ cmd = args->devfsadm_cmd;
+
+ vprint(DEVNAME_MID, "devname_lookup_handler: cmd %d\n", cmd);
+ switch (cmd) {
+ case DEVFSADMD_NS_LOOKUP:
+ case DEVFSADMD_NS_READDIR:
+ ns_name = s_strdup(args->ns_hdl.ns_name);
+ ns_map = s_strdup(args->ns_hdl.ns_map);
+
+ vprint(DEVNAME_MID, " ns_name %s ns_map %s\n", ns_name, ns_map);
+ if (ns_name == NULL || ns_map == NULL) {
+ error = DEVFSADM_RUN_INVALID;
+ goto done;
+ }
+
+ devname_ns_services(cmd, ns_name, ns_map);
+ return;
+ case DEVFSADMD_RUN_ALL:
+ /*
+ * run "devfsadm"
+ */
+ dci.dci_root = "/";
+ dci.dci_minor = NULL;
+ dci.dci_driver = NULL;
+ dci.dci_error = 0;
+ dci.dci_flags = 0;
+ dci.dci_arg = NULL;
+
+ lock_dev();
+ update_drvconf((major_t)-1);
+ dci.dci_flags |= DCA_FLUSH_PATHINST;
+
+ pre_and_post_cleanup(RM_PRE);
+ devi_tree_walk(&dci, DINFOFORCE|DI_CACHE_SNAPSHOT_FLAGS, NULL);
+ error = (int32_t)dci.dci_error;
+ if (!error) {
+ pre_and_post_cleanup(RM_POST);
+ update_database = TRUE;
+ unlock_dev(SYNC_STATE);
+ update_database = FALSE;
+ } else {
+ if (DEVFSADM_DEBUG_ON) {
+ vprint(INFO_MID, "devname_lookup_handler: "
+ "DEVFSADMD_RUN_ALL failed\n");
+ }
+
+ unlock_dev(SYNC_STATE);
+ }
+ break;
+ default:
+ /* log an error here? */
+ error = DEVFSADM_RUN_NOTSUP;
+ break;
+ }
+
+done:
+ vprint(DEVNAME_MID, "devname_lookup_handler: error %d\n", error);
+ res.devfsadm_error = error;
+ (void) door_return((char *)&res, sizeof (struct sdev_door_res),
+ NULL, 0);
+}
+
+/*
+ * Use of the dev filesystem's private readdir does not trigger
+ * the implicit device reconfiguration.
+ *
+ * Note: only useable with paths mounted on an instance of the
+ * dev filesystem.
+ *
+ * Does not return the . and .. entries.
+ * Empty directories are returned as an zero-length list.
+ * ENOENT is returned as a NULL list pointer.
+ */
+static char *
+dev_readdir(char *path)
+{
+ int rv;
+ int64_t bufsiz;
+ char *pathlist;
+ char *p;
+ int len;
+
+ assert((strcmp(path, "/dev") == 0) ||
+ (strncmp(path, "/dev/", 4) == 0));
+
+ rv = modctl(MODDEVREADDIR, path, strlen(path), NULL, &bufsiz);
+ if (rv != 0) {
+ vprint(READDIR_MID, "%s: %s\n", path, strerror(errno));
+ return (NULL);
+ }
+
+ for (;;) {
+ assert(bufsiz != 0);
+ pathlist = s_malloc(bufsiz);
+
+ rv = modctl(MODDEVREADDIR, path, strlen(path),
+ pathlist, &bufsiz);
+ if (rv == 0) {
+ vprint(READDIR_MID, "%s\n", path);
+ vprint(READDIR_ALL_MID, "%s:\n", path);
+ for (p = pathlist; (len = strlen(p)) > 0; p += len+1) {
+ vprint(READDIR_ALL_MID, " %s\n", p);
+ }
+ return (pathlist);
+ }
+ free(pathlist);
+ switch (errno) {
+ case EAGAIN:
+ break;
+ case ENOENT:
+ default:
+ vprint(READDIR_MID, "%s: %s\n", path, strerror(errno));
+ return (NULL);
+ }
+ }
+}