summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libzfs')
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h12
-rw-r--r--usr/src/lib/libzfs/common/libzfs_changelist.c62
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c80
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h23
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c313
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c4
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers7
7 files changed, 396 insertions, 105 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 73bd80d201..265d22e66b 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -110,6 +110,8 @@ enum {
EZFS_BADPERMSET, /* invalid permission set name */
EZFS_NODELEGATION, /* delegated administration is disabled */
EZFS_PERMRDONLY, /* pemissions are readonly */
+ EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */
+ EZFS_SHARESMBFAILED, /* failed to share over smb */
EZFS_UNKNOWN
};
@@ -320,7 +322,6 @@ extern const char *zfs_get_name(const zfs_handle_t *);
/*
* zfs dataset property management
*/
-extern int zfs_prop_valid_for_type(zfs_prop_t, int);
extern const char *zfs_prop_default_string(zfs_prop_t);
extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
extern const char *zfs_prop_column_name(zfs_prop_t);
@@ -459,15 +460,22 @@ extern int zfs_unshare(zfs_handle_t *);
* Protocol-specific share support functions.
*/
extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
+extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
extern int zfs_share_nfs(zfs_handle_t *);
+extern int zfs_share_smb(zfs_handle_t *);
+extern int zfs_shareall(zfs_handle_t *);
extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
+extern int zfs_unshare_smb(zfs_handle_t *, const char *);
extern int zfs_unshareall_nfs(zfs_handle_t *);
+extern int zfs_unshareall_smb(zfs_handle_t *);
+extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
+extern int zfs_unshareall(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);
+ void *, void *, int, zfs_share_op_t);
/*
* When dealing with nvlists, verify() is extremely useful
diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c
index 9ceefdc3b1..2b53f7d983 100644
--- a/usr/src/lib/libzfs/common/libzfs_changelist.c
+++ b/usr/src/lib/libzfs/common/libzfs_changelist.c
@@ -71,6 +71,7 @@ typedef struct prop_changenode {
struct prop_changelist {
zfs_prop_t cl_prop;
zfs_prop_t cl_realprop;
+ zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */
uu_list_pool_t *cl_pool;
uu_list_t *cl_list;
boolean_t cl_waslegacy;
@@ -185,6 +186,7 @@ changelist_postfix(prop_changelist_t *clp)
cn = uu_list_prev(clp->cl_list, cn)) {
boolean_t sharenfs;
+ boolean_t sharesmb;
/*
* If we are in the global zone, but this dataset is exported
@@ -222,14 +224,18 @@ changelist_postfix(prop_changelist_t *clp)
/*
* Remount if previously mounted or mountpoint was legacy,
- * or sharenfs property is set.
+ * or sharenfs or sharesmb property is set.
*/
sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
shareopts, sizeof (shareopts), NULL, NULL, 0,
B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
- if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs) &&
- !zfs_is_mounted(cn->cn_handle, NULL) &&
+ sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
+ shareopts, sizeof (shareopts), NULL, NULL, 0,
+ B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
+
+ if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs ||
+ sharesmb) && !zfs_is_mounted(cn->cn_handle, NULL) &&
zfs_mount(cn->cn_handle, NULL, 0) != 0)
ret = -1;
@@ -237,11 +243,16 @@ changelist_postfix(prop_changelist_t *clp)
* We always re-share even if the filesystem is currently
* shared, so that we can adopt any new options.
*/
- if (cn->cn_shared || clp->cl_waslegacy || sharenfs) {
+ if (cn->cn_shared || clp->cl_waslegacy ||
+ sharenfs || sharesmb) {
if (sharenfs)
ret = zfs_share_nfs(cn->cn_handle);
else
ret = zfs_unshare_nfs(cn->cn_handle, NULL);
+ if (sharesmb)
+ ret = zfs_share_smb(cn->cn_handle);
+ else
+ ret = zfs_unshare_smb(cn->cn_handle, NULL);
}
}
@@ -302,21 +313,22 @@ changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
}
/*
- * Given a gathered changelist for the 'sharenfs' property, unshare all the
- * datasets in the list.
+ * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property,
+ * unshare all the datasets in the list.
*/
int
-changelist_unshare(prop_changelist_t *clp)
+changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
{
prop_changenode_t *cn;
int ret = 0;
- if (clp->cl_prop != ZFS_PROP_SHARENFS)
+ if (clp->cl_prop != ZFS_PROP_SHARENFS &&
+ clp->cl_prop != ZFS_PROP_SHARESMB)
return (0);
for (cn = uu_list_first(clp->cl_list); cn != NULL;
cn = uu_list_next(clp->cl_list, cn)) {
- if (zfs_unshare_nfs(cn->cn_handle, NULL) != 0)
+ if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0)
ret = -1;
}
@@ -386,6 +398,7 @@ change_one(zfs_handle_t *zhp, void *data)
char where[64];
prop_changenode_t *cn;
zprop_source_t sourcetype;
+ zprop_source_t share_sourcetype;
/*
* We only want to unmount/unshare those filesystems that may inherit
@@ -405,9 +418,25 @@ change_one(zfs_handle_t *zhp, void *data)
return (0);
}
+ /*
+ * If we are "watching" sharenfs or sharesmb
+ * then check out the companion property which is tracked
+ * in cl_shareprop
+ */
+ if (clp->cl_shareprop != ZPROP_INVAL &&
+ zfs_prop_get(zhp, clp->cl_shareprop, property,
+ sizeof (property), &share_sourcetype, where, sizeof (where),
+ B_FALSE) != 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
if (clp->cl_alldependents || clp->cl_allchildren ||
sourcetype == ZPROP_SRC_DEFAULT ||
- sourcetype == ZPROP_SRC_INHERITED) {
+ sourcetype == ZPROP_SRC_INHERITED ||
+ (clp->cl_shareprop != ZPROP_INVAL &&
+ (share_sourcetype == ZPROP_SRC_DEFAULT ||
+ share_sourcetype == ZPROP_SRC_INHERITED))) {
if ((cn = zfs_alloc(zfs_get_handle(zhp),
sizeof (prop_changenode_t))) == NULL) {
zfs_close(zhp);
@@ -507,7 +536,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
* order, regardless of their position in the hierarchy.
*/
if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
- prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
+ prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) {
compare = compare_mountpoints;
clp->cl_sorted = B_TRUE;
}
@@ -561,9 +591,19 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
clp->cl_prop != ZFS_PROP_SHARENFS &&
+ clp->cl_prop != ZFS_PROP_SHARESMB &&
clp->cl_prop != ZFS_PROP_SHAREISCSI)
return (clp);
+ /*
+ * If watching SHARENFS or SHARESMB then
+ * also watch its companion property.
+ */
+ if (clp->cl_prop == ZFS_PROP_SHARENFS)
+ clp->cl_shareprop = ZFS_PROP_SHARESMB;
+ else if (clp->cl_prop == ZFS_PROP_SHARESMB)
+ clp->cl_shareprop = ZFS_PROP_SHARENFS;
+
if (clp->cl_alldependents) {
if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
changelist_free(clp);
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index 04a37032ea..db912e7f20 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -51,6 +51,7 @@
#include <sys/spa.h>
#include <sys/zio.h>
#include <sys/zap.h>
+#include <sys/zfs_i18n.h>
#include <libzfs.h>
#include "zfs_namecheck.h"
@@ -376,7 +377,7 @@ top:
if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0)
goto top;
/*
- * If we can sucessfully destroy it, pretend that it
+ * If we can successfully destroy it, pretend that it
* never existed.
*/
if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
@@ -481,6 +482,8 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
char *strval;
zfs_prop_t prop;
nvlist_t *ret;
+ int chosen_normal = -1;
+ int chosen_utf = -1;
if (type == ZFS_TYPE_SNAPSHOT) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -545,7 +548,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}
if (zfs_prop_readonly(prop) &&
- (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) {
+ (!zfs_prop_setonce(prop) || zhp != NULL)) {
zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "'%s' is readonly"),
propname);
@@ -636,19 +639,23 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
/*FALLTHRU*/
+ case ZFS_PROP_SHARESMB:
case ZFS_PROP_SHARENFS:
/*
- * For the mountpoint and sharenfs properties, check if
- * it can be set in a global/non-global zone based on
+ * For the mountpoint and sharenfs or sharesmb
+ * properties, check if it can be set in a
+ * global/non-global zone based on
* the zoned property value:
*
* global zone non-global zone
* --------------------------------------------------
* zoned=on mountpoint (no) mountpoint (yes)
* sharenfs (no) sharenfs (no)
+ * sharesmb (no) sharesmb (no)
*
* zoned=off mountpoint (yes) N/A
* sharenfs (yes)
+ * sharesmb (yes)
*/
if (zoned) {
if (getzoneid() == GLOBAL_ZONEID) {
@@ -659,7 +666,8 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
(void) zfs_error(hdl, EZFS_ZONED,
errbuf);
goto error;
- } else if (prop == ZFS_PROP_SHARENFS) {
+ } else if (prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s' cannot be set in "
"a non-global zone"), propname);
@@ -684,17 +692,24 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
* property. Now we want to make sure that the
* property value is valid if it is sharenfs.
*/
- if (prop == ZFS_PROP_SHARENFS &&
+ if ((prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) &&
strcmp(strval, "on") != 0 &&
strcmp(strval, "off") != 0) {
+ zfs_share_proto_t proto;
+
+ if (prop == ZFS_PROP_SHARESMB)
+ proto = PROTO_SMB;
+ else
+ proto = PROTO_NFS;
/*
- * Must be an NFS option string so
- * init the libshare in order to
- * enable the parser and then parse
- * the options. We use the control API
- * since we don't care about the
- * current configuration and don't
+ * Must be an valid sharing protocol
+ * option string so init the libshare
+ * in order to enable the parser and
+ * then parse the options. We use the
+ * control API since we don't care about
+ * the current configuration and don't
* want the overhead of loading it
* until we actually do something.
*/
@@ -714,7 +729,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
goto error;
}
- if (zfs_parse_options(strval, "nfs") != SA_OK) {
+ if (zfs_parse_options(strval, proto) != SA_OK) {
/*
* There was an error in parsing so
* deal with it by issuing an error
@@ -734,6 +749,12 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}
break;
+ case ZFS_PROP_UTF8ONLY:
+ chosen_utf = (int)intval;
+ break;
+ case ZFS_PROP_NORMALIZE:
+ chosen_normal = (int)intval;
+ break;
}
/*
@@ -786,6 +807,27 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}
/*
+ * If normalization was chosen, but no UTF8 choice was made,
+ * enforce rejection of non-UTF8 names.
+ *
+ * If normalization was chosen, but rejecting non-UTF8 names
+ * was explicitly not chosen, it is an error.
+ */
+ if (chosen_normal > ZFS_NORMALIZE_NONE && chosen_utf < 0) {
+ if (nvlist_add_uint64(ret,
+ zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ } else if (chosen_normal > ZFS_NORMALIZE_NONE && chosen_utf == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be set 'on' if normalization chosen"),
+ zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ /*
* If this is an existing volume, and someone is setting the volsize,
* make sure that it matches the reservation, or add it if necessary.
*/
@@ -941,7 +983,7 @@ zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr,
* 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
+ * perms: common 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.
@@ -1833,6 +1875,11 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
mntopt_on = MNTOPT_XATTR;
mntopt_off = MNTOPT_NOXATTR;
break;
+
+ case ZFS_PROP_NBMAND:
+ mntopt_on = MNTOPT_NBMAND;
+ mntopt_off = MNTOPT_NONBMAND;
+ break;
}
/*
@@ -1871,6 +1918,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
case ZFS_PROP_READONLY:
case ZFS_PROP_SETUID:
case ZFS_PROP_XATTR:
+ case ZFS_PROP_NBMAND:
*val = getprop_uint64(zhp, prop, source);
if (hasmntopt(&mnt, mntopt_on) && !*val) {
@@ -4177,7 +4225,7 @@ zfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred)
int
zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
- void *export, void *sharetab, int sharemax, boolean_t share_on)
+ void *export, void *sharetab, int sharemax, zfs_share_op_t operation)
{
zfs_cmd_t zc = { 0 };
int error;
@@ -4186,7 +4234,7 @@ zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
(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_sharetype = operation;
zc.zc_share.z_sharemax = sharemax;
error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index 19a7590cee..cfc03791dd 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -90,6 +90,23 @@ struct zpool_handle {
diskaddr_t zpool_start_block;
};
+typedef enum {
+ PROTO_NFS = 0,
+ PROTO_SMB = 1,
+ PROTO_END = 2
+} zfs_share_proto_t;
+
+/*
+ * The following can be used as a bitmask and any new values
+ * added must preserve that capability.
+ */
+typedef enum {
+ SHARED_NOT_SHARED = 0x0,
+ SHARED_ISCSI = 0x1,
+ SHARED_NFS = 0x2,
+ SHARED_SMB = 0x4
+} zfs_share_type_t;
+
int zfs_error(libzfs_handle_t *, int, const char *);
int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
void zfs_error_aux(libzfs_handle_t *, const char *, ...);
@@ -127,7 +144,7 @@ void changelist_rename(prop_changelist_t *, const char *, const char *);
void changelist_remove(zfs_handle_t *, prop_changelist_t *);
void changelist_free(prop_changelist_t *);
prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int);
-int changelist_unshare(prop_changelist_t *);
+int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
int changelist_haszonedchild(prop_changelist_t *);
void remove_mountpoint(zfs_handle_t *);
@@ -148,8 +165,10 @@ void namespace_clear(libzfs_handle_t *);
extern int zfs_init_libshare(libzfs_handle_t *, int);
extern void zfs_uninit_libshare(libzfs_handle_t *);
-extern int zfs_parse_options(char *, char *);
+extern int zfs_parse_options(char *, zfs_share_proto_t);
+extern int zfs_unshare_proto(zfs_handle_t *zhp,
+ const char *, zfs_share_proto_t *);
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index d7dd227bc8..6810f7efdc 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -45,11 +45,17 @@
* zfs_unshare()
*
* zfs_is_shared_nfs()
- * zfs_share_nfs()
- * zfs_unshare_nfs()
- * zfs_unshareall_nfs()
+ * zfs_is_shared_smb()
* zfs_is_shared_iscsi()
+ * zfs_share_proto()
+ * zfs_shareall();
* zfs_share_iscsi()
+ * zfs_unshare_nfs()
+ * zfs_unshare_smb()
+ * zfs_unshareall_nfs()
+ * zfs_unshareall_smb()
+ * zfs_unshareall()
+ * zfs_unshareall_bypath()
* zfs_unshare_iscsi()
*
* The following functions are available for pool consumers, and will
@@ -82,11 +88,46 @@
#include <sys/systeminfo.h>
#define MAXISALEN 257 /* based on sysinfo(2) man page */
+static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
+zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
+ zfs_share_proto_t);
+
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)();
+/*
+ * The share protocols table must be in the same order as the zfs_share_prot_t
+ * enum in libzfs_impl.h
+ */
+typedef struct {
+ zfs_prop_t p_prop;
+ char *p_name;
+ int p_share_err;
+ int p_unshare_err;
+} proto_table_t;
+
+proto_table_t proto_table[PROTO_END] = {
+ {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
+ {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
+};
+
+zfs_share_proto_t nfs_only[] = {
+ PROTO_NFS,
+ PROTO_END
+};
+
+zfs_share_proto_t smb_only[] = {
+ PROTO_SMB,
+ PROTO_END
+};
+zfs_share_proto_t share_all_proto[] = {
+ PROTO_NFS,
+ PROTO_SMB,
+ PROTO_END
+};
+
#pragma init(zfs_iscsi_init)
static void
zfs_iscsi_init(void)
@@ -111,29 +152,54 @@ zfs_iscsi_init(void)
}
/*
- * Search the sharetab for the given mountpoint, returning true if it is found.
+ * Search the sharetab for the given mountpoint and protocol, returning
+ * a zfs_share_type_t value.
*/
-static boolean_t
-is_shared(libzfs_handle_t *hdl, const char *mountpoint)
+static zfs_share_type_t
+is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
{
char buf[MAXPATHLEN], *tab;
+ char *ptr;
if (hdl->libzfs_sharetab == NULL)
- return (0);
+ return (SHARED_NOT_SHARED);
(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
/* the mountpoint is the first entry on each line */
- if ((tab = strchr(buf, '\t')) != NULL) {
+ if ((tab = strchr(buf, '\t')) == NULL)
+ continue;
+
+ *tab = '\0';
+ if (strcmp(buf, mountpoint) == 0) {
+ /*
+ * the protocol field is the third field
+ * skip over second field
+ */
+ ptr = ++tab;
+ if ((tab = strchr(ptr, '\t')) == NULL)
+ continue;
+ ptr = ++tab;
+ if ((tab = strchr(ptr, '\t')) == NULL)
+ continue;
*tab = '\0';
- if (strcmp(buf, mountpoint) == 0)
- return (B_TRUE);
+ if (strcmp(ptr,
+ proto_table[proto].p_name) == 0) {
+ switch (proto) {
+ case PROTO_NFS:
+ return (SHARED_NFS);
+ case PROTO_SMB:
+ return (SHARED_SMB);
+ default:
+ return (0);
+ }
+ }
}
}
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
}
/*
@@ -349,12 +415,12 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
/*
* Unshare and unmount the filesystem
*/
- if (zfs_unshare_nfs(zhp, mntpt) != 0)
+ if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
return (-1);
if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) {
free(mntpt);
- (void) zfs_share_nfs(zhp);
+ (void) zfs_shareall(zhp);
return (-1);
}
free(mntpt);
@@ -387,10 +453,17 @@ zfs_unmountall(zfs_handle_t *zhp, int flags)
boolean_t
zfs_is_shared(zfs_handle_t *zhp)
{
+ zfs_share_type_t rc = 0;
+ zfs_share_proto_t *curr_proto;
+
if (ZFS_IS_VOLUME(zhp))
return (zfs_is_shared_iscsi(zhp));
- return (zfs_is_shared_nfs(zhp, NULL));
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++)
+ rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
+
+ return (rc ? B_TRUE : B_FALSE);
}
int
@@ -399,7 +472,7 @@ zfs_share(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp))
return (zfs_share_iscsi(zhp));
- return (zfs_share_nfs(zhp));
+ return (zfs_share_proto(zhp, share_all_proto));
}
int
@@ -408,32 +481,47 @@ zfs_unshare(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp))
return (zfs_unshare_iscsi(zhp));
- return (zfs_unshare_nfs(zhp, NULL));
+ return (zfs_unshareall(zhp));
}
/*
* Check to see if the filesystem is currently shared.
*/
-boolean_t
-zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+zfs_share_type_t
+zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
{
char *mountpoint;
+ zfs_share_type_t rc;
if (!zfs_is_mounted(zhp, &mountpoint))
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
- if (is_shared(zhp->zfs_hdl, mountpoint)) {
+ if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
if (where != NULL)
*where = mountpoint;
else
free(mountpoint);
- return (B_TRUE);
+ return (rc);
} else {
free(mountpoint);
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
}
}
+boolean_t
+zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_NFS) != SHARED_NOT_SHARED);
+}
+
+boolean_t
+zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_SMB) != SHARED_NOT_SHARED);
+}
+
/*
* Make sure things will work if libshare isn't installed by using
* wrapper functions that check to see that the pointers to functions
@@ -552,12 +640,13 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
*/
int
-zfs_parse_options(char *options, char *proto)
+zfs_parse_options(char *options, zfs_share_proto_t proto)
{
int ret;
if (_sa_parse_legacy_options != NULL)
- ret = _sa_parse_legacy_options(NULL, options, proto);
+ ret = _sa_parse_legacy_options(NULL, options,
+ proto_table[proto].p_name);
else
ret = SA_CONFIG_ERR;
return (ret);
@@ -609,74 +698,102 @@ zfs_sa_disable_share(sa_share_t share, char *proto)
}
/*
- * Share the given filesystem according to the options in 'sharenfs'. We rely
+ * Share the given filesystem according to the options in the specified
+ * protocol specific properties (sharenfs, sharesmb). We rely
* on "libshare" to the dirty work for us.
*/
-int
-zfs_share_nfs(zfs_handle_t *zhp)
+static int
+zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
char mountpoint[ZFS_MAXPROPLEN];
char shareopts[ZFS_MAXPROPLEN];
libzfs_handle_t *hdl = zhp->zfs_hdl;
sa_share_t share;
+ zfs_share_proto_t *curr_proto;
int ret;
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
- /*
- * Return success if there are no share options.
- */
- if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
- NULL, NULL, 0, B_FALSE) != 0 ||
- strcmp(shareopts, "off") == 0)
- return (0);
-
- /*
- * If the 'zoned' property is set, then zfs_is_mountable() will have
- * already bailed out if we are in the global zone. But local
- * zones cannot be NFS servers, so we ignore it for local zones as well.
- */
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
- return (0);
-
if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
zfs_get_name(zhp), _sa_errorstr(ret));
return (-1);
}
- share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
- if (share != NULL) {
- int err;
- err = zfs_sa_enable_share(share, "nfs");
- if (err != SA_OK) {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+
+ for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+ /*
+ * Return success if there are no share options.
+ */
+ if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
+ shareopts, sizeof (shareopts), NULL, NULL,
+ 0, B_FALSE) != 0 || strcmp(shareopts, "off") == 0)
+ continue;
+
+ /*
+ * If the 'zoned' property is set, then zfs_is_mountable()
+ * will have already bailed out if we are in the global zone.
+ * But local zones cannot be NFS servers, so we ignore it for
+ * local zones as well.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
+ continue;
+
+ share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+ if (share != NULL) {
+ int err;
+ err = zfs_sa_enable_share(share,
+ proto_table[*curr_proto].p_name);
+ if (err != SA_OK) {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp));
+ return (-1);
+ }
+ } else {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
zfs_get_name(zhp));
return (-1);
}
- } else {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
- dgettext(TEXT_DOMAIN, "cannot share '%s'"),
- zfs_get_name(zhp));
- return (-1);
- }
+ }
return (0);
}
+
+int
+zfs_share_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, nfs_only));
+}
+
+int
+zfs_share_smb(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, smb_only));
+}
+
+int
+zfs_shareall(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, share_all_proto));
+}
+
/*
* Unshare a filesystem by mountpoint.
*/
static int
-unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+ zfs_share_proto_t proto)
{
sa_share_t share;
int err;
char *mntpt;
-
/*
* Mountpoint could get trashed if libshare calls getmntany
* which id does during API initialization, so strdup the
@@ -696,7 +813,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
free(mntpt); /* don't need the copy anymore */
if (share != NULL) {
- err = zfs_sa_disable_share(share, "nfs");
+ err = zfs_sa_disable_share(share, proto_table[proto].p_name);
if (err != SA_OK) {
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
@@ -714,7 +831,8 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
* Unshare the given filesystem.
*/
int
-zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
+ zfs_share_proto_t *proto)
{
struct mnttab search = { 0 }, entry;
char *mntpt = NULL;
@@ -724,19 +842,25 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
search.mnt_fstype = MNTTYPE_ZFS;
rewind(zhp->zfs_hdl->libzfs_mnttab);
if (mountpoint != NULL)
- mountpoint = mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
+ mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
+ zfs_share_proto_t *curr_proto;
if (mountpoint == NULL)
- mountpoint = entry.mnt_mountp;
+ mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
- if (is_shared(zhp->zfs_hdl, mountpoint) &&
- unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) {
- if (mntpt != NULL)
- free(mntpt);
- return (-1);
+ for (curr_proto = proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+
+ if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) &&
+ unshare_one(zhp->zfs_hdl, zhp->zfs_name,
+ mntpt, *curr_proto) != 0) {
+ if (mntpt != NULL)
+ free(mntpt);
+ return (-1);
+ }
}
}
if (mntpt != NULL)
@@ -745,11 +869,23 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
return (0);
}
+int
+zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
+}
+
+int
+zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, smb_only));
+}
+
/*
- * Same as zfs_unmountall(), but for NFS unshares.
+ * Same as zfs_unmountall(), but for NFS and SMB unshares.
*/
int
-zfs_unshareall_nfs(zfs_handle_t *zhp)
+zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
prop_changelist_t *clp;
int ret;
@@ -758,12 +894,36 @@ zfs_unshareall_nfs(zfs_handle_t *zhp)
if (clp == NULL)
return (-1);
- ret = changelist_unshare(clp);
+ ret = changelist_unshare(clp, proto);
changelist_free(clp);
return (ret);
}
+int
+zfs_unshareall_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, nfs_only));
+}
+
+int
+zfs_unshareall_smb(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, smb_only));
+}
+
+int
+zfs_unshareall(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
+}
+
/*
* Remove the mountpoint associated with the current dataset, if necessary.
* We only remove the underlying directory if:
@@ -805,7 +965,7 @@ zfs_is_shared_iscsi(zfs_handle_t *zhp)
* If iscsi deamon isn't running then we aren't shared
*/
if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
- return (0);
+ return (B_FALSE);
else
return (iscsitgt_zfs_is_shared != NULL &&
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
@@ -853,7 +1013,7 @@ zfs_unshare_iscsi(zfs_handle_t *zhp)
/*
* Return if the volume is not shared
*/
- if (!zfs_is_shared_iscsi(zhp))
+ if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
return (0);
/*
@@ -1143,9 +1303,14 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
* Walk through and first unshare everything.
*/
for (i = 0; i < used; i++) {
- if (is_shared(hdl, mountpoints[i]) &&
- unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
- goto out;
+ zfs_share_proto_t *curr_proto;
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+ if (is_shared(hdl, mountpoints[i], *curr_proto) &&
+ unshare_one(hdl, mountpoints[i],
+ mountpoints[i], *curr_proto) != 0)
+ goto out;
+ }
}
/*
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index d446b32091..8a1ad6d656 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -136,6 +136,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_UNSHARESMBFAILED:
+ return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
+ case EZFS_SHARESMBFAILED:
+ return (dgettext(TEXT_DOMAIN, "smb add share failed"));
case EZFS_ISCSISVCUNAVAIL:
return (dgettext(TEXT_DOMAIN,
"iscsitgt service need to be enabled by "
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index 1ca0da3453..d7d68f8708 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -53,6 +53,7 @@ SUNWprivate_1.1 {
zfs_is_shared;
zfs_is_shared_iscsi;
zfs_is_shared_nfs;
+ zfs_is_shared_smb;
zfs_iter_children;
zfs_iter_dependents;
zfs_iter_filesystems;
@@ -92,7 +93,9 @@ SUNWprivate_1.1 {
zfs_rollback;
zfs_send;
zfs_share;
+ zfs_shareall;
zfs_share_nfs;
+ zfs_share_smb;
zfs_share_iscsi;
zfs_snapshot;
zfs_type_to_name;
@@ -101,7 +104,11 @@ SUNWprivate_1.1 {
zfs_unshare;
zfs_unshare_iscsi;
zfs_unshare_nfs;
+ zfs_unshare_smb;
+ zfs_unshareall;
+ zfs_unshareall_bypath;
zfs_unshareall_nfs;
+ zfs_unshareall_smb;
zpool_add;
zpool_clear;
zpool_close;