diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/devfsadm/devfsadm.c | 118 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/devfsadm_impl.h | 1 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devperm.c | 46 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_finddev.c | 136 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/libdevinfo.h | 6 |
5 files changed, 169 insertions, 138 deletions
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c index 3ae1e8275b..63d88dad62 100644 --- a/usr/src/cmd/devfsadm/devfsadm.c +++ b/usr/src/cmd/devfsadm/devfsadm.c @@ -3103,8 +3103,9 @@ rm_parent_dir_if_empty(char *pathname) { char *ptr, path[PATH_MAX + 1]; char *fcn = "rm_parent_dir_if_empty: "; - char *pathlist; - int len; + finddevhdl_t fhandle; + const char *f; + int rv; vprint(REMOVE_MID, "%schecking %s if empty\n", fcn, pathname); @@ -3122,17 +3123,17 @@ rm_parent_dir_if_empty(char *pathname) *ptr = '\0'; - if ((pathlist = dev_readdir(path)) == NULL) { - err_print(OPENDIR_FAILED, path, strerror(errno)); + if ((rv = finddev_readdir(path, &fhandle)) != 0) { + err_print(OPENDIR_FAILED, path, strerror(rv)); return; } /* * An empty pathlist implies an empty directory */ - len = strlen(pathlist); - free(pathlist); - if (len == 0) { + f = finddev_next(fhandle); + finddev_close(fhandle); + if (f == NULL) { if (s_rmdir(path) == 0) { vprint(REMOVE_MID, "%sremoving empty dir %s\n", fcn, path); @@ -4219,13 +4220,13 @@ recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd) char new_path[PATH_MAX + 1]; char *anchored_path_re; size_t len; - char *pathlist; - char *listp; + finddevhdl_t fhandle; + const char *fp; vprint(RECURSEDEV_MID, "recurse_dev_re: curr = %s path=%s\n", current_dir, path_re); - if ((pathlist = dev_readdir(current_dir)) == NULL) + if (finddev_readdir(current_dir, &fhandle) != 0) return; len = strlen(path_re); @@ -4243,13 +4244,13 @@ recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd) free(anchored_path_re); - for (listp = pathlist; (len = strlen(listp)) > 0; listp += len+1) { + while ((fp = finddev_next(fhandle)) != NULL) { - if (regexec(&re1, listp, 0, NULL, 0) == 0) { + if (regexec(&re1, fp, 0, NULL, 0) == 0) { /* match */ (void) strcpy(new_path, current_dir); (void) strcat(new_path, "/"); - (void) strcat(new_path, listp); + (void) strcat(new_path, fp); vprint(RECURSEDEV_MID, "recurse_dev_re: match, new " "path = %s\n", new_path); @@ -4268,7 +4269,7 @@ recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd) regfree(&re1); out: - free(pathlist); + finddev_close(fhandle); } /* @@ -5016,9 +5017,8 @@ int get_stat_info(char *namebuf, struct stat *sb) { char *cp; - char *pathlist; - char *listp; - int len; + finddevhdl_t fhandle; + const char *fp; if (lstat(namebuf, sb) < 0) { (void) err_print(LSTAT_FAILED, namebuf, strerror(errno)); @@ -5035,7 +5035,7 @@ get_stat_info(char *namebuf, struct stat *sb) */ if ((sb->st_mode & S_IFMT) == S_IFDIR) { - if ((pathlist = dev_readdir(namebuf)) == NULL) { + if (finddev_readdir(namebuf, &fhandle) != 0) { return (DEVFSADM_FAILURE); } @@ -5043,21 +5043,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. */ - for (listp = pathlist; - (len = strlen(listp)) > 0; listp += len+1) { + while ((fp = finddev_next(fhandle)) != NULL) { cp = namebuf + strlen(namebuf); if ((strlcat(namebuf, "/", PATH_MAX) >= PATH_MAX) || - (strlcat(namebuf, listp, PATH_MAX) >= PATH_MAX)) { + (strlcat(namebuf, fp, PATH_MAX) >= PATH_MAX)) { *cp = '\0'; + finddev_close(fhandle); return (DEVFSADM_FAILURE); } if (get_stat_info(namebuf, sb) == DEVFSADM_SUCCESS) { - free(pathlist); + finddev_close(fhandle); return (DEVFSADM_SUCCESS); } *cp = '\0'; } - free(pathlist); + finddev_close(fhandle); } /* no symlink found, so return error */ @@ -5182,11 +5182,10 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, char *slash; char *new_path; char *numeral_id; - char *pathlist; - char *listp; - int len; + finddevhdl_t fhandle; + const char *fp; - if ((pathlist = dev_readdir(current_dir)) == NULL) { + if (finddev_readdir(current_dir, &fhandle) != 0) { return; } @@ -5199,7 +5198,7 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, *slash = '\0'; } - for (listp = pathlist; (len = strlen(listp)) > 0; listp += len+1) { + while ((fp = finddev_next(fhandle)) != NULL) { /* * Returns true if path_left matches the list entry. @@ -5208,15 +5207,15 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, * numeral_id. */ numeral_id = NULL; - if (match_path_component(path_left, listp, &numeral_id, + if (match_path_component(path_left, (char *)fp, &numeral_id, slash ? 0 : rules[index].subexp)) { new_path = s_malloc(strlen(current_dir) + - strlen(listp) + 2); + strlen(fp) + 2); (void) strcpy(new_path, current_dir); (void) strcat(new_path, "/"); - (void) strcat(new_path, listp); + (void) strcat(new_path, fp); if (slash != NULL) { enumerate_recurse(new_path, slash + 1, @@ -5235,7 +5234,7 @@ enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, if (slash != NULL) { *slash = '/'; } - free(pathlist); + finddev_close(fhandle); } @@ -8372,58 +8371,3 @@ done: (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); - } - } -} diff --git a/usr/src/cmd/devfsadm/devfsadm_impl.h b/usr/src/cmd/devfsadm/devfsadm_impl.h index 5217649e7b..71f167d230 100644 --- a/usr/src/cmd/devfsadm/devfsadm_impl.h +++ b/usr/src/cmd/devfsadm/devfsadm_impl.h @@ -494,7 +494,6 @@ static nvlist_t *build_event_attributes(char *, char *, char *, di_node_t, char *, int); static void log_event(char *, char *, nvlist_t *); static void build_and_log_event(char *, char *, char *, di_node_t); -static char *dev_readdir(char *); static void read_logindevperm_file(void); static void set_logindev_perms(char *devlink); diff --git a/usr/src/lib/libdevinfo/devinfo_devperm.c b/usr/src/lib/libdevinfo/devinfo_devperm.c index 18e2409065..e9a9ea1696 100644 --- a/usr/src/lib/libdevinfo/devinfo_devperm.c +++ b/usr/src/lib/libdevinfo/devinfo_devperm.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -384,8 +384,6 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, { struct stat stat_buf; int err = 0; - DIR *dirp; - struct dirent *direntp; char errstring[MAX_LINELEN]; char *p; regex_t regex; @@ -393,7 +391,6 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, char *match; char *name, *newpath, *remainder_path; finddevhdl_t handle; - int find_method; /* * Determine if the search needs to be performed via finddev, @@ -403,13 +400,7 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, * reconfig for names managed by logindevperm but not present * on the system. */ - find_method = ((getzoneid() == GLOBAL_ZONEID) && - ((strcmp(path, "/dev") == 0) || - (strncmp(path, "/dev/", 5) == 0))) ? - FLAG_USE_FINDDEV : FLAG_USE_READDIR; - - /* path must be a valid name */ - if (find_method == FLAG_USE_FINDDEV && !device_exists(path)) { + if (!device_exists(path)) { return (-1); } if (stat(path, &stat_buf) == -1) { @@ -444,24 +435,20 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, } } - if (find_method == FLAG_USE_READDIR) { - dirp = opendir(path); - if (dirp == NULL) - return (0); - } else { - if (finddev_readdir(path, &handle) != 0) - return (0); - } + if (finddev_readdir(path, &handle) != 0) + return (0); p = strchr(left_to_do, '/'); alwaysmatch = 0; newpath = (char *)malloc(MAXPATHLEN); if (newpath == NULL) { + finddev_close(handle); return (-1); } match = (char *)calloc(MAXPATHLEN, 1); if (match == NULL) { + finddev_close(handle); free(newpath); return (-1); } @@ -478,23 +465,12 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, if (regcomp(®ex, match, REG_EXTENDED) != 0) { free(newpath); free(match); + finddev_close(handle); return (-1); } } - for (;;) { - if (find_method == FLAG_USE_READDIR) { - if ((direntp = readdir(dirp)) == NULL) - break; - name = direntp->d_name; - if ((strcmp(name, ".") == 0) || - (strcmp(name, "..") == 0)) - continue; - } else { - if ((name = (char *)finddev_next(handle)) == NULL) - break; - } - + while ((name = (char *)finddev_next(handle)) != NULL) { if (alwaysmatch || regexec(®ex, name, 0, NULL, 0) == 0) { if (strcmp(path, "/") == 0) { @@ -518,11 +494,7 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, } } - if (find_method == FLAG_USE_READDIR) { - (void) closedir(dirp); - } else { - finddev_close(handle); - } + finddev_close(handle); free(newpath); free(match); if (!alwaysmatch) { diff --git a/usr/src/lib/libdevinfo/devinfo_finddev.c b/usr/src/lib/libdevinfo/devinfo_finddev.c index 1b89afb7b3..28ce5e3f1b 100644 --- a/usr/src/lib/libdevinfo/devinfo_finddev.c +++ b/usr/src/lib/libdevinfo/devinfo_finddev.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,9 +40,10 @@ #include <errno.h> #include <stdarg.h> #include <libdevinfo.h> +#include <zone.h> #include <sys/modctl.h> #include <syslog.h> - +#include <sys/stat.h> #include <assert.h> @@ -53,17 +54,125 @@ struct finddevhdl { }; +/* + * Return true if a device exists + * If the path refers into the /dev filesystem, use a + * private interface to query if the device exists but + * without triggering an implicit reconfig if it does not. + * Note: can only function properly with absolute pathnames + * and only functions for persisted global /dev names, ie + * those managed by devfsadm. For paths other than + * /dev, stat(2) is sufficient. + */ int device_exists(const char *devname) { int rv; + struct stat st; - rv = modctl(MODDEVEXISTS, devname, strlen(devname)); - return ((rv == 0) ? 1 : 0); + if ((getzoneid() == GLOBAL_ZONEID) && + ((strcmp(devname, "/dev") == 0) || + (strncmp(devname, "/dev/", 5) == 0))) { + rv = modctl(MODDEVEXISTS, devname, strlen(devname)); + return ((rv == 0) ? 1 : 0); + } + if (stat(devname, &st) == 0) + return (1); + return (0); } -int -finddev_readdir(const char *dir, finddevhdl_t *handlep) + +/* + * Use the standard library readdir to read the contents of + * directories on alternate root mounted filesystems. + * Return results as per dev_readdir_devfs(). + * + * The directory is traversed twice. First, to calculate + * the size of the buffer required; second, to copy the + * directory contents into the buffer. If the directory + * contents grow in between passes, which should almost + * never happen, start over again. + */ +static int +finddev_readdir_alt(const char *path, finddevhdl_t *handlep) +{ + struct finddevhdl *handle; + DIR *dir; + struct dirent *dp; + size_t n; + + *handlep = NULL; + if ((dir = opendir(path)) == NULL) + return (ENOENT); + +restart: + handle = calloc(1, sizeof (struct finddevhdl)); + if (handle == NULL) { + (void) closedir(dir); + return (ENOMEM); + } + + handle->npaths = 0; + handle->curpath = 0; + handle->paths = NULL; + + n = 0; + rewinddir(dir); + while ((dp = readdir(dir)) != NULL) { + if ((strcmp(dp->d_name, ".") == 0) || + (strcmp(dp->d_name, "..") == 0)) + continue; + n++; + } + + handle->npaths = n; + handle->paths = calloc(n, sizeof (char *)); + if (handle->paths == NULL) { + free(handle); + (void) closedir(dir); + return (ENOMEM); + } + + n = 0; + rewinddir(dir); + while ((dp = readdir(dir)) != NULL) { + if ((strcmp(dp->d_name, ".") == 0) || + (strcmp(dp->d_name, "..") == 0)) + continue; + if (n == handle->npaths) { + /* + * restart if directory contents have out-grown + * buffer allocated in the first pass. + */ + finddev_close((finddevhdl_t)handle); + goto restart; + } + handle->paths[n] = strdup(dp->d_name); + if (handle->paths[n] == NULL) { + (void) closedir(dir); + finddev_close((finddevhdl_t)handle); + return (ENOMEM); + } + n++; + } + (void) closedir(dir); + *handlep = (finddevhdl_t)handle; + return (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 int +finddev_readdir_devfs(const char *path, finddevhdl_t *handlep) { struct finddevhdl *handle; int n; @@ -82,7 +191,7 @@ finddev_readdir(const char *dir, finddevhdl_t *handlep) handle->curpath = 0; handle->paths = NULL; - rv = modctl(MODDEVREADDIR, dir, strlen(dir), NULL, &bufsiz); + rv = modctl(MODDEVREADDIR, path, strlen(path), NULL, &bufsiz); if (rv != 0) { free(handle); return (rv); @@ -95,7 +204,7 @@ finddev_readdir(const char *dir, finddevhdl_t *handlep) return (ENOMEM); } - rv = modctl(MODDEVREADDIR, dir, strlen(dir), + rv = modctl(MODDEVREADDIR, path, strlen(path), pathlist, &bufsiz); if (rv == 0) { for (n = 0, p = pathlist; @@ -135,6 +244,17 @@ finddev_readdir(const char *dir, finddevhdl_t *handlep) /*NOTREACHED*/ } +int +finddev_readdir(const char *path, finddevhdl_t *handlep) +{ + if ((getzoneid() == GLOBAL_ZONEID) && + ((strcmp(path, "/dev") == 0) || + (strncmp(path, "/dev/", 4) == 0))) { + return (finddev_readdir_devfs(path, handlep)); + } + return (finddev_readdir_alt(path, handlep)); +} + void finddev_close(finddevhdl_t arg) { diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h index 56c4b4982c..d570e8e714 100644 --- a/usr/src/lib/libdevinfo/libdevinfo.h +++ b/usr/src/lib/libdevinfo/libdevinfo.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -413,10 +413,6 @@ extern int finddev_readdir(const char *, finddevhdl_t *); extern void finddev_close(finddevhdl_t); extern const char *finddev_next(finddevhdl_t); -/* For interfaces implementing search either by readdir or finddev */ -#define FLAG_USE_READDIR 0 -#define FLAG_USE_FINDDEV 1 - /* * Private interfaces for non-global /dev profile |