summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshare/common/libshare_zfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libshare/common/libshare_zfs.c')
-rw-r--r--usr/src/lib/libshare/common/libshare_zfs.c388
1 files changed, 301 insertions, 87 deletions
diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c
index 1cfbcbe72a..e0ee84ef8a 100644
--- a/usr/src/lib/libshare/common/libshare_zfs.c
+++ b/usr/src/lib/libshare/common/libshare_zfs.c
@@ -36,7 +36,7 @@
#include <sys/mnttab.h>
#include <sys/mntent.h>
-extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
+extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
extern char *sa_fstype(char *);
extern void set_node_attr(void *, char *, char *);
@@ -109,7 +109,7 @@ sa_zfs_fini(sa_handle_impl_t impl_handle)
/*
* get_one_filesystem(zfs_handle_t, data)
*
- * an interator function called while iterating through the ZFS
+ * an iterator function called while iterating through the ZFS
* root. It accumulates into an array of file system handles that can
* be used to derive info about those file systems.
*
@@ -390,7 +390,7 @@ sa_zfs_is_shared(sa_handle_t sahandle, char *path)
}
/*
- * find_or_create_group(groupname, proto, *err)
+ * find_or_create_group(handle, groupname, proto, *err)
*
* While walking the ZFS tree, we need to add shares to a defined
* group. If the group doesn't exist, create it first, making sure it
@@ -424,19 +424,8 @@ find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
if (group != NULL) {
if (proto != NULL) {
optionset = sa_get_optionset(group, proto);
- if (optionset == NULL) {
+ if (optionset == NULL)
optionset = sa_create_optionset(group, proto);
- } else {
- char **protolist;
- int numprotos, i;
- numprotos = sa_get_protocols(&protolist);
- for (i = 0; i < numprotos; i++) {
- optionset = sa_create_optionset(group,
- protolist[i]);
- }
- if (protolist != NULL)
- free(protolist);
- }
}
}
if (err != NULL)
@@ -457,8 +446,8 @@ find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
*/
static sa_group_t
-find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
- char *optstring, int *err)
+find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
+ char *optstring, int *err)
{
sa_group_t group = NULL;
sa_group_t zfs;
@@ -494,30 +483,58 @@ find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
options = strdup(optstring);
if (options != NULL) {
*err = sa_parse_legacy_options(group,
- options, "nfs");
+ options, proto);
+
+ /* If no optionset, add one */
+ if (sa_get_optionset(group, proto) ==
+ NULL)
+ (void) sa_create_optionset(
+ group, proto);
free(options);
} else {
*err = SA_NO_MEMORY;
}
}
+ } else if (proto != NULL && strcmp(proto, "smb") == 0) {
+ *err = SA_PROP_SHARE_ONLY;
}
}
return (group);
}
/*
+ * zfs_construct_resource(share, name, base, dataset)
+ *
+ * Add a resource to the share using name as a template. If name ==
+ * NULL, then construct a name based on the dataset value.
+ * name.
+ */
+static void
+zfs_construct_resource(sa_share_t share, char *dataset)
+{
+ char buff[SA_MAX_RESOURCE_NAME + 1];
+ int ret = SA_OK;
+
+ (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
+ sa_fix_resource_name(buff);
+ (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
+}
+
+/*
* zfs_inherited(handle, source, sourcestr)
*
- * handle case of inherited sharenfs. Pulled out of sa_get_zfs_shares
+ * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
* for readability.
*/
static int
zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
- char *shareopts, char *mountpoint)
+ char *shareopts, char *mountpoint, char *proto, char *dataset)
{
int doshopt = 0;
int err = SA_OK;
sa_group_t group;
+ sa_resource_t resource;
+ uint64_t features;
/*
* Need to find the "real" parent sub-group. It may not be
@@ -525,11 +542,18 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
* variable. The real parent not mounted can occur if
* "canmount=off and sharenfs=on".
*/
- group = find_or_create_zfs_subgroup(handle, sourcestr, shareopts,
- &doshopt);
+ group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
+ shareopts, &doshopt);
if (group != NULL) {
- share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
- &err);
+ /*
+ * We may need the first share for resource
+ * prototype. We only care about it if it has a
+ * resource that sets a prefix value.
+ */
+ if (share == NULL)
+ share = _sa_add_share(group, mountpoint,
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
/*
* some options may only be on shares. If the opt
* string contains one of those, we put it just on the
@@ -539,10 +563,27 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
char *options;
options = strdup(shareopts);
if (options != NULL) {
+ set_node_attr(share, "dataset", dataset);
err = sa_parse_legacy_options(share, options,
- "nfs");
+ proto);
+ set_node_attr(share, "dataset", NULL);
free(options);
}
+ if (sa_get_optionset(group, proto) == NULL)
+ (void) sa_create_optionset(group, proto);
+ }
+ features = sa_proto_get_featureset(proto);
+ if (share != NULL && features & SA_FEATURE_RESOURCE) {
+ /*
+ * We have a share and the protocol requires
+ * that at least one resource exist (probably
+ * SMB). We need to make sure that there is at
+ * least one.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource == NULL) {
+ zfs_construct_resource(share, dataset);
+ }
}
} else {
err = SA_NO_MEMORY;
@@ -557,45 +598,60 @@ zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
* of sa_get_zfs_shares for readability.
*/
static int
-zfs_notinherited(sa_group_t group, char *mountpoint, char *shareopts)
+zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
+ char *shareopts, char *proto, char *dataset)
{
int err = SA_OK;
- sa_share_t share;
- char *options;
+ sa_resource_t resource;
+ uint64_t features;
set_node_attr(group, "zfs", "true");
- share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, &err);
+ if (share == NULL)
+ share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
+ &err, (uint64_t)SA_FEATURE_NONE);
if (err == SA_OK) {
if (strcmp(shareopts, "on") == 0)
- shareopts = "rw";
-
- options = strdup(shareopts);
- if (options != NULL) {
- err = sa_parse_legacy_options(group, options,
- "nfs");
- free(options);
- }
- if (err == SA_PROP_SHARE_ONLY) {
- /*
- * Same as above, some properties may
- * only be on shares, but due to the
- * ZFS sub-groups being artificial, we
- * sometimes get this and have to deal
- * with it. We do it by attempting to
- * put it on the share.
- */
+ shareopts = "";
+ if (shareopts != NULL) {
+ char *options;
options = strdup(shareopts);
if (options != NULL) {
- err = sa_parse_legacy_options(share,
- options, "nfs");
+ err = sa_parse_legacy_options(group, options,
+ proto);
free(options);
}
+ if (err == SA_PROP_SHARE_ONLY) {
+ /*
+ * Same as above, some properties may
+ * only be on shares, but due to the
+ * ZFS sub-groups being artificial, we
+ * sometimes get this and have to deal
+ * with it. We do it by attempting to
+ * put it on the share.
+ */
+ options = strdup(shareopts);
+ if (options != NULL) {
+ err = sa_parse_legacy_options(share,
+ options, proto);
+ free(options);
+ }
+ }
+ /* unmark the share's changed state */
+ set_node_attr(share, "changed", NULL);
+ }
+ features = sa_proto_get_featureset(proto);
+ if (share != NULL && features & SA_FEATURE_RESOURCE) {
+ /*
+ * We have a share and the protocol requires
+ * that at least one resource exist (probably
+ * SMB). We need to make sure that there is at
+ * least one.
+ */
+ resource = sa_get_share_resource(share, NULL);
+ if (resource == NULL) {
+ zfs_construct_resource(share, dataset);
+ }
}
- /* Mark as the defining node of the subgroup */
- set_node_attr(share, "subgroup", "true");
-
- /* unmark the share's changed state */
- set_node_attr(share, "changed", NULL);
}
return (err);
}
@@ -619,6 +675,46 @@ zfs_grp_error(int err)
}
/*
+ * zfs_process_share(handle, share, mountpoint, proto, source,
+ * shareopts, sourcestr)
+ *
+ * Creates the subgroup, if necessary and adds shares and adds shares
+ * and properties.
+ */
+static int
+zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
+ char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
+ char *sourcestr, char *dataset)
+{
+ int err = SA_OK;
+
+ if (source & ZPROP_SRC_INHERITED) {
+ err = zfs_inherited(handle, share, sourcestr, shareopts,
+ mountpoint, proto, dataset);
+ } else {
+ group = find_or_create_zfs_subgroup(handle, dataset, proto,
+ shareopts, &err);
+ if (group == NULL) {
+ static int err = 0;
+ /*
+ * there is a problem, but we can't do
+ * anything about it at this point so we issue
+ * a warning an move on.
+ */
+ zfs_grp_error(err);
+ err = 1;
+ }
+ set_node_attr(group, "zfs", "true");
+ /*
+ * Add share with local opts via zfs_notinherited.
+ */
+ err = zfs_notinherited(group, share, mountpoint, shareopts,
+ proto, dataset);
+ }
+ return (err);
+}
+
+/*
* sa_get_zfs_shares(handle, groupname)
*
* Walk the mnttab for all zfs mounts and determine which are
@@ -652,7 +748,7 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
if (zfs_libhandle == NULL)
return (SA_SYSTEM_ERR);
- zfsgroup = find_or_create_group(handle, groupname, "nfs", &err);
+ zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
if (zfsgroup == NULL)
return (legacy);
@@ -666,6 +762,7 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
group = zfsgroup;
for (i = 0; i < count; i++) {
char *dataset;
+ int foundnfs = 0;
source = ZPROP_SRC_ALL;
/* If no mountpoint, skip. */
@@ -694,8 +791,9 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
ZFS_MAXPROPLEN, B_FALSE) == 0 &&
strcmp(shareopts, "off") != 0) {
/* it is shared so add to list */
- share = sa_find_share(handle, mountpoint);
err = SA_OK;
+ foundnfs = 1;
+ share = sa_find_share(handle, mountpoint);
if (share != NULL) {
/*
* A zfs file system had been shared
@@ -711,36 +809,36 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname)
share = NULL;
}
if (err == SA_OK) {
- if (source & ZPROP_SRC_INHERITED) {
- err = zfs_inherited(handle,
- share, sourcestr,
- shareopts, mountpoint);
- } else {
- group = _sa_create_zfs_group(
- zfsgroup, dataset);
- if (group == NULL) {
- static int err = 0;
- /*
- * there is a problem,
- * but we can't do
- * anything about it
- * at this point so we
- * issue a warning an
- * move on.
- */
- zfs_grp_error(err);
- err = 1;
- continue;
- }
- set_node_attr(group, "zfs",
- "true");
- /*
- * Add share with local opts via
- * zfs_notinherited.
- */
- err = zfs_notinherited(group,
- mountpoint, shareopts);
- }
+ err = zfs_process_share(handle, group,
+ share, mountpoint, "nfs", source,
+ shareopts, sourcestr, dataset);
+ }
+ }
+ if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts,
+ sizeof (shareopts), &source, sourcestr,
+ ZFS_MAXPROPLEN, B_FALSE) == 0 &&
+ strcmp(shareopts, "off") != 0) {
+ /* it is shared so add to list */
+ err = SA_OK;
+ share = sa_find_share(handle, mountpoint);
+ if (share != NULL && !foundnfs) {
+ /*
+ * A zfs file system had been shared
+ * through traditional methods
+ * (share/dfstab or added to a non-zfs
+ * group. Now it has been added to a
+ * ZFS group via the zfs
+ * command. Remove from previous
+ * config and setup with current
+ * options.
+ */
+ err = sa_remove_share(share);
+ share = NULL;
+ }
+ if (err == SA_OK) {
+ err = zfs_process_share(handle, group,
+ share, mountpoint, "smb", source,
+ shareopts, sourcestr, dataset);
}
}
}
@@ -811,6 +909,122 @@ sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
}
/*
+ * add_resources(share, opt)
+ *
+ * Add resource properties to those in "opt". Resources are prefixed
+ * with name=resourcename.
+ */
+static char *
+add_resources(sa_share_t share, char *opt)
+{
+ char *newopt = NULL;
+ char *propstr;
+ sa_resource_t resource;
+
+ newopt = strdup(opt);
+ if (newopt == NULL)
+ return (newopt);
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ char *name;
+ size_t size;
+
+ name = sa_get_resource_attr(resource, "name");
+ if (name == NULL) {
+ free(newopt);
+ return (NULL);
+ }
+ size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
+ newopt = calloc(1, size);
+ if (newopt != NULL)
+ (void) snprintf(newopt, size, "%s,name=%s", opt, name);
+ free(opt);
+ opt = newopt;
+ propstr = sa_proto_legacy_format("smb", resource, 0);
+ if (propstr == NULL) {
+ free(opt);
+ return (NULL);
+ }
+ size = strlen(propstr) + strlen(opt) + 2;
+ newopt = calloc(1, size);
+ if (newopt != NULL)
+ (void) snprintf(newopt, size, "%s,%s", opt, propstr);
+ free(opt);
+ opt = newopt;
+ }
+ return (opt);
+}
+
+/*
+ * sa_zfs_set_sharesmb(group, path, on)
+ *
+ * Update the "sharesmb" property on the path. If on is true, then set
+ * to the properties on the group or "on" if no properties are
+ * defined. Set to "off" if on is false.
+ */
+
+int
+sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
+{
+ int ret = SA_NOT_IMPLEMENTED;
+ char *command;
+ sa_share_t share;
+
+ /* In case SMB not enabled */
+ if (sa_get_optionset(group, "smb") == NULL)
+ return (SA_NOT_SUPPORTED);
+
+ command = malloc(ZFS_MAXPROPLEN * 2);
+ if (command != NULL) {
+ char *opts = NULL;
+ char *dataset = NULL;
+ FILE *pfile;
+ sa_handle_impl_t impl_handle;
+
+ if (on) {
+ char *newopt;
+
+ share = sa_get_share(group, NULL);
+ opts = sa_proto_legacy_format("smb", share, 1);
+ if (opts != NULL && strlen(opts) == 0) {
+ free(opts);
+ opts = strdup("on");
+ }
+ newopt = add_resources(opts, share);
+ free(opts);
+ opts = newopt;
+ }
+
+ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ assert(impl_handle != NULL);
+ if (impl_handle != NULL)
+ dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
+ else
+ ret = SA_SYSTEM_ERR;
+
+ if (dataset != NULL) {
+ (void) snprintf(command, ZFS_MAXPROPLEN * 2,
+ "echo %s set sharesmb=\"%s\" %s", COMMAND,
+ opts != NULL ? opts : "off", dataset);
+ pfile = popen(command, "r");
+ if (pfile != NULL) {
+ ret = pclose(pfile);
+ if (ret != 0)
+ ret = SA_SYSTEM_ERR;
+ }
+ }
+ if (opts != NULL)
+ free(opts);
+ if (dataset != NULL)
+ free(dataset);
+ free(command);
+ }
+ return (ret);
+}
+
+/*
* sa_zfs_update(group)
*
* call back to ZFS to update the share if necessary.
@@ -986,7 +1200,7 @@ sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
int
sa_share_zfs(sa_share_t share, char *path, share_t *sh,
- void *exportdata, boolean_t on)
+ void *exportdata, zfs_share_op_t operation)
{
libzfs_handle_t *libhandle;
sa_group_t group;
@@ -1057,7 +1271,7 @@ sa_share_zfs(sa_share_t share, char *path, share_t *sh,
sh->sh_size += j;
SMAX(i, j);
err = zfs_deleg_share_nfs(libhandle, dataset, path,
- exportdata, sh, i, on);
+ exportdata, sh, i, operation);
libzfs_fini(libhandle);
}
free(dataset);