summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
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>