summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorllai1 <none@none>2006-08-25 17:24:25 -0700
committerllai1 <none@none>2006-08-25 17:24:25 -0700
commitfacf4a8d7b59fde89a8662b4f4c73a758e6c402c (patch)
tree4e0024c5508351006df1496ec4be6e7b564c3ce8 /usr/src/lib
parentadcafb0fe4c49c4d46c0b393dfba36d4e1b55c0e (diff)
downloadillumos-gate-facf4a8d7b59fde89a8662b4f4c73a758e6c402c.tar.gz
PSARC/2003/246 Filesystem Driven Device Naming
5050715 logical device names not created during early boot 6292952 devfsadm mishandles optarg 6362924 devfsadm secondary link generation is not zones aware 6413127 Integrate the Devname Project 6464196 bfu should remove pt_chmod, obsoleted by /dev filesystem --HG-- rename : usr/src/cmd/pt_chmod/Makefile => deleted_files/usr/src/cmd/pt_chmod/Makefile rename : usr/src/cmd/pt_chmod/pt_chmod.c => deleted_files/usr/src/cmd/pt_chmod/pt_chmod.c
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/libc/port/gen/pt.c128
-rw-r--r--usr/src/lib/libdevinfo/Makefile.com3
-rw-r--r--usr/src/lib/libdevinfo/devinfo_devlink.c103
-rw-r--r--usr/src/lib/libdevinfo/devinfo_devlink.h10
-rw-r--r--usr/src/lib/libdevinfo/devinfo_devname.c701
-rw-r--r--usr/src/lib/libdevinfo/devinfo_devperm.c152
-rw-r--r--usr/src/lib/libdevinfo/devinfo_finddev.c163
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h45
-rw-r--r--usr/src/lib/libdevinfo/mapfile-vers15
-rw-r--r--usr/src/lib/libtsol/common/label.h8
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c298
-rw-r--r--usr/src/lib/libzonecfg/common/mapfile-vers5
-rw-r--r--usr/src/lib/libzonecfg/dtd/zonecfg.dtd.120
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(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex);
- }
+ } else {
+ finddev_close(handle);
+ }
+ free(newpath);
+ free(match);
+ if (!alwaysmatch) {
+ regfree(&regex);
}
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>