summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorDai Ngo <dai.ngo@sun.com>2009-10-14 11:15:07 -0500
committerDai Ngo <dai.ngo@sun.com>2009-10-14 11:15:07 -0500
commit7a286c471efbab8562f7655a82931904703fffe0 (patch)
treebbd1ea3af4176ce7e295afaa9eb7cb86b95010c0 /usr/src
parent635216b673cf196ac523ff2a7ab715717e553292 (diff)
downloadillumos-gate-7a286c471efbab8562f7655a82931904703fffe0.tar.gz
6886081 Solaris needs reparse point support (PSARC 2009/387)
PSARC 2009/387 Pathname Reparse Points
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/cmd/fs.d/Makefile2
-rw-r--r--usr/src/cmd/fs.d/reparsed/Makefile60
-rw-r--r--usr/src/cmd/fs.d/reparsed/reparsed.c358
-rw-r--r--usr/src/cmd/fs.d/reparsed/reparsed.xml108
-rw-r--r--usr/src/common/fsreparse/fs_reparse.c328
-rw-r--r--usr/src/common/xattr/xattr_common.c6
-rw-r--r--usr/src/lib/Makefile6
-rw-r--r--usr/src/lib/libreparse/Makefile60
-rw-r--r--usr/src/lib/libreparse/Makefile.com57
-rw-r--r--usr/src/lib/libreparse/amd64/Makefile29
-rw-r--r--usr/src/lib/libreparse/common/fs_reparse_lib.c437
-rw-r--r--usr/src/lib/libreparse/common/llib-lreparse46
-rw-r--r--usr/src/lib/libreparse/common/mapfile-vers54
-rw-r--r--usr/src/lib/libreparse/common/rp_plugin.h75
-rw-r--r--usr/src/lib/libreparse/i386/Makefile28
-rw-r--r--usr/src/lib/libreparse/sparc/Makefile28
-rw-r--r--usr/src/lib/libreparse/sparcv9/Makefile29
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt1
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile1
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfReparseStates.html37
-rw-r--r--usr/src/lib/libsecdb/help/profiles/Makefile1
-rw-r--r--usr/src/lib/libsecdb/help/profiles/RtReparseMngmnt.html37
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt1
-rw-r--r--usr/src/lib/libzpool/common/sys/zfs_context.h3
-rw-r--r--usr/src/pkgdefs/SUNW0on/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_i3861
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_sparc3
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_i3862
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_sparc2
-rw-r--r--usr/src/pkgdefs/SUNWcsr/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com2
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/fs/Makefile14
-rw-r--r--usr/src/uts/common/fs/fs_reparse.h88
-rw-r--r--usr/src/uts/common/fs/fs_subr.c181
-rw-r--r--usr/src/uts/common/fs/vfs.c4
-rw-r--r--usr/src/uts/common/fs/vnode.c46
-rw-r--r--usr/src/uts/common/fs/xattr.c13
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_znode.h1
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_log.c3
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_replay.c6
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c1
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c12
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_znode.c4
-rw-r--r--usr/src/uts/common/fs/zut/zut.c3
-rw-r--r--usr/src/uts/common/sys/attr.h7
-rw-r--r--usr/src/uts/common/sys/vfs.h1
-rw-r--r--usr/src/uts/common/sys/vnode.h8
53 files changed, 2192 insertions, 22 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index e9f7a30667..873460b38d 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -405,6 +405,7 @@ COMMON_SUBDIRS = \
lib/libraidcfg \
lib/librcm \
lib/librdc \
+ lib/libreparse \
lib/librestart \
lib/librstp \
lib/librt \
diff --git a/usr/src/cmd/fs.d/Makefile b/usr/src/cmd/fs.d/Makefile
index 20ffc9f17c..a2e02bba6a 100644
--- a/usr/src/cmd/fs.d/Makefile
+++ b/usr/src/cmd/fs.d/Makefile
@@ -43,7 +43,7 @@ include ../Makefile.cmd
SUBDIR1= lofs zfs
SUBDIR2= dev fd pcfs nfs hsfs proc ctfs udfs ufs tmpfs cachefs \
- autofs mntfs objfs sharefs smbclnt
+ autofs mntfs objfs sharefs smbclnt reparsed
SUBDIRS= $(SUBDIR1) $(SUBDIR2)
I18NDIRS= $(SUBDIR2)
diff --git a/usr/src/cmd/fs.d/reparsed/Makefile b/usr/src/cmd/fs.d/reparsed/Makefile
new file mode 100644
index 0000000000..9df265a3c9
--- /dev/null
+++ b/usr/src/cmd/fs.d/reparsed/Makefile
@@ -0,0 +1,60 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+include $(SRC)/Makefile.master
+
+FSTYPE= reparse
+TYPEPROG= reparsed
+
+include ../Makefile.fstype
+
+OBJS= $(TYPEPROG).o
+SRCS= $(TYPEPROG).c
+POFILE= $(TYPEPROG).po
+
+CLOBBERFILES += $(TYPEPROG)
+
+CFLAGS += $(CCVERBOSE)
+C99MODE= $(C99_ENABLE)
+
+LDLIBS += -lreparse -lnsl
+
+CPPFLAGS += -I$(SRC)/uts/common
+
+all: $(TYPEPROG)
+
+catalog: $(POFILE)
+
+lint: lint_SRCS
+
+clean:
+ $(RM) $(OBJS) $(POFILE)
+
+MANIFEST= reparsed.xml
+ROOTMANIFESTDIR= $(ROOTSVCNETWORKSHARES)
+$(ROOTMANIFEST) := FILEMODE = 0444
+install: $(ROOTMANIFEST)
+
+.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/reparsed/reparsed.c b/usr/src/cmd/fs.d/reparsed/reparsed.c
new file mode 100644
index 0000000000..17027b0c78
--- /dev/null
+++ b/usr/src/cmd/fs.d/reparsed/reparsed.c
@@ -0,0 +1,358 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Reparsed daemon
+ */
+
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <alloca.h>
+#include <ucontext.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <door.h>
+#include <wait.h>
+#include <libintl.h>
+#include <locale.h>
+#include <sys/param.h>
+#include <sys/systeminfo.h>
+#include <sys/thread.h>
+#include <rpc/xdr.h>
+#include <priv.h>
+#include <sys/fs_reparse.h>
+#include <priv_utils.h>
+#include <rpcsvc/daemon_utils.h>
+
+#define REPARSED_CMD_OPTS "v"
+#define DOOR_RESULT_BUFSZ (MAXPATHLEN + sizeof (reparsed_door_res_t))
+#define SAFETY_BUFFER 8*1024
+
+static char *MyName;
+static int verbose = 0;
+
+static int start_reparsed_svcs();
+static void daemonize(void);
+static void reparsed_door_call_error(int error, int buflen);
+static void reparsed_doorfunc(void *cookie, char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc);
+
+static void
+usage()
+{
+ syslog(LOG_ERR, "Usage: %s", MyName);
+ syslog(LOG_ERR, "\t[-v]\t\tverbose error messages)");
+ exit(1);
+}
+
+static void
+warn_hup(int i)
+{
+ syslog(LOG_ERR, "SIGHUP received: ignored");
+ (void) signal(SIGHUP, warn_hup);
+}
+
+/*
+ * Processing for daemonization
+ */
+static void
+daemonize(void)
+{
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "reparsed: can't fork - errno %d", errno);
+ exit(2);
+ /* NOTREACHED */
+ case 0: /* child */
+ break;
+
+ default: /* parent */
+ _exit(0);
+ }
+ (void) chdir("/");
+
+ /*
+ * Close stdin, stdout, and stderr.
+ * Open again to redirect input+output
+ */
+ (void) close(0);
+ (void) close(1);
+ (void) close(2);
+ (void) open("/dev/null", O_RDONLY);
+ (void) open("/dev/null", O_WRONLY);
+ (void) dup(1);
+ (void) setsid();
+}
+
+int
+main(int argc, char *argv[])
+{
+ pid_t pid;
+ int c, error;
+ struct rlimit rlset;
+ char *defval;
+
+ /*
+ * There is no check for non-global zone and Trusted Extensions.
+ * Reparsed works in both of these environments as long as the
+ * services that use reparsed are supported.
+ */
+
+ MyName = argv[0];
+ if (geteuid() != 0) {
+ syslog(LOG_ERR, "%s must be run as root", MyName);
+ exit(1);
+ }
+
+ while ((c = getopt(argc, argv, REPARSED_CMD_OPTS)) != EOF) {
+ switch (c) {
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ daemonize();
+ openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+
+ (void) _create_daemon_lock(REPARSED, DAEMON_UID, DAEMON_GID);
+ (void) enable_extended_FILE_stdio(-1, -1);
+ switch (_enter_daemon_lock(REPARSED)) {
+ case 0:
+ break;
+ case -1:
+ syslog(LOG_ERR, "Error locking for %s", REPARSED);
+ exit(2);
+ default:
+ /* daemon was already running */
+ exit(0);
+ }
+
+ (void) signal(SIGHUP, warn_hup);
+
+ /*
+ * Make the process a privilege aware daemon.
+ * Only "basic" privileges are required.
+ *
+ */
+ if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
+ (char *)NULL) == -1) {
+ syslog(LOG_ERR, "should be run with sufficient privileges");
+ exit(3);
+ }
+
+ /*
+ * Clear basic privileges not required by reparsed.
+ */
+ __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
+ PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
+
+ return (start_reparsed_svcs());
+}
+
+static void
+reparsed_door_call_error(int error, int buflen)
+{
+ reparsed_door_res_t rpd_res;
+
+ memset(&rpd_res, 0, sizeof (reparsed_door_res_t));
+ rpd_res.res_status = error;
+ rpd_res.res_len = buflen;
+ door_return((char *)&rpd_res, sizeof (reparsed_door_res_t), NULL, 0);
+
+ (void) door_return(NULL, 0, NULL, 0);
+ /* NOTREACHED */
+}
+
+/*
+ * reparsed_doorfunc
+ *
+ * argp: "service_type:service_data" string
+ * dp & n_desc: not used.
+ */
+static void
+reparsed_doorfunc(void *cookie, char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc)
+{
+ int err;
+ size_t bufsz;
+ char *svc_type, *svc_data;
+ char *cp, *buf, *sbuf, res_buf[DOOR_RESULT_BUFSZ];
+ reparsed_door_res_t *resp;
+
+ if ((argp == NULL) || (arg_size == 0)) {
+ reparsed_door_call_error(EINVAL, 0);
+ /* NOTREACHED */
+ }
+
+ if (verbose)
+ syslog(LOG_NOTICE, "reparsed_door: [%s, %d]", argp, arg_size);
+
+ if ((svc_type = strdup(argp)) == NULL) {
+ reparsed_door_call_error(ENOMEM, 0);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Door argument string comes in "service_type:service_data" format.
+ * Need to break it into separate "service_type" and "service_data"
+ * string before passing them to reparse_deref() to process them.
+ */
+ if ((cp = strchr(svc_type, ':')) == NULL) {
+ free(svc_type);
+ reparsed_door_call_error(EINVAL, 0);
+ /* NOTREACHED */
+ }
+ *cp++ = '\0';
+ svc_data = cp;
+
+ /*
+ * Setup buffer for reparse_deref(). 'bufsz' is the actual
+ * buffer size to hold the result returned by reparse_deref().
+ */
+ resp = (reparsed_door_res_t *)res_buf;
+ buf = resp->res_data;
+ bufsz = sizeof (res_buf) - sizeof (reparsed_door_res_t);
+
+ /*
+ * reparse_deref() calls the service type plugin library to process
+ * the service data. The plugin library function should understand
+ * the context of the service data and should be the one to XDR the
+ * results before returning it to the caller.
+ */
+ err = reparse_deref(svc_type, svc_data, buf, &bufsz);
+
+ if (verbose)
+ syslog(LOG_NOTICE,
+ "reparsed_deref(svc_type: %s, data: %s, size: %d) -> %d",
+ svc_type, svc_data, bufsz, err);
+
+ switch (err) {
+ case 0:
+ break;
+
+ case EOVERFLOW:
+ /*
+ * bufsz was returned with size needed by reparse_deref().
+ *
+ * We cannot use malloc() here because door_return() never
+ * returns, and memory allocated by malloc() would get leaked.
+ */
+ sbuf = alloca(bufsz + sizeof (reparsed_door_res_t));
+ if (sbuf == NULL || stack_inbounds(buf) == 0 ||
+ stack_inbounds(buf + sizeof (reparsed_door_res_t) +
+ SAFETY_BUFFER - 1) == 0) {
+ free(svc_type);
+ reparsed_door_call_error(ENOMEM, 0);
+ /* NOTREACHED */
+ }
+
+ resp = (reparsed_door_res_t *)sbuf;
+ if ((err = reparse_deref(svc_type, svc_data, resp->res_data,
+ &bufsz)) == 0)
+ break;
+
+ /* fall through */
+
+ default:
+ free(svc_type);
+ reparsed_door_call_error(err, 0);
+ /* NOTREACHED */
+ }
+
+ free(svc_type);
+
+ if (verbose)
+ syslog(LOG_NOTICE, "reparsed_door_return <buf=%s> size=%d",
+ buf, bufsz);
+
+ resp->res_status = 0;
+ resp->res_len = bufsz;
+ (void) door_return((char *)resp, bufsz + sizeof (reparsed_door_res_t),
+ NULL, 0);
+
+ (void) door_return(NULL, 0, NULL, 0);
+ /* NOTREACHED */
+}
+
+static int
+start_reparsed_svcs()
+{
+ int doorfd;
+ int dfd;
+
+ if ((doorfd = door_create(reparsed_doorfunc, NULL,
+ DOOR_REFUSE_DESC|DOOR_NO_CANCEL)) == -1) {
+ syslog(LOG_ERR, "Unable to create door");
+ return (1);
+ }
+
+ /*
+ * Create a file system path for the door
+ */
+ if ((dfd = open(REPARSED_DOOR, O_RDWR|O_CREAT|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
+ syslog(LOG_ERR, "unable to open %s", REPARSED_DOOR);
+ (void) close(doorfd);
+ return (1);
+ }
+
+ /*
+ * Clean up any stale associations
+ */
+ (void) fdetach(REPARSED_DOOR);
+
+ /*
+ * Register in the kernel namespace for door_ki_open().
+ */
+ if (fattach(doorfd, REPARSED_DOOR) == -1) {
+ syslog(LOG_ERR, "Unable to fattach door %s", REPARSED_DOOR);
+ (void) close(doorfd);
+ (void) close(dfd);
+ return (1);
+ }
+ (void) close(dfd);
+
+ /*
+ * Wait for incoming calls
+ */
+ /*CONSTCOND*/
+ while (1)
+ (void) pause();
+
+ syslog(LOG_ERR, "Door server exited");
+ return (10);
+}
diff --git a/usr/src/cmd/fs.d/reparsed/reparsed.xml b/usr/src/cmd/fs.d/reparsed/reparsed.xml
new file mode 100644
index 0000000000..62f5e5cb21
--- /dev/null
+++ b/usr/src/cmd/fs.d/reparsed/reparsed.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ 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
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+
+ Note: if this service is modified to consist of anything other
+ than a single instance named 'default', you must make changes to
+ $SRC/head/rpcsvc/daemon_utils.h and libnsl:open_daemon_lock().
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:reparse'>
+
+<service
+ name='system/filesystem/reparse'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance />
+
+ <dependency name='network'
+ grouping='require_any'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/milestone/network' />
+ </dependency>
+
+ <dependency name='name-services'
+ grouping='require_all'
+ restart_on='refresh'
+ type='service'>
+ <service_fmri value='svc:/milestone/name-services' />
+ </dependency>
+
+ <dependency name='filesystem-minimal'
+ grouping='require_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/lib/reparse/reparsed'
+ timeout_seconds='60' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <property_group name='general' type='framework'>
+ <!-- to start stop reparse service -->
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.reparse' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.manage.reparse' />
+ </property_group>
+
+ <property_group name='application' type='framework'>
+ <stability value='Evolving' />
+ <propval name='auto_enable' type='boolean' value='true' />
+ </property_group>
+
+ <stability value='Stable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Reparse Point daemon
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='reparsed' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/common/fsreparse/fs_reparse.c b/usr/src/common/fsreparse/fs_reparse.c
new file mode 100644
index 0000000000..82da0349fd
--- /dev/null
+++ b/usr/src/common/fsreparse/fs_reparse.c
@@ -0,0 +1,328 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+
+#ifdef _KERNEL
+#include <sys/sunddi.h>
+#include <fs/fs_reparse.h>
+#else
+#include <string.h>
+#include <limits.h>
+#include <sys/fs_reparse.h>
+
+#define strfree(str) free((str))
+#endif
+
+static char *reparse_skipspace(char *cp);
+static int reparse_create_nvlist(const char *string, nvlist_t *nvl);
+static int reparse_add_nvpair(char *token, nvlist_t *nvl);
+static boolean_t reparse_validate_svctype(char *svc_str);
+static int reparse_validate_create_nvlist(const char *string, nvlist_t *nvl);
+
+/* array of characters not allowed in service type string */
+static char svctype_invalid_chars[] = { '{', '}', 0 };
+
+/*
+ * reparse_init()
+ *
+ * Function to allocate a new name-value pair list.
+ * Caller needs to call reparse_free() to free memory
+ * used by the list when done.
+ *
+ * Return pointer to new list else return NULL.
+ */
+nvlist_t *
+reparse_init(void)
+{
+ nvlist_t *nvl;
+
+ /*
+ * Service type is unique, only one entry
+ * of each service type is allowed
+ */
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0))
+ return (NULL);
+
+ return (nvl);
+}
+
+/*
+ * reparse_free()
+ *
+ * Function to free memory of a nvlist allocated previously
+ * by reparse_init().
+ */
+void
+reparse_free(nvlist_t *nvl)
+{
+ if (nvl)
+ nvlist_free(nvl);
+}
+
+/*
+ * reparse_parse()
+ *
+ * Parse the specified string and populate the nvlist with the svc_types
+ * and data from the 'string'. The string could be read from the reparse
+ * point symlink body. This routine will allocate memory that must be
+ * freed by reparse_free().
+ *
+ * If ok return 0 and the nvlist is populated, otherwise return error code.
+ */
+int
+reparse_parse(const char *string, nvlist_t *nvl)
+{
+ int err;
+
+ if (string == NULL || nvl == NULL)
+ return (EINVAL);
+
+ if ((err = reparse_validate(string)) != 0)
+ return (err);
+
+ if ((err = reparse_create_nvlist(string, nvl)) != 0)
+ return (err);
+
+ return (0);
+}
+
+static char *
+reparse_skipspace(char *cp)
+{
+ while ((*cp) && (*cp == ' ' || *cp == '\t'))
+ cp++;
+ return (cp);
+}
+
+static boolean_t
+reparse_validate_svctype(char *svc_str)
+{
+ int nx, ix, len;
+
+ if (svc_str == NULL)
+ return (B_FALSE);
+
+ len = strlen(svc_str);
+ for (ix = 0; ix < len; ix++) {
+ for (nx = 0; nx < sizeof (svctype_invalid_chars); nx++) {
+ if (svc_str[ix] == svctype_invalid_chars[nx])
+ return (B_FALSE);
+ }
+ }
+ return (B_TRUE);
+}
+
+static boolean_t
+reparse_validate_svc_token(char *svc_token)
+{
+ char save_c, *cp;
+
+ if (svc_token == NULL)
+ return (B_FALSE);
+ if ((cp = strchr(svc_token, ':')) == NULL)
+ return (B_FALSE);
+
+ save_c = *cp;
+ *cp = '\0';
+
+ /*
+ * make sure service type and service data are non-empty string.
+ */
+ if (strlen(svc_token) == 0 || strlen(cp + 1) == 0) {
+ *cp = save_c;
+ return (B_FALSE);
+ }
+
+ *cp = save_c;
+ return (B_TRUE);
+}
+
+/*
+ * Format of reparse data:
+ * @{REPARSE@{servicetype:data} [@{servicetype:data}] ...}
+ * REPARSE_TAG_STR@{REPARSE_TOKEN} [@{REPARSE_TOKEN}] ... REPARSE_TAG_END
+ *
+ * Validating reparse data:
+ * . check for valid length of reparse data
+ * . check for valid reparse data format
+ * Return 0 if OK else return error code.
+ */
+int
+reparse_validate(const char *string)
+{
+ return (reparse_validate_create_nvlist(string, NULL));
+}
+
+/*
+ * reparse_validate_create_nvlist
+ *
+ * dual-purpose function:
+ * . Validate a reparse data string.
+ * . Validate a reparse data string and parse the data
+ * into a nvlist.
+ */
+static int
+reparse_validate_create_nvlist(const char *string, nvlist_t *nvl)
+{
+ int err, tcnt;
+ char *reparse_data, save_c, save_e, *save_e_ptr, *cp, *s_str, *e_str;
+
+ if (string == NULL)
+ return (EINVAL);
+
+ if (strlen(string) >= MAXREPARSELEN)
+ return (ENAMETOOLONG);
+
+ if ((reparse_data = strdup(string)) == NULL)
+ return (ENOMEM);
+
+ /* check FS_REPARSE_TAG_STR */
+ if (strncmp(reparse_data, FS_REPARSE_TAG_STR,
+ strlen(FS_REPARSE_TAG_STR))) {
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ /* locate FS_REPARSE_TAG_END_CHAR */
+ if ((cp = strrchr(reparse_data, FS_REPARSE_TAG_END_CHAR)) == NULL) {
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+ save_e = *cp;
+ save_e_ptr = cp;
+ *cp = '\0';
+
+ e_str = cp;
+ cp++; /* should point to NULL, or spaces */
+
+ cp = reparse_skipspace(cp);
+ if (*cp) {
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ /* skip FS_REPARSE_TAG_STR */
+ s_str = reparse_data + strlen(FS_REPARSE_TAG_STR);
+
+ /* skip spaces after FS_REPARSE_TAG_STR */
+ s_str = reparse_skipspace(s_str);
+
+ tcnt = 0;
+ while (s_str < e_str) {
+ /* check FS_TOKEN_START_STR */
+ if (strncmp(s_str, FS_TOKEN_START_STR,
+ strlen(FS_TOKEN_START_STR))) {
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ /* skip over FS_TOKEN_START_STR */
+ s_str += strlen(FS_TOKEN_START_STR);
+
+ /* locate FS_TOKEN_END_STR */
+ if ((cp = strstr(s_str, FS_TOKEN_END_STR)) == NULL) {
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ tcnt++;
+ save_c = *cp;
+ *cp = '\0';
+
+ /* check for valid characters in service type */
+ if (reparse_validate_svctype(s_str) == B_FALSE) {
+ *cp = save_c;
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ if (strlen(s_str) == 0) {
+ *cp = save_c;
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ if (reparse_validate_svc_token(s_str) == B_FALSE) {
+ *cp = save_c;
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (EINVAL);
+ }
+
+ /* create a nvpair entry */
+ if (nvl != NULL &&
+ (err = reparse_add_nvpair(s_str, nvl)) != 0) {
+ *cp = save_c;
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+ return (err);
+ }
+
+ *cp = save_c;
+
+ /* skip over FS_TOKEN_END_STR */
+ cp += strlen(FS_TOKEN_END_STR);
+ cp = reparse_skipspace(cp);
+ s_str = cp;
+ }
+ *save_e_ptr = save_e;
+ strfree(reparse_data);
+
+ return (tcnt ? 0 : EINVAL);
+}
+
+static int
+reparse_add_nvpair(char *token, nvlist_t *nvl)
+{
+ int err;
+ char save_c, *cp;
+
+ if ((cp = strchr(token, ':')) == NULL)
+ return (EINVAL);
+
+ save_c = *cp;
+ *cp = '\0';
+ err = nvlist_add_string(nvl, token, cp + 1);
+ *cp = save_c;
+
+ return (err);
+}
+
+static int
+reparse_create_nvlist(const char *string, nvlist_t *nvl)
+{
+ if (nvl == NULL)
+ return (EINVAL);
+
+ return (reparse_validate_create_nvlist(string, nvl));
+}
diff --git a/usr/src/common/xattr/xattr_common.c b/usr/src/common/xattr/xattr_common.c
index d20eaf6a61..efe782c5f9 100644
--- a/usr/src/common/xattr/xattr_common.c
+++ b/usr/src/common/xattr/xattr_common.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/attr.h>
#if defined(_KERNEL)
#include <sys/systm.h>
@@ -63,6 +61,8 @@ static xattr_entry_t xattrs[F_ATTR_ALL] = {
{ A_OWNERSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST },
{ A_GROUPSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST },
{ A_FSID, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT64 },
+ { A_REPARSE_POINT, O_REPARSE_POINT, XATTR_VIEW_READONLY,
+ DATA_TYPE_BOOLEAN_VALUE },
};
const char *
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 9c364883a7..b535355b13 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -261,6 +261,7 @@ SUBDIRS += \
libsun_ima \
mpapi \
librstp \
+ libreparse \
$($(MACH)_SUBDIRS)
i386_SUBDIRS= \
@@ -359,7 +360,8 @@ MSGSUBDIRS= \
mpss \
pam_modules \
pyzfs \
- rpcsec_gss
+ rpcsec_gss \
+ libreparse
MSGSUBDIRS += \
$($(MACH)_MSGSUBDIRS)
@@ -491,6 +493,7 @@ HDRSUBDIRS= \
libsun_ima \
mpapi \
mms \
+ libreparse \
$($(MACH)_HDRSUBDIRS)
$(CLOSED_BUILD)HDRSUBDIRS += \
@@ -637,6 +640,7 @@ scsi: libnvpair
mpapi: libpthread libdevinfo libsysevent libnvpair
libgrubmgmt: libdevinfo libzfs libfstyp
pyzfs: libnvpair libsec libidmap libzfs
+libreparse: libnvpair
#
# The reason this rule checks for the existence of the
diff --git a/usr/src/lib/libreparse/Makefile b/usr/src/lib/libreparse/Makefile
new file mode 100644
index 0000000000..1f0e0b4647
--- /dev/null
+++ b/usr/src/lib/libreparse/Makefile
@@ -0,0 +1,60 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.lib
+
+HDRS= rp_plugin.h
+HDRDIR= common
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+POFILE= libreparse.po
+MSGFILES= common/fs_reparse_lib.c
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(POFILE): pofile_MSGFILES
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/libreparse/Makefile.com b/usr/src/lib/libreparse/Makefile.com
new file mode 100644
index 0000000000..ca913755fe
--- /dev/null
+++ b/usr/src/lib/libreparse/Makefile.com
@@ -0,0 +1,57 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY= libreparse.a
+VERS= .1
+
+LOCOBJS = fs_reparse_lib.o
+COMOBJS = fs_reparse.o
+OBJECTS = $(LOCOBJS) $(COMOBJS)
+COMDIR = $(SRC)/common/fsreparse
+
+include ../../Makefile.lib
+
+SRCDIR = ../common
+SRCS = $(LOCOBJS:%.o=$(SRCDIR)/%.c) $(COMOBJS:%.o=$(COMDIR)/%.c)
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lnvpair
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(COMDIR) -D_FILE_OFFSET_BITS=64
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
+
+pics/%.o: $(COMDIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libreparse/amd64/Makefile b/usr/src/lib/libreparse/amd64/Makefile
new file mode 100644
index 0000000000..036c13779e
--- /dev/null
+++ b/usr/src/lib/libreparse/amd64/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libreparse/common/fs_reparse_lib.c b/usr/src/lib/libreparse/common/fs_reparse_lib.c
new file mode 100644
index 0000000000..b1ac809e63
--- /dev/null
+++ b/usr/src/lib/libreparse/common/fs_reparse_lib.c
@@ -0,0 +1,437 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <libnvpair.h>
+#include <dlfcn.h>
+#include <libintl.h>
+#include <sys/systeminfo.h>
+#include <sys/fs_reparse.h>
+#include "rp_plugin.h"
+
+#define MAXISALEN 257 /* based on sysinfo(2) man page */
+
+static rp_proto_handle_t rp_proto_handle;
+static rp_proto_plugin_t *rp_proto_list;
+
+int rp_plugin_init(void);
+static void proto_plugin_fini(void);
+static rp_plugin_ops_t *rp_find_protocol(const char *svctype);
+
+extern int errno;
+static int rp_plugin_inited = 0;
+
+/*
+ * reparse_create()
+ *
+ * Create a symlink at the specified 'path' as a reparse point.
+ * This function will fail if path refers to an existing file system
+ * object or an object named string already exists at the given path.
+ *
+ * return 0 if ok else return error code.
+ */
+int
+reparse_create(const char *path, const char *string)
+{
+ int err;
+ struct stat sbuf;
+
+ if (path == NULL || string == NULL)
+ return (EINVAL);
+
+ if ((err = reparse_validate(string)) != 0)
+ return (err);
+
+ /* check if object exists */
+ if (lstat(path, &sbuf) == 0)
+ return (EEXIST);
+
+ return (symlink(string, path) ? errno : 0);
+}
+
+/*
+ * reparse_unparse()
+ *
+ * Convert an nvlist back to a string format suitable to write
+ * to the reparse point symlink body. The string returned is in
+ * allocated memory and must be freed by the caller.
+ *
+ * return 0 if ok else return error code.
+ */
+int
+reparse_unparse(nvlist_t *nvl, char **stringp)
+{
+ int err, buflen;
+ char *buf, *stype, *val;
+ nvpair_t *curr;
+
+ if (nvl == NULL || stringp == NULL ||
+ ((curr = nvlist_next_nvpair(nvl, NULL)) == NULL))
+ return (EINVAL);
+
+ buflen = SYMLINK_MAX;
+ if ((buf = malloc(buflen)) == NULL)
+ return (ENOMEM);
+
+ err = 0;
+ (void) snprintf(buf, buflen, "%s", FS_REPARSE_TAG_STR);
+ while (curr != NULL) {
+ if (!(stype = nvpair_name(curr))) {
+ err = EINVAL;
+ break;
+ }
+ if ((strlcat(buf, FS_TOKEN_START_STR, buflen) >= buflen) ||
+ (strlcat(buf, stype, buflen) >= buflen) ||
+ (strlcat(buf, ":", buflen) >= buflen) ||
+ (nvpair_value_string(curr, &val) != 0) ||
+ (strlcat(buf, val, buflen) >= buflen) ||
+ (strlcat(buf, FS_TOKEN_END_STR, buflen) >= buflen)) {
+ err = E2BIG;
+ break;
+ }
+ curr = nvlist_next_nvpair(nvl, curr);
+ }
+ if (err != 0) {
+ free(buf);
+ return (err);
+ }
+ if (strlcat(buf, FS_REPARSE_TAG_END_STR, buflen) >= buflen) {
+ free(buf);
+ return (E2BIG);
+ }
+
+ *stringp = buf;
+ return (0);
+}
+
+/*
+ * reparse_deref()
+ *
+ * Accepts the service-specific item from the reparse point and returns
+ * the service-specific data requested. The caller specifies the size
+ * of the buffer provided via *bufsz.
+ *
+ * if ok return 0 and *bufsz is updated to contain the actual length of
+ * the returned results, else return error code. If the error code is
+ * EOVERFLOW; results do not fit in the buffer, *bufsz will be updated
+ * to contain the number of bytes needed to hold the results.
+ */
+int
+reparse_deref(const char *svc_type, const char *svc_data, char *buf,
+ size_t *bufsz)
+{
+ rp_plugin_ops_t *ops;
+
+ if ((svc_type == NULL) || (svc_data == NULL) || (buf == NULL) ||
+ (bufsz == NULL))
+ return (EINVAL);
+
+ ops = rp_find_protocol(svc_type);
+ if ((ops != NULL) && (ops->rpo_deref != NULL))
+ return (ops->rpo_deref(svc_type, svc_data, buf, bufsz));
+
+ /* no plugin, return error */
+ return (ENOTSUP);
+}
+
+/*
+ * reparse_delete()
+ *
+ * Delete a reparse point at a given pathname. It will fail if
+ * a reparse point does not exist at the given path or the pathname
+ * is not a symlink.
+ *
+ * return 0 if ok else return error code.
+ */
+int
+reparse_delete(const char *path)
+{
+ struct stat sbuf;
+
+ if (path == NULL)
+ return (EINVAL);
+
+ /* check if object exists */
+ if (lstat(path, &sbuf) != 0)
+ return (errno);
+
+ if ((sbuf.st_mode & S_IFLNK) != S_IFLNK)
+ return (EINVAL);
+
+ return (unlink(path) ? errno : 0);
+}
+
+/*
+ * reparse_add()
+ *
+ * Add a service type entry to a nvlist with a copy of svc_data,
+ * replacing one of the same type if already present.
+ *
+ * return 0 if ok else return error code.
+ */
+int
+reparse_add(nvlist_t *nvl, const char *svc_type, const char *svc_data)
+{
+ int err;
+ char *buf;
+ size_t bufsz;
+ rp_plugin_ops_t *ops;
+
+ if ((nvl == NULL) || (svc_type == NULL) || (svc_data == NULL))
+ return (EINVAL);
+
+ bufsz = SYMLINK_MAX; /* no need to mess around */
+ if ((buf = malloc(bufsz)) == NULL)
+ return (ENOMEM);
+
+ ops = rp_find_protocol(svc_type);
+ if ((ops != NULL) && (ops->rpo_form != NULL))
+ err = ops->rpo_form(svc_type, svc_data, buf, &bufsz);
+ else
+ err = ENOTSUP; /* no plugin */
+
+ if (err != 0) {
+ free(buf);
+ return (err);
+ }
+
+ err = nvlist_add_string(nvl, svc_type, buf);
+ free(buf);
+ return (err);
+}
+
+/*
+ * reparse_remove()
+ *
+ * Remove a service type entry from the nvlist, if present.
+ *
+ * return 0 if ok else return error code.
+ */
+int
+reparse_remove(nvlist_t *nvl, const char *svc_type)
+{
+ if ((nvl == NULL) || (svc_type == NULL))
+ return (EINVAL);
+
+ return (nvlist_remove_all(nvl, svc_type));
+}
+
+/*
+ * Returns true if name is "." or "..", otherwise returns false.
+ */
+static boolean_t
+rp_is_dot_or_dotdot(const char *name)
+{
+ if (*name != '.')
+ return (B_FALSE);
+
+ if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+static void
+proto_plugin_fini()
+{
+ rp_proto_plugin_t *p;
+
+ /*
+ * Protocols may call this framework during _fini
+ */
+ for (p = rp_proto_list; p != NULL; p = p->plugin_next) {
+ if (p->plugin_ops->rpo_fini)
+ p->plugin_ops->rpo_fini();
+ }
+ while ((p = rp_proto_list) != NULL) {
+ rp_proto_list = p->plugin_next;
+ if (p->plugin_handle != NULL)
+ (void) dlclose(p->plugin_handle);
+ free(p);
+ }
+
+ if (rp_proto_handle.rp_ops != NULL) {
+ free(rp_proto_handle.rp_ops);
+ rp_proto_handle.rp_ops = NULL;
+ }
+ rp_proto_handle.rp_num_proto = 0;
+}
+
+/*
+ * rp_plugin_init()
+ *
+ * Initialize the service type specific plugin modules.
+ * For each reparse service type, there should be a plugin library for it.
+ * This function walks /usr/lib/reparse directory for plugin libraries.
+ * For each plugin library found, initialize it and add it to the internal
+ * list of service type plugin. These are used for service type specific
+ * operations.
+ */
+int
+rp_plugin_init()
+{
+ int err, ret = RP_OK;
+ char isa[MAXISALEN], dirpath[MAXPATHLEN], path[MAXPATHLEN];
+ int num_protos = 0;
+ rp_proto_handle_t *rp_hdl;
+ rp_proto_plugin_t *proto, *tmp;
+ rp_plugin_ops_t *plugin_ops;
+ struct stat st;
+ void *dlhandle;
+ DIR *dir;
+ struct dirent *dent;
+
+#if defined(_LP64)
+ if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
+ isa[0] = '\0';
+#else
+ isa[0] = '\0';
+#endif
+
+ (void) snprintf(dirpath, MAXPATHLEN,
+ "%s/%s", RP_LIB_DIR, isa);
+
+ if ((dir = opendir(dirpath)) == NULL)
+ return (RP_NO_PLUGIN_DIR);
+
+ while ((dent = readdir(dir)) != NULL) {
+ if (rp_is_dot_or_dotdot(dent->d_name))
+ continue;
+
+ (void) snprintf(path, MAXPATHLEN,
+ "%s/%s", dirpath, dent->d_name);
+
+ /*
+ * If file doesn't exist, don't try to map it
+ */
+ if (stat(path, &st) < 0)
+ continue;
+ if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL)
+ continue;
+
+ plugin_ops = (rp_plugin_ops_t *)
+ dlsym(dlhandle, "rp_plugin_ops");
+ if (plugin_ops == NULL) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Error in plugin ops for service type %s\n%s\n"),
+ dent->d_name, dlerror());
+ (void) dlclose(dlhandle);
+ continue;
+ }
+ proto = (rp_proto_plugin_t *)
+ calloc(1, sizeof (rp_proto_plugin_t));
+ if (proto == NULL) {
+ (void) dlclose(dlhandle);
+ (void) fprintf(stderr,
+ dgettext(TEXT_DOMAIN, "No memory for plugin %s\n"),
+ dent->d_name);
+ ret = RP_NO_MEMORY;
+ break;
+ }
+
+ proto->plugin_ops = plugin_ops;
+ proto->plugin_handle = dlhandle;
+ num_protos++;
+ proto->plugin_next = rp_proto_list;
+ rp_proto_list = proto;
+ }
+
+ (void) closedir(dir);
+
+ if ((num_protos == 0) && (ret == 0))
+ ret = RP_NO_PLUGIN;
+ /*
+ * There was an error, so cleanup prior to return of failure.
+ */
+ if (ret != RP_OK) {
+ proto_plugin_fini();
+ return (ret);
+ }
+
+ rp_proto_handle.rp_ops = (rp_plugin_ops_t **)calloc(num_protos,
+ sizeof (rp_plugin_ops_t *));
+ if (!rp_proto_handle.rp_ops) {
+ proto_plugin_fini();
+ return (RP_NO_MEMORY);
+ }
+
+ rp_hdl = &rp_proto_handle;
+ rp_hdl->rp_num_proto = 0;
+ for (tmp = rp_proto_list; rp_hdl->rp_num_proto < num_protos &&
+ tmp != NULL; tmp = tmp->plugin_next) {
+
+ err = RP_OK;
+ if (tmp->plugin_ops->rpo_init != NULL)
+ err = tmp->plugin_ops->rpo_init();
+ if (err != RP_OK)
+ continue;
+ rp_hdl->rp_ops[rp_hdl->rp_num_proto++] = tmp->plugin_ops;
+ }
+
+ return (rp_hdl->rp_num_proto > 0 ? RP_OK : RP_NO_PLUGIN);
+}
+
+
+/*
+ * find_protocol()
+ *
+ * Search the plugin list for the specified protocol and return the
+ * ops vector. return NULL if protocol is not defined.
+ */
+static rp_plugin_ops_t *
+rp_find_protocol(const char *svc_type)
+{
+ int i;
+ rp_plugin_ops_t *ops = NULL;
+
+ if (svc_type == NULL)
+ return (NULL);
+
+ if (rp_plugin_inited == 0) {
+ if (rp_plugin_init() == RP_OK)
+ rp_plugin_inited = 1;
+ else
+ return (NULL);
+ }
+
+ for (i = 0; i < rp_proto_handle.rp_num_proto; i++) {
+ ops = rp_proto_handle.rp_ops[i];
+ if (ops->rpo_supports_svc(svc_type))
+ return (ops);
+
+ }
+ return (NULL);
+}
diff --git a/usr/src/lib/libreparse/common/llib-lreparse b/usr/src/lib/libreparse/common/llib-lreparse
new file mode 100644
index 0000000000..082aa4032d
--- /dev/null
+++ b/usr/src/lib/libreparse/common/llib-lreparse
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/fs_reparse.h>
+#include "rp_plugin.h"
+
+/*
+ * usr/src/lib/libreparse
+ */
+int reparse_add(nvlist_t *, const char *, const char *);
+int reparse_create(const char *, const char *);
+int reparse_delete(const char *);
+int reparse_deref(const char *, const char *, char *, size_t *);
+void reparse_free(nvlist_t *);
+nvlist_t *reparse_init(void);
+int reparse_parse(const char *, nvlist_t *);
+int reparse_remove(nvlist_t *, const char *);
+int reparse_remove(nvlist_t *, const char *);
+int reparse_unparse(nvlist_t *, char **);
+int reparse_validate(const char *);
+int rp_plugin_init();
diff --git a/usr/src/lib/libreparse/common/mapfile-vers b/usr/src/lib/libreparse/common/mapfile-vers
new file mode 100644
index 0000000000..94bfba08ec
--- /dev/null
+++ b/usr/src/lib/libreparse/common/mapfile-vers
@@ -0,0 +1,54 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate {
+ global:
+ reparse_add;
+ reparse_create;
+ reparse_delete;
+ reparse_deref;
+ reparse_free;
+ reparse_init;
+ reparse_parse;
+ reparse_remove;
+ reparse_unparse;
+ reparse_validate;
+ rp_plugin_init;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libreparse/common/rp_plugin.h b/usr/src/lib/libreparse/common/rp_plugin.h
new file mode 100644
index 0000000000..a12b45776c
--- /dev/null
+++ b/usr/src/lib/libreparse/common/rp_plugin.h
@@ -0,0 +1,75 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _RP_PLUGIN_H
+#define _RP_PLUGIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define RP_LIB_DIR "/usr/lib/reparse"
+#define RP_PLUGIN_V1 1
+
+/*
+ * some error codes
+ */
+#define RP_OK 0
+#define RP_NO_PLUGIN ENOENT
+#define RP_NO_MEMORY ENOMEM
+#define RP_NO_PLUGIN_DIR ENOTDIR
+#define RP_INVALID_PROTOCOL EINVAL
+
+extern int rp_plugin_init();
+
+typedef struct rp_plugin_ops {
+ int rpo_version;
+ int (*rpo_init)(void);
+ int (*rpo_fini)(void);
+ char *(*rpo_svc_types)(void);
+ boolean_t (*rpo_supports_svc)(const char *);
+ int (*rpo_form)(const char *, const char *, char *, size_t *);
+ int (*rpo_deref)(const char *, const char *, char *, size_t *);
+} rp_plugin_ops_t;
+
+typedef struct rp_proto_plugin {
+ struct rp_proto_plugin *plugin_next;
+ rp_plugin_ops_t *plugin_ops;
+ void *plugin_handle;
+} rp_proto_plugin_t;
+
+typedef struct rp_proto_handle {
+ int rp_num_proto;
+ rp_plugin_ops_t **rp_ops;
+} rp_proto_handle_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RP_PLUGIN_H */
diff --git a/usr/src/lib/libreparse/i386/Makefile b/usr/src/lib/libreparse/i386/Makefile
new file mode 100644
index 0000000000..c86be4377c
--- /dev/null
+++ b/usr/src/lib/libreparse/i386/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libreparse/sparc/Makefile b/usr/src/lib/libreparse/sparc/Makefile
new file mode 100644
index 0000000000..c86be4377c
--- /dev/null
+++ b/usr/src/lib/libreparse/sparc/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libreparse/sparcv9/Makefile b/usr/src/lib/libreparse/sparcv9/Makefile
new file mode 100644
index 0000000000..036c13779e
--- /dev/null
+++ b/usr/src/lib/libreparse/sparcv9/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index f3df01c4f7..b09d1f7a1e 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -139,6 +139,7 @@ solaris.smf.manage.nwam:::Manage Network Auto-Magic Service States::help=SmfNWAM
solaris.smf.manage.power:::Manage Power Management Service States::help=SmfPowerStates.html
solaris.smf.manage.smb:::Manage SMB Service States::help=SmfSMBStates.html
solaris.smf.manage.smbfs:::Manage SMB Client States::help=SmfSMBFSStates.html
+solaris.smf.manage.reparse:::Manage Reparse Service States::help=SmfReparseStates.html
solaris.smf.manage.rmvolmgr:::Manage Rmvolmgr Service States::help=SmfRmvolmgrStates.html
solaris.smf.manage.routing:::Manage Routing Service States::help=SmfRoutingStates.html
solaris.smf.manage.rpc.bind:::Manage RPC Program number mapper::help=SmfRPCBind.html
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index b18c017f5c..e5611950f5 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -86,6 +86,7 @@ HTMLENTS = \
SmfNDMPStates.html \
SmfNWAMStates.html \
SmfPowerStates.html \
+ SmfReparseStates.html \
SmfRoutingStates.html \
SmfSendmailStates.html \
SmfSshStates.html \
diff --git a/usr/src/lib/libsecdb/help/auths/SmfReparseStates.html b/usr/src/lib/libsecdb/help/auths/SmfReparseStates.html
new file mode 100644
index 0000000000..c4c0d406e5
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfReparseStates.html
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+ 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 2009 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage Reparse Service States is in the Authorizations Include
+column, it grants the authorization to enable, disable, or restart
+the Reparse service.
+<p>
+If Manage Reparse Service States is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile
index 153d1eae39..cb36914f91 100644
--- a/usr/src/lib/libsecdb/help/profiles/Makefile
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile
@@ -69,6 +69,7 @@ HTMLENTS = \
RtObAccessMngmnt.html \
RtPrntAdmin.html \
RtProcManagement.html \
+ RtReparseMngmnt.html \
RtRightsDelegate.html \
RtSMBMngmnt.html \
RtSMBFSMngmnt.html \
diff --git a/usr/src/lib/libsecdb/help/profiles/RtReparseMngmnt.html b/usr/src/lib/libsecdb/help/profiles/RtReparseMngmnt.html
new file mode 100644
index 0000000000..c4c0d406e5
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/profiles/RtReparseMngmnt.html
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+ 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 2009 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage Reparse Service States is in the Authorizations Include
+column, it grants the authorization to enable, disable, or restart
+the Reparse service.
+<p>
+If Manage Reparse Service States is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index 1bb782d6d3..96bfbfc5c9 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -72,6 +72,7 @@ Name Service Management:::Non-security name service scripts/commands:help=RtName
Name Service Security:::Security related name service scripts/commands:help=RtNameServiceSecure.html
Object Access Management:::Change ownership and permission on files:help=RtObAccessMngmnt.html
Process Management:::Manage current processes and processors:auths=solaris.smf.manage.cron,solaris.smf.manage.power;help=RtProcManagement.html
+Reparse Management:::Manage the reparse service:auths=solaris.smf.manage.reparse:help=RtReparseMngmnt.html
Rights Delegation:::Delegate ability to assign rights to users and roles:auths=solaris.role.delegate,solaris.profmgr.delegate,solaris.grant;help=RtRightsDelegate.html
Rmvolmgr Management:::Manage Removable Volume Manager SMF service:auths=solaris.smf.manage.rmvolmgr;help=RtRmvolmgrMngmnt.html
Service Management:::Manage services:auths=solaris.smf.manage,solaris.smf.modify
diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h
index 2c02170556..b4707ce9ee 100644
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h
@@ -346,6 +346,7 @@ typedef struct vnode {
char *v_path;
} vnode_t;
+#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
typedef struct xoptattr {
timestruc_t xoa_createtime; /* Create time of file */
@@ -361,6 +362,8 @@ typedef struct xoptattr {
uint8_t xoa_opaque;
uint8_t xoa_av_quarantined;
uint8_t xoa_av_modified;
+ uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
} xoptattr_t;
typedef struct vattr {
diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com
index 0466324e8b..59d362abea 100644
--- a/usr/src/pkgdefs/SUNW0on/prototype_com
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com
@@ -259,6 +259,7 @@ f none usr/lib/help/auths/locale/SmfNscdStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfNADDStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfNWAMStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfPowerStates.html 444 root bin
+f none usr/lib/help/auths/locale/SmfReparseStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfRoutingStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfSendmailStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfSMBFSStates.html 444 root bin
@@ -380,6 +381,7 @@ f none usr/lib/help/profiles/locale/RtNetWifiSecure.html 444 root bin
f none usr/lib/help/profiles/locale/RtNetLinkSecure.html 444 root bin
f none usr/lib/help/profiles/locale/RtObAccessMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtProcManagement.html 444 root bin
+f none usr/lib/help/profiles/locale/RtReparseMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtRightsDelegate.html 444 root bin
f none usr/lib/help/profiles/locale/RtSoftwareInstall.html 444 root bin
f none usr/lib/help/profiles/locale/RtSMBFSMngmnt.html 444 root bin
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com
index 57a3212f7a..75cd755017 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_com
+++ b/usr/src/pkgdefs/SUNWarc/prototype_com
@@ -150,6 +150,8 @@ s none usr/lib/llib-lposix4=../../lib/llib-lrt
s none usr/lib/llib-lposix4.ln=../../lib/llib-lrt.ln
f none usr/lib/llib-lproject 644 root bin
f none usr/lib/llib-lproject.ln 644 root bin
+f none usr/lib/llib-lreparse 644 root bin
+f none usr/lib/llib-lreparse.ln 644 root bin
s none usr/lib/llib-lresolv=../../lib/llib-lresolv
s none usr/lib/llib-lresolv.ln=../../lib/llib-lresolv.ln
s none usr/lib/llib-lrpcsvc=../../lib/llib-lrpcsvc
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386
index 3ed9cf42d8..ac0c40de89 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386
@@ -114,6 +114,7 @@ f none usr/lib/amd64/llib-l300s.ln 644 root bin
f none usr/lib/amd64/llib-l4014.ln 644 root bin
f none usr/lib/amd64/llib-l450.ln 644 root bin
s none usr/lib/amd64/llib-lpthread.ln=../../../lib/amd64/llib-lpthread.ln
+f none usr/lib/amd64/llib-lreparse.ln 644 root bin
s none usr/lib/amd64/llib-lresolv.ln=../../../lib/amd64/llib-lresolv.ln
s none usr/lib/amd64/llib-lrpcsvc.ln=../../../lib/amd64/llib-lrpcsvc.ln
s none usr/lib/amd64/llib-lrt.ln=../../../lib/amd64/llib-lrt.ln
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc
index 46af1deb3d..9315cb47a8 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -110,6 +110,7 @@ f none usr/lib/sparcv9/llib-l300s.ln 644 root bin
f none usr/lib/sparcv9/llib-l4014.ln 644 root bin
f none usr/lib/sparcv9/llib-l450.ln 644 root bin
s none usr/lib/sparcv9/llib-lpthread.ln=../../../lib/sparcv9/llib-lpthread.ln
+f none usr/lib/sparcv9/llib-lreparse.ln 644 root bin
s none usr/lib/sparcv9/llib-lresolv.ln=../../../lib/sparcv9/llib-lresolv.ln
s none usr/lib/sparcv9/llib-lrpcsvc.ln=../../../lib/sparcv9/llib-lrpcsvc.ln
s none usr/lib/sparcv9/llib-lrt.ln=../../../lib/sparcv9/llib-lrt.ln
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com
index 8132fc38a3..13001f6c96 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com
@@ -210,6 +210,8 @@ s none usr/lib/libpthread.so=../../lib/libpthread.so.1
s none usr/lib/libpthread.so.1=../../lib/libpthread.so.1
s none usr/lib/librcm.so=../../lib/librcm.so.1
s none usr/lib/librcm.so.1=../../lib/librcm.so.1
+f none usr/lib/libreparse.so.1 755 root bin
+s none usr/lib/libreparse.so=./libreparse.so.1
s none usr/lib/libresolv.so=../../lib/libresolv.so.2
s none usr/lib/libresolv.so.1=../../lib/libresolv.so.1
s none usr/lib/libresolv.so.2=../../lib/libresolv.so.2
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386
index 5998608f6d..d7a759507d 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386
@@ -298,6 +298,8 @@ s none usr/lib/amd64/libpthread.so.1=../../../lib/amd64/libpthread.so.1
s none usr/lib/amd64/libpthread.so=../../../lib/amd64/libpthread.so.1
s none usr/lib/amd64/librcm.so.1=../../../lib/amd64/librcm.so.1
s none usr/lib/amd64/librcm.so=../../../lib/amd64/librcm.so.1
+f none usr/lib/amd64/libreparse.so.1 755 root bin
+s none usr/lib/amd64/libreparse.so=libreparse.so.1
s none usr/lib/amd64/libresolv.so.2=../../../lib/amd64/libresolv.so.2
s none usr/lib/amd64/libresolv.so=../../../lib/amd64/libresolv.so.2
s none usr/lib/amd64/librpcsvc.so.1=../../../lib/amd64/librpcsvc.so.1
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
index bbf2f51dda..2eb58e5d50 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
@@ -288,6 +288,8 @@ s none usr/lib/sparcv9/libpthread.so.1=../../../lib/sparcv9/libpthread.so.1
s none usr/lib/sparcv9/libpthread.so=../../../lib/sparcv9/libpthread.so.1
s none usr/lib/sparcv9/librcm.so.1=../../../lib/sparcv9/librcm.so.1
s none usr/lib/sparcv9/librcm.so=../../../lib/sparcv9/librcm.so.1
+f none usr/lib/sparcv9/libreparse.so.1 755 root bin
+s none usr/lib/sparcv9/libreparse.so=libreparse.so.1
s none usr/lib/sparcv9/libresolv.so.2=../../../lib/sparcv9/libresolv.so.2
s none usr/lib/sparcv9/libresolv.so=../../../lib/sparcv9/libresolv.so.2
s none usr/lib/sparcv9/librestart.so.1=../../../lib/sparcv9/librestart.so.1
diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com
index 52640a47a3..168304edec 100644
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com
@@ -531,6 +531,7 @@ d none var/svc/manifest/network/ssl 0755 root sys
f manifest var/svc/manifest/network/ssl/kssl-proxy.xml 0444 root sys
d none var/svc/manifest/network/shares 0755 root sys
f manifest var/svc/manifest/network/shares/group.xml 0444 root sys
+f manifest var/svc/manifest/network/shares/reparsed.xml 0444 root sys
d none var/svc/manifest/platform 755 root sys
d none var/svc/manifest/site 755 root sys
d none var/svc/manifest/system 755 root sys
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index 2e310f335d..4bf58d60f4 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -501,6 +501,7 @@ f none usr/lib/help/auths/locale/C/SmfNscdStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfNADDStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfNWAMStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfPowerStates.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfReparseStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfRoutingStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfSendmailStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfSMBFSStates.html 444 root bin
@@ -604,6 +605,7 @@ f none usr/lib/help/profiles/locale/C/RtNetLinkSecure.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtObAccessMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtPrntAdmin.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtProcManagement.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtReparseMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtRightsDelegate.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSoftwareInstall.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSMBFSMngmnt.html 444 root bin
@@ -697,6 +699,8 @@ f none usr/lib/rcm/modules/SUNW_aggr_rcm.so 555 root bin
f none usr/lib/rcm/modules/SUNW_swap_rcm.so 555 root bin
f none usr/lib/rcm/rcm_daemon 555 root bin
d none usr/lib/rcm/scripts 755 root bin
+d none usr/lib/reparse 755 root bin
+f none usr/lib/reparse/reparsed 555 root sys
s none usr/lib/rsh=../../sbin/sh
d none usr/lib/saf 755 root bin
f none usr/lib/saf/listen 755 root sys
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index 4e1d00c89b..03cfc436a0 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -470,6 +470,7 @@ f none usr/include/regexp.h 644 root bin
f none usr/include/regexpr.h 644 root bin
f none usr/include/resolv.h 644 root bin
f none usr/include/rje.h 644 root bin
+f none usr/include/rp_plugin.h 644 root bin
d none usr/include/iso 755 root bin
s none usr/include/iso/assert_iso.h=../assert.h
f none usr/include/iso/ctype_c99.h 644 root bin
@@ -913,6 +914,7 @@ f none usr/include/sys/fs/ufs_quota.h 644 root bin
f none usr/include/sys/fs/ufs_snap.h 644 root bin
f none usr/include/sys/fs/ufs_trans.h 644 root bin
f none usr/include/sys/fs/zfs.h 644 root bin
+f none usr/include/sys/fs_reparse.h 644 root bin
f none usr/include/sys/fs_subr.h 644 root bin
f none usr/include/sys/fsid.h 644 root bin
f none usr/include/sys/fssnap.h 644 root bin
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 2c0777fc54..7d8ed8dac1 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -162,6 +162,7 @@ GENUNIX_OBJS += \
fork.o \
vpm.o \
fsat.o \
+ fs_reparse.o \
fs_subr.o \
fsflush.o \
ftrace.o \
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 75354e4c62..01a28db0be 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -340,6 +340,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/pmcs/%.bin
$(COMPILE.b) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/fsreparse/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
KMECHKRB5_BASE=$(UTSBASE)/common/gssapi/mechs/krb5
KGSSDFLAGS=-I $(UTSBASE)/common/gssapi/include
@@ -2530,3 +2534,6 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/vr/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/yge/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(COMMONBASE)/fsreparse/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/fs/Makefile b/usr/src/uts/common/fs/Makefile
index 28ad019955..53660e655d 100644
--- a/usr/src/uts/common/fs/Makefile
+++ b/usr/src/uts/common/fs/Makefile
@@ -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,17 +18,16 @@
#
# CDDL HEADER END
#
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright (c) 1989 by Sun Microsystems, Inc.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
#
# uts/common/fs/Makefile
#
# include global definitions
include ../../../Makefile.master
-HDRS= fs_subr.h
+HDRS= fs_subr.h \
+ fs_reparse.h
PROCHDRS= prdata.h
diff --git a/usr/src/uts/common/fs/fs_reparse.h b/usr/src/uts/common/fs/fs_reparse.h
new file mode 100644
index 0000000000..ec44484117
--- /dev/null
+++ b/usr/src/uts/common/fs/fs_reparse.h
@@ -0,0 +1,88 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FS_REPARSE_H
+#define _FS_REPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/time.h>
+#include <sys/nvpair.h>
+#else
+#include <libnvpair.h>
+#endif
+
+#define FS_REPARSE_TAG_STR "@{REPARSE"
+#define FS_REPARSE_TAG_END_CHAR '}'
+#define FS_REPARSE_TAG_END_STR "}"
+#define FS_TOKEN_START_STR "@{"
+#define FS_TOKEN_END_STR "}"
+
+#define REPARSED "svc:/system/filesystem/reparse:default"
+#define MAXREPARSELEN MAXPATHLEN
+#define REPARSED_DOOR "/var/run/reparsed_door"
+#define REPARSED_DOORCALL_MAX_RETRY 4
+
+/*
+ * This structure is shared between kernel code and user reparsed daemon.
+ * The 'res_len' must be defined as int, and not size_t, for 32-bit reparsed
+ * binary and 64-bit kernel code to work together.
+ */
+typedef struct reparsed_door_res {
+ int res_status;
+ int res_len;
+ char res_data[1];
+} reparsed_door_res_t;
+
+extern nvlist_t *reparse_init(void);
+extern void reparse_free(nvlist_t *nvl);
+extern int reparse_parse(const char *reparse_data, nvlist_t *nvl);
+extern int reparse_validate(const char *reparse_data);
+
+#ifdef _KERNEL
+extern int reparse_kderef(const char *svc_type, const char *svc_data,
+ char *buf, size_t *bufsz);
+extern int reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl);
+#else
+extern int reparse_add(nvlist_t *nvl, const char *svc_type,
+ const char *svc_data);
+extern int reparse_remove(nvlist_t *nvl, const char *svc_type);
+extern int reparse_unparse(nvlist_t *nvl, char **stringp);
+extern int reparse_create(const char *path, const char *string);
+extern int reparse_delete(const char *path);
+extern int reparse_deref(const char *svc_type, const char *svc_data,
+ char *buf, size_t *bufsz);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FS_REPARSE_H */
diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c
index 5187ecf327..a465a97043 100644
--- a/usr/src/uts/common/fs/fs_subr.c
+++ b/usr/src/uts/common/fs/fs_subr.c
@@ -48,6 +48,8 @@
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <fs/fs_subr.h>
+#include <fs/fs_reparse.h>
+#include <sys/door.h>
#include <sys/acl.h>
#include <sys/share.h>
#include <sys/file.h>
@@ -55,6 +57,7 @@
#include <sys/file.h>
#include <sys/nbmlock.h>
#include <acl/acl_common.h>
+#include <sys/pathname.h>
static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
@@ -64,6 +67,12 @@ static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
int fs_estale_retry = 5;
/*
+ * supports for reparse point door upcall
+ */
+static door_handle_t reparsed_door;
+static kmutex_t reparsed_door_lock;
+
+/*
* The associated operation is not supported by the file system.
*/
int
@@ -838,3 +847,175 @@ fs_vscan(vnode_t *vp, cred_t *cr, int async)
return (ret);
}
+
+/*
+ * support functions for reparse point
+ */
+/*
+ * reparse_vnode_parse
+ *
+ * Read the symlink data of a reparse point specified by the vnode
+ * and return the reparse data as name-value pair in the nvlist.
+ */
+int
+reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl)
+{
+ int err;
+ char *lkdata;
+ struct uio uio;
+ struct iovec iov;
+
+ if (vp == NULL || nvl == NULL)
+ return (EINVAL);
+
+ lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP);
+
+ /*
+ * Set up io vector to read sym link data
+ */
+ iov.iov_base = lkdata;
+ iov.iov_len = MAXREPARSELEN;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ uio.uio_loffset = (offset_t)0;
+ uio.uio_resid = MAXREPARSELEN;
+
+ if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) {
+ *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0';
+ err = reparse_parse(lkdata, nvl);
+ }
+ kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */
+
+ return (err);
+}
+
+void
+reparse_point_init()
+{
+ mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+static door_handle_t
+reparse_door_get_handle()
+{
+ door_handle_t dh;
+
+ mutex_enter(&reparsed_door_lock);
+ if ((dh = reparsed_door) == NULL) {
+ if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) {
+ reparsed_door = NULL;
+ dh = NULL;
+ } else
+ dh = reparsed_door;
+ }
+ mutex_exit(&reparsed_door_lock);
+ return (dh);
+}
+
+static void
+reparse_door_reset_handle()
+{
+ mutex_enter(&reparsed_door_lock);
+ reparsed_door = NULL;
+ mutex_exit(&reparsed_door_lock);
+}
+
+/*
+ * reparse_kderef
+ *
+ * Accepts the service-specific item from the reparse point and returns
+ * the service-specific data requested. The caller specifies the size of
+ * the buffer provided via *bufsz; the routine will fail with EOVERFLOW
+ * if the results will not fit in the buffer, in which case, *bufsz will
+ * contain the number of bytes needed to hold the results.
+ *
+ * if ok return 0 and update *bufsize with length of actual result
+ * else return error code.
+ */
+int
+reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
+ size_t *bufsize)
+{
+ int err, retries, need_free;
+ size_t dlen, res_len;
+ char *darg;
+ door_arg_t door_args;
+ reparsed_door_res_t *resp;
+ door_handle_t rp_door;
+
+ if (svc_type == NULL || svc_data == NULL || buf == NULL ||
+ bufsize == NULL)
+ return (EINVAL);
+
+ /* get reparsed's door handle */
+ if ((rp_door = reparse_door_get_handle()) == NULL)
+ return (EBADF);
+
+ /* setup buffer for door_call args and results */
+ dlen = strlen(svc_type) + strlen(svc_data) + 2;
+ if (*bufsize < dlen) {
+ darg = kmem_alloc(dlen, KM_SLEEP);
+ need_free = 1;
+ } else {
+ darg = buf; /* use same buffer for door's args & results */
+ need_free = 0;
+ }
+
+ /* build argument string of door call */
+ (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data);
+
+ /* setup args for door call */
+ door_args.data_ptr = darg;
+ door_args.data_size = dlen;
+ door_args.desc_ptr = NULL;
+ door_args.desc_num = 0;
+ door_args.rbuf = buf;
+ door_args.rsize = *bufsize;
+
+ /* do the door_call */
+ retries = 0;
+ door_ki_hold(rp_door);
+ while ((err = door_ki_upcall_limited(rp_door, &door_args,
+ NULL, SIZE_MAX, 0)) != 0) {
+ if (err == EAGAIN || err == EINTR) {
+ if (++retries < REPARSED_DOORCALL_MAX_RETRY) {
+ delay(SEC_TO_TICK(1));
+ continue;
+ }
+ } else if (err == EBADF) {
+ /* door server goes away... */
+ reparse_door_reset_handle();
+ }
+ break;
+ }
+ door_ki_rele(rp_door);
+ if (need_free)
+ kmem_free(darg, dlen); /* done with args buffer */
+
+ if (err != 0)
+ return (err);
+
+ resp = (reparsed_door_res_t *)door_args.rbuf;
+ if ((err = resp->res_status) == 0) {
+ /*
+ * have to save the length of the results before the
+ * bcopy below since it's can be an overlap copy that
+ * overwrites the reparsed_door_res_t structure at
+ * the beginning of the buffer.
+ */
+ res_len = (size_t)resp->res_len;
+
+ /* deref call is ok */
+ if (res_len > *bufsize)
+ err = EOVERFLOW;
+ else
+ bcopy(resp->res_data, buf, res_len);
+ *bufsize = res_len;
+ }
+ if (door_args.rbuf != buf)
+ kmem_free(door_args.rbuf, door_args.rsize);
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c
index bf9d325048..0d750e00ed 100644
--- a/usr/src/uts/common/fs/vfs.c
+++ b/usr/src/uts/common/fs/vfs.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -4252,6 +4252,8 @@ vfsinit(void)
}
xattr_init();
+
+ reparse_point_init();
}
vfs_t *
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c
index 09a011fc87..a42259df93 100644
--- a/usr/src/uts/common/fs/vnode.c
+++ b/usr/src/uts/common/fs/vnode.c
@@ -64,6 +64,7 @@
#include <sys/fcntl.h>
#include <fs/fs_subr.h>
#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
/* Determine if this vnode is a file that is read-only */
#define ISROFILE(vp) \
@@ -106,6 +107,11 @@ int vopstats_enabled = 1;
static void *vsd_realloc(void *, size_t, size_t);
/*
+ * forward declarations for reparse point functions
+ */
+static int fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr);
+
+/*
* VSD -- VNODE SPECIFIC DATA
* The v_data pointer is typically used by a file system to store a
* pointer to the file system's private node (e.g. ufs inode, nfs rnode).
@@ -3604,6 +3610,7 @@ fop_symlink(
int flags)
{
int err;
+ xvattr_t xvattr;
/*
* If this file system doesn't support case-insensitive access
@@ -3616,6 +3623,14 @@ fop_symlink(
VOPXID_MAP_CR(dvp, cr);
+ /* check for reparse point */
+ if ((vfs_has_feature(dvp->v_vfsp, VFSFT_REPARSE)) &&
+ (strncmp(target, FS_REPARSE_TAG_STR,
+ strlen(FS_REPARSE_TAG_STR)) == 0)) {
+ if (!fs_reparse_mark(target, vap, &xvattr))
+ vap = (vattr_t *)&xvattr;
+ }
+
err = (*(dvp)->v_op->vop_symlink)
(dvp, linkname, vap, target, cr, ct, flags);
VOPSTATS_UPDATE(dvp, symlink);
@@ -4395,3 +4410,34 @@ vsd_realloc(void *old, size_t osize, size_t nsize)
}
return (new);
}
+
+/*
+ * Setup the extensible system attribute for creating a reparse point.
+ * The symlink data 'target' is validated for proper format of a reparse
+ * string and a check also made to make sure the symlink data does not
+ * point to an existing file.
+ *
+ * return 0 if ok else -1.
+ */
+static int
+fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
+{
+ xoptattr_t *xoap;
+
+ if ((!target) || (!vap) || (!xvattr))
+ return (-1);
+
+ /* validate reparse string */
+ if (reparse_validate((const char *)target))
+ return (-1);
+
+ xva_init(xvattr);
+ xvattr->xva_vattr = *vap;
+ xvattr->xva_vattr.va_mask |= AT_XVATTR;
+ xoap = xva_getxoptattr(xvattr);
+ ASSERT(xoap);
+ XVA_SET_REQ(xvattr, XAT_REPARSE);
+ xoap->xoa_reparse = 1;
+
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c
index 274c57869c..137379ecc3 100644
--- a/usr/src/uts/common/fs/xattr.c
+++ b/usr/src/uts/common/fs/xattr.c
@@ -212,6 +212,9 @@ xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
fsid) == 0);
break;
+ case F_REPARSE:
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+ break;
default:
break;
}
@@ -294,6 +297,11 @@ xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
sizeof (xoap->xoa_createtime) /
sizeof (uint64_t)) == 0);
}
+ if (XVA_ISSET_RTN(&xvattr, XAT_REPARSE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_REPARSE),
+ xoap->xoa_reparse) == 0);
+ }
}
/*
* Check for optional ownersid/groupsid
@@ -667,6 +675,10 @@ xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
return (EINVAL);
}
break;
+ case F_REPARSE:
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+ xoap->xoa_reparse = value;
+ break;
default:
break;
}
@@ -807,6 +819,7 @@ xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
pdvp = gfs_file_parent(sdvp);
error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
index 5db5b8d518..ca826abbac 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
@@ -57,6 +57,7 @@ extern "C" {
#define ZFS_OPAQUE 0x0000010000000000
#define ZFS_AV_QUARANTINED 0x0000020000000000
#define ZFS_AV_MODIFIED 0x0000040000000000
+#define ZFS_REPARSE 0x0000080000000000
#define ZFS_ATTR_SET(zp, attr, value) \
{ \
diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c
index 4df7115f58..f0a713ed94 100644
--- a/usr/src/uts/common/fs/zfs/zfs_log.c
+++ b/usr/src/uts/common/fs/zfs/zfs_log.c
@@ -175,6 +175,9 @@ zfs_log_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime);
if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ);
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
+ *attrs |= (xoap->xoa_reparse == 0) ? 0 :
+ XAT0_REPARSE;
}
static void *
diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c
index 85b79703a7..232422b0f8 100644
--- a/usr/src/uts/common/fs/zfs/zfs_replay.c
+++ b/usr/src/uts/common/fs/zfs/zfs_replay.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -129,6 +127,8 @@ zfs_replay_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime);
if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
+ xoap->xoa_reparse = ((*attrs & XAT0_REPARSE) != 0);
}
static int
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 8f51a0dbf2..7a6b850d1c 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -1049,6 +1049,7 @@ zfs_set_fuid_feature(zfsvfs_t *zfsvfs)
vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS);
vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE);
vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER);
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_REPARSE);
}
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 644b2dba9a..6513640437 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -2370,6 +2370,12 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
ZFS_TIME_DECODE(&xoap->xoa_createtime, pzp->zp_crtime);
XVA_SET_RTN(xvap, XAT_CREATETIME);
}
+
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ xoap->xoa_reparse =
+ ((pzp->zp_flags & ZFS_REPARSE) != 0);
+ XVA_SET_RTN(xvap, XAT_REPARSE);
+ }
}
ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime);
@@ -2671,6 +2677,12 @@ top:
}
}
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ mutex_exit(&zp->z_lock);
+ ZFS_EXIT(zfsvfs);
+ return (EPERM);
+ }
+
if (need_policy == FALSE &&
(XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) ||
XVA_ISSET_REQ(xvap, XAT_OPAQUE))) {
diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c
index 62156fb4f6..c861bd9936 100644
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c
@@ -909,6 +909,10 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap)
zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP;
XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
}
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ ZFS_ATTR_SET(zp, ZFS_REPARSE, xoap->xoa_reparse);
+ XVA_SET_RTN(xvap, XAT_REPARSE);
+ }
}
int
diff --git a/usr/src/uts/common/fs/zut/zut.c b/usr/src/uts/common/fs/zut/zut.c
index 9381b69aea..c655585968 100644
--- a/usr/src/uts/common/fs/zut/zut.c
+++ b/usr/src/uts/common/fs/zut/zut.c
@@ -217,6 +217,7 @@ zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
XVA_SET_REQ(&xv, XAT_OPAQUE);
XVA_SET_REQ(&xv, XAT_AV_QUARANTINED);
XVA_SET_REQ(&xv, XAT_AV_MODIFIED);
+ XVA_SET_REQ(&xv, XAT_REPARSE);
xv.xva_vattr.va_mask |= AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
if (error = VOP_GETATTR(vp, &xv.xva_vattr, flag, cr, NULL))
@@ -263,6 +264,8 @@ zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
*xvs |= (1 << F_AV_QUARANTINED);
if (XVA_ISSET_RTN(&xv, XAT_AV_MODIFIED) && xoap->xoa_av_modified)
*xvs |= (1 << F_AV_MODIFIED);
+ if (XVA_ISSET_RTN(&xv, XAT_REPARSE) && xoap->xoa_reparse)
+ *xvs |= (1 << F_REPARSE);
return (0);
}
diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h
index 86c4cd5d6c..b312b5a429 100644
--- a/usr/src/uts/common/sys/attr.h
+++ b/usr/src/uts/common/sys/attr.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_ATTR_H
#define _SYS_ATTR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -56,6 +54,7 @@ extern "C" {
#define A_AV_SCANSTAMP "av_scanstamp"
#define A_OWNERSID "ownersid"
#define A_GROUPSID "groupsid"
+#define A_REPARSE_POINT "reparse"
/* Attribute option for utilities */
#define O_HIDDEN "H"
@@ -68,6 +67,7 @@ extern "C" {
#define O_NODUMP "d"
#define O_AV_QUARANTINED "q"
#define O_AV_MODIFIED "m"
+#define O_REPARSE_POINT "r"
#define O_NONE ""
/* ownersid and groupsid are composed of two nvpairs */
@@ -92,6 +92,7 @@ typedef enum {
F_OWNERSID,
F_GROUPSID,
F_FSID,
+ F_REPARSE,
F_ATTR_ALL
} f_attr_t;
diff --git a/usr/src/uts/common/sys/vfs.h b/usr/src/uts/common/sys/vfs.h
index 17ee536024..4d0d6d1257 100644
--- a/usr/src/uts/common/sys/vfs.h
+++ b/usr/src/uts/common/sys/vfs.h
@@ -297,6 +297,7 @@ typedef uint64_t vfs_feature_t;
#define VFSFT_ACEMASKONACCESS 0x100000020 /* Can use ACEMASK for access */
#define VFSFT_SYSATTR_VIEWS 0x100000040 /* Supports sysattr view i/f */
#define VFSFT_ACCESS_FILTER 0x100000080 /* dirents filtered by access */
+#define VFSFT_REPARSE 0x100000100 /* Supports reparse point */
/*
* Argument structure for mount(2).
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index f3e3fe6879..a060c30434 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -387,6 +387,7 @@ typedef struct xoptattr {
uint8_t xoa_av_quarantined;
uint8_t xoa_av_modified;
uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
} xoptattr_t;
/*
@@ -565,11 +566,12 @@ typedef vattr_t vattr32_t;
#define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */
#define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */
#define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */
+#define XAT0_REPARSE 0x00002000 /* FS reparse point */
#define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \
- XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP)
+ XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP|XAT0_REPARSE)
/* Support for XAT_* optional attributes */
#define XVA_MASK 0xffffffff /* Used to mask off 32 bits */
@@ -602,6 +604,7 @@ typedef vattr_t vattr32_t;
#define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
#define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
#define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+#define XAT_REPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
/*
* The returned attribute map array (xva_rtnattrmap[]) is located past the
@@ -1274,6 +1277,9 @@ void xattr_init(void); /* Initialize vnodeops for xattrs */
/* GFS tunnel for xattrs */
int xattr_dir_lookup(vnode_t *, vnode_t **, int, cred_t *);
+/* Reparse Point */
+void reparse_point_init(void);
+
/* Context identification */
u_longlong_t fs_new_caller_id();