diff options
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/libc/port/gen/pt.c | 128 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/Makefile.com | 3 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devlink.c | 103 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devlink.h | 10 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devname.c | 701 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devperm.c | 152 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_finddev.c | 163 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/libdevinfo.h | 45 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/mapfile-vers | 15 | ||||
-rw-r--r-- | usr/src/lib/libtsol/common/label.h | 8 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/common/libzonecfg.c | 298 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/common/mapfile-vers | 5 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 | 20 |
13 files changed, 1178 insertions, 473 deletions
diff --git a/usr/src/lib/libc/port/gen/pt.c b/usr/src/lib/libc/port/gen/pt.c index 2aa63e92e2..86bcd319c3 100644 --- a/usr/src/lib/libc/port/gen/pt.c +++ b/usr/src/lib/libc/port/gen/pt.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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,15 +57,14 @@ #include <thread.h> #include <spawn.h> #include <libc.h> +#include <grp.h> #include "tsd.h" #define PTSNAME "/dev/pts/" /* slave name */ #define PTLEN 32 /* slave name length */ -#define PTPATH "/usr/lib/pt_chmod" /* setuid root program */ -#define PTPGM "pt_chmod" /* setuid root program */ +#define DEFAULT_TTY_GROUP "tty" /* slave device group owner */ static void itoa(int, char *); -static int grantpt_u(int, int); /* * Check that fd argument is a file descriptor of an opened master. @@ -94,18 +92,6 @@ ptsdev(int fd) return (minor(status.st_rdev)); } -static int -ptscreate(void) -{ - static mutex_t clk = DEFAULTMUTEX; - int ret; - - lmutex_lock(&clk); - ret = grantpt_u(-1, 1); - lmutex_unlock(&clk); - return (ret); -} - char * ptsname(int fd) { @@ -122,12 +108,12 @@ ptsname(int fd) itoa(dev, sname + strlen(PTSNAME)); /* - * devfsadm synchronization: if the node does not exist, - * attempt to synchronize with slave device node creation. + * This lookup will create the /dev/pts node (if the corresponding + * pty exists. */ - if (access(sname, F_OK) == 0 || - (ptscreate() == 0 && access(sname, F_OK) == 0)) + if (access(sname, F_OK) == 0) return (sname); + return (NULL); } @@ -151,92 +137,36 @@ unlockpt(int fd) return (0); } - -/* - * Execute a setuid root program to change the mode, ownership and - * group of the slave device. The parent forks a child process that - * executes the setuid program. It then waits for the child to return. - * - * When create is 1, execute the setuid root program without arguments, - * to create minor nodes and symlinks for all slave devices. - */ -static int -grantpt_u(int fd, int create) +int +grantpt(int fd) { - extern char **environ; - char *argvec[3]; - int st_loc; - pid_t pid; - int w; - char fds[24]; - sigset_t oset, nset; - int error; + struct strioctl istr; + pt_own_t pto; + struct group *gr_name; /* validate the file descriptor before proceeding */ - if (create != 1 && ptsdev(fd) == NODEV) - return (-1); - - if (sigemptyset(&nset) == -1) - return (-1); - if (sigaddset(&nset, SIGCHLD) == -1) - return (-1); - if (sigprocmask(SIG_BLOCK, &nset, &oset) == -1) + if (ptsdev(fd) == NODEV) return (-1); - itoa(fd, fds); - argvec[0] = PTPGM; - argvec[1] = create == 1 ? NULL : fds; - argvec[2] = NULL; - error = posix_spawn(&pid, PTPATH, NULL, NULL, argvec, environ); - if (error) { - (void) sigprocmask(SIG_SETMASK, &oset, NULL); - errno = error; - return (-1); - } + pto.pto_ruid = getuid(); - /* - * waitpid() returns the process id for the child process - * on success or -1 on failure. - */ - while ((w = waitpid(pid, &st_loc, 0)) < 0 && errno == EINTR) - continue; + gr_name = getgrnam(DEFAULT_TTY_GROUP); + if (gr_name) + pto.pto_rgid = gr_name->gr_gid; + else + pto.pto_rgid = getgid(); - /* Restore signal mask */ - (void) sigprocmask(SIG_SETMASK, &oset, NULL); + istr.ic_cmd = PT_OWNER; + istr.ic_len = sizeof (pt_own_t); + istr.ic_timout = 0; + istr.ic_dp = (char *)&pto; - /* - * If SIGCHLD is currently ignored, waitpid() fails with - * ECHILD after the child terminates. - * This is not a failure; assume the child succeded. - */ - if (w == -1) { - if (errno != ECHILD) - return (-1); - st_loc = 0; + if (ioctl(fd, I_STR, &istr) != 0) { + errno = EACCES; + return (-1); } - /* - * If child terminated due to exit() and the exit status is zero - * return success - * else it was an exit(-1) or it was struck by a signal - * return failure (EACCES) - */ - if (WIFEXITED(st_loc) && WEXITSTATUS(st_loc) == 0) - return (0); - errno = EACCES; - return (-1); -} - -int -grantpt(int fd) -{ - static mutex_t glk = DEFAULTMUTEX; - int ret; - - lmutex_lock(&glk); - ret = grantpt_u(fd, 0); - lmutex_unlock(&glk); - return (ret); + return (0); } /* diff --git a/usr/src/lib/libdevinfo/Makefile.com b/usr/src/lib/libdevinfo/Makefile.com index 048c28653f..adcea87c26 100644 --- a/usr/src/lib/libdevinfo/Makefile.com +++ b/usr/src/lib/libdevinfo/Makefile.com @@ -29,7 +29,8 @@ LIBRARY= libdevinfo.a VERS= .1 OBJECTS= devfsinfo.o devinfo.o devinfo_prop_decode.o devinfo_devlink.o \ - devinfo_devperm.o devfsmap.o devinfo_dli.o + devinfo_devperm.o devfsmap.o devinfo_devname.o \ + devinfo_finddev.o devinfo_dli.o include ../../Makefile.lib include ../../Makefile.rootfs 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; diff --git a/usr/src/lib/libdevinfo/devinfo_devlink.h b/usr/src/lib/libdevinfo/devinfo_devlink.h index 0bee7f4c39..d16bb7e52d 100644 --- a/usr/src/lib/libdevinfo/devinfo_devlink.h +++ b/usr/src/lib/libdevinfo/devinfo_devlink.h @@ -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. @@ -19,7 +18,7 @@ * * 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. */ @@ -56,6 +55,7 @@ extern "C" { #include <sys/wait.h> #include <door.h> #include <signal.h> +#include <sys/statvfs.h> struct db_link { uint32_t attr; /* primary or secondary */ @@ -143,6 +143,7 @@ struct db { struct di_devlink_handle { char *dev_dir; /* <root-dir>/dev */ + char *db_dir; /* <root-dir>/etc/dev */ uint_t flags; /* handle flags */ uint_t error; /* records errors encountered */ int lock_fd; /* lock file for updates */ @@ -199,6 +200,7 @@ typedef enum { #define DB_NIL 0 #define DEV "/dev" +#define ETCDEV "/etc/dev" #define DEVICES_SUFFIX "ices" #define HDR_LEN sizeof (struct db_hdr) diff --git a/usr/src/lib/libdevinfo/devinfo_devname.c b/usr/src/lib/libdevinfo/devinfo_devname.c new file mode 100644 index 0000000000..379c156627 --- /dev/null +++ b/usr/src/lib/libdevinfo/devinfo_devname.c @@ -0,0 +1,701 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <unistd.h> +#include <stdarg.h> +#include <fcntl.h> +#include <stdlib.h> +#include <libnvpair.h> +#include <libdevinfo.h> +#include <syslog.h> +#include <sys/param.h> +#include <errno.h> +#include <assert.h> +#include <sys/systeminfo.h> +#include <sys/modctl.h> +#include <sys/fs/sdev_node.h> + + +#define LINEMAX 1024 +#define SPC " \t\n" +#define QUOTES "\'\"" + +/* + * This is for local file supports of DBNR configurations. + */ +static int di_devname_getmapent_files(char *, char *, nvlist_t **); +static int di_devname_get_mapinfo_files(char *, nvlist_t **); +static int parse_mapinfo_file(FILE *, nvlist_t **); +static FILE *open_local_map(char *); +static void unquote(char *, char *); + +static int msglog = 1; +typedef enum { + DBG_ERR = 1, + DBG_INFO, + DBG_STEP, + DBG_ALL +} debug_level_t; +static int devname_debug = 1; +static void dprintf(debug_level_t, const char *, ...); + +extern int isspace(int); + +/* exported interfaces */ +void di_devname_print_mapinfo(nvlist_t *); +int di_devname_get_mapinfo(char *, nvlist_t **); +int di_devname_get_mapent(char *, char *, nvlist_t **); +int di_devname_action_on_key(nvlist_t *, uint8_t, char *, void *); + +/* + * Returns 0 and the valid maplist, otherwise errno. + */ +int +di_devname_get_mapinfo_files(char *mapname, nvlist_t **maplist) +{ + FILE *fp; + int rval = 0; + nvlist_t *nvl = NULL; + + fp = open_local_map(mapname); + if (fp == NULL) { + dprintf(DBG_INFO, "di_devname_get_mapinfo_files: file %s does" + "not exist\n", mapname); + return (ENOENT); + } + + rval = parse_mapinfo_file(fp, &nvl); + if (rval == 0) { + *maplist = nvl; + } + (void) fclose(fp); + + return (rval); +} + +static FILE * +open_local_map(char *mapname) +{ + char filename[LINEMAX]; + + if (*mapname != '/') { + (void) snprintf(filename, sizeof (filename), "/etc/dev/%s", + mapname); + } else { + (void) snprintf(filename, sizeof (filename), "%s", mapname); + } + + return (fopen(filename, "r")); +} + +static void +unquote(char *str, char *qbuf) +{ + register int escaped, inquote, quoted; + register char *ip, *bp, *qp; + char buf[LINEMAX]; + + escaped = inquote = quoted = 0; + + for (ip = str, bp = buf, qp = qbuf; *ip; ip++) { + if (!escaped) { + if (*ip == '\\') { + escaped = 1; + quoted ++; + continue; + } else if (*ip == '"') { + inquote = !inquote; + quoted ++; + continue; + } + } + + *bp++ = *ip; + *qp++ = (inquote || escaped) ? '^' : ' '; + escaped = 0; + } + *bp = '\0'; + *qp = '\0'; + if (quoted) + (void) strcpy(str, buf); +} + +/* + * gets the qualified characters in *p into w, which has space allocated + * already + */ +static int +getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz) +{ + char *tmp = w; + char *tmpq = wq; + int count = wordsz; + + if (wordsz <= 0) { + return (-1); + } + + while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ') { + (*p)++; + (*pq)++; + } + + while (**p && + !((delim == ' ' ? isspace(**p) : **p == delim) && + **pq == ' ')) { + if (--count <= 0) { + *tmp = '\0'; + *tmpq = '\0'; + dprintf(DBG_INFO, "maximum word length %d exceeded\n", + wordsz); + return (-1); + } + *w++ = *(*p)++; + *wq++ = *(*pq)++; + } + *w = '\0'; + *wq = '\0'; + return (0); +} + +static int +parse_mapinfo_file(FILE *fp, nvlist_t **ret_nvlp) +{ + int error = 0; + nvlist_t *nvl = NULL, *attrs = NULL; + char line[LINEMAX], lineq[LINEMAX]; + char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; + char *lp, *lq; + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { + return (EFAULT); + } + + while (fgets(line, sizeof (line), fp)) { + char *name, *key, *val; + + lp = (char *)line; + lq = (char *)lineq; + unquote(lp, lq); + if ((getword(word, wordq, &lp, &lq, ' ', + sizeof (word)) == -1) || (word[0] == '\0')) + continue; + + if (word[0] == '#') + continue; + + name = strtok(line, SPC); + if (name == NULL) + continue; + + (void) dprintf(DBG_INFO, "get a line for %s\n", name); + key = strtok(NULL, "="); + if (key == NULL) { + (void) dprintf(DBG_INFO, "no attributes specified for " + "%s\n", name); + continue; + } + + attrs = NULL; + if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) { + error = EFAULT; + goto fail1; + } + + while (key && *key) { + char *rest; + rest = strtok(NULL, "\n"); + if (rest == NULL) { + (void) dprintf(DBG_INFO, "no value for key " + "%s\n", key); + break; + } + if (rest[0] == ';') { + val = strdup("devname_null"); + rest++; + } else { + val = strtok(rest, ";"); + rest = strtok(NULL, ""); + } + (void) dprintf(DBG_INFO, "parse_map_info: one entry " + "key=%s val=%s\n", key, val); + if (nvlist_add_string(attrs, key, val) != 0) { + error = EFAULT; + goto fail; + } + + key = strtok(rest, "="); + } + (void) dprintf(DBG_INFO, "parse_map_info: add entry name=%s\n", + name); + if (nvlist_add_nvlist(nvl, name, attrs) != 0) { + error = EFAULT; + goto fail; + } + } + +done: + *ret_nvlp = nvl; + return (0); + +fail: + nvlist_free(attrs); +fail1: + nvlist_free(nvl); + return (error); +} + +void +di_devname_print_mapinfo(nvlist_t *nvl) +{ + char *name, *key, *val; + nvlist_t *attrs; + nvpair_t *nvp, *kvp; + + nvp = nvlist_next_nvpair(nvl, NULL); + while (nvp) { + name = nvpair_name(nvp); + (void) nvpair_value_nvlist(nvp, &attrs); + (void) printf("name = %s, binding attributes:\n", name); + kvp = nvlist_next_nvpair(attrs, NULL); + while (kvp) { + key = nvpair_name(kvp); + (void) nvpair_value_string(kvp, &val); + (void) printf("\t%s = %s\n", key, val); + kvp = nvlist_next_nvpair(attrs, kvp); + } + nvp = nvlist_next_nvpair(nvl, nvp); + } +} + +static int +action_mklink(char *target, char *source) +{ + (void) dprintf(DBG_INFO, "mklink for source %s target %s\n", + source, target); + return (symlink(source, target)); +} + +static struct actions { + char *key; + devname_spec_t spec; + int (*action)(char *, char *); +} actions[] = { + {"devices-path", DEVNAME_NS_PATH, action_mklink}, + {"dev-path", DEVNAME_NS_DEV, action_mklink}, + {NULL, DEVNAME_NS_NONE, NULL} +}; + +static int +action_on_key(uint_t cmd, char *dir_name, char *devname, nvpair_t *attr, + uint32_t *nsmapcount, char **devfsadm_link, devname_spec_t *devfsadm_spec) +{ + int i = 0; + int error = 0; + char *attrname, *attrval; + int len = 0; + char *path = NULL; + + attrname = nvpair_name(attr); + (void) nvpair_value_string(attr, &attrval); + (void) dprintf(DBG_INFO, "key = %s; value = %s\n", attrname, attrval); + + while (actions[i].key) { + if (strcmp(actions[i].key, attrname) == 0) { + switch (cmd) { + case DEVFSADMD_NS_READDIR: + len = strlen(dir_name) + strlen(devname) + 2; + path = malloc(len); + (void) snprintf(path, len, "%s/%s", dir_name, + devname); + error = actions[i].action(path, attrval); + free(path); + if (error) { + (void) dprintf(DBG_INFO, "action " + "failed %d\n", error); + return (error); + } else { + (*nsmapcount)++; + (void) dprintf(DBG_INFO, + "mapcount %d\n", *nsmapcount); + } + break; + case DEVFSADMD_NS_LOOKUP: + *devfsadm_link = strdup(attrval); + *devfsadm_spec = actions[i].spec; + break; + default: + break; + } + } + i++; + } + return (0); +} + +int +di_devname_action_on_key(nvlist_t *map, uint8_t cmd, char *dir_name, void *hdl) +{ + char *name = NULL; + nvpair_t *entry; + nvlist_t *attrs; + int32_t error = 0; + uint32_t ns_mapcount = 0; + char *devfsadm_link = NULL; + devname_spec_t devfsadm_spec = DEVNAME_NS_NONE; + sdev_door_res_t *resp; + + entry = nvlist_next_nvpair(map, NULL); + while (entry) { + nvpair_t *attr; + name = nvpair_name(entry); + (void) dprintf(DBG_INFO, "di_devname_action_on_key: name %s\n", + name); + (void) nvpair_value_nvlist(entry, &attrs); + + attr = nvlist_next_nvpair(attrs, NULL); + while (attr) { + error = action_on_key(cmd, dir_name, name, attr, + &ns_mapcount, &devfsadm_link, &devfsadm_spec); + + /* do not continue if encountered the first error */ + if (error) { + (void) dprintf(DBG_INFO, "error %d\n", error); + return ((int32_t)error); + } + attr = nvlist_next_nvpair(attrs, attr); + } + entry = nvlist_next_nvpair(map, entry); + } + + resp = (sdev_door_res_t *)hdl; + (void) dprintf(DBG_INFO, "cmd is %d\n", cmd); + switch (cmd) { + case DEVFSADMD_NS_READDIR: + resp->ns_rdr_hdl.ns_mapcount = (uint32_t)ns_mapcount; + (void) dprintf(DBG_INFO, "mapcount is %d\n", ns_mapcount); + break; + case DEVFSADMD_NS_LOOKUP: + if (devfsadm_link && devfsadm_spec != DEVNAME_NS_NONE) { + (void) dprintf(DBG_INFO, "devfsadm_link is %s\n", + devfsadm_link); + (void) snprintf(resp->ns_lkp_hdl.devfsadm_link, + strlen(devfsadm_link) + 1, "%s", devfsadm_link); + resp->ns_lkp_hdl.devfsadm_spec = devfsadm_spec; + } else { + (void) dprintf(DBG_INFO, "error out\n"); + return (1); + } + break; + default: + (void) dprintf(DBG_INFO, "error NOTSUP out\n"); + return (ENOTSUP); + } + + return (0); +} + + +static nvlist_t * +getent_mapinfo_file(FILE *fp, char *match) +{ + nvlist_t *nvl, *attrs; + char line[LINEMAX], lineq[LINEMAX]; + char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; + int count = 0; + char *lp, *lq; + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) + return (NULL); + + while (fgets(line, sizeof (line), fp)) { + char *name, *key, *val; + + if (line[0] == '#') + continue; + + dprintf(DBG_INFO, "getent_mapinfo_file: get a line %s\n", line); + lp = (char *)line; + lq = (char *)lineq; + unquote(lp, lq); + if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word)) + == -1) || (word[0] == '\0')) + continue; + + name = strtok(line, SPC); + if (name == NULL) + continue; + + dprintf(DBG_INFO, "macthing with the key %s match %s\n", + name, match); + /* bypass the non-related entries */ + if (strcmp(name, match) != 0) + continue; + + /* get a matched entry */ + key = strtok(NULL, "="); + if (key == NULL) { + (void) dprintf(DBG_INFO, "no attributes specified " + "for %s\n", name); + goto fail1; + } + + attrs = NULL; + if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) + goto fail1; + while (key && *key) { + char *rest; + rest = strtok(NULL, "\n"); + if (rest == NULL) { + (void) dprintf(DBG_INFO, "no value for key " + "%s\n", key); + goto fail; + } + if (rest[0] == ';') { + val = strdup("devname_null"); + rest++; + } else { + val = strtok(rest, ";"); + rest = strtok(NULL, ""); + } + (void) dprintf(DBG_INFO, "found entry %s %s for %s\n", + key, val, name); + if (nvlist_add_string(attrs, key, val) != 0) + goto fail; + + key = strtok(rest, "="); + } + (void) dprintf(DBG_INFO, "adding nvlist for %s\n", name); + if (nvlist_add_nvlist(nvl, name, attrs) != 0) + goto fail; + count++; + break; + } + + if (count == 0) + goto fail1; + + return (nvl); + +fail: + nvlist_free(attrs); +fail1: + nvlist_free(nvl); + errno = EFAULT; + return (NULL); +} + +static int +di_devname_getmapent_files(char *key, char *mapname, nvlist_t **map) +{ + FILE *fp; + int rval = 0; + nvlist_t *nvl = NULL; + + fp = open_local_map(mapname); + if (fp == NULL) + return (1); + + nvl = getent_mapinfo_file(fp, key); + if (nvl != NULL) { + *map = nvl; + } else { + rval = errno; + } + (void) fclose(fp); + + return (rval); +} + +int +di_devname_get_mapent(char *key, char *mapname, nvlist_t **map) +{ + dprintf(DBG_INFO, "di_devname_get_mapent: called for %s in %s\n", + key, mapname); + + return (di_devname_getmapent_files(key, mapname, map)); + +} + +int +di_devname_get_mapinfo(char *mapname, nvlist_t **maps) +{ + dprintf(DBG_INFO, "di_devname_get_mapinfo: called for %s\n", mapname); + + return (di_devname_get_mapinfo_files(mapname, maps)); +} + +static void +debug_print(debug_level_t msglevel, const char *fmt, va_list ap) +{ + if (devname_debug < msglevel) + return; + + /* Print a distinctive label for error msgs */ + if (msglevel == DBG_ERR) { + (void) fprintf(stderr, "[ERROR]: "); + } + + if (msglog == TRUE) { + (void) vsyslog(LOG_NOTICE, fmt, ap); + } else { + (void) vfprintf(stderr, fmt, ap); + } +} + +/* ARGSUSED */ +/* PRINTFLIKE2 */ +static void +dprintf(debug_level_t msglevel, const char *fmt, ...) +{ + va_list ap; + + assert(msglevel > 0); + + if (!devname_debug) + return; + + va_start(ap, fmt); + debug_print(msglevel, fmt, ap); + va_end(ap); +} + + +/* + * Private interfaces for non-global /dev profile + */ + +/* + * Allocate opaque data structure for passing profile to the kernel for + * the given mount point. + * + * Note that this interface returns an empty, initialized, profile. + * It does not return what may have been previously committed. + */ +int +di_prof_init(const char *mountpt, di_prof_t *profp) +{ + nvlist_t *nvl; + + if (nvlist_alloc(&nvl, 0, 0)) + return (-1); + + if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) { + nvlist_free(nvl); + return (-1); + } + + *profp = (di_prof_t)nvl; + return (0); +} + +/* + * Free space allocated by di_prof_init(). + */ +void +di_prof_fini(di_prof_t prof) +{ + nvlist_free((nvlist_t *)prof); +} + +/* + * Sends profile to the kernel. + */ +int +di_prof_commit(di_prof_t prof) +{ + char *buf = NULL; + size_t buflen = 0; + int rv; + + if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0)) + return (-1); + rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen); + free(buf); + return (rv); +} + +/* + * Add a device or directory to profile's include list. + * + * Note that there is no arbitration between conflicting + * include and exclude profile entries, most recent + * is the winner. + */ +int +di_prof_add_dev(di_prof_t prof, const char *dev) +{ + if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev)) + return (-1); + return (0); +} + +/* + * Add a device or directory to profile's exclude list. + * This can effectively remove a previously committed device. + */ +int +di_prof_add_exclude(di_prof_t prof, const char *dev) +{ + if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_EXCLUDE, dev)) + return (-1); + return (0); +} + +/* + * Add a symlink to profile. + */ +int +di_prof_add_symlink(di_prof_t prof, const char *linkname, const char *target) +{ + nvlist_t *nvl = (nvlist_t *)prof; + char *syml[2]; + + syml[0] = (char *)linkname; /* 1st entry must be the symlink */ + syml[1] = (char *)target; /* 2nd entry must be the target */ + if (nvlist_add_string_array(nvl, SDEV_NVNAME_SYMLINK, syml, 2)) + return (-1); + return (0); +} + +/* + * Add a name mapping to profile. + */ +int +di_prof_add_map(di_prof_t prof, const char *source, const char *target) +{ + nvlist_t *nvl = (nvlist_t *)prof; + char *map[2]; + + map[0] = (char *)source; /* 1st entry must be the source */ + map[1] = (char *)target; /* 2nd entry must be the target */ + if (nvlist_add_string_array(nvl, SDEV_NVNAME_MAP, map, 2)) + return (-1); + return (0); +} diff --git a/usr/src/lib/libdevinfo/devinfo_devperm.c b/usr/src/lib/libdevinfo/devinfo_devperm.c index b4fb3fb217..32af4dbe11 100644 --- a/usr/src/lib/libdevinfo/devinfo_devperm.c +++ b/usr/src/lib/libdevinfo/devinfo_devperm.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. @@ -116,6 +115,7 @@ setdevaccess(char *dev, uid_t uid, gid_t gid, mode_t mode, * doesn't support ACLs, therefore, we must assume that * there were no ACLs to remove in the first place. */ + err = 0; if (errno != ENOSYS) { err = -1; @@ -377,8 +377,29 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, DIR *dirp; struct dirent *direntp; char errstring[MAX_LINELEN]; + char *p; + regex_t regex; + int alwaysmatch = 0; + char *match; + char *name, *newpath, *remainder_path; + finddevhdl_t handle; + int find_method; + + /* + * Determine to begin if the search needs to be performed via + * finddev, which returns only persisted names in /dev, or readdir, + * for paths other than /dev. This use of finddev avoids triggering + * potential implicit reconfig for names noted as managed by + * logindevperm but not present on the system. + */ + find_method = ((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)) { + return (-1); + } if (stat(path, &stat_buf) == -1) { /* * ENOENT errors are expected errors when there are @@ -411,76 +432,89 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode, } } - dirp = opendir(path); - if (dirp == NULL) { - return (0); + if (find_method == FLAG_USE_READDIR) { + dirp = opendir(path); + if (dirp == NULL) + return (0); } else { - char *p = strchr(left_to_do, '/'); - regex_t regex; - int alwaysmatch = 0; - char *match; - char *name, *newpath, *remainder_path; - - newpath = (char *)malloc(MAXPATHLEN); - if (newpath == NULL) { - return (-1); - } - match = (char *)calloc(MAXPATHLEN, 1); - if (match == NULL) { - free(newpath); - return (-1); - } + if (finddev_readdir(path, &handle) != 0) + return (0); + } - if (p) { - (void) strncpy(match, left_to_do, p - left_to_do); - } else { - (void) strcpy(match, left_to_do); - } + p = strchr(left_to_do, '/'); + alwaysmatch = 0; - if (strcmp(match, "*") == 0) { - alwaysmatch = 1; - } else { - if (regcomp(®ex, match, REG_EXTENDED) != 0) { - free(newpath); - free(match); - return (-1); - } + newpath = (char *)malloc(MAXPATHLEN); + if (newpath == NULL) { + return (-1); + } + match = (char *)calloc(MAXPATHLEN, 1); + if (match == NULL) { + free(newpath); + return (-1); + } + + if (p) { + (void) strncpy(match, left_to_do, p - left_to_do); + } else { + (void) strcpy(match, left_to_do); + } + + if (strcmp(match, "*") == 0) { + alwaysmatch = 1; + } else { + if (regcomp(®ex, match, REG_EXTENDED) != 0) { + free(newpath); + free(match); + return (-1); } + } - while ((direntp = readdir(dirp)) != NULL) { + 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; + } - if (alwaysmatch || - regexec(®ex, name, 0, NULL, 0) == 0) { - if (strcmp(path, "/") == 0) { - (void) snprintf(newpath, - MAXPATHLEN, "%s%s", path, name); - } else { - (void) snprintf(newpath, - MAXPATHLEN, "%s/%s", path, name); - } + if (alwaysmatch || + regexec(®ex, name, 0, NULL, 0) == 0) { + if (strcmp(path, "/") == 0) { + (void) snprintf(newpath, + MAXPATHLEN, "%s%s", path, name); + } else { + (void) snprintf(newpath, + MAXPATHLEN, "%s/%s", path, name); + } - /* - * recurse but adjust what is still left to do - */ - remainder_path = (p ? - left_to_do + (p - left_to_do) + 1 : - &left_to_do[strlen(left_to_do)]); - if (dir_dev_acc(newpath, remainder_path, - uid, gid, mode, line, errmsg)) { - err = -1; - } + /* + * recurse but adjust what is still left to do + */ + remainder_path = (p ? + left_to_do + (p - left_to_do) + 1 : + &left_to_do[strlen(left_to_do)]); + if (dir_dev_acc(newpath, remainder_path, + uid, gid, mode, line, errmsg)) { + err = -1; } } + } + + if (find_method == FLAG_USE_READDIR) { (void) closedir(dirp); - free(newpath); - free(match); - if (!alwaysmatch) { - regfree(®ex); - } + } else { + finddev_close(handle); + } + free(newpath); + free(match); + if (!alwaysmatch) { + regfree(®ex); } return (err); diff --git a/usr/src/lib/libdevinfo/devinfo_finddev.c b/usr/src/lib/libdevinfo/devinfo_finddev.c new file mode 100644 index 0000000000..1b89afb7b3 --- /dev/null +++ b/usr/src/lib/libdevinfo/devinfo_finddev.c @@ -0,0 +1,163 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <thread.h> +#include <synch.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <dirent.h> +#include <regex.h> +#include <errno.h> +#include <stdarg.h> +#include <libdevinfo.h> +#include <sys/modctl.h> +#include <syslog.h> + +#include <assert.h> + + +struct finddevhdl { + int npaths; + int curpath; + char **paths; +}; + + +int +device_exists(const char *devname) +{ + int rv; + + rv = modctl(MODDEVEXISTS, devname, strlen(devname)); + return ((rv == 0) ? 1 : 0); +} + +int +finddev_readdir(const char *dir, finddevhdl_t *handlep) +{ + struct finddevhdl *handle; + int n; + int rv; + int64_t bufsiz; + char *pathlist; + char *p; + int len; + + *handlep = NULL; + handle = calloc(1, sizeof (struct finddevhdl)); + if (handle == NULL) + return (ENOMEM); + + handle->npaths = 0; + handle->curpath = 0; + handle->paths = NULL; + + rv = modctl(MODDEVREADDIR, dir, strlen(dir), NULL, &bufsiz); + if (rv != 0) { + free(handle); + return (rv); + } + + for (;;) { + assert(bufsiz != 0); + if ((pathlist = malloc(bufsiz)) == NULL) { + free(handle); + return (ENOMEM); + } + + rv = modctl(MODDEVREADDIR, dir, strlen(dir), + pathlist, &bufsiz); + if (rv == 0) { + for (n = 0, p = pathlist; + (len = strlen(p)) > 0; p += len+1) { + n++; + } + handle->npaths = n; + handle->paths = calloc(n, sizeof (char *)); + if (handle->paths == NULL) { + free(handle); + free(pathlist); + return (ENOMEM); + } + for (n = 0, p = pathlist; + (len = strlen(p)) > 0; p += len+1, n++) { + handle->paths[n] = strdup(p); + if (handle->paths[n] == NULL) { + finddev_close((finddevhdl_t)handle); + free(pathlist); + return (ENOMEM); + } + } + *handlep = (finddevhdl_t)handle; + free(pathlist); + return (0); + } + free(pathlist); + switch (errno) { + case EAGAIN: + break; + case ENOENT: + default: + free(handle); + return (errno); + } + } + /*NOTREACHED*/ +} + +void +finddev_close(finddevhdl_t arg) +{ + struct finddevhdl *handle = (struct finddevhdl *)arg; + int i; + + for (i = 0; i < handle->npaths; i++) { + if (handle->paths[i]) + free(handle->paths[i]); + } + free(handle->paths); + free(handle); +} + +const char * +finddev_next(finddevhdl_t arg) +{ + struct finddevhdl *handle = (struct finddevhdl *)arg; + const char *path = NULL; + + if (handle->curpath < handle->npaths) { + path = handle->paths[handle->curpath]; + handle->curpath++; + } + return (path); +} diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h index 62fa27bcb2..0fac182582 100644 --- a/usr/src/lib/libdevinfo/libdevinfo.h +++ b/usr/src/lib/libdevinfo/libdevinfo.h @@ -28,7 +28,12 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#ifdef __cplusplus +extern "C" { +#endif + #include <errno.h> +#include <libnvpair.h> #include <sys/param.h> #include <sys/sunddi.h> #include <sys/sunmdi.h> @@ -37,10 +42,6 @@ #include <sys/devinfo_impl.h> #include <limits.h> -#ifdef __cplusplus -extern "C" { -#endif - /* * flags for di_walk_node */ @@ -394,6 +395,42 @@ extern int di_dli_openr(char *); extern int di_dli_openw(char *); extern void di_dli_close(int); +/* + * Private interface for parsing devname binding info + */ +extern void di_devname_print_mapinfo(nvlist_t *); +extern int di_devname_get_mapinfo(char *, nvlist_t **); +extern int di_devname_get_mapent(char *, char *, nvlist_t **); +extern int di_devname_action_on_key(nvlist_t *, uint8_t, char *, void *); + +/* + * finddev - alternate readdir to discover only /dev persisted device names + */ +typedef struct __finddevhdl *finddevhdl_t; + +extern int device_exists(const char *); +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 + */ +typedef struct __di_prof *di_prof_t; + +extern int di_prof_init(const char *mountpt, di_prof_t *); +extern void di_prof_fini(di_prof_t); +extern int di_prof_commit(di_prof_t); +extern int di_prof_add_dev(di_prof_t, const char *); +extern int di_prof_add_exclude(di_prof_t, const char *); +extern int di_prof_add_symlink(di_prof_t, const char *, const char *); +extern int di_prof_add_map(di_prof_t, const char *, const char *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers index 6e84e1bee1..5a6310b03d 100644 --- a/usr/src/lib/libdevinfo/mapfile-vers +++ b/usr/src/lib/libdevinfo/mapfile-vers @@ -145,6 +145,10 @@ SUNWprivate_1.1 { di_devlink_walk; di_devperm_login; di_devperm_logout; + di_devname_get_mapinfo; + di_devname_get_mapent; + di_devname_action_on_key; + di_devname_print_mapinfo; di_driver_private_data; di_init_driver; di_init_impl; @@ -173,6 +177,13 @@ SUNWprivate_1.1 { di_path_state; di_phci_first_node; di_phci_next_node; + di_prof_add_dev; + di_prof_add_exclude; + di_prof_add_map; + di_prof_add_symlink; + di_prof_commit; + di_prof_init; + di_prof_fini; di_prop_drv_next; di_prop_global_next; di_prop_hw_next; @@ -184,6 +195,10 @@ SUNWprivate_1.1 { di_dli_openr; di_dli_openw; di_dli_close; + device_exists; + finddev_readdir; + finddev_close; + finddev_next; local: *; }; diff --git a/usr/src/lib/libtsol/common/label.h b/usr/src/lib/libtsol/common/label.h index 6a5bfdc205..ed397f5fa3 100644 --- a/usr/src/lib/libtsol/common/label.h +++ b/usr/src/lib/libtsol/common/label.h @@ -235,6 +235,14 @@ extern int labelfields(struct name_fields *); extern int userdefs(m_label_t *, m_label_t *); extern int zonecopy(m_label_t *, char *, char *, char *, int); +#ifdef DEBUG +/* testing hook: see devfsadm.c, mkdevalloc.c and allocate.c */ +#define is_system_labeled_debug(statbufp) \ + ((stat("/ALLOCATE_FORCE_LABEL", (statbufp)) == 0) ? 1 : 0) +#else /* DEBUG */ +#define is_system_labeled_debug(statbufp) 0 +#endif /* DEBUG */ + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c index 6aef12bbed..569d0f6ba9 100644 --- a/usr/src/lib/libzonecfg/common/libzonecfg.c +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c @@ -70,7 +70,6 @@ #define DTD_ELEM_ATTR (const xmlChar *) "attr" #define DTD_ELEM_COMMENT (const xmlChar *) "comment" #define DTD_ELEM_DEVICE (const xmlChar *) "device" -#define DTD_ELEM_DELETEDDEVICE (const xmlChar *) "deleted-device" #define DTD_ELEM_FS (const xmlChar *) "filesystem" #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" @@ -2142,9 +2141,8 @@ zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) static int zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) { - xmlNodePtr newnode, cur = handle->zone_dh_cur; + xmlNodePtr cur = handle->zone_dh_cur; int match_match; - int err; for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) @@ -2154,19 +2152,6 @@ zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) tabptr->zone_dev_match); if (match_match) { - /* - * Since we're succesfully deleting (or modifying) - * a device entry, we need to do device node cleanup - * on the next zone bootup, so we leave behind a - * historical record for zoneadmd to consume. - */ - newnode = xmlNewTextChild(handle->zone_dh_top, NULL, - DTD_ELEM_DELETEDDEVICE, NULL); - - if ((err = newprop(newnode, DTD_ATTR_MATCH, - tabptr->zone_dev_match)) != Z_OK) - return (err); - xmlUnlinkNode(cur); xmlFreeNode(cur); return (Z_OK); @@ -2193,43 +2178,6 @@ zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) } int -zonecfg_clear_deldevs(zone_dochandle_t handle) -{ - xmlNodePtr cur; - int err; - - if ((err = operation_prep(handle)) != Z_OK) - return (err); - - cur = handle->zone_dh_cur; - for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { - if (xmlStrcmp(cur->name, DTD_ELEM_DELETEDDEVICE) != 0) - continue; - - xmlUnlinkNode(cur); - xmlFreeNode(cur); - } - return (Z_OK); -} - -int -zonecfg_has_deldevs(zone_dochandle_t handle) -{ - xmlNodePtr cur; - int err; - - if ((err = operation_prep(handle)) != Z_OK) - return (err); - - cur = handle->zone_dh_cur; - for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { - if (xmlStrcmp(cur->name, DTD_ELEM_DELETEDDEVICE) == 0) - return (Z_OK); - } - return (Z_NO_ENTRY); -} - -int zonecfg_modify_dev( zone_dochandle_t handle, struct zone_devtab *oldtabptr, @@ -2388,54 +2336,6 @@ zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, } /* - * This is the set of devices which must be present in every zone. Users - * can augment this list with additional device rules in their zone - * configuration, but at present cannot remove any of the this set of - * standard devices. All matching is done by /dev pathname (the "/dev" - * part is implicit. Try to keep rules which match a large number of - * devices (like the pts rule) first. - */ -static const char *standard_devs[] = { - "pts/*", - "ptmx", - "random", - "urandom", - "poll", - "pool", - "kstat", - "zero", - "null", - "crypto", - "cryptoadm", - "ticots", - "ticotsord", - "ticlts", - "lo0", - "lo1", - "lo2", - "lo3", - "sad/user", - "tty", - "logindmux", - "log", - "conslog", - "arp", - "tcp", - "tcp6", - "udp", - "udp6", - "sysevent", -#ifdef __sparc - "openprom", -#endif - "cpu/self/cpuid", - "dtrace/*", - "dtrace/provider/*", - "zfs", - NULL -}; - -/* * This function finds everything mounted under a zone's rootpath. * This returns the number of mounts under rootpath, or -1 on error. * callback is called once per mount found with the first argument @@ -2493,174 +2393,6 @@ out: return (rv); } -/* - * This routine is used to determine if a given device should appear in the - * zone represented by 'handle'. First it consults the list of "standard" - * zone devices. Then it scans the user-supplied device entries. - */ -int -zonecfg_match_dev(zone_dochandle_t handle, const char *devpath, - struct zone_devtab *out_match) -{ - int err; - boolean_t found = B_FALSE; - char match[MAXPATHLEN]; - const char **stdmatch; - xmlNodePtr cur; - - if (handle == NULL || devpath == NULL) - return (Z_INVAL); - - /* - * Check the "standard" devices which we require to be present. - */ - for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) { - /* - * fnmatch gives us simple but powerful shell-style matching. - */ - if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) { - if (!out_match) - return (Z_OK); - (void) snprintf(out_match->zone_dev_match, - sizeof (out_match->zone_dev_match), - "/dev/%s", *stdmatch); - return (Z_OK); - } - } - - /* - * We got no hits in the set of standard devices. On to the user - * supplied ones. - */ - if ((err = operation_prep(handle)) != Z_OK) { - handle->zone_dh_cur = NULL; - return (err); - } - - cur = handle->zone_dh_cur; - cur = cur->xmlChildrenNode; - if (cur == NULL) - return (Z_NO_ENTRY); - handle->zone_dh_cur = cur; - - for (; cur != NULL; cur = cur->next) { - char *m; - if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0) - continue; - if ((err = fetchprop(cur, DTD_ATTR_MATCH, match, - sizeof (match))) != Z_OK) { - handle->zone_dh_cur = handle->zone_dh_top; - return (err); - } - m = match; - /* - * fnmatch gives us simple but powerful shell-style matching; - * but first, we need to strip out /dev/ from the matching rule. - */ - if (strncmp(m, "/dev/", 5) == 0) - m += 5; - - if (fnmatch(m, devpath, FNM_PATHNAME) == 0) { - found = B_TRUE; - break; - } - } - - if (!found) - return (Z_NO_ENTRY); - - if (!out_match) - return (Z_OK); - - (void) strlcpy(out_match->zone_dev_match, match, - sizeof (out_match->zone_dev_match)); - return (Z_OK); -} - -/* - * This routine answers the question: do we think <devpath> should be - * deleted during this zone's bootup? - * - * The criteria are: - * - Is there a matching rule for devpath? If yes, then NO. - * - Is this a CHR or BLK device node? If no, then NO. - * - Is there a deleted device entry which matches devpath? Then, YES - * - Else NO - */ -int -zonecfg_should_deldev(zone_dochandle_t handle, const char *devpath, - boolean_t *del) -{ - int err; - char match[MAXPATHLEN]; - xmlNodePtr cur; - struct stat st; - char fullpath[MAXPATHLEN]; - char zonepath[MAXPATHLEN]; - - if (handle == NULL || devpath == NULL || del == NULL) - return (Z_INVAL); - - *del = B_FALSE; - - /* - * If a matching rule exists for this device, then leave it alone. - */ - if (zonecfg_match_dev(handle, devpath, NULL) == Z_OK) - return (Z_OK); - - /* - * lstat it. If it's a regular file, a directory, a link or - * something else miscellaneous, we'll be cautious and not - * touch it. - */ - if ((err = zonecfg_get_zonepath(handle, zonepath, - sizeof (zonepath))) != Z_OK) - return (err); - - (void) snprintf(fullpath, sizeof (fullpath), "%s/dev/%s", zonepath, - devpath); - if (lstat(fullpath, &st) == -1 || - (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))) - return (Z_OK); - - if ((err = operation_prep(handle)) != Z_OK) { - handle->zone_dh_cur = NULL; - return (err); - } - - cur = handle->zone_dh_cur; - cur = cur->xmlChildrenNode; - if (cur == NULL) - return (Z_NO_ENTRY); - handle->zone_dh_cur = cur; - - for (; cur != NULL; cur = cur->next) { - char *m; - if (xmlStrcmp(cur->name, DTD_ELEM_DELETEDDEVICE) != 0) - continue; - if ((err = fetchprop(cur, DTD_ATTR_MATCH, match, - sizeof (match))) != Z_OK) { - handle->zone_dh_cur = handle->zone_dh_top; - return (err); - } - m = match; - /* - * fnmatch gives us simple but powerful shell-style matching; - * but first, we need to strip out /dev/ from the matching rule. - */ - if (strncmp(m, "/dev/", 5) == 0) - m += 5; - - if (fnmatch(m, devpath, FNM_PATHNAME) == 0) { - *del = B_TRUE; - break; - } - } - - return (Z_OK); -} - int zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) { @@ -3967,6 +3699,34 @@ zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) return (Z_OK); } +/* + * Return the appropriate root for the active /dev. + * For normal zone, the path is $ZONEPATH/root; + * for scratch zone, the dev path is $ZONEPATH/lu. + */ +int +zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) +{ + int err; + char *suffix; + zone_state_t state; + + /* This function makes sense for non-global zones only. */ + if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) + return (Z_BOGUS_ZONE_NAME); + if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) + return (err); + + if (zone_get_state(zone_name, &state) == Z_OK && + state == ZONE_STATE_MOUNTED) + suffix = "/lu"; + else + suffix = "/root"; + if (strlcat(devroot, suffix, rp_sz) >= rp_sz) + return (Z_TOO_BIG); + return (Z_OK); +} + static zone_state_t kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) { diff --git a/usr/src/lib/libzonecfg/common/mapfile-vers b/usr/src/lib/libzonecfg/common/mapfile-vers index 9654a93300..79d3de5d15 100644 --- a/usr/src/lib/libzonecfg/common/mapfile-vers +++ b/usr/src/lib/libzonecfg/common/mapfile-vers @@ -45,7 +45,6 @@ SUNWprivate_1.1 { zonecfg_add_scratch; zonecfg_attach_manifest; zonecfg_check_handle; - zonecfg_clear_deldevs; zonecfg_close_scratch; zonecfg_construct_rctlblk; zonecfg_create_snapshot; @@ -109,7 +108,6 @@ SUNWprivate_1.1 { zonecfg_get_template_handle; zonecfg_get_uuid; zonecfg_get_zonepath; - zonecfg_has_deldevs; zonecfg_in_alt_root; zonecfg_init_handle; zonecfg_is_rctl; @@ -122,7 +120,6 @@ SUNWprivate_1.1 { zonecfg_lookup_ipd; zonecfg_lookup_nwif; zonecfg_lookup_rctl; - zonecfg_match_dev; zonecfg_modify_attr; zonecfg_modify_dev; zonecfg_modify_ds; @@ -159,7 +156,6 @@ SUNWprivate_1.1 { zonecfg_setrctlent; zonecfg_set_root; zonecfg_set_zonepath; - zonecfg_should_deldev; zonecfg_strerror; zonecfg_validate_zonename; zonecfg_valid_fs_type; @@ -167,6 +163,7 @@ SUNWprivate_1.1 { zonecfg_valid_rctl; zonecfg_valid_rctlblk; zonecfg_valid_rctlname; + zone_get_devroot; zone_get_id; zone_get_rootpath; zone_get_state; diff --git a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 index 6050fe6463..46e10f761b 100644 --- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 +++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 @@ -52,16 +52,16 @@ <!ATTLIST device match CDATA #REQUIRED> <!-- - The deleted-device element denotes a used-to-be device element. - We keep track of device elements which the user has deleted or - modified, and make an attempt to cleanse /dev of associated entries - at next zone boot. - - The 'devnames' project will ultimately obsolete the need for this - functionality, but this element MUST remain in perpetuity, since - it is possible that zones crossing from pre-devnames to post-devnames - bits could carry a deleted-device element, and would therefore fail - XML validation if this were removed + Historically, the deleted-device element denoted a used-to-be + device element. This was used to keep track of device elements + deleted or modified by the user, and to cleanse /dev of such + entries at next zone boot. + + With the ability to now configure devices dynamically, this + requirement no longer exists, but this element MUST remain in + perpetuity, since it is possible that an upgraded zone could + carry a deleted-device element, and would therefore fail XML + validation if removed --> <!ELEMENT deleted-device EMPTY> |