summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authormarks <none@none>2007-06-26 07:44:24 -0700
committermarks <none@none>2007-06-26 07:44:24 -0700
commitecd6cf800b63704be73fb264c3f5b6e0dafc068d (patch)
treeec83d040bc56ee0a46e9533a645e832e58d8ba86 /usr/src/lib
parent8ac1b93fdff76ea81638299d410b2d474240ee2b (diff)
downloadillumos-joyent-ecd6cf800b63704be73fb264c3f5b6e0dafc068d.tar.gz
PSARC/2006/465 ZFS Delegated Administration
PSARC/2006/577 zpool property to disable delegation PSARC/2006/625 Enhancements to zpool history PSARC/2007/228 ZFS delegation amendments PSARC/2007/295 ZFS Delegated Administration Addendum 6280676 restore "owner" property 6349470 investigate non-root restore/backup 6572465 'zpool set bootfs=...' records history as 'zfs set bootfs=...'
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/libiscsitgt/Makefile.com5
-rw-r--r--usr/src/lib/libiscsitgt/common/gen.c18
-rw-r--r--usr/src/lib/libiscsitgt/common/if_zfs.c42
-rw-r--r--usr/src/lib/libiscsitgt/common/libiscsitgt.h7
-rw-r--r--usr/src/lib/libiscsitgt/common/mapfile-vers3
-rw-r--r--usr/src/lib/libshare/common/libshare.c4
-rw-r--r--usr/src/lib/libshare/common/libshare.h2
-rw-r--r--usr/src/lib/libshare/common/libshare_impl.h11
-rw-r--r--usr/src/lib/libshare/common/libshare_zfs.c75
-rw-r--r--usr/src/lib/libshare/common/libsharecore.c16
-rw-r--r--usr/src/lib/libshare/common/mapfile-vers4
-rw-r--r--usr/src/lib/libshare/common/plugin.c4
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.c105
-rw-r--r--usr/src/lib/libzfs/Makefile.com4
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h67
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c946
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h3
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c44
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c79
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c55
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers10
-rw-r--r--usr/src/lib/libzpool/Makefile.com1
-rw-r--r--usr/src/lib/libzpool/common/kernel.c42
-rw-r--r--usr/src/lib/libzpool/common/sys/zfs_context.h11
24 files changed, 1414 insertions, 144 deletions
diff --git a/usr/src/lib/libiscsitgt/Makefile.com b/usr/src/lib/libiscsitgt/Makefile.com
index 1a160df7de..3d4559c7fd 100644
--- a/usr/src/lib/libiscsitgt/Makefile.com
+++ b/usr/src/lib/libiscsitgt/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -42,7 +42,8 @@ SRCS = $(OBJECTS:%.o=$(SRCDIR)/%.c)
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CFLAGS += $(CCVERBOSE)
-CPPFLAGS += -I/usr/include/libxml2 -I$(SRCDIR)
+CPPFLAGS += -I/usr/include/libxml2 -I$(SRCDIR) \
+ -I../../../cmd/iscsi/iscsitgtd
.KEEP_STATE:
diff --git a/usr/src/lib/libiscsitgt/common/gen.c b/usr/src/lib/libiscsitgt/common/gen.c
index 93fc956643..706378d4f6 100644
--- a/usr/src/lib/libiscsitgt/common/gen.c
+++ b/usr/src/lib/libiscsitgt/common/gen.c
@@ -52,8 +52,8 @@ tgt_door_call(char *str, int smf_flags)
{
tgt_node_t *n = NULL;
door_arg_t d;
- int s,
- allocated;
+ int s;
+ int allocated;
xmlTextReaderPtr r;
char *door_buf = NULL;
@@ -194,8 +194,8 @@ is_auto_enabled(void)
static Boolean_t
check_and_online(int smf_flags)
{
- int i,
- fd;
+ int i;
+ int fd;
door_arg_t d;
if (!is_online()) {
@@ -245,3 +245,13 @@ check_and_online(int smf_flags)
}
return (False);
}
+
+/*
+ * Not using Boolean_t here, since that is a
+ * private type to the library
+ */
+int
+iscsitgt_svc_online()
+{
+ return ((is_online() == True) ? 0 : 1);
+}
diff --git a/usr/src/lib/libiscsitgt/common/if_zfs.c b/usr/src/lib/libiscsitgt/common/if_zfs.c
index ffaca97b79..3528872286 100644
--- a/usr/src/lib/libiscsitgt/common/if_zfs.c
+++ b/usr/src/lib/libiscsitgt/common/if_zfs.c
@@ -35,6 +35,7 @@
#include <strings.h>
#include <errno.h>
#include <libscf.h>
+#include <errcode.h>
#include "iscsitgt_impl.h"
@@ -55,19 +56,27 @@ iscsitgt_zfs_share(const char *dataset)
tgt_buf_add_tag(&str, "create", Tag_End);
if ((n = tgt_door_call(str, SMF_TEMPORARY)) == NULL) {
- errno = EINVAL;
+ if (iscsitgt_svc_online() != 0) {
+ errno = EPERM;
+ } else {
+ errno = EINVAL;
+ }
free(str);
return (-1);
}
+
if (strcmp(n->x_name, XML_ELEMENT_ERROR) == 0 &&
- tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True &&
- code == 1000) {
- free(str);
- tgt_node_free(n);
- return (0);
+ tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True) {
+ if (code == 1000) {
+ free(str);
+ tgt_node_free(n);
+ return (0);
+ } else {
+ errno = (code == ERR_NO_PERMISSION) ? EPERM : EINVAL;
+ }
+ } else {
+ errno = EINVAL;
}
-
- errno = EINVAL;
free(str);
tgt_node_free(n);
return (-1);
@@ -94,17 +103,22 @@ iscsitgt_zfs_unshare(const char *dataset)
free(str);
return (-1);
}
+
if (strcmp(n->x_name, XML_ELEMENT_ERROR) == 0 &&
- tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True &&
- code == 1000) {
- free(str);
- tgt_node_free(n);
- return (0);
+ tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True) {
+ if (code == 1000) {
+ free(str);
+ tgt_node_free(n);
+ return (0);
+ } else {
+ errno = (code == ERR_NO_PERMISSION) ? EPERM : EINVAL;
+ }
+ } else {
+ errno = EINVAL;
}
free(str);
tgt_node_free(n);
- errno = EINVAL;
return (-1);
}
diff --git a/usr/src/lib/libiscsitgt/common/libiscsitgt.h b/usr/src/lib/libiscsitgt/common/libiscsitgt.h
index 690ac009b5..cf01a62fea 100644
--- a/usr/src/lib/libiscsitgt/common/libiscsitgt.h
+++ b/usr/src/lib/libiscsitgt/common/libiscsitgt.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -566,6 +566,11 @@ void iscsit_list_tpgt_free(iscsit_tpgt_t *t);
iscsit_admin_t *iscsit_list_adm(iscsit_handle_t h);
void iscsit_list_adm_free(iscsit_admin_t *t);
+/*
+ * Misc functions
+ */
+int iscsitgt_svc_online();
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libiscsitgt/common/mapfile-vers b/usr/src/lib/libiscsitgt/common/mapfile-vers
index 8702abfdfb..11ceede106 100644
--- a/usr/src/lib/libiscsitgt/common/mapfile-vers
+++ b/usr/src/lib/libiscsitgt/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -27,6 +27,7 @@
SUNWprivate_1.1 {
global:
+ iscsitgt_svc_online;
iscsitgt_zfs_is_shared;
iscsitgt_zfs_share;
iscsitgt_zfs_unshare;
diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c
index 6809ab92cf..25213e97a4 100644
--- a/usr/src/lib/libshare/common/libshare.c
+++ b/usr/src/lib/libshare/common/libshare.c
@@ -1367,10 +1367,10 @@ sa_disable_share(sa_share_t share, char *protocol)
shared = sa_get_share_attr(share, "shared");
if (protocol != NULL) {
- ret = sa_proto_unshare(protocol, path);
+ ret = sa_proto_unshare(share, protocol, path);
} else {
/* need to do all protocols */
- ret = sa_proto_unshare("nfs", path);
+ ret = sa_proto_unshare(share, "nfs", path);
}
if (ret == SA_OK)
(void) sa_set_share_attr(share, "shared", NULL);
diff --git a/usr/src/lib/libshare/common/libshare.h b/usr/src/lib/libshare/common/libshare.h
index 754ef61c69..c78b0822c6 100644
--- a/usr/src/lib/libshare/common/libshare.h
+++ b/usr/src/lib/libshare/common/libshare.h
@@ -216,7 +216,7 @@ extern int sa_delete_sharetab(char *, char *);
/* ZFS functions */
extern int sa_zfs_is_shared(sa_handle_t, char *);
extern int sa_group_is_zfs(sa_group_t);
-
+extern int sa_path_is_zfs(char *);
/* SA Handle specific functions */
extern sa_handle_t sa_find_group_handle(sa_group_t);
diff --git a/usr/src/lib/libshare/common/libshare_impl.h b/usr/src/lib/libshare/common/libshare_impl.h
index 2eef7559c9..a428110a81 100644
--- a/usr/src/lib/libshare/common/libshare_impl.h
+++ b/usr/src/lib/libshare/common/libshare_impl.h
@@ -38,6 +38,8 @@
#include <libscf.h>
#include <scfutil.h>
#include <libzfs.h>
+#include <sharefs/share.h>
+#include "sharetab.h"
#ifdef __cplusplus
extern "C" {
@@ -58,7 +60,7 @@ struct sa_plugin_ops {
int (*sa_init)();
void (*sa_fini)();
int (*sa_share)(sa_share_t); /* start sharing */
- int (*sa_unshare)(char *); /* stop sharing */
+ int (*sa_unshare)(sa_share_t, char *); /* stop sharing */
int (*sa_valid_prop)(sa_property_t, sa_optionset_t);
int (*sa_valid_space)(char *); /* is name valid optionspace? */
int (*sa_security_prop)(char *); /* property is security */
@@ -91,7 +93,7 @@ typedef struct propertylist {
} property_list_t;
extern int sa_proto_share(char *, sa_share_t);
-extern int sa_proto_unshare(char *, char *);
+extern int sa_proto_unshare(sa_share_t, char *, char *);
extern int sa_proto_valid_prop(char *, sa_property_t, sa_optionset_t);
extern int sa_proto_security_prop(char *, char *);
extern int sa_proto_legacy_opts(char *, sa_group_t, char *);
@@ -113,10 +115,15 @@ extern int sa_delete_share(scfutilhandle_t *, sa_group_t, sa_share_t);
extern int sa_delete_instance(scfutilhandle_t *, char *);
extern int sa_create_pgroup(scfutilhandle_t *, char *);
extern int sa_delete_pgroup(scfutilhandle_t *, char *);
+extern void sa_fillshare(sa_share_t share, char *proto, struct share *sh);
+extern void sa_emptyshare(struct share *sh);
/* ZFS functions */
extern int sa_get_zfs_shares(sa_handle_t, char *);
extern int sa_zfs_update(sa_share_t);
+extern int sa_share_zfs(sa_share_t, char *, share_t *, void *, boolean_t);
+extern int sa_sharetab_fill_zfs(sa_share_t share, struct share *sh,
+ char *proto);
/* plugin specific functions */
extern int proto_plugin_init();
diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c
index b7ac6c0d74..8beb621524 100644
--- a/usr/src/lib/libshare/common/libshare_zfs.c
+++ b/usr/src/lib/libshare/common/libshare_zfs.c
@@ -254,7 +254,7 @@ get_zfs_dataset(sa_handle_impl_t impl_handle, char *path)
/* canmount must be set */
canmount[0] = '\0';
- if (!zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount,
+ if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount,
sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
strcmp(canmount, "off") == 0)
continue;
@@ -914,3 +914,76 @@ sa_path_is_zfs(char *path)
sa_free_fstype(fstype);
return (ret);
}
+
+int
+sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
+{
+ char *path;
+
+ path = sa_get_share_attr(share, "path");
+ if (path != NULL) {
+ (void) memset(sh, 0, sizeof (sh));
+ (void) sa_fillshare(share, proto, sh);
+ return (0);
+ } else
+ return (1);
+}
+
+#define SMAX(i, j) \
+ if ((j) > (i)) { \
+ (i) = (j); \
+ }
+
+int
+sa_share_zfs(sa_share_t share, char *path, share_t *sh,
+ void *exportdata, boolean_t on)
+{
+ libzfs_handle_t *libhandle;
+ sa_group_t group;
+ sa_handle_t sahandle;
+ char *dataset;
+ int err = EINVAL;
+ int i, j;
+
+ /*
+ * First find the dataset name
+ */
+ if ((group = sa_get_parent_group(share)) == NULL) {
+ return (SA_SYSTEM_ERR);
+ }
+ if ((sahandle = sa_find_group_handle(group)) == NULL) {
+ return (SA_SYSTEM_ERR);
+ }
+
+ if ((dataset = get_zfs_dataset(sahandle, path)) == NULL) {
+ return (SA_SYSTEM_ERR);
+ }
+
+ libhandle = libzfs_init();
+ if (libhandle != NULL) {
+
+ i = (sh->sh_path ? strlen(sh->sh_path) : 0);
+ sh->sh_size = i;
+
+ j = (sh->sh_res ? strlen(sh->sh_res) : 0);
+ sh->sh_size += j;
+ SMAX(i, j);
+
+ j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
+ sh->sh_size += j;
+ SMAX(i, j);
+
+ j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
+ sh->sh_size += j;
+ SMAX(i, j);
+
+ j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
+ sh->sh_size += j;
+ SMAX(i, j);
+ err = zfs_deleg_share_nfs(libhandle, dataset, path,
+ exportdata, sh, i, on);
+ libzfs_fini(libhandle);
+ }
+ free(dataset);
+ return (err);
+}
diff --git a/usr/src/lib/libshare/common/libsharecore.c b/usr/src/lib/libshare/common/libsharecore.c
index d3bf9f4f6d..cbef53feab 100644
--- a/usr/src/lib/libshare/common/libsharecore.c
+++ b/usr/src/lib/libshare/common/libsharecore.c
@@ -1832,12 +1832,12 @@ sa_free_derived_security(sa_security_t security)
*/
/*
- * fillshare(share, proto, sh)
+ * sa_fillshare(share, proto, sh)
*
* Fill the struct share with values obtained from the share object.
*/
-static void
-fillshare(sa_share_t share, char *proto, struct share *sh)
+void
+sa_fillshare(sa_share_t share, char *proto, struct share *sh)
{
char *groupname = NULL;
char *value;
@@ -1916,13 +1916,13 @@ fillshare(sa_share_t share, char *proto, struct share *sh)
}
/*
- * emptyshare(sh)
+ * sa_emptyshare(sh)
*
* Free the strings in the non-NULL members of sh.
*/
-static void
-emptyshare(struct share *sh)
+void
+sa_emptyshare(struct share *sh)
{
if (sh->sh_path != NULL)
free(sh->sh_path);
@@ -1962,9 +1962,9 @@ sa_update_sharetab(sa_share_t share, char *proto)
/*
* Fill in share structure and send it to the kernel.
*/
- (void) fillshare(share, proto, &sh);
+ (void) sa_fillshare(share, proto, &sh);
(void) sharefs(SHAREFS_ADD, &sh);
- emptyshare(&sh);
+ sa_emptyshare(&sh);
sa_free_attr_string(path);
}
diff --git a/usr/src/lib/libshare/common/mapfile-vers b/usr/src/lib/libshare/common/mapfile-vers
index eb71ae23fb..317623b3b4 100644
--- a/usr/src/lib/libshare/common/mapfile-vers
+++ b/usr/src/lib/libshare/common/mapfile-vers
@@ -62,10 +62,14 @@ SUNWprivate {
sa_commit_properties;
sa_parse_legacy_options;
sa_zfs_is_shared;
+ sa_share_zfs;
+ sa_path_is_zfs;
sa_get_derived_optionset;
sa_move_share;
sa_group_is_zfs;
sa_update_config;
+ sa_sharetab_fill_zfs;
+ sa_emptyshare;
sa_get_share_attr;
sa_create_optionset;
sa_valid_property;
diff --git a/usr/src/lib/libshare/common/plugin.c b/usr/src/lib/libshare/common/plugin.c
index ab682e6f10..83bc4d5d94 100644
--- a/usr/src/lib/libshare/common/plugin.c
+++ b/usr/src/lib/libshare/common/plugin.c
@@ -240,13 +240,13 @@ sa_proto_share(char *proto, sa_share_t share)
*/
int
-sa_proto_unshare(char *proto, char *path)
+sa_proto_unshare(sa_share_t share, char *proto, char *path)
{
struct sa_plugin_ops *ops = find_protocol(proto);
int ret = SA_INVALID_PROTOCOL;
if (ops != NULL && ops->sa_unshare != NULL)
- ret = ops->sa_unshare(path);
+ ret = ops->sa_unshare(share, path);
return (ret);
}
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index f7b8e8ecba..ec25f19efe 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -49,6 +49,7 @@
#include "libshare_nfs.h"
#include <rpcsvc/daemon_utils.h>
#include <nfs/nfs.h>
+#include <nfs/nfssys.h>
/* should really be in some global place */
#define DEF_WIN 30000
@@ -56,12 +57,13 @@
int debug = 0;
+#define NFS_SERVER_SVC "svc:/network/nfs/server:default"
/* internal functions */
static int nfs_init();
static void nfs_fini();
static int nfs_enable_share(sa_share_t);
-static int nfs_disable_share(char *);
+static int nfs_disable_share(sa_share_t, char *);
static int nfs_validate_property(sa_property_t, sa_optionset_t);
static int nfs_validate_security_mode(char *);
static int nfs_is_security_opt(char *);
@@ -1616,6 +1618,7 @@ nfs_enable_share(sa_share_t share)
char *path;
int err = SA_OK;
int i;
+ int iszfs;
/* Don't drop core if the NFS module isn't loaded. */
(void) signal(SIGSYS, SIG_IGN);
@@ -1625,6 +1628,7 @@ nfs_enable_share(sa_share_t share)
if (path == NULL)
return (SA_NO_SUCH_PATH);
+ iszfs = sa_path_is_zfs(path);
/*
* find the optionsets and security sets. There may not be
* any or there could be one or two for each of optionset and
@@ -1741,18 +1745,67 @@ nfs_enable_share(sa_share_t share)
* call the exportfs system call which is implemented
* via the nfssys() call as the EXPORTFS subfunction.
*/
- if ((err = exportfs(path, &export)) < 0) {
+ if (iszfs) {
+ struct exportfs_args ea;
+ share_t sh;
+ char *str;
+ priv_set_t *priv_effective;
+ int privileged;
+
+ /*
+ * If we aren't a privileged user
+ * and NFS server service isn't running
+ * then print out an error message
+ * and return EPERM
+ */
+
+ priv_effective = priv_allocset();
+ (void) getppriv(PRIV_EFFECTIVE, priv_effective);
+
+ privileged = (priv_isfullset(priv_effective) == B_TRUE);
+ priv_freeset(priv_effective);
+
+ if (!privileged &&
+ (str = smf_get_state(NFS_SERVER_SVC)) != NULL) {
+ err = 0;
+ if (strcmp(str, SCF_STATE_STRING_ONLINE) != 0) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "NFS: Cannot share remote "
+ "filesystem: %s\n"), path);
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "NFS: Service needs to be enabled "
+ "by a privileged user\n"));
+ err = SA_SYSTEM_ERR;
+ errno = EPERM;
+ }
+ free(str);
+ }
+
+ if (err == 0) {
+ ea.dname = path;
+ ea.uex = &export;
+
+ sa_sharetab_fill_zfs(share, &sh, "nfs");
+ err = sa_share_zfs(share, path, &sh, &ea, B_TRUE);
+ sa_emptyshare(&sh);
+ }
+ } else {
+ err = exportfs(path, &export);
+ }
+
+ if (err < 0) {
err = SA_SYSTEM_ERR;
switch (errno) {
case EREMOTE:
(void) printf(dgettext(TEXT_DOMAIN,
- "NFS: Cannot share remote "
- "filesystem: %s\n"), path);
+ "NFS: Cannot share filesystems "
+ "in non-global zones: %s\n"), path);
+ err = SA_NOT_SUPPORTED;
break;
case EPERM:
if (getzoneid() != GLOBAL_ZONEID) {
(void) printf(dgettext(TEXT_DOMAIN,
- "NFS: Cannot share filesystems "
+ "NFS: Cannot share file systems "
"in non-global zones: %s\n"), path);
err = SA_NOT_SUPPORTED;
break;
@@ -1764,7 +1817,9 @@ nfs_enable_share(sa_share_t share)
}
} else {
/* update sharetab with an add/modify */
- (void) sa_update_sharetab(share, "nfs");
+ if (!iszfs) {
+ (void) sa_update_sharetab(share, "nfs");
+ }
}
if (err == SA_OK) {
@@ -1817,38 +1872,56 @@ out:
* done? We only do basic errors for now.
*/
static int
-nfs_disable_share(char *share)
+nfs_disable_share(sa_share_t share, char *path)
{
int err;
int ret = SA_OK;
+ int iszfs;
+
+
+ if (path != NULL) {
+ iszfs = sa_path_is_zfs(path);
+
+ if (iszfs) {
+ struct exportfs_args ea;
+ share_t sh = { 0 };
+
+ ea.dname = path;
+ ea.uex = NULL;
+ sh.sh_path = path;
+ sh.sh_fstype = "nfs";
- if (share != NULL) {
- err = exportfs(share, NULL);
+ err = sa_share_zfs(share, path, &sh, &ea, B_FALSE);
+ } else
+ err = exportfs(path, NULL);
if (err < 0) {
/*
- * TBD: only an error in some cases - need
- * better analysis
+ * TBD: only an error in some
+ * cases - need better analysis
*/
+
switch (errno) {
case EPERM:
case EACCES:
ret = SA_NO_PERMISSION;
- if (getzoneid() != GLOBAL_ZONEID)
+ if (getzoneid() != GLOBAL_ZONEID) {
ret = SA_NOT_SUPPORTED;
+ }
break;
case EINVAL:
case ENOENT:
ret = SA_NO_SUCH_PATH;
- break;
+ break;
default:
ret = SA_SYSTEM_ERR;
- break;
+ break;
}
}
if (ret == SA_OK || ret == SA_NO_SUCH_PATH) {
- (void) sa_delete_sharetab(share, "nfs");
+ if (!iszfs)
+ (void) sa_delete_sharetab(path, "nfs");
/* just in case it was logged */
- (void) nfslogtab_deactivate(share);
+ (void) nfslogtab_deactivate(path);
}
}
return (ret);
diff --git a/usr/src/lib/libzfs/Makefile.com b/usr/src/lib/libzfs/Makefile.com
index 952965eed6..531487193c 100644
--- a/usr/src/lib/libzfs/Makefile.com
+++ b/usr/src/lib/libzfs/Makefile.com
@@ -28,7 +28,7 @@
LIBRARY= libzfs.a
VERS= .1
-OBJS_SHARED= zfs_namecheck.o zfs_prop.o
+OBJS_SHARED= zfs_namecheck.o zfs_prop.o zfs_deleg.o
OBJS_COMMON= libzfs_dataset.o libzfs_util.o libzfs_graph.o libzfs_mount.o \
libzfs_pool.o libzfs_changelist.o libzfs_config.o libzfs_import.o \
libzfs_status.o
@@ -49,7 +49,7 @@ INCS += -I../../../common/zfs
C99MODE= -xc99=%all
C99LMODE= -Xc99=%all
-LDLIBS += -lc -lm -ldevinfo -ldevid -lgen -lnvpair -luutil -lefi
+LDLIBS += -lc -lm -ldevinfo -ldevid -lgen -lnvpair -luutil -lavl -lefi
CPPFLAGS += $(INCS) -D_REENTRANT
SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 1a27fa14fb..06ea0a885c 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -35,6 +35,9 @@
#include <sys/types.h>
#include <sys/varargs.h>
#include <sys/fs/zfs.h>
+#include <sys/avl.h>
+#include <libuutil.h>
+#include <ucred.h>
#ifdef __cplusplus
extern "C" {
@@ -101,10 +104,53 @@ enum {
EZFS_OPENFAILED, /* open of device failed */
EZFS_NOCAP, /* couldn't get capacity */
EZFS_LABELFAILED, /* write of label failed */
+ EZFS_ISCSISVCUNAVAIL, /* iscsi service unavailable */
+ EZFS_BADWHO, /* invalid permission who */
+ EZFS_BADPERM, /* invalid permission */
+ EZFS_BADPERMSET, /* invalid permission set name */
+ EZFS_PERMSET_CIRCULAR, /* circular dependency on permset */
+ EZFS_NODELEGATION, /* delegated administration is disabled */
+ EZFS_PERMRDONLY, /* pemissions are readonly */
EZFS_UNKNOWN
};
/*
+ * The following data structures are all part
+ * of the zfs_allow_t data structure which is
+ * used for printing 'allow' permissions.
+ * It is a linked list of zfs_allow_t's which
+ * then contain avl tree's for user/group/sets/...
+ * and each one of the entries in those trees have
+ * avl tree's for the permissions they belong to and
+ * whether they are local,descendent or local+descendent
+ * permissions. The AVL trees are used primarily for
+ * sorting purposes, but also so that we can quickly find
+ * a given user and or permission.
+ */
+typedef struct zfs_perm_node {
+ avl_node_t z_node;
+ char z_pname[MAXPATHLEN];
+} zfs_perm_node_t;
+
+typedef struct zfs_allow_node {
+ avl_node_t z_node;
+ char z_key[MAXPATHLEN]; /* name, such as joe */
+ avl_tree_t z_localdescend; /* local+descendent perms */
+ avl_tree_t z_local; /* local permissions */
+ avl_tree_t z_descend; /* descendent permissions */
+} zfs_allow_node_t;
+
+typedef struct zfs_allow {
+ struct zfs_allow *z_next;
+ char z_setpoint[MAXPATHLEN];
+ avl_tree_t z_sets;
+ avl_tree_t z_crperms;
+ avl_tree_t z_user;
+ avl_tree_t z_group;
+ avl_tree_t z_everyone;
+} zfs_allow_t;
+
+/*
* Basic handle types
*/
typedef struct zfs_handle zfs_handle_t;
@@ -247,14 +293,16 @@ extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
/*
* Miscellaneous pool functions
*/
+struct zfs_cmd;
+
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *);
extern int zpool_upgrade(zpool_handle_t *);
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
-extern void zpool_log_history(libzfs_handle_t *, int, char **, const char *,
- boolean_t, boolean_t);
+extern void zpool_stage_history(libzfs_handle_t *, int, char **,
+ boolean_t zfs_cmd, boolean_t pool_create);
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t len);
-
+extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
/*
* Basic handle manipulations. These functions do not create or destroy the
* underlying datasets, only the references to them.
@@ -368,6 +416,16 @@ extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
zfs_type_t);
/*
+ * dataset permission functions.
+ */
+extern int zfs_perm_set(zfs_handle_t *, nvlist_t *);
+extern int zfs_perm_remove(zfs_handle_t *, nvlist_t *);
+extern int zfs_build_perms(zfs_handle_t *, char *, char *,
+ zfs_deleg_who_type_t, zfs_deleg_inherit_t, nvlist_t **nvlist_t);
+extern int zfs_perm_get(zfs_handle_t *, zfs_allow_t **);
+extern void zfs_free_allows(zfs_allow_t *);
+
+/*
* Mount support functions.
*/
extern boolean_t is_mounted(libzfs_handle_t *, const char *special, char **);
@@ -393,6 +451,9 @@ extern int zfs_unshareall_nfs(zfs_handle_t *);
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *);
extern int zfs_share_iscsi(zfs_handle_t *);
extern int zfs_unshare_iscsi(zfs_handle_t *);
+extern int zfs_iscsi_perm_check(libzfs_handle_t *, char *, ucred_t *);
+extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *,
+ void *, void *, int, boolean_t);
/*
* When dealing with nvlists, verify() is extremely useful
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index 93ffe03980..5cea7c3fea 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -41,6 +41,12 @@
#include <sys/mntent.h>
#include <sys/mnttab.h>
#include <sys/mount.h>
+#include <sys/avl.h>
+#include <priv.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stddef.h>
+#include <ucred.h>
#include <sys/spa.h>
#include <sys/zio.h>
@@ -50,6 +56,7 @@
#include "zfs_namecheck.h"
#include "zfs_prop.h"
#include "libzfs_impl.h"
+#include "zfs_deleg.h"
static int create_parents(libzfs_handle_t *, char *, int);
static int zvol_create_link_common(libzfs_handle_t *, const char *, int);
@@ -307,16 +314,25 @@ zfs_handle_t *
make_dataset_handle(libzfs_handle_t *hdl, const char *path)
{
zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+ char *logstr;
if (zhp == NULL)
return (NULL);
zhp->zfs_hdl = hdl;
+ /*
+ * Preserve history log string.
+ * any changes performed here will be
+ * logged as an internal event.
+ */
+ logstr = zhp->zfs_hdl->libzfs_log_str;
+ zhp->zfs_hdl->libzfs_log_str = NULL;
top:
(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
if (get_stats(zhp) != 0) {
+ zhp->zfs_hdl->libzfs_log_str = logstr;
free(zhp);
return (NULL);
}
@@ -356,6 +372,7 @@ top:
* never existed.
*/
if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
+ zhp->zfs_hdl->libzfs_log_str = logstr;
free(zhp);
errno = ENOENT;
return (NULL);
@@ -382,6 +399,7 @@ top:
else
abort(); /* we should never see any other types */
+ zhp->zfs_hdl->libzfs_log_str = logstr;
return (zhp);
}
@@ -1120,6 +1138,742 @@ error:
return (NULL);
}
+static int
+zfs_get_perm_who(const char *who, zfs_deleg_who_type_t *who_type,
+ uint64_t *ret_who)
+{
+ struct passwd *pwd;
+ struct group *grp;
+ uid_t id;
+
+ if (*who_type == ZFS_DELEG_EVERYONE || *who_type == ZFS_DELEG_CREATE ||
+ *who_type == ZFS_DELEG_NAMED_SET) {
+ *ret_who = -1;
+ return (0);
+ }
+ if (who == NULL && !(*who_type == ZFS_DELEG_EVERYONE))
+ return (EZFS_BADWHO);
+
+ if (*who_type == ZFS_DELEG_WHO_UNKNOWN &&
+ strcmp(who, "everyone") == 0) {
+ *ret_who = -1;
+ *who_type = ZFS_DELEG_EVERYONE;
+ return (0);
+ }
+
+ pwd = getpwnam(who);
+ grp = getgrnam(who);
+
+ if ((*who_type == ZFS_DELEG_USER) && pwd) {
+ *ret_who = pwd->pw_uid;
+ } else if ((*who_type == ZFS_DELEG_GROUP) && grp) {
+ *ret_who = grp->gr_gid;
+ } else if (pwd) {
+ *ret_who = pwd->pw_uid;
+ *who_type = ZFS_DELEG_USER;
+ } else if (grp) {
+ *ret_who = grp->gr_gid;
+ *who_type = ZFS_DELEG_GROUP;
+ } else {
+ char *end;
+
+ id = strtol(who, &end, 10);
+ if (errno != 0 || *end != '\0') {
+ return (EZFS_BADWHO);
+ } else {
+ *ret_who = id;
+ if (*who_type == ZFS_DELEG_WHO_UNKNOWN)
+ *who_type = ZFS_DELEG_USER;
+ }
+ }
+
+ return (0);
+}
+
+static void
+zfs_perms_add_to_nvlist(nvlist_t *who_nvp, char *name, nvlist_t *perms_nvp)
+{
+ if (perms_nvp != NULL) {
+ verify(nvlist_add_nvlist(who_nvp,
+ name, perms_nvp) == 0);
+ } else {
+ verify(nvlist_add_boolean(who_nvp, name) == 0);
+ }
+}
+
+static void
+helper(zfs_deleg_who_type_t who_type, uint64_t whoid, char *whostr,
+ zfs_deleg_inherit_t inherit, nvlist_t *who_nvp, nvlist_t *perms_nvp,
+ nvlist_t *sets_nvp)
+{
+ boolean_t do_perms, do_sets;
+ char name[ZFS_MAX_DELEG_NAME];
+
+ do_perms = (nvlist_next_nvpair(perms_nvp, NULL) != NULL);
+ do_sets = (nvlist_next_nvpair(sets_nvp, NULL) != NULL);
+
+ if (!do_perms && !do_sets)
+ do_perms = do_sets = B_TRUE;
+
+ if (do_perms) {
+ zfs_deleg_whokey(name, who_type, inherit,
+ (who_type == ZFS_DELEG_NAMED_SET) ?
+ whostr : (void *)&whoid);
+ zfs_perms_add_to_nvlist(who_nvp, name, perms_nvp);
+ }
+ if (do_sets) {
+ zfs_deleg_whokey(name, toupper(who_type), inherit,
+ (who_type == ZFS_DELEG_NAMED_SET) ?
+ whostr : (void *)&whoid);
+ zfs_perms_add_to_nvlist(who_nvp, name, sets_nvp);
+ }
+}
+
+static void
+zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr,
+ nvlist_t *perms_nvp, nvlist_t *sets_nvp,
+ zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit)
+{
+ if (who_type == ZFS_DELEG_NAMED_SET || who_type == ZFS_DELEG_CREATE) {
+ helper(who_type, whoid, whostr, 0,
+ who_nvp, perms_nvp, sets_nvp);
+ } else {
+ if (inherit & ZFS_DELEG_PERM_LOCAL) {
+ helper(who_type, whoid, whostr, ZFS_DELEG_LOCAL,
+ who_nvp, perms_nvp, sets_nvp);
+ }
+ if (inherit & ZFS_DELEG_PERM_DESCENDENT) {
+ helper(who_type, whoid, whostr, ZFS_DELEG_DESCENDENT,
+ who_nvp, perms_nvp, sets_nvp);
+ }
+ }
+}
+
+/*
+ * Construct nvlist to pass down to kernel for setting/removing permissions.
+ *
+ * The nvlist is constructed as a series of nvpairs with an optional embedded
+ * nvlist of permissions to remove or set. The topmost nvpairs are the actual
+ * base attribute named stored in the dsl.
+ * Arguments:
+ *
+ * whostr: is a comma separated list of users, groups, or a single set name.
+ * whostr may be null for everyone or create perms.
+ * who_type: is the type of entry in whostr. Typically this will be
+ * ZFS_DELEG_WHO_UNKNOWN.
+ * perms: comman separated list of permissions. May be null if user
+ * is requested to remove permissions by who.
+ * inherit: Specifies the inheritance of the permissions. Will be either
+ * ZFS_DELEG_PERM_LOCAL and/or ZFS_DELEG_PERM_DESCENDENT.
+ * nvp The constructed nvlist to pass to zfs_perm_set().
+ * The output nvp will look something like this.
+ * ul$1234 -> {create ; destroy }
+ * Ul$1234 -> { @myset }
+ * s-$@myset - { snapshot; checksum; compression }
+ */
+int
+zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
+ zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit, nvlist_t **nvp)
+{
+ nvlist_t *who_nvp;
+ nvlist_t *perms_nvp = NULL;
+ nvlist_t *sets_nvp = NULL;
+ char errbuf[1024];
+ char *who_tok;
+ int error;
+
+ *nvp = NULL;
+
+ if (perms) {
+ /* Make sure permission string doesn't have an '=' sign in it */
+ if (strchr(perms, '=') != NULL) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "permissions can't contain equal sign : '%s'"),
+ perms);
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, errbuf));
+ }
+
+ if ((error = nvlist_alloc(&perms_nvp,
+ NV_UNIQUE_NAME, 0)) != 0) {
+ return (1);
+ }
+ if ((error = nvlist_alloc(&sets_nvp,
+ NV_UNIQUE_NAME, 0)) != 0) {
+ nvlist_free(perms_nvp);
+ return (1);
+ }
+ }
+
+ if ((error = nvlist_alloc(&who_nvp, NV_UNIQUE_NAME, 0)) != 0) {
+ if (perms_nvp)
+ nvlist_free(perms_nvp);
+ if (sets_nvp)
+ nvlist_free(sets_nvp);
+ return (1);
+ }
+
+ if (who_type == ZFS_DELEG_NAMED_SET) {
+ namecheck_err_t why;
+ char what;
+
+ if ((error = permset_namecheck(whostr, &why, &what)) != 0) {
+ switch (why) {
+ case NAME_ERR_NO_AT:
+ zfs_error_aux(zhp->zfs_hdl,
+ dgettext(TEXT_DOMAIN,
+ "set definition must begin with an '@' "
+ "character"));
+ }
+ return (zfs_error(zhp->zfs_hdl,
+ EZFS_BADPERMSET, whostr));
+ }
+ }
+
+ /*
+ * Build up nvlist(s) of permissions. Two nvlists are maintained.
+ * The first nvlist perms_nvp will have normal permissions and the
+ * other sets_nvp will have only permssion set names in it.
+ */
+
+
+ while (perms && *perms != '\0') {
+ char *value;
+ char *perm_name;
+ nvlist_t *update_nvp;
+ int perm_num;
+ char canonical_name[64];
+ char *canonicalp = canonical_name;
+
+
+ update_nvp = perms_nvp;
+
+ perm_num = getsubopt(&perms, zfs_deleg_perm_tab, &value);
+ if (perm_num == -1) {
+ zfs_prop_t prop;
+
+ prop = zfs_name_to_prop(value);
+ if (prop != ZFS_PROP_INVAL) {
+ (void) snprintf(canonical_name,
+ sizeof (canonical_name), "%s",
+ zfs_prop_to_name(prop));
+ perm_num = getsubopt(&canonicalp,
+ zfs_deleg_perm_tab, &value);
+ }
+ }
+ if (perm_num != -1) {
+ perm_name = zfs_deleg_perm_tab[perm_num];
+ } else { /* check and see if permission is a named set */
+ if (value[0] == '@') {
+
+ /*
+ * make sure permssion set isn't defined
+ * in terms of itself. ie.
+ * @set1 = create,destroy,@set1
+ */
+ if (who_type == ZFS_DELEG_NAMED_SET &&
+ strcmp(value, whostr) == 0) {
+ nvlist_free(who_nvp);
+ nvlist_free(perms_nvp);
+ if (sets_nvp)
+ nvlist_free(sets_nvp);
+ (void) snprintf(errbuf,
+ sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Invalid permission %s"), value);
+ return (zfs_error(zhp->zfs_hdl,
+ EZFS_PERMSET_CIRCULAR, errbuf));
+ }
+ update_nvp = sets_nvp;
+ perm_name = value;
+ } else {
+ nvlist_free(who_nvp);
+ nvlist_free(perms_nvp);
+ if (sets_nvp)
+ nvlist_free(sets_nvp);
+ return (zfs_error(zhp->zfs_hdl,
+ EZFS_BADPERM, value));
+ }
+ }
+ verify(nvlist_add_boolean(update_nvp, perm_name) == 0);
+ }
+
+ if (whostr && who_type != ZFS_DELEG_CREATE) {
+ who_tok = strtok(whostr, ",");
+ if (who_tok == NULL) {
+ nvlist_free(who_nvp);
+ nvlist_free(perms_nvp);
+ if (sets_nvp)
+ nvlist_free(sets_nvp);
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "Who string is NULL"),
+ whostr);
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf));
+ }
+ }
+
+ /*
+ * Now create the nvlist(s)
+ */
+ do {
+ uint64_t who_id;
+
+ error = zfs_get_perm_who(who_tok, &who_type,
+ &who_id);
+ if (error) {
+ nvlist_free(who_nvp);
+ nvlist_free(perms_nvp);
+ if (sets_nvp)
+ nvlist_free(sets_nvp);
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Unable to determine uid/gid for "
+ "%s "), who_tok);
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf));
+ }
+
+ /*
+ * add entries for both local and descendent when required
+ */
+
+ zfs_perms_add_who_nvlist(who_nvp, who_id, who_tok,
+ perms_nvp, sets_nvp, who_type, inherit);
+
+ } while (who_tok = strtok(NULL, ","));
+ *nvp = who_nvp;
+ return (0);
+}
+
+static int
+zfs_perm_set_common(zfs_handle_t *zhp, nvlist_t *nvp, boolean_t unset)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+ size_t sz;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "Cannot update 'allows' for '%s'"),
+ zhp->zfs_name);
+
+ if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, nvp, &sz))
+ return (-1);
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ zc.zc_perm_action = unset;
+
+ error = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SET_FSACL, &zc);
+ if (error && errno == ENOTSUP) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ gettext("Pool must be upgraded to use 'allow/unallow'"));
+ zcmd_free_nvlists(&zc);
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION, errbuf));
+ } else if (error) {
+ return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf));
+ }
+ zcmd_free_nvlists(&zc);
+
+ return (error);
+}
+
+int
+zfs_perm_set(zfs_handle_t *zhp, nvlist_t *nvp)
+{
+ return (zfs_perm_set_common(zhp, nvp, B_FALSE));
+}
+
+int
+zfs_perm_remove(zfs_handle_t *zhp, nvlist_t *perms)
+{
+ return (zfs_perm_set_common(zhp, perms, B_TRUE));
+}
+
+static int
+perm_compare(const void *arg1, const void *arg2)
+{
+ const zfs_perm_node_t *node1 = arg1;
+ const zfs_perm_node_t *node2 = arg2;
+ int ret;
+
+ ret = strcmp(node1->z_pname, node2->z_pname);
+
+ if (ret > 0)
+ return (1);
+ if (ret < 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static void
+zfs_destroy_perm_tree(avl_tree_t *tree)
+{
+ zfs_perm_node_t *permnode;
+ void *cookie;
+
+ cookie = NULL;
+ while ((permnode = avl_destroy_nodes(tree, &cookie)) != NULL) {
+ avl_remove(tree, permnode);
+ free(permnode);
+ }
+}
+
+static void
+zfs_destroy_tree(avl_tree_t *tree)
+{
+ zfs_allow_node_t *allownode;
+ void *cookie;
+
+ cookie = NULL;
+ while ((allownode = avl_destroy_nodes(tree, &cookie)) != NULL) {
+ zfs_destroy_perm_tree(&allownode->z_localdescend);
+ zfs_destroy_perm_tree(&allownode->z_local);
+ zfs_destroy_perm_tree(&allownode->z_descend);
+ avl_remove(tree, allownode);
+ free(allownode);
+ }
+}
+
+void
+zfs_free_allows(zfs_allow_t *allow)
+{
+ zfs_allow_t *allownext;
+ zfs_allow_t *freeallow;
+
+ allownext = allow;
+ while (allownext) {
+ zfs_destroy_tree(&allownext->z_sets);
+ zfs_destroy_tree(&allownext->z_crperms);
+ zfs_destroy_tree(&allownext->z_user);
+ zfs_destroy_tree(&allownext->z_group);
+ zfs_destroy_tree(&allownext->z_everyone);
+ freeallow = allownext;
+ allownext = allownext->z_next;
+ free(freeallow);
+ }
+}
+
+static zfs_allow_t *
+zfs_alloc_perm_tree(zfs_handle_t *zhp, zfs_allow_t *prev, char *setpoint)
+{
+ zfs_allow_t *ptree;
+
+ if ((ptree = zfs_alloc(zhp->zfs_hdl,
+ sizeof (zfs_allow_t))) == NULL) {
+ return (NULL);
+ }
+
+ (void) strlcpy(ptree->z_setpoint, setpoint, sizeof (ptree->z_setpoint));
+ avl_create(&ptree->z_sets,
+ perm_compare, sizeof (zfs_allow_node_t),
+ offsetof(zfs_allow_node_t, z_node));
+ avl_create(&ptree->z_crperms,
+ perm_compare, sizeof (zfs_allow_node_t),
+ offsetof(zfs_allow_node_t, z_node));
+ avl_create(&ptree->z_user,
+ perm_compare, sizeof (zfs_allow_node_t),
+ offsetof(zfs_allow_node_t, z_node));
+ avl_create(&ptree->z_group,
+ perm_compare, sizeof (zfs_allow_node_t),
+ offsetof(zfs_allow_node_t, z_node));
+ avl_create(&ptree->z_everyone,
+ perm_compare, sizeof (zfs_allow_node_t),
+ offsetof(zfs_allow_node_t, z_node));
+
+ if (prev)
+ prev->z_next = ptree;
+ ptree->z_next = NULL;
+ return (ptree);
+}
+
+/*
+ * Add permissions to the appropriate AVL permission tree.
+ * The appropriate tree may not be the requested tree.
+ * For example if ld indicates a local permission, but
+ * same permission also exists as a descendent permission
+ * then the permission will be removed from the descendent
+ * tree and add the the local+descendent tree.
+ */
+static int
+zfs_coalesce_perm(zfs_handle_t *zhp, zfs_allow_node_t *allownode,
+ char *perm, char ld)
+{
+ zfs_perm_node_t pnode, *permnode, *permnode2;
+ zfs_perm_node_t *newnode;
+ avl_index_t where, where2;
+ avl_tree_t *tree, *altree;
+
+ (void) strlcpy(pnode.z_pname, perm, sizeof (pnode.z_pname));
+
+ if (ld == ZFS_DELEG_NA) {
+ tree = &allownode->z_localdescend;
+ altree = &allownode->z_descend;
+ } else if (ld == ZFS_DELEG_LOCAL) {
+ tree = &allownode->z_local;
+ altree = &allownode->z_descend;
+ } else {
+ tree = &allownode->z_descend;
+ altree = &allownode->z_local;
+ }
+ permnode = avl_find(tree, &pnode, &where);
+ permnode2 = avl_find(altree, &pnode, &where2);
+
+ if (permnode2) {
+ avl_remove(altree, permnode2);
+ free(permnode2);
+ if (permnode == NULL) {
+ tree = &allownode->z_localdescend;
+ }
+ }
+
+ /*
+ * Now insert new permission in either requested location
+ * local/descendent or into ld when perm will exist in both.
+ */
+ if (permnode == NULL) {
+ if ((newnode = zfs_alloc(zhp->zfs_hdl,
+ sizeof (zfs_perm_node_t))) == NULL) {
+ return (-1);
+ }
+ *newnode = pnode;
+ avl_add(tree, newnode);
+ }
+ return (0);
+}
+/*
+ * Uggh, this is going to be a bit complicated.
+ * we have an nvlist coming out of the kernel that
+ * will indicate where the permission is set and then
+ * it will contain allow of the various "who's", and what
+ * their permissions are. To further complicate this
+ * we will then have to coalesce the local,descendent
+ * and local+descendent permissions where appropriate.
+ * The kernel only knows about a permission as being local
+ * or descendent, but not both.
+ *
+ * In order to make this easier for zfs_main to deal with
+ * a series of AVL trees will be used to maintain
+ * all of this, primarily for sorting purposes as well
+ * as the ability to quickly locate a specific entry.
+ *
+ * What we end up with are tree's for sets, create perms,
+ * user, groups and everyone. With each of those trees
+ * we have subtrees for local, descendent and local+descendent
+ * permissions.
+ */
+int
+zfs_perm_get(zfs_handle_t *zhp, zfs_allow_t **zfs_perms)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+ nvlist_t *nvlist;
+ nvlist_t *permnv, *sourcenv;
+ nvpair_t *who_pair, *source_pair;
+ nvpair_t *perm_pair;
+ char errbuf[1024];
+ zfs_allow_t *zallowp, *newallowp;
+ char ld;
+ char *nvpname;
+ uid_t uid;
+ gid_t gid;
+ avl_tree_t *tree;
+ avl_index_t where;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+
+ while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
+ if (errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ } else if (errno == ENOTSUP) {
+ zcmd_free_nvlists(&zc);
+ (void) snprintf(errbuf, sizeof (errbuf),
+ gettext("Pool must be upgraded to use 'allow'"));
+ return (zfs_error(zhp->zfs_hdl,
+ EZFS_BADVERSION, errbuf));
+ } else {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ }
+
+ if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &nvlist) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+
+ zcmd_free_nvlists(&zc);
+
+ source_pair = nvlist_next_nvpair(nvlist, NULL);
+
+ if (source_pair == NULL) {
+ *zfs_perms = NULL;
+ return (0);
+ }
+
+ *zfs_perms = zfs_alloc_perm_tree(zhp, NULL, nvpair_name(source_pair));
+ if (*zfs_perms == NULL) {
+ return (0);
+ }
+
+ zallowp = *zfs_perms;
+
+ for (;;) {
+ struct passwd *pwd;
+ struct group *grp;
+ zfs_allow_node_t *allownode;
+ zfs_allow_node_t findallownode;
+ zfs_allow_node_t *newallownode;
+
+ (void) strlcpy(zallowp->z_setpoint,
+ nvpair_name(source_pair),
+ sizeof (zallowp->z_setpoint));
+
+ if ((error = nvpair_value_nvlist(source_pair, &sourcenv)) != 0)
+ goto abort;
+
+ /*
+ * Make sure nvlist is composed correctly
+ */
+ if (zfs_deleg_verify_nvlist(sourcenv)) {
+ goto abort;
+ }
+
+ who_pair = nvlist_next_nvpair(sourcenv, NULL);
+ if (who_pair == NULL) {
+ goto abort;
+ }
+
+ do {
+ error = nvpair_value_nvlist(who_pair, &permnv);
+ if (error) {
+ goto abort;
+ }
+
+ /*
+ * First build up the key to use
+ * for looking up in the various
+ * who trees.
+ */
+ ld = nvpair_name(who_pair)[1];
+ nvpname = nvpair_name(who_pair);
+ switch (nvpair_name(who_pair)[0]) {
+ case ZFS_DELEG_USER:
+ case ZFS_DELEG_USER_SETS:
+ tree = &zallowp->z_user;
+ uid = atol(&nvpname[3]);
+ pwd = getpwuid(uid);
+ (void) snprintf(findallownode.z_key,
+ sizeof (findallownode.z_key), "user %s",
+ (pwd) ? pwd->pw_name :
+ &nvpair_name(who_pair)[3]);
+ break;
+ case ZFS_DELEG_GROUP:
+ case ZFS_DELEG_GROUP_SETS:
+ tree = &zallowp->z_group;
+ gid = atol(&nvpname[3]);
+ grp = getgrgid(gid);
+ (void) snprintf(findallownode.z_key,
+ sizeof (findallownode.z_key), "group %s",
+ (grp) ? grp->gr_name :
+ &nvpair_name(who_pair)[3]);
+ break;
+ case ZFS_DELEG_CREATE:
+ case ZFS_DELEG_CREATE_SETS:
+ tree = &zallowp->z_crperms;
+ (void) strlcpy(findallownode.z_key, "",
+ sizeof (findallownode.z_key));
+ break;
+ case ZFS_DELEG_EVERYONE:
+ case ZFS_DELEG_EVERYONE_SETS:
+ (void) snprintf(findallownode.z_key,
+ sizeof (findallownode.z_key), "everyone");
+ tree = &zallowp->z_everyone;
+ break;
+ case ZFS_DELEG_NAMED_SET:
+ case ZFS_DELEG_NAMED_SET_SETS:
+ (void) snprintf(findallownode.z_key,
+ sizeof (findallownode.z_key), "%s",
+ &nvpair_name(who_pair)[3]);
+ tree = &zallowp->z_sets;
+ break;
+ }
+
+ /*
+ * Place who in tree
+ */
+ allownode = avl_find(tree, &findallownode, &where);
+ if (allownode == NULL) {
+ if ((newallownode = zfs_alloc(zhp->zfs_hdl,
+ sizeof (zfs_allow_node_t))) == NULL) {
+ goto abort;
+ }
+ avl_create(&newallownode->z_localdescend,
+ perm_compare,
+ sizeof (zfs_perm_node_t),
+ offsetof(zfs_perm_node_t, z_node));
+ avl_create(&newallownode->z_local,
+ perm_compare,
+ sizeof (zfs_perm_node_t),
+ offsetof(zfs_perm_node_t, z_node));
+ avl_create(&newallownode->z_descend,
+ perm_compare,
+ sizeof (zfs_perm_node_t),
+ offsetof(zfs_perm_node_t, z_node));
+ (void) strlcpy(newallownode->z_key,
+ findallownode.z_key,
+ sizeof (findallownode.z_key));
+ avl_insert(tree, newallownode, where);
+ allownode = newallownode;
+ }
+
+ /*
+ * Now iterate over the permissions and
+ * place them in the appropriate local,
+ * descendent or local+descendent tree.
+ *
+ * The permissions are added to the tree
+ * via zfs_coalesce_perm().
+ */
+ perm_pair = nvlist_next_nvpair(permnv, NULL);
+ if (perm_pair == NULL)
+ goto abort;
+ do {
+ if (zfs_coalesce_perm(zhp, allownode,
+ nvpair_name(perm_pair), ld) != 0)
+ goto abort;
+ } while (perm_pair = nvlist_next_nvpair(permnv,
+ perm_pair));
+ } while (who_pair = nvlist_next_nvpair(sourcenv, who_pair));
+
+ source_pair = nvlist_next_nvpair(nvlist, source_pair);
+ if (source_pair == NULL)
+ break;
+
+ /*
+ * allocate another node from the link list of
+ * zfs_allow_t structures
+ */
+ newallowp = zfs_alloc_perm_tree(zhp, zallowp,
+ nvpair_name(source_pair));
+ if (newallowp == NULL) {
+ goto abort;
+ }
+ zallowp = newallowp;
+ }
+ nvlist_free(nvlist);
+ return (0);
+abort:
+ zfs_free_allows(*zfs_perms);
+ nvlist_free(nvlist);
+ return (-1);
+}
+
/*
* Given a property name and value, set the property for the given dataset.
*/
@@ -1174,7 +1928,7 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0)
goto error;
- ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
+ ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
if (ret != 0) {
switch (errno) {
@@ -1283,8 +2037,7 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname)
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
- if (ioctl(zhp->zfs_hdl->libzfs_fd,
- ZFS_IOC_SET_PROP, &zc) != 0)
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SET_PROP, &zc) != 0)
return (zfs_standard_error(hdl, errno, errbuf));
return (0);
@@ -1336,8 +2089,7 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname)
if ((ret = changelist_prefix(cl)) != 0)
goto error;
- if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd,
- ZFS_IOC_SET_PROP, &zc)) != 0) {
+ if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SET_PROP, &zc)) != 0) {
return (zfs_standard_error(hdl, errno, errbuf));
} else {
@@ -2220,7 +2972,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
nvlist_free(props);
/* create the dataset */
- ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
+ ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc);
if (ret == 0 && type == ZFS_TYPE_VOLUME) {
ret = zvol_create_link(hdl, path);
@@ -2292,10 +3044,13 @@ zfs_destroy(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp)) {
/*
- * Unconditionally unshare this zvol ignoring failure as it
- * indicates only that the volume wasn't shared initially.
+ * If user doesn't have permissions to unshare volume, then
+ * abort the request. This would only happen for a
+ * non-privileged user.
*/
- (void) zfs_unshare_iscsi(zhp);
+ if (zfs_unshare_iscsi(zhp) != 0) {
+ return (-1);
+ }
if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
return (-1);
@@ -2305,7 +3060,7 @@ zfs_destroy(zfs_handle_t *zhp)
zc.zc_objset_type = DMU_OST_ZFS;
}
- if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) {
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) {
return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
zhp->zfs_name));
@@ -2379,7 +3134,7 @@ zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname)
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc);
+ ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc);
if (ret != 0) {
char errbuf[1024];
@@ -2454,7 +3209,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
+ ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc);
zcmd_free_nvlists(&zc);
@@ -2605,7 +3360,7 @@ zfs_promote(zfs_handle_t *zhp)
(void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of,
sizeof (zc.zc_value));
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc);
+ ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
if (ret != 0) {
int save_errno = errno;
@@ -2704,15 +3459,21 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
+ if (ZFS_IS_VOLUME(zhp))
+ zc.zc_objset_type = DMU_OST_ZVOL;
+ else
+ zc.zc_objset_type = DMU_OST_ZFS;
zc.zc_cookie = recursive;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc);
+ ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc);
/*
* if it was recursive, the one that actually failed will be in
* zc.zc_name.
*/
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
+ if (ret != 0)
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
+
if (ret == 0 && recursive) {
struct createdata cd;
@@ -2723,8 +3484,13 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) {
ret = zvol_create_link(zhp->zfs_hdl, path);
if (ret != 0) {
- (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY,
- &zc);
+ (void) zfs_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN,
+ "Volume successfully snapshotted, but device links "
+ "were not created"));
+ free(parent);
+ zfs_close(zhp);
+ return (-1);
}
}
@@ -2815,6 +3581,7 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
for (cp = target + prefixlen + 1;
cp = strchr(cp, '/'); *cp = '/', cp++) {
const char *opname;
+ char *logstr;
*cp = '\0';
@@ -2826,10 +3593,15 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
}
opname = dgettext(TEXT_DOMAIN, "create");
+ logstr = hdl->libzfs_log_str;
+ hdl->libzfs_log_str = NULL;
if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
- NULL) != 0)
+ NULL) != 0) {
+ hdl->libzfs_log_str = logstr;
goto ancestorerr;
+ }
+ hdl->libzfs_log_str = logstr;
opname = dgettext(TEXT_DOMAIN, "open");
h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
if (h == NULL)
@@ -2985,7 +3757,11 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
return (-1);
}
} else {
- (void) zvol_remove_link(hdl, h->zfs_name);
+ if (zvol_remove_link(hdl, h->zfs_name) != 0) {
+ zfs_close(h);
+ return (-1);
+ }
+
}
}
zfs_close(h);
@@ -3032,7 +3808,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
}
if (dryrun)
return (0);
- err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc);
+ err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECVBACKUP, &zc);
if (ioctl_err != 0) {
switch (errno) {
case ENODEV:
@@ -3149,6 +3925,7 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
cbp->cb_create) {
+ char *logstr;
cbp->cb_dependent = B_TRUE;
if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy,
@@ -3156,10 +3933,13 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
cbp->cb_error = 1;
cbp->cb_dependent = B_FALSE;
+ logstr = zhp->zfs_hdl->libzfs_log_str;
+ zhp->zfs_hdl->libzfs_log_str = NULL;
if (zfs_destroy(zhp) != 0)
cbp->cb_error = 1;
else
changelist_remove(zhp, cbp->cb_clp);
+ zhp->zfs_hdl->libzfs_log_str = logstr;
}
} else {
if (zfs_destroy(zhp) != 0)
@@ -3202,8 +3982,7 @@ do_rollback(zfs_handle_t *zhp)
* condition where the user has taken a snapshot since we verified that
* this was the most recent.
*/
- if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK,
- &zc)) != 0) {
+ if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) {
(void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
zhp->zfs_name);
@@ -3465,7 +4244,7 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive)
zc.zc_cookie = recursive;
- if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) {
+ if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
/*
* if it was recursive, the one that actually failed will
* be in zc.zc_name
@@ -3540,6 +4319,8 @@ zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists)
{
zfs_cmd_t zc = { 0 };
di_devlink_handle_t dhdl;
+ priv_set_t *priv_effective;
+ int privileged;
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
@@ -3576,17 +4357,51 @@ zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists)
}
/*
- * Call devfsadm and wait for the links to magically appear.
+ * If privileged call devfsadm and wait for the links to
+ * magically appear.
+ * Otherwise, print out an informational message.
*/
- if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) {
- zfs_error_aux(hdl, strerror(errno));
- (void) zfs_error_fmt(hdl, EZFS_DEVLINKS,
- dgettext(TEXT_DOMAIN, "cannot create device links "
- "for '%s'"), dataset);
- (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc);
- return (-1);
+
+ priv_effective = priv_allocset();
+ (void) getppriv(PRIV_EFFECTIVE, priv_effective);
+ privileged = (priv_isfullset(priv_effective) == B_TRUE);
+ priv_freeset(priv_effective);
+
+ if (privileged) {
+ if ((dhdl = di_devlink_init(ZFS_DRIVER,
+ DI_MAKE_LINK)) == NULL) {
+ zfs_error_aux(hdl, strerror(errno));
+ (void) zfs_standard_error_fmt(hdl, EZFS_DEVLINKS,
+ dgettext(TEXT_DOMAIN, "cannot create device links "
+ "for '%s'"), dataset);
+ (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc);
+ return (-1);
+ } else {
+ (void) di_devlink_fini(&dhdl);
+ }
} else {
- (void) di_devlink_fini(&dhdl);
+ char pathname[MAXPATHLEN];
+ struct stat64 statbuf;
+ int i;
+
+#define MAX_WAIT 10
+
+ /*
+ * This is the poor mans way of waiting for the link
+ * to show up. If after 10 seconds we still don't
+ * have it, then print out a message.
+ */
+ (void) snprintf(pathname, sizeof (pathname), "/dev/zvol/dsk/%s",
+ dataset);
+
+ for (i = 0; i != MAX_WAIT; i++) {
+ if (stat64(pathname, &statbuf) == 0)
+ break;
+ (void) sleep(1);
+ }
+ if (i == MAX_WAIT)
+ (void) printf(gettext("%s may not be immediately "
+ "available\n"), pathname);
}
return (0);
@@ -3917,3 +4732,68 @@ zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp)
return (0);
}
+
+int
+zfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *nvp;
+ size_t sz;
+ gid_t gid;
+ uid_t uid;
+ const gid_t *groups;
+ int group_cnt;
+ int error;
+
+ if (nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0) != 0)
+ return (no_memory(hdl));
+
+ uid = ucred_geteuid(cred);
+ gid = ucred_getegid(cred);
+ group_cnt = ucred_getgroups(cred, &groups);
+
+ if (uid == (uid_t)-1 || gid == (uid_t)-1 || group_cnt == (uid_t)-1)
+ return (1);
+
+ if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_UID, uid) != 0) {
+ nvlist_free(nvp);
+ return (1);
+ }
+
+ if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_GID, gid) != 0) {
+ nvlist_free(nvp);
+ return (1);
+ }
+
+ if (nvlist_add_uint32_array(nvp,
+ ZFS_DELEG_PERM_GROUPS, (uint32_t *)groups, group_cnt) != 0) {
+ nvlist_free(nvp);
+ return (1);
+ }
+ (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+
+ if (zcmd_write_src_nvlist(hdl, &zc, nvp, &sz))
+ return (-1);
+
+ error = ioctl(hdl->libzfs_fd, ZFS_IOC_ISCSI_PERM_CHECK, &zc);
+ nvlist_free(nvp);
+ return (error);
+}
+
+int
+zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
+ void *export, void *sharetab, int sharemax, boolean_t share_on)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+
+ (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
+ zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
+ zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
+ zc.zc_share.z_sharetype = share_on;
+ zc.zc_share.z_sharemax = sharemax;
+
+ error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
+ return (error);
+}
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index 20042e8c90..76f4823f29 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -33,6 +33,7 @@
#include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_acl.h>
+#include <sys/spa.h>
#include <sys/nvpair.h>
#include <libuutil.h>
@@ -54,6 +55,8 @@ struct libzfs_handle {
int libzfs_desc_active;
char libzfs_action[1024];
char libzfs_desc[1024];
+ char *libzfs_log_str;
+ int libzfs_log_type;
int libzfs_printerr;
void *libzfs_sharehdl; /* libshare handle */
};
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index 39cc9403c8..eb301116b3 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -85,6 +85,7 @@
static int (*iscsitgt_zfs_share)(const char *);
static int (*iscsitgt_zfs_unshare)(const char *);
static int (*iscsitgt_zfs_is_shared)(const char *);
+static int (*iscsitgt_svc_online)();
#pragma init(zfs_iscsi_init)
static void
@@ -99,10 +100,13 @@ zfs_iscsi_init(void)
(iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
"iscsitgt_zfs_unshare")) == NULL ||
(iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
- "iscsitgt_zfs_is_shared")) == NULL) {
+ "iscsitgt_zfs_is_shared")) == NULL ||
+ (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt,
+ "iscsitgt_svc_online")) == NULL) {
iscsitgt_zfs_share = NULL;
iscsitgt_zfs_unshare = NULL;
iscsitgt_zfs_is_shared = NULL;
+ iscsitgt_svc_online = NULL;
}
}
@@ -284,6 +288,9 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
if (errno == EBUSY) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"mountpoint or dataset is busy"));
+ } else if (errno == EPERM) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Insufficient privileges"));
} else {
zfs_error_aux(hdl, strerror(errno));
}
@@ -793,8 +800,15 @@ remove_mountpoint(zfs_handle_t *zhp)
boolean_t
zfs_is_shared_iscsi(zfs_handle_t *zhp)
{
- return (iscsitgt_zfs_is_shared != NULL &&
- iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
+
+ /*
+ * If iscsi deamon isn't running then we aren't shared
+ */
+ if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
+ return (0);
+ else
+ return (iscsitgt_zfs_is_shared != NULL &&
+ iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
}
int
@@ -812,9 +826,20 @@ zfs_share_iscsi(zfs_handle_t *zhp)
strcmp(shareopts, "off") == 0)
return (0);
- if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0)
- return (zfs_error_fmt(hdl, EZFS_SHAREISCSIFAILED,
+ if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) {
+ int error = EZFS_SHAREISCSIFAILED;
+
+ /*
+ * If service isn't availabele and EPERM was
+ * returned then use special error.
+ */
+ if (iscsitgt_svc_online && errno == EPERM &&
+ (iscsitgt_svc_online() != 0))
+ error = EZFS_ISCSISVCUNAVAIL;
+
+ return (zfs_error_fmt(hdl, error,
dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
+ }
return (0);
}
@@ -836,9 +861,13 @@ zfs_unshare_iscsi(zfs_handle_t *zhp)
* we should return success in that case.
*/
if (iscsitgt_zfs_unshare == NULL ||
- (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV))
+ (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) {
+ if (errno == EPERM)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Insufficient privileges to unshare iscsi"));
return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
+ }
return (0);
}
@@ -991,7 +1020,8 @@ zvol_cb(const char *dataset, void *data)
(zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
return (0);
- (void) zfs_unshare_iscsi(zhp);
+ if (zfs_unshare_iscsi(zhp) != 0)
+ return (-1);
zfs_close(zhp);
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index cf08df2ebc..9c1d197f4d 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -409,7 +409,7 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
if (altroot != NULL)
(void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) {
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc) != 0) {
zcmd_free_nvlists(&zc);
switch (errno) {
@@ -451,7 +451,6 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
return (zpool_standard_error(hdl, errno, msg));
}
}
-
zcmd_free_nvlists(&zc);
/*
@@ -493,7 +492,7 @@ zpool_destroy(zpool_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
"cannot destroy '%s'"), zhp->zpool_name);
@@ -547,7 +546,7 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
return (-1);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) {
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
switch (errno) {
case EBUSY:
/*
@@ -621,7 +620,7 @@ zpool_export(zpool_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_EXPORT, &zc) != 0)
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0)
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot export '%s'"),
zhp->zpool_name));
@@ -675,7 +674,7 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
return (-1);
ret = 0;
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
char desc[1024];
if (newname == NULL)
(void) snprintf(desc, sizeof (desc),
@@ -705,6 +704,7 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
ret = -1;
} else {
zpool_handle_t *zhp;
+
/*
* This should never fail, but play it safe anyway.
*/
@@ -714,8 +714,10 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
ret = zpool_create_zvol_links(zhp);
zpool_close(zhp);
}
+
}
+
zcmd_free_nvlists(&zc);
return (ret);
}
@@ -733,7 +735,7 @@ zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = type;
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SCRUB, &zc) == 0)
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0)
return (0);
(void) snprintf(msg, sizeof (msg),
@@ -893,7 +895,7 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
zc.zc_obj = flags;
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
return (zpool_standard_error(hdl, errno, msg));
*newstate = zc.zc_cookie;
@@ -927,7 +929,7 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
zc.zc_cookie = VDEV_STATE_OFFLINE;
zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
return (0);
switch (errno) {
@@ -1105,7 +1107,7 @@ zpool_vdev_attach(zpool_handle_t *zhp,
if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
return (-1);
- ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc);
+ ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc);
zcmd_free_nvlists(&zc);
@@ -1206,7 +1208,7 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0)
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
return (0);
switch (errno) {
@@ -1261,7 +1263,7 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
return (0);
return (zpool_standard_error(hdl, errno, msg));
@@ -1300,7 +1302,7 @@ zpool_clear(zpool_handle_t *zhp, const char *path)
&zc.zc_guid) == 0);
}
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
+ if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0)
return (0);
return (zpool_standard_error(hdl, errno, msg));
@@ -1780,11 +1782,10 @@ zpool_upgrade(zpool_handle_t *zhp)
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strcpy(zc.zc_name, zhp->zpool_name);
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
return (zpool_standard_error_fmt(hdl, errno,
dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
zhp->zpool_name));
-
return (0);
}
@@ -1797,39 +1798,32 @@ zpool_upgrade(zpool_handle_t *zhp)
* poolname. 'argc' and 'argv' are used to construct the command string.
*/
void
-zpool_log_history(libzfs_handle_t *hdl, int argc, char **argv, const char *path,
- boolean_t pool, boolean_t pool_create)
+zpool_stage_history(libzfs_handle_t *hdl, int argc, char **argv,
+ boolean_t zfs_cmd, boolean_t pool_create)
{
- char cmd_buf[HIS_MAX_RECORD_LEN];
- char *dspath;
- zfs_cmd_t zc = { 0 };
+ char *cmd_buf;
int i;
- /* construct the command string */
- (void) strcpy(cmd_buf, pool ? "zpool" : "zfs");
- for (i = 0; i < argc; i++) {
- if (strlen(cmd_buf) + 1 + strlen(argv[i]) > HIS_MAX_RECORD_LEN)
- break;
- (void) strcat(cmd_buf, " ");
- (void) strcat(cmd_buf, argv[i]);
+ if (hdl->libzfs_log_str != NULL) {
+ free(hdl->libzfs_log_str);
}
- /* figure out the poolname */
- dspath = strpbrk(path, "/@");
- if (dspath == NULL) {
- (void) strcpy(zc.zc_name, path);
- } else {
- (void) strncpy(zc.zc_name, path, dspath - path);
- zc.zc_name[dspath-path] = '\0';
- }
-
- zc.zc_history = (uint64_t)(uintptr_t)cmd_buf;
- zc.zc_history_len = strlen(cmd_buf);
+ if ((hdl->libzfs_log_str = zfs_alloc(hdl, HIS_MAX_RECORD_LEN)) == NULL)
+ return;
- /* overloading zc_history_offset */
- zc.zc_history_offset = pool_create;
+ hdl->libzfs_log_type =
+ (pool_create == B_TRUE) ? LOG_CMD_POOL_CREATE : LOG_CMD_NORMAL;
+ cmd_buf = hdl->libzfs_log_str;
- (void) ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_LOG_HISTORY, &zc);
+ /* construct the command string */
+ (void) strlcpy(cmd_buf, zfs_cmd ? "zfs" : "zpool",
+ HIS_MAX_RECORD_LEN);
+ for (i = 1; i < argc; i++) {
+ if (strlen(cmd_buf) + 1 + strlen(argv[i]) > HIS_MAX_RECORD_LEN)
+ break;
+ (void) strlcat(cmd_buf, " ", HIS_MAX_RECORD_LEN);
+ (void) strlcat(cmd_buf, argv[i], HIS_MAX_RECORD_LEN);
+ }
}
/*
@@ -2221,7 +2215,7 @@ zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl, NULL) != 0)
return (-1);
- ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SET_PROPS, &zc);
+ ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
zcmd_free_nvlists(&zc);
if (ret)
@@ -2308,6 +2302,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf,
(void) strlcpy(propbuf, strvalue, proplen);
break;
+ case ZPOOL_PROP_DELEGATION:
case ZPOOL_PROP_AUTOREPLACE:
if (nvlist_lookup_nvlist(zhp->zpool_props,
zpool_prop_to_name(prop), &nvp) != 0) {
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index 2ae3e2e6ce..029cfbdf45 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -133,6 +133,10 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
case EZFS_SHARENFSFAILED:
return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
+ case EZFS_ISCSISVCUNAVAIL:
+ return (dgettext(TEXT_DOMAIN,
+ "iscsitgt service need to be enabled by "
+ "a privileged user"));
case EZFS_DEVLINKS:
return (dgettext(TEXT_DOMAIN, "failed to create /dev links"));
case EZFS_PERM:
@@ -176,6 +180,21 @@ libzfs_error_description(libzfs_handle_t *hdl)
"disk capacity information could not be retrieved"));
case EZFS_LABELFAILED:
return (dgettext(TEXT_DOMAIN, "write of label failed"));
+ case EZFS_BADWHO:
+ return (dgettext(TEXT_DOMAIN, "invalid user/group"));
+ case EZFS_BADPERM:
+ return (dgettext(TEXT_DOMAIN, "invalid permission"));
+ case EZFS_BADPERMSET:
+ return (dgettext(TEXT_DOMAIN, "invalid permission set name"));
+ case EZFS_PERMSET_CIRCULAR:
+ return (dgettext(TEXT_DOMAIN,
+ "Cannot define a permission set in terms of itself"));
+ case EZFS_NODELEGATION:
+ return (dgettext(TEXT_DOMAIN, "delegated administration is "
+ "disabled on pool"));
+ case EZFS_PERMRDONLY:
+ return (dgettext(TEXT_DOMAIN, "snapshot permissions cannot be"
+ " modified"));
case EZFS_UNKNOWN:
return (dgettext(TEXT_DOMAIN, "unknown error"));
default:
@@ -256,6 +275,10 @@ zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
zfs_verror(hdl, EZFS_PERM, fmt, ap);
return (-1);
+ case ECANCELED:
+ zfs_verror(hdl, EZFS_NODELEGATION, fmt, ap);
+ return (-1);
+
case EIO:
zfs_verror(hdl, EZFS_IO, fmt, ap);
return (-1);
@@ -315,11 +338,14 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
"dataset is busy"));
zfs_verror(hdl, EZFS_BUSY, fmt, ap);
break;
-
+ case EROFS:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshot permissions cannot be modified"));
+ zfs_verror(hdl, EZFS_PERMRDONLY, fmt, ap);
+ break;
case ENAMETOOLONG:
zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
break;
-
default:
zfs_error_aux(hdl, strerror(errno));
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
@@ -389,6 +415,11 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);
break;
+ case ENOSPC:
+ case EDQUOT:
+ zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+ return (-1);
+
default:
zfs_error_aux(hdl, strerror(error));
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
@@ -537,6 +568,8 @@ libzfs_fini(libzfs_handle_t *hdl)
if (hdl->libzfs_sharetab)
(void) fclose(hdl->libzfs_sharetab);
zfs_uninit_libshare(hdl);
+ if (hdl->libzfs_log_str)
+ (void) free(hdl->libzfs_log_str);
namespace_clear(hdl);
free(hdl);
}
@@ -852,3 +885,21 @@ libzfs_print_one_property(const char *name, libzfs_get_cbdata_t *cbp,
(void) printf("\n");
}
+
+int
+zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
+{
+ int error;
+
+ zc->zc_history = (uint64_t)(uintptr_t)hdl->libzfs_log_str;
+ zc->zc_history_offset = hdl->libzfs_log_type;
+ error = ioctl(hdl->libzfs_fd, request, zc);
+ if (hdl->libzfs_log_str) {
+ free(hdl->libzfs_log_str);
+ hdl->libzfs_log_str = NULL;
+ }
+ zc->zc_history = 0;
+ zc->zc_history_offset = 0;
+
+ return (error);
+}
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index af27ecb1c0..d870f339f8 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -34,20 +34,24 @@ SUNWprivate_1.1 {
libzfs_init;
libzfs_print_on_error;
libzfs_print_one_property;
+ zfs_build_perms;
zfs_clone;
zfs_close;
zfs_create;
zfs_create_ancestors;
zfs_dataset_exists;
+ zfs_deleg_share_nfs;
zfs_destroy;
zfs_destroy_snaps;
zfs_expand_proplist;
+ zfs_free_allows;
zfs_free_proplist;
zfs_get_handle;
zfs_get_name;
zfs_get_user_props;
zfs_get_proplist;
zfs_get_type;
+ zfs_iscsi_perm_check;
zfs_is_mounted;
zfs_is_shared;
zfs_is_shared_iscsi;
@@ -64,6 +68,9 @@ SUNWprivate_1.1 {
zfs_nicestrtonum;
zfs_open;
zfs_path_to_zhandle;
+ zfs_perm_get;
+ zfs_perm_remove;
+ zfs_perm_set;
zfs_promote;
zfs_prop_align_right;
zfs_prop_column_name;
@@ -131,8 +138,8 @@ SUNWprivate_1.1 {
zpool_in_use;
zpool_iter;
zpool_label_disk;
- zpool_log_history;
zpool_mount_datasets;
+ zpool_name_to_prop;
zpool_obj_to_path;
zpool_open;
zpool_open_canfail;
@@ -144,6 +151,7 @@ SUNWprivate_1.1 {
zpool_remove_zvol_links;
zpool_scrub;
zpool_set_prop;
+ zpool_stage_history;
zpool_unmount_datasets;
zpool_upgrade;
zpool_vdev_attach;
diff --git a/usr/src/lib/libzpool/Makefile.com b/usr/src/lib/libzpool/Makefile.com
index 6d1254186f..6a51a25230 100644
--- a/usr/src/lib/libzpool/Makefile.com
+++ b/usr/src/lib/libzpool/Makefile.com
@@ -54,6 +54,7 @@ LIBS += $(LINTLIB)
INCS += -I../common
INCS += -I../../../uts/common/fs/zfs
INCS += -I../../../common/zfs
+INCS += -I../../../common
$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
diff --git a/usr/src/lib/libzpool/common/kernel.c b/usr/src/lib/libzpool/common/kernel.c
index 6410efa5f6..c601d1811e 100644
--- a/usr/src/lib/libzpool/common/kernel.c
+++ b/usr/src/lib/libzpool/common/kernel.c
@@ -800,3 +800,45 @@ z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
return (ret);
}
+
+uid_t
+crgetuid(cred_t *cr)
+{
+ return (0);
+}
+
+gid_t
+crgetgid(cred_t *cr)
+{
+ return (0);
+}
+
+int
+crgetngroups(cred_t *cr)
+{
+ return (0);
+}
+
+gid_t *
+crgetgroups(cred_t *cr)
+{
+ return (NULL);
+}
+
+int
+zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
+{
+ return (0);
+}
+
+int
+zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
+{
+ return (0);
+}
+
+int
+zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
+{
+ return (0);
+}
diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h
index e30f1c704d..4f3bdc6f36 100644
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h
@@ -63,6 +63,7 @@ extern "C" {
#include <time.h>
#include <sys/note.h>
#include <sys/types.h>
+#include <sys/cred.h>
#include <sys/sysmacros.h>
#include <sys/bitmap.h>
#include <sys/resource.h>
@@ -250,6 +251,11 @@ extern int rw_tryupgrade(krwlock_t *rwlp);
extern void rw_exit(krwlock_t *rwlp);
#define rw_downgrade(rwlp) do { } while (0)
+extern uid_t crgetuid(cred_t *cr);
+extern gid_t crgetgid(cred_t *cr);
+extern int crgetngroups(cred_t *cr);
+extern gid_t *crgetgroups(cred_t *cr);
+
/*
* Condition variables
*/
@@ -448,6 +454,11 @@ extern int kobj_read_file(struct _buf *file, char *buf, unsigned size,
unsigned off);
extern void kobj_close_file(struct _buf *file);
extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
+extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr);
+extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
+ cred_t *cr);
+extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
+extern zoneid_t getzoneid(void);
#ifdef __cplusplus
}