diff options
Diffstat (limited to 'usr/src/lib/libdevinfo/devinfo_devlink.c')
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devlink.c | 103 |
1 files changed, 80 insertions, 23 deletions
diff --git a/usr/src/lib/libdevinfo/devinfo_devlink.c b/usr/src/lib/libdevinfo/devinfo_devlink.c index 5417b88bc3..3bc5dadf6d 100644 --- a/usr/src/lib/libdevinfo/devinfo_devlink.c +++ b/usr/src/lib/libdevinfo/devinfo_devlink.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" +#include "libdevinfo.h" #include "devinfo_devlink.h" #undef DEBUG @@ -205,7 +205,7 @@ get_db_path( } #endif if (dir == NULL) { - dir = hdp->dev_dir; + dir = hdp->db_dir; } (void) snprintf(buf, blen, "%s/%s", dir, fname); @@ -246,6 +246,14 @@ open_db(struct di_devlink_handle *hdp, int flags) get_db_path(hdp, DB_TMP, path, sizeof (path)); } + /* + * Avoid triggering /dev reconfigure for read when not present + */ + if (IS_RDONLY(flags) && + (strncmp(path, "/dev/", 5) == 0) && !device_exists(path)) { + return (-1); + } + if ((fd = open(path, flg, DB_PERMS)) == -1) { return (-1); } @@ -298,12 +306,13 @@ open_db(struct di_devlink_handle *hdp, int flags) static struct di_devlink_handle * handle_alloc(const char *root_dir, uint_t flags) { - char dev_dir[PATH_MAX], path[PATH_MAX]; + char dev_dir[PATH_MAX], path[PATH_MAX], db_dir[PATH_MAX]; struct di_devlink_handle *hdp, proto = {0}; assert(flags == OPEN_RDWR || flags == OPEN_RDONLY); dev_dir[0] = '\0'; + db_dir[0] = '\0'; /* * NULL and the empty string are equivalent to "/" @@ -319,18 +328,24 @@ handle_alloc(const char *root_dir, uint_t flags) /*LINTED*/ assert(sizeof (dev_dir) >= PATH_MAX); #endif - if (realpath(root_dir, dev_dir) == NULL) { + if ((realpath(root_dir, dev_dir) == NULL) || + (realpath(root_dir, db_dir) == NULL)) { return (NULL); } } if (strcmp(dev_dir, "/") == 0) { - (void) strlcpy(dev_dir, DEV, sizeof (dev_dir)); + dev_dir[0] = 0; + db_dir[0] = 0; } else { - (void) strlcat(dev_dir, DEV, sizeof (dev_dir)); + (void) strlcpy(db_dir, dev_dir, sizeof (db_dir)); } + (void) strlcat(dev_dir, DEV, sizeof (dev_dir)); + (void) strlcat(db_dir, ETCDEV, sizeof (db_dir)); + proto.dev_dir = dev_dir; + proto.db_dir = db_dir; proto.flags = flags; proto.lock_fd = -1; @@ -366,6 +381,11 @@ handle_alloc(const char *root_dir, uint_t flags) goto error; } + if ((hdp->db_dir = strdup(proto.db_dir)) == NULL) { + free(hdp->dev_dir); + free(hdp); + goto error; + } return (hdp); @@ -1110,6 +1130,8 @@ link2minor(struct di_devlink_handle *hdp, cache_link_t *clp) cache_link_t *plp; const char *minor_path; char *cp, buf[PATH_MAX], link[PATH_MAX]; + char abspath[PATH_MAX]; + struct stat st; if (TYPE_PRI(attr2type(clp->attr))) { /* @@ -1127,7 +1149,7 @@ link2minor(struct di_devlink_handle *hdp, cache_link_t *clp) /* * If secondary, the primary link is derived from the secondary * link contents. Secondary link contents can have two formats: - * audio -> /dev/sound/0 + * audio -> /dev/sound/0 * fb0 -> fbs/afb0 */ @@ -1162,6 +1184,35 @@ follow_link: /*LINTED*/ assert(sizeof (buf) >= PATH_MAX); #endif + + /* + * A realpath attempt to lookup a dangling link can invoke implicit + * reconfig so verify there's an actual device behind the link first. + */ + if (lstat(link, &st) == -1) + return (NULL); + if (S_ISLNK(st.st_mode)) { + if (s_readlink(link, buf, sizeof (buf)) < 0) + return (NULL); + if (buf[0] != '/') { + char *p; + size_t n = sizeof (abspath); + if (strlcpy(abspath, link, n) >= n) + return (NULL); + p = strrchr(abspath, '/') + 1; + *p = 0; + n = sizeof (abspath) - strlen(p); + if (strlcpy(p, buf, n) >= n) + return (NULL); + } else { + if (strlcpy(abspath, buf, sizeof (abspath)) >= + sizeof (abspath)) + return (NULL); + } + if (!device_exists(abspath)) + return (NULL); + } + if (realpath(link, buf) == NULL || !is_minor_node(buf, &minor_path)) { return (NULL); } @@ -2399,13 +2450,13 @@ do_recurse( recurse_t *rp, int *retp) { - DIR *dp; size_t len; const char *rel; struct stat sbuf; char cur[PATH_MAX], *cp; int i, rv = DI_WALK_CONTINUE; - struct dirent *entp; + finddevhdl_t handle; + char *d_name; if ((rel = rel_path(hdp, dir)) == NULL) @@ -2424,7 +2475,7 @@ do_recurse( (void) dprintf(DBG_STEP, "do_recurse: dir = %s\n", dir); - if ((dp = opendir(dir)) == NULL) + if (finddev_readdir(dir, &handle) != 0) return (DI_WALK_CONTINUE); (void) snprintf(cur, sizeof (cur), "%s/", dir); @@ -2432,14 +2483,12 @@ do_recurse( cp = cur + len; len = sizeof (cur) - len; - while ((entp = readdir(dp)) != NULL) { - - if (strcmp(entp->d_name, ".") == 0 || - strcmp(entp->d_name, "..") == 0) { - continue; - } + for (;;) { + if ((d_name = (char *)finddev_next(handle)) == NULL) + break; - (void) snprintf(cp, len, "%s", entp->d_name); + if (strlcpy(cp, d_name, len) >= len) + break; /* * Skip files we are not interested in. @@ -2475,7 +2524,7 @@ next_entry: break; } - (void) closedir(dp); + finddev_close(handle); return (rv); } @@ -3011,7 +3060,7 @@ exit_update_lock(struct di_devlink_handle *hdp) * returns 1 if contents is a minor node in /devices. * If mn_root is not NULL, mn_root is set to: * if contents is a /dev node, mn_root = contents - * OR + * OR * if contents is a /devices node, mn_root set to the '/' * following /devices. */ @@ -3203,9 +3252,17 @@ daemon_call(const char *root, struct dca_off *dcp) int fd, door_error; sigset_t oset, nset; char synch_door[PATH_MAX]; + struct statvfs svf; + char *prefix; + /* + * If readonly root, assume we are in install + */ + prefix = + (statvfs("/etc/dev", &svf) == 0 && (svf.f_flag & ST_RDONLY)) ? + "/tmp" : (char *)root; (void) snprintf(synch_door, sizeof (synch_door), - "%s/dev/%s", root, DEVFSADM_SYNCH_DOOR); + "%s/etc/dev/%s", prefix, DEVFSADM_SYNCH_DOOR); if ((fd = open(synch_door, O_RDONLY)) == -1) { dcp->dca_error = errno; |