summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshare/common
diff options
context:
space:
mode:
authoramw <none@none>2007-10-25 16:34:29 -0700
committeramw <none@none>2007-10-25 16:34:29 -0700
commitda6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch)
tree65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/lib/libshare/common
parente845e33dd0d1aea22db7edaa8c7d43955d24609b (diff)
downloadillumos-gate-da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0.tar.gz
PSARC/2007/218 caller_context_t in all VOPs
PSARC/2007/227 VFS Feature Registration and ACL on Create PSARC/2007/244 ZFS Case-insensitive support PSARC/2007/315 Extensible Attribute Interfaces PSARC/2007/394 ls(1) new command line options '-/' and '-%': CIFS system attributes support PSARC/2007/403 Modified Access Checks for CIFS PSARC/2007/410 Add system attribute support to chmod(1) PSARC/2007/432 CIFS system attributes support for cp(1), pack(1), unpack(1), compress(1) and uncompress(1) PSARC/2007/444 Rescind SETTABLE Attribute PSARC/2007/459 CIFS system attributes support for cpio(1), pax(1), tar(1) PSARC/2007/546 Update utilities to match CIFS system attributes changes. PSARC/2007/560 ZFS sharesmb property 4890717 want append-only files 6417428 Case-insensitive file system name lookup to support CIFS 6417435 DOS attributes and additional timestamps to support for CIFS 6417442 File system quarantined and modified attributes to support an integrated Anti-Virus service 6417453 FS boolean property for rejecting/allowing invalid UTF-8 sequences in file names 6473733 RFE: Need support for open-deny modes 6473755 RFE: Need ability to reconcile oplock and delegation conflicts 6494624 sharemgr needs to support CIFS shares better 6546705 All vnode operations need to pass caller_context_t 6546706 Need VOP_SETATTR/VOP_GETATTR to support new, optional attributes 6546893 Solaris system attribute support 6550962 ZFS ACL inheritance needs to be enhanced to support Automatic Inheritance 6553589 RFE: VFS Feature Registration facility 6553770 RFE: ZFS support for ACL-on-CREATE (PSARC 2007/227) 6565581 ls(1) should support file system attributes proposed in PSARC/2007/315 6566784 NTFS streams are not copied along with the files. 6576205 cp(1), pack(1) and compress(1) should support file system attributes proposed in PSARC/2007/315 6578875 RFE: kernel interfaces for nbmand need improvement 6578883 RFE: VOP_SHRLOCK needs additional access types 6578885 chmod(1) should support file system attributes proposed in PSARC/2007/315 6578886 RFE: disallow nbmand state to change on remount 6583349 ACL parser needs to support audit/alarm ACE types 6590347 tar(1) should support filesystem attributes proposed in PSARC/2007/315 6597357 *tar* xv@ doesn't show the hidden directory even though it is restored 6597360 *tar* should re-init xattr info if openat() fails during extraction of and extended attribute 6597368 *tar* cannot restore hard linked extended attributes 6597374 *tar* doesn't display "x " when hard linked attributes are restored 6597375 *tar* extended attribute header off by one 6614861 *cpio* incorrectly archives extended system attributes with -@ 6614896 *pax* incorrectly archives extended system attributes with -@ 6615225 *tar* incorrectly archives extended system attributes with -@ 6617183 CIFS Service - PSARC 2006/715
Diffstat (limited to 'usr/src/lib/libshare/common')
-rw-r--r--usr/src/lib/libshare/common/libshare.c1194
-rw-r--r--usr/src/lib/libshare/common/libshare.h48
-rw-r--r--usr/src/lib/libshare/common/libshare_impl.h13
-rw-r--r--usr/src/lib/libshare/common/libshare_zfs.c388
-rw-r--r--usr/src/lib/libshare/common/libsharecore.c236
-rw-r--r--usr/src/lib/libshare/common/mapfile-vers19
-rw-r--r--usr/src/lib/libshare/common/plugin.c175
-rw-r--r--usr/src/lib/libshare/common/scfutil.c418
8 files changed, 2143 insertions, 348 deletions
diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c
index 25213e97a4..49104b2abe 100644
--- a/usr/src/lib/libshare/common/libshare.c
+++ b/usr/src/lib/libshare/common/libshare.c
@@ -58,6 +58,16 @@
#define SA_STRSIZE 256 /* max string size for names */
/*
+ * internal object type values returned by sa_get_object_type()
+ */
+#define SA_TYPE_UNKNOWN 0
+#define SA_TYPE_GROUP 1
+#define SA_TYPE_SHARE 2
+#define SA_TYPE_RESOURCE 3
+#define SA_TYPE_OPTIONSET 4
+#define SA_TYPE_ALTSPACE 5
+
+/*
* internal data structures
*/
@@ -69,16 +79,20 @@ extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
extern int sa_valid_property(void *, char *, sa_property_t);
extern char *sa_fstype(char *);
extern int sa_is_share(void *);
+extern int sa_is_resource(void *);
extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
extern int sa_group_is_zfs(sa_group_t);
extern int sa_path_is_zfs(char *);
extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
+extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
extern void update_legacy_config(sa_handle_t);
extern int issubdir(char *, char *);
extern int sa_zfs_init(sa_handle_impl_t);
extern void sa_zfs_fini(sa_handle_impl_t);
extern void sablocksigs(sigset_t *);
extern void saunblocksigs(sigset_t *);
+static sa_group_t sa_get_optionset_parent(sa_optionset_t);
+static char *get_node_attr(void *, char *);
/*
* Data structures for finding/managing the document root to access
@@ -188,6 +202,21 @@ sa_errorstr(int err)
case SA_NOT_SHARED:
ret = dgettext(TEXT_DOMAIN, "not shared");
break;
+ case SA_NO_SUCH_RESOURCE:
+ ret = dgettext(TEXT_DOMAIN, "no such resource");
+ break;
+ case SA_RESOURCE_REQUIRED:
+ ret = dgettext(TEXT_DOMAIN, "resource name required");
+ break;
+ case SA_MULTIPLE_ERROR:
+ ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
+ break;
+ case SA_PATH_IS_SUBDIR:
+ ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
+ break;
+ case SA_PATH_IS_PARENTDIR:
+ ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
+ break;
default:
(void) snprintf(errstr, sizeof (errstr),
dgettext(TEXT_DOMAIN, "unknown %d"), err);
@@ -376,6 +405,36 @@ is_shared(sa_share_t share)
}
/*
+ * excluded_protocol(share, proto)
+ *
+ * Returns B_TRUE if the specified protocol appears in the "exclude"
+ * property. This is used to prevent sharing special case shares
+ * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is
+ * returned if the protocol isn't in the list.
+ */
+static boolean_t
+excluded_protocol(sa_share_t share, char *proto)
+{
+ char *protolist;
+ char *str;
+ char *token;
+
+ protolist = sa_get_share_attr(share, "exclude");
+ if (protolist != NULL) {
+ str = protolist;
+ while ((token = strtok(str, ",")) != NULL) {
+ if (strcmp(token, proto) == 0) {
+ sa_free_attr_string(protolist);
+ return (B_TRUE);
+ }
+ str = NULL;
+ }
+ sa_free_attr_string(protolist);
+ }
+ return (B_FALSE);
+}
+
+/*
* checksubdirgroup(group, newpath, strictness)
*
* check all the specified newpath against all the paths in the
@@ -392,6 +451,11 @@ checksubdirgroup(sa_group_t group, char *newpath, int strictness)
sa_share_t share;
char *path;
int issub = SA_OK;
+ int subdir;
+ int parent;
+
+ if (newpath == NULL)
+ return (SA_INVALID_PATH);
for (share = sa_get_share(group, NULL); share != NULL;
share = sa_get_next_share(share)) {
@@ -417,13 +481,18 @@ checksubdirgroup(sa_group_t group, char *newpath, int strictness)
*/
if (path == NULL)
continue;
- if (newpath != NULL &&
- (strcmp(path, newpath) == 0 || issubdir(newpath, path) ||
- issubdir(path, newpath))) {
- sa_free_attr_string(path);
- path = NULL;
+
+ if (strcmp(path, newpath) == 0) {
issub = SA_INVALID_PATH;
- break;
+ } else {
+ subdir = issubdir(newpath, path);
+ parent = issubdir(path, newpath);
+ if (subdir || parent) {
+ sa_free_attr_string(path);
+ path = NULL;
+ return (subdir ?
+ SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR);
+ }
}
sa_free_attr_string(path);
path = NULL;
@@ -446,15 +515,16 @@ static int
checksubdir(sa_handle_t handle, char *newpath, int strictness)
{
sa_group_t group;
- int issub;
+ int issub = SA_OK;
char *path = NULL;
- for (issub = 0, group = sa_get_group(handle, NULL);
- group != NULL && !issub; group = sa_get_next_group(group)) {
+ for (group = sa_get_group(handle, NULL);
+ group != NULL && issub == SA_OK;
+ group = sa_get_next_group(group)) {
if (sa_group_is_zfs(group)) {
sa_group_t subgroup;
for (subgroup = sa_get_sub_group(group);
- subgroup != NULL && !issub;
+ subgroup != NULL && issub == SA_OK;
subgroup = sa_get_next_group(subgroup))
issub = checksubdirgroup(subgroup, newpath,
strictness);
@@ -517,14 +587,17 @@ validpath(sa_handle_t handle, char *path, int strictness)
/*
* check to see if group/share is persistent.
+ *
+ * "group" can be either an sa_group_t or an sa_share_t. (void *)
+ * works since both thse types are also void *.
*/
-static int
-is_persistent(sa_group_t group)
+int
+sa_is_persistent(void *group)
{
char *type;
int persist = 1;
- type = sa_get_group_attr(group, "type");
+ type = sa_get_group_attr((sa_group_t)group, "type");
if (type != NULL && strcmp(type, "transient") == 0)
persist = 0;
if (type != NULL)
@@ -590,6 +663,35 @@ is_zfs_group(sa_group_t group)
}
/*
+ * sa_get_object_type(object)
+ *
+ * This function returns a numeric value representing the object
+ * type. This allows using simpler checks when doing type specific
+ * operations.
+ */
+
+static int
+sa_get_object_type(void *object)
+{
+ xmlNodePtr node = (xmlNodePtr)object;
+ int type;
+
+ if (xmlStrcmp(node->name, (xmlChar *)"group") == 0)
+ type = SA_TYPE_GROUP;
+ else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0)
+ type = SA_TYPE_SHARE;
+ else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
+ type = SA_TYPE_RESOURCE;
+ else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0)
+ type = SA_TYPE_OPTIONSET;
+ else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0)
+ type = SA_TYPE_ALTSPACE;
+ else
+ assert(0);
+ return (type);
+}
+
+/*
* sa_optionset_name(optionset, oname, len, id)
* return the SMF name for the optionset. If id is not NULL, it
* will have the GUID value for a share and should be used
@@ -605,15 +707,34 @@ static int
sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id)
{
char *proto;
+ void *parent;
+ int ptype;
if (id == NULL)
id = "optionset";
- proto = sa_get_optionset_attr(optionset, "type");
- len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default");
+ parent = sa_get_optionset_parent(optionset);
+ if (parent != NULL) {
+ ptype = sa_get_object_type(parent);
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (ptype != SA_TYPE_RESOURCE) {
+ len = snprintf(oname, len, "%s_%s", id,
+ proto ? proto : "default");
+ } else {
+ char *index;
+ index = get_node_attr((void *)parent, "id");
+ if (index != NULL)
+ len = snprintf(oname, len, "%s_%s_%s", id,
+ proto ? proto : "default", index);
+ else
+ len = 0;
+ }
- if (proto != NULL)
- sa_free_attr_string(proto);
+ if (proto != NULL)
+ sa_free_attr_string(proto);
+ } else {
+ len = 0;
+ }
return (len);
}
@@ -660,6 +781,7 @@ verifydefgroupopts(sa_handle_t handle)
{
sa_group_t defgrp;
sa_optionset_t opt;
+
defgrp = sa_get_group(handle, "default");
if (defgrp != NULL) {
opt = sa_get_optionset(defgrp, NULL);
@@ -1187,7 +1309,7 @@ sa_find_share(sa_handle_t handle, char *sharepath)
/*
* sa_check_path(group, path, strictness)
*
- * check that path is a valid path relative to the group. Currently,
+ * Check that path is a valid path relative to the group. Currently,
* we are ignoring the group and checking only the NFS rules. Later,
* we may want to use the group to then check against the protocols
* enabled on the group. The strictness values mean:
@@ -1206,16 +1328,84 @@ sa_check_path(sa_group_t group, char *path, int strictness)
}
/*
- * _sa_add_share(group, sharepath, persist, *error)
+ * mark_excluded_protos(group, share, flags)
+ *
+ * Walk through all the protocols enabled for the group and check to
+ * see if the share has any of them should be in the exclude list
+ * based on the featureset of the protocol. If there are any, add the
+ * "exclude" property to the share.
+ */
+static void
+mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags)
+{
+ sa_optionset_t optionset;
+ char exclude_list[SA_STRSIZE];
+ char *sep = "";
+
+ exclude_list[0] = '\0';
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *value;
+ uint64_t features;
+ value = sa_get_optionset_attr(optionset, "type");
+ if (value == NULL)
+ continue;
+ features = sa_proto_get_featureset(value);
+ sa_free_attr_string(value);
+ if (!(features & flags)) {
+ (void) strlcat(exclude_list, sep,
+ sizeof (exclude_list));
+ (void) strlcat(exclude_list, value,
+ sizeof (exclude_list));
+ sep = ",";
+ }
+ }
+ if (exclude_list[0] != '\0')
+ xmlSetProp(share, (xmlChar *)"exclude",
+ (xmlChar *)exclude_list);
+}
+
+/*
+ * get_all_features(group)
*
- * common code for all types of add_share. sa_add_share() is the
+ * Walk through all the protocols on the group and collect all
+ * possible enabled features. This is the OR of all the featuresets.
+ */
+static uint64_t
+get_all_features(sa_group_t group)
+{
+ sa_optionset_t optionset;
+ uint64_t features = 0;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *value;
+ value = sa_get_optionset_attr(optionset, "type");
+ if (value == NULL)
+ continue;
+ features |= sa_proto_get_featureset(value);
+ sa_free_attr_string(value);
+ }
+ return (features);
+}
+
+
+/*
+ * _sa_add_share(group, sharepath, persist, *error, flags)
+ *
+ * Common code for all types of add_share. sa_add_share() is the
* public API, we also need to be able to do this when parsing legacy
* files and construction of the internal configuration while
- * extracting config info from SMF.
+ * extracting config info from SMF. "flags" indicates if some
+ * protocols need relaxed rules while other don't. These values are
+ * the featureset values defined in libshare.h.
*/
sa_share_t
-_sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
+_sa_add_share(sa_group_t group, char *sharepath, int persist, int *error,
+ uint64_t flags)
{
xmlNodePtr node = NULL;
int err;
@@ -1223,52 +1413,60 @@ _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
err = SA_OK; /* assume success */
node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL);
- if (node != NULL) {
- xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
- xmlSetProp(node, (xmlChar *)"type",
- persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
- if (persist != SA_SHARE_TRANSIENT) {
- /*
- * persistent shares come in two flavors: SMF and
- * ZFS. Sort this one out based on target group and
- * path type. Currently, only NFS is supported in the
- * ZFS group and it is always on.
- */
- if (sa_group_is_zfs(group) &&
- sa_path_is_zfs(sharepath)) {
+ if (node == NULL) {
+ if (error != NULL)
+ *error = SA_NO_MEMORY;
+ return (node);
+ }
+
+ xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
+ xmlSetProp(node, (xmlChar *)"type",
+ persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
+ if (flags != 0)
+ mark_excluded_protos(group, node, flags);
+ if (persist != SA_SHARE_TRANSIENT) {
+ /*
+ * persistent shares come in two flavors: SMF and
+ * ZFS. Sort this one out based on target group and
+ * path type. Both NFS and SMB are supported. First,
+ * check to see if the protocol is enabled on the
+ * subgroup and then setup the share appropriately.
+ */
+ if (sa_group_is_zfs(group) &&
+ sa_path_is_zfs(sharepath)) {
+ if (sa_get_optionset(group, "nfs") != NULL)
err = sa_zfs_set_sharenfs(group, sharepath, 1);
+ else if (sa_get_optionset(group, "smb") != NULL)
+ err = sa_zfs_set_sharesmb(group, sharepath, 1);
+ } else {
+ sa_handle_impl_t impl_handle;
+ impl_handle =
+ (sa_handle_impl_t)sa_find_group_handle(group);
+ if (impl_handle != NULL) {
+ err = sa_commit_share(impl_handle->scfhandle,
+ group, (sa_share_t)node);
} else {
- sa_handle_impl_t impl_handle;
- impl_handle =
- (sa_handle_impl_t)sa_find_group_handle(
- group);
- if (impl_handle != NULL) {
- err = sa_commit_share(
- impl_handle->scfhandle, group,
- (sa_share_t)node);
- } else {
- err = SA_SYSTEM_ERR;
- }
+ err = SA_SYSTEM_ERR;
}
}
- if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) {
- /* called by the dfstab parser so could be a show */
- err = SA_OK;
- }
- if (err != SA_OK) {
- /*
- * we couldn't commit to the repository so undo
- * our internal state to reflect reality.
- */
- xmlUnlinkNode(node);
- xmlFreeNode(node);
- node = NULL;
- }
- } else {
- err = SA_NO_MEMORY;
}
+ if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
+ /* called by the dfstab parser so could be a show */
+ err = SA_OK;
+
+ if (err != SA_OK) {
+ /*
+ * we couldn't commit to the repository so undo
+ * our internal state to reflect reality.
+ */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ node = NULL;
+ }
+
if (error != NULL)
*error = err;
+
return (node);
}
@@ -1285,9 +1483,10 @@ sa_share_t
sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
{
xmlNodePtr node = NULL;
- sa_share_t dup;
int strictness = SA_CHECK_NORMAL;
sa_handle_t handle;
+ uint64_t special = 0;
+ uint64_t features;
/*
* If the share is to be permanent, use strict checking so a
@@ -1304,12 +1503,33 @@ sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
handle = sa_find_group_handle(group);
- if ((dup = sa_find_share(handle, sharepath)) == NULL &&
- (*error = sa_check_path(group, sharepath, strictness)) == SA_OK) {
- node = _sa_add_share(group, sharepath, persist, error);
- }
- if (dup != NULL)
+ /*
+ * need to determine if the share is valid. The rules are:
+ * - The path must not already exist
+ * - The path must not be a subdir or parent dir of an
+ * existing path unless at least one protocol allows it.
+ * The sub/parent check is done in sa_check_path().
+ */
+
+ if (sa_find_share(handle, sharepath) == NULL) {
+ *error = sa_check_path(group, sharepath, strictness);
+ features = get_all_features(group);
+ switch (*error) {
+ case SA_PATH_IS_SUBDIR:
+ if (features & SA_FEATURE_ALLOWSUBDIRS)
+ special |= SA_FEATURE_ALLOWSUBDIRS;
+ break;
+ case SA_PATH_IS_PARENTDIR:
+ if (features & SA_FEATURE_ALLOWPARDIRS)
+ special |= SA_FEATURE_ALLOWPARDIRS;
+ break;
+ }
+ if (*error == SA_OK || special != SA_FEATURE_NONE)
+ node = _sa_add_share(group, sharepath, persist,
+ error, special);
+ } else {
*error = SA_DUPLICATE_NAME;
+ }
return ((sa_share_t)node);
}
@@ -1324,28 +1544,52 @@ sa_enable_share(sa_share_t share, char *protocol)
{
char *sharepath;
struct stat st;
- int err = 0;
+ int err = SA_OK;
+ int ret;
sharepath = sa_get_share_attr(share, "path");
+ if (sharepath == NULL)
+ return (SA_NO_MEMORY);
if (stat(sharepath, &st) < 0) {
err = SA_NO_SUCH_PATH;
} else {
/* tell the server about the share */
if (protocol != NULL) {
+ if (excluded_protocol(share, protocol))
+ goto done;
+
/* lookup protocol specific handler */
err = sa_proto_share(protocol, share);
if (err == SA_OK)
- (void) sa_set_share_attr(share, "shared",
- "true");
+ (void) sa_set_share_attr(share,
+ "shared", "true");
} else {
- /*
- * Tell all protocols. Only NFS for now but
- * SMB is coming.
- */
- err = sa_proto_share("nfs", share);
+ /* Tell all protocols about the share */
+ sa_group_t group;
+ sa_optionset_t optionset;
+
+ group = sa_get_parent_group(share);
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+ proto = sa_get_optionset_attr(optionset,
+ "type");
+ if (proto != NULL) {
+ if (!excluded_protocol(share, proto)) {
+ ret = sa_proto_share(proto,
+ share);
+ if (ret != SA_OK)
+ err = ret;
+ }
+ sa_free_attr_string(proto);
+ }
+ }
(void) sa_set_share_attr(share, "shared", "true");
}
}
+done:
if (sharepath != NULL)
sa_free_attr_string(sharepath);
return (err);
@@ -1353,31 +1597,47 @@ sa_enable_share(sa_share_t share, char *protocol)
/*
* sa_disable_share(share, protocol)
- * Disable the specified share to the specified protocol.
- * If protocol is NULL, then all protocols.
+ * Disable the specified share to the specified protocol. If
+ * protocol is NULL, then all protocols that are enabled for the
+ * share should be disabled.
*/
int
sa_disable_share(sa_share_t share, char *protocol)
{
char *path;
- char *shared;
+ int err = SA_OK;
int ret = SA_OK;
path = sa_get_share_attr(share, "path");
- shared = sa_get_share_attr(share, "shared");
if (protocol != NULL) {
ret = sa_proto_unshare(share, protocol, path);
} else {
/* need to do all protocols */
- ret = sa_proto_unshare(share, "nfs", path);
+ sa_group_t group;
+ sa_optionset_t optionset;
+
+ group = sa_get_parent_group(share);
+
+ /* Tell all protocols about the share */
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *proto;
+
+ proto = sa_get_optionset_attr(optionset, "type");
+ if (proto != NULL) {
+ err = sa_proto_unshare(share, proto, path);
+ if (err != SA_OK)
+ ret = err;
+ sa_free_attr_string(proto);
+ }
+ }
}
if (ret == SA_OK)
(void) sa_set_share_attr(share, "shared", NULL);
if (path != NULL)
sa_free_attr_string(path);
- if (shared != NULL)
- sa_free_attr_string(shared);
return (ret);
}
@@ -1415,7 +1675,7 @@ sa_remove_share(sa_share_t share)
/* only do SMF action if permanent */
if (!transient || zfs != NULL) {
/* remove from legacy dfstab as well as possible SMF */
- ret = sa_delete_legacy(share);
+ ret = sa_delete_legacy(share, NULL);
if (ret == SA_OK) {
if (!sa_group_is_zfs(group)) {
sa_handle_impl_t impl_handle;
@@ -1497,7 +1757,7 @@ sa_move_share(sa_group_t group, sa_share_t share)
/*
* sa_get_parent_group(share)
*
- * Return the containg group for the share. If a group was actually
+ * Return the containing group for the share. If a group was actually
* passed in, we don't want a parent so return NULL.
*/
@@ -1728,7 +1988,7 @@ sa_update_config(sa_handle_t handle)
/*
* get_node_attr(node, tag)
*
- * Get the speficied tag(attribute) if it exists on the node. This is
+ * Get the specified tag(attribute) if it exists on the node. This is
* used internally by a number of attribute oriented functions.
*/
@@ -1746,7 +2006,7 @@ get_node_attr(void *nodehdl, char *tag)
/*
* get_node_attr(node, tag)
*
- * Set the speficied tag(attribute) to the specified value This is
+ * Set the specified tag(attribute) to the specified value This is
* used internally by a number of attribute oriented functions. It
* doesn't update the repository, only the internal document state.
*/
@@ -1792,6 +2052,14 @@ sa_set_group_attr(sa_group_t group, char *tag, char *value)
char *groupname;
sa_handle_impl_t impl_handle;
+ /*
+ * ZFS group/subgroup doesn't need the handle so shortcut.
+ */
+ if (sa_group_is_zfs(group)) {
+ set_node_attr((void *)group, tag, value);
+ return (SA_OK);
+ }
+
impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
if (impl_handle != NULL) {
groupname = sa_get_group_attr(group, "name");
@@ -1833,47 +2101,15 @@ sa_get_share_attr(sa_share_t share, char *tag)
}
/*
- * sa_get_resource(group, resource)
- *
- * Search all the shares in the speified group for a share with a
- * resource name matching the one specified.
- *
- * In the future, it may be advantageous to allow group to be NULL and
- * search all groups but that isn't needed at present.
- */
-
-sa_share_t
-sa_get_resource(sa_group_t group, char *resource)
-{
- sa_share_t share = NULL;
- char *name = NULL;
-
- if (resource != NULL) {
- for (share = sa_get_share(group, NULL); share != NULL;
- share = sa_get_next_share(share)) {
- name = sa_get_share_attr(share, "resource");
- if (name != NULL) {
- if (strcmp(name, resource) == 0)
- break;
- sa_free_attr_string(name);
- name = NULL;
- }
- }
- if (name != NULL)
- sa_free_attr_string(name);
- }
- return ((sa_share_t)share);
-}
-
-/*
* _sa_set_share_description(share, description)
*
- * Add a description tag with text contents to the specified share.
- * A separate XML tag is used rather than a property.
+ * Add a description tag with text contents to the specified share. A
+ * separate XML tag is used rather than a property. This can also be
+ * used with resources.
*/
xmlNodePtr
-_sa_set_share_description(sa_share_t share, char *content)
+_sa_set_share_description(void *share, char *content)
{
xmlNodePtr node;
node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description",
@@ -2205,7 +2441,6 @@ sa_set_share_description(sa_share_t share, char *content)
break;
}
}
- group = sa_get_parent_group(share);
/* no existing description but want to add */
if (node == NULL && content != NULL) {
/* add a description */
@@ -2218,7 +2453,8 @@ sa_set_share_description(sa_share_t share, char *content)
xmlUnlinkNode(node);
xmlFreeNode(node);
}
- if (group != NULL && is_persistent((sa_group_t)share)) {
+ group = sa_get_parent_group(share);
+ if (group != NULL && sa_is_persistent(share)) {
sa_handle_impl_t impl_handle;
impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
if (impl_handle != NULL) {
@@ -2269,7 +2505,7 @@ sa_get_share_description(sa_share_t share)
}
}
if (node != NULL) {
- description = xmlNodeGetContent((xmlNodePtr)share);
+ description = xmlNodeGetContent(node);
fixproblemchars((char *)description);
}
return ((char *)description);
@@ -2299,12 +2535,44 @@ sa_create_optionset(sa_group_t group, char *proto)
{
sa_optionset_t optionset;
sa_group_t parent = group;
+ sa_share_t share = NULL;
+ int err = SA_OK;
+ char *id = NULL;
optionset = sa_get_optionset(group, proto);
if (optionset != NULL) {
/* can't have a duplicate protocol */
optionset = NULL;
} else {
+ /*
+ * Account for resource names being slightly
+ * different.
+ */
+ if (sa_is_share(group)) {
+ /*
+ * Transient shares do not have an "id" so not an
+ * error to not find one.
+ */
+ id = sa_get_share_attr((sa_share_t)group, "id");
+ } else if (sa_is_resource(group)) {
+ share = sa_get_resource_parent(
+ (sa_resource_t)group);
+ id = sa_get_resource_attr(share, "id");
+
+ /* id can be NULL if the group is transient (ZFS) */
+ if (id == NULL && sa_is_persistent(group))
+ err = SA_NO_MEMORY;
+ }
+ if (err == SA_NO_MEMORY) {
+ /*
+ * Couldn't get the id for the share or
+ * resource. While this could be a
+ * configuration issue, it is most likely an
+ * out of memory. In any case, fail the create.
+ */
+ return (NULL);
+ }
+
optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group,
NULL, (xmlChar *)"optionset", NULL);
/*
@@ -2314,38 +2582,44 @@ sa_create_optionset(sa_group_t group, char *proto)
if (optionset != NULL) {
char oname[SA_STRSIZE];
char *groupname;
- char *id = NULL;
- if (sa_is_share(group))
+ /*
+ * Need to get parent group in all cases, but also get
+ * the share if this is a resource.
+ */
+ if (sa_is_share(group)) {
parent = sa_get_parent_group((sa_share_t)group);
+ } else if (sa_is_resource(group)) {
+ share = sa_get_resource_parent(
+ (sa_resource_t)group);
+ parent = sa_get_parent_group(share);
+ }
sa_set_optionset_attr(optionset, "type", proto);
- if (sa_is_share(group)) {
- id = sa_get_share_attr((sa_share_t)group, "id");
- }
(void) sa_optionset_name(optionset, oname,
sizeof (oname), id);
groupname = sa_get_group_attr(parent, "name");
- if (groupname != NULL && is_persistent(group)) {
+ if (groupname != NULL && sa_is_persistent(group)) {
sa_handle_impl_t impl_handle;
- impl_handle = (sa_handle_impl_t)
- sa_find_group_handle(group);
+ impl_handle =
+ (sa_handle_impl_t)sa_find_group_handle(
+ group);
assert(impl_handle != NULL);
if (impl_handle != NULL) {
(void) sa_get_instance(
- impl_handle->scfhandle,
- groupname);
+ impl_handle->scfhandle, groupname);
(void) sa_create_pgroup(
impl_handle->scfhandle, oname);
}
}
if (groupname != NULL)
sa_free_attr_string(groupname);
- if (id != NULL)
- sa_free_attr_string(id);
}
}
+
+ if (id != NULL)
+ sa_free_attr_string(id);
return (optionset);
}
@@ -2388,7 +2662,7 @@ sa_get_optionset_parent(sa_optionset_t optionset)
*
* In order to avoid making multiple updates to a ZFS share when
* setting properties, the share attribute "changed" will be set to
- * true when a property is added or modifed. When done adding
+ * true when a property is added or modified. When done adding
* properties, we can then detect that an update is needed. We then
* clear the state here to detect additional changes.
*/
@@ -2470,7 +2744,7 @@ sa_commit_properties(sa_optionset_t optionset, int clear)
/*
* sa_destroy_optionset(optionset)
*
- * Remove the optionset from its group. Update the repostory to
+ * Remove the optionset from its group. Update the repository to
* reflect this change.
*/
@@ -2486,9 +2760,16 @@ sa_destroy_optionset(sa_optionset_t optionset)
/* now delete the prop group */
group = sa_get_optionset_parent(optionset);
- if (group != NULL && sa_is_share(group)) {
- ispersist = is_persistent(group);
- id = sa_get_share_attr((sa_share_t)group, "id");
+ if (group != NULL) {
+ if (sa_is_resource(group)) {
+ sa_resource_t resource = group;
+ sa_share_t share = sa_get_resource_parent(resource);
+ group = sa_get_parent_group(share);
+ id = sa_get_share_attr(share, "id");
+ } else if (sa_is_share(group)) {
+ id = sa_get_share_attr((sa_share_t)group, "id");
+ }
+ ispersist = sa_is_persistent(group);
}
if (ispersist) {
sa_handle_impl_t impl_handle;
@@ -2559,7 +2840,7 @@ sa_create_security(sa_group_t group, char *sectype, char *proto)
sa_set_security_attr(security, "sectype", sectype);
(void) sa_security_name(security, oname,
sizeof (oname), id);
- if (groupname != NULL && is_persistent(group)) {
+ if (groupname != NULL && sa_is_persistent(group)) {
sa_handle_impl_t impl_handle;
impl_handle =
(sa_handle_impl_t)sa_find_group_handle(
@@ -2603,7 +2884,7 @@ sa_destroy_security(sa_security_t security)
if (group != NULL && !iszfs) {
if (sa_is_share(group))
- ispersist = is_persistent(group);
+ ispersist = sa_is_persistent(group);
id = sa_get_share_attr((sa_share_t)group, "id");
}
if (ispersist) {
@@ -2666,7 +2947,6 @@ is_nodetype(void *node, char *type)
return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0);
}
-
/*
* add_or_update()
*
@@ -2721,12 +3001,12 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
int opttype; /* 1 == optionset, 0 == security */
char *id = NULL;
int iszfs = 0;
- int isshare = 0;
sa_group_t parent = NULL;
+ sa_share_t share = NULL;
sa_handle_impl_t impl_handle;
scfutilhandle_t *scf_handle;
- if (!is_persistent(group)) {
+ if (!sa_is_persistent(group)) {
/*
* if the group/share is not persistent we don't need
* to do anything here
@@ -2742,12 +3022,20 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
entry = scf_entry_create(scf_handle->handle);
opttype = is_nodetype((void *)optionset, "optionset");
+ /*
+ * Check for share vs. resource since they need slightly
+ * different treatment given the hierarchy.
+ */
if (valstr != NULL && entry != NULL) {
if (sa_is_share(group)) {
- isshare = 1;
parent = sa_get_parent_group(group);
+ share = (sa_share_t)group;
if (parent != NULL)
iszfs = is_zfs_group(parent);
+ } else if (sa_is_resource(group)) {
+ share = sa_get_parent_group(group);
+ if (share != NULL)
+ parent = sa_get_parent_group(share);
} else {
iszfs = is_zfs_group(group);
}
@@ -2755,15 +3043,13 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
if (scf_handle->trans == NULL) {
char oname[SA_STRSIZE];
char *groupname = NULL;
- if (isshare) {
- if (parent != NULL) {
+ if (share != NULL) {
+ if (parent != NULL)
groupname =
sa_get_group_attr(parent,
"name");
- }
- id =
- sa_get_share_attr((sa_share_t)group,
- "id");
+ id = sa_get_share_attr(
+ (sa_share_t)share, "id");
} else {
groupname = sa_get_group_attr(group,
"name");
@@ -2870,14 +3156,22 @@ sa_add_property(void *object, sa_property_t property)
sa_free_attr_string(proto);
parent = sa_get_parent_group(object);
- if (!is_persistent(parent)) {
+ if (!sa_is_persistent(parent))
return (ret);
- }
- if (sa_is_share(parent))
+ if (sa_is_resource(parent)) {
+ /*
+ * Resources are children of share. Need to go up two
+ * levels to find the group but the parent needs to be
+ * the share at this point in order to get the "id".
+ */
+ parent = sa_get_parent_group(parent);
group = sa_get_parent_group(parent);
- else
+ } else if (sa_is_share(parent)) {
+ group = sa_get_parent_group(parent);
+ } else {
group = parent;
+ }
if (property == NULL) {
ret = SA_NO_MEMORY;
@@ -3110,7 +3404,7 @@ sa_set_protocol_property(sa_property_t prop, char *value)
/*
* sa_add_protocol_property(propset, prop)
*
- * Add a new property to the protocol sepcific property set.
+ * Add a new property to the protocol specific property set.
*/
int
@@ -3128,7 +3422,7 @@ sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop)
/*
* sa_create_protocol_properties(proto)
*
- * Create a protocol specifity property set.
+ * Create a protocol specific property set.
*/
sa_protocol_properties_t
@@ -3141,3 +3435,583 @@ sa_create_protocol_properties(char *proto)
xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
return (node);
}
+
+/*
+ * sa_get_share_resource(share, resource)
+ *
+ * Get the named resource from the share, if it exists. If resource is
+ * NULL, get the first resource.
+ */
+
+sa_resource_t
+sa_get_share_resource(sa_share_t share, char *resource)
+{
+ xmlNodePtr node = NULL;
+ xmlChar *name;
+
+ if (share != NULL) {
+ for (node = ((xmlNodePtr)share)->children; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) {
+ if (resource == NULL) {
+ /*
+ * We are looking for the first
+ * resource node and not a names
+ * resource.
+ */
+ break;
+ } else {
+ /* is it the correct share? */
+ name = xmlGetProp(node,
+ (xmlChar *)"name");
+ if (name != NULL &&
+ xmlStrcasecmp(name,
+ (xmlChar *)resource) == 0) {
+ xmlFree(name);
+ break;
+ }
+ xmlFree(name);
+ }
+ }
+ }
+ }
+ return ((sa_resource_t)node);
+}
+
+/*
+ * sa_get_next_resource(resource)
+ * Return the next share following the specified share
+ * from the internal list of shares. Returns NULL if there
+ * are no more shares. The list is relative to the same
+ * group.
+ */
+sa_share_t
+sa_get_next_resource(sa_resource_t resource)
+{
+ xmlNodePtr node = NULL;
+
+ if (resource != NULL) {
+ for (node = ((xmlNodePtr)resource)->next; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
+ break;
+ }
+ }
+ return ((sa_share_t)node);
+}
+
+/*
+ * _sa_get_next_resource_index(share)
+ *
+ * get the next resource index number (one greater then current largest)
+ */
+
+static int
+_sa_get_next_resource_index(sa_share_t share)
+{
+ sa_resource_t resource;
+ int index = 0;
+ char *id;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ id = get_node_attr((void *)resource, "id");
+ if (id != NULL) {
+ int val;
+ val = atoi(id);
+ if (val > index)
+ index = val;
+ sa_free_attr_string(id);
+ }
+ }
+ return (index + 1);
+}
+
+
+/*
+ * sa_add_resource(share, resource, persist, &err)
+ *
+ * Adds a new resource name associated with share. The resource name
+ * must be unique in the system and will be case insensitive (eventually).
+ */
+
+sa_resource_t
+sa_add_resource(sa_share_t share, char *resource, int persist, int *error)
+{
+ xmlNodePtr node;
+ int err = SA_OK;
+ sa_resource_t res;
+ sa_group_t group;
+ sa_handle_t handle;
+ char istring[8]; /* just big enough for an integer value */
+ int index;
+
+ group = sa_get_parent_group(share);
+ handle = sa_find_group_handle(group);
+ res = sa_find_resource(handle, resource);
+ if (res != NULL) {
+ err = SA_DUPLICATE_NAME;
+ res = NULL;
+ } else {
+ node = xmlNewChild((xmlNodePtr)share, NULL,
+ (xmlChar *)"resource", NULL);
+ if (node != NULL) {
+ xmlSetProp(node, (xmlChar *)"name",
+ (xmlChar *)resource);
+ xmlSetProp(node, (xmlChar *)"type", persist ?
+ (xmlChar *)"persist" : (xmlChar *)"transient");
+ if (persist != SA_SHARE_TRANSIENT) {
+ index = _sa_get_next_resource_index(share);
+ (void) snprintf(istring, sizeof (istring), "%d",
+ index);
+ xmlSetProp(node, (xmlChar *)"id",
+ (xmlChar *)istring);
+ if (!sa_group_is_zfs(group) &&
+ sa_is_persistent((sa_group_t)share)) {
+ /* ZFS doesn't use resource names */
+ sa_handle_impl_t ihandle;
+ ihandle = (sa_handle_impl_t)
+ sa_find_group_handle(
+ group);
+ if (ihandle != NULL)
+ err = sa_commit_share(
+ ihandle->scfhandle, group,
+ share);
+ else
+ err = SA_SYSTEM_ERR;
+ }
+ }
+ }
+ }
+ if (error != NULL)
+ *error = err;
+ return ((sa_resource_t)node);
+}
+
+/*
+ * sa_remove_resource(resource)
+ *
+ * Remove the resource name from the share (and the system)
+ */
+
+int
+sa_remove_resource(sa_resource_t resource)
+{
+ sa_share_t share;
+ sa_group_t group;
+ char *type;
+ int ret = SA_OK;
+ int transient = 0;
+
+ share = sa_get_resource_parent(resource);
+ type = sa_get_share_attr(share, "type");
+ group = sa_get_parent_group(share);
+
+
+ if (type != NULL) {
+ if (strcmp(type, "persist") != 0)
+ transient = 1;
+ sa_free_attr_string(type);
+ }
+
+ /* Remove from the share */
+ xmlUnlinkNode((xmlNode *)resource);
+ xmlFreeNode((xmlNode *)resource);
+
+ /* only do SMF action if permanent and not ZFS */
+ if (!transient && !sa_group_is_zfs(group)) {
+ sa_handle_impl_t ihandle;
+ ihandle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (ihandle != NULL)
+ ret = sa_commit_share(ihandle->scfhandle, group, share);
+ else
+ ret = SA_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * proto_resource_rename(handle, group, resource, newname)
+ *
+ * Helper function for sa_rename_resource that notifies the protocol
+ * of a resource name change prior to a config repository update.
+ */
+static int
+proto_rename_resource(sa_handle_t handle, sa_group_t group,
+ sa_resource_t resource, char *newname)
+{
+ sa_optionset_t optionset;
+ int ret = SA_OK;
+ int err;
+
+ for (optionset = sa_get_optionset(group, NULL);
+ optionset != NULL;
+ optionset = sa_get_next_optionset(optionset)) {
+ char *type;
+ type = sa_get_optionset_attr(optionset, "type");
+ if (type != NULL) {
+ err = sa_proto_rename_resource(handle, type, resource,
+ newname);
+ if (err != SA_OK)
+ ret = err;
+ sa_free_attr_string(type);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_rename_resource(resource, newname)
+ *
+ * Rename the resource to the new name, if it is unique.
+ */
+
+int
+sa_rename_resource(sa_resource_t resource, char *newname)
+{
+ sa_share_t share;
+ sa_group_t group = NULL;
+ sa_resource_t target;
+ int ret = SA_CONFIG_ERR;
+ sa_handle_t handle = NULL;
+
+ share = sa_get_resource_parent(resource);
+ if (share == NULL)
+ return (ret);
+
+ group = sa_get_parent_group(share);
+ if (group == NULL)
+ return (ret);
+
+ handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (handle == NULL)
+ return (ret);
+
+ target = sa_find_resource(handle, newname);
+ if (target != NULL) {
+ ret = SA_DUPLICATE_NAME;
+ } else {
+ /*
+ * Everything appears to be valid at this
+ * point. Change the name of the active share and then
+ * update the share in the appropriate repository.
+ */
+ ret = proto_rename_resource(handle, group, resource, newname);
+ set_node_attr(resource, "name", newname);
+ if (!sa_group_is_zfs(group) &&
+ sa_is_persistent((sa_group_t)share)) {
+ sa_handle_impl_t ihandle = (sa_handle_impl_t)handle;
+ ret = sa_commit_share(ihandle->scfhandle, group,
+ share);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_get_resource_attr(resource, tag)
+ *
+ * Get the named attribute of the resource. "name" and "id" are
+ * currently defined. NULL if tag not defined.
+ */
+
+char *
+sa_get_resource_attr(sa_resource_t resource, char *tag)
+{
+ return (get_node_attr((void *)resource, tag));
+}
+
+/*
+ * sa_set_resource_attr(resource, tag, value)
+ *
+ * Get the named attribute of the resource. "name" and "id" are
+ * currently defined. NULL if tag not defined. Currently we don't do
+ * much, but additional checking may be needed in the future.
+ */
+
+int
+sa_set_resource_attr(sa_resource_t resource, char *tag, char *value)
+{
+ set_node_attr((void *)resource, tag, value);
+ return (SA_OK);
+}
+
+/*
+ * sa_get_resource_parent(resource_t)
+ *
+ * Returns the share associated with the resource.
+ */
+
+sa_share_t
+sa_get_resource_parent(sa_resource_t resource)
+{
+ sa_share_t share = NULL;
+
+ if (resource != NULL)
+ share = (sa_share_t)((xmlNodePtr)resource)->parent;
+ return (share);
+}
+
+/*
+ * find_resource(group, name)
+ *
+ * Find the resource within the group.
+ */
+
+static sa_resource_t
+find_resource(sa_group_t group, char *resname)
+{
+ sa_share_t share;
+ sa_resource_t resource = NULL;
+ char *name;
+
+ /* Iterate over all the shares and resources in the group. */
+ for (share = sa_get_share(group, NULL);
+ share != NULL && resource == NULL;
+ share = sa_get_next_share(share)) {
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ name = sa_get_resource_attr(resource, "name");
+ if (name != NULL && xmlStrcasecmp((xmlChar*)name,
+ (xmlChar*)resname) == 0) {
+ sa_free_attr_string(name);
+ break;
+ }
+ if (name != NULL) {
+ sa_free_attr_string(name);
+ }
+ }
+ }
+ return (resource);
+}
+
+/*
+ * sa_find_resource(name)
+ *
+ * Find the named resource in the system.
+ */
+
+sa_resource_t
+sa_find_resource(sa_handle_t handle, char *name)
+{
+ sa_group_t group;
+ sa_group_t zgroup;
+ sa_resource_t resource = NULL;
+
+ /*
+ * Iterate over all groups and zfs subgroups and check for
+ * resource name in them.
+ */
+ for (group = sa_get_group(handle, NULL); group != NULL;
+ group = sa_get_next_group(group)) {
+
+ if (is_zfs_group(group)) {
+ for (zgroup =
+ (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
+ (xmlChar *)"group");
+ zgroup != NULL && resource == NULL;
+ zgroup = sa_get_next_group(zgroup)) {
+ resource = find_resource(zgroup, name);
+ }
+ } else {
+ resource = find_resource(group, name);
+ }
+ if (resource != NULL)
+ break;
+ }
+ return (resource);
+}
+
+/*
+ * sa_get_resource(group, resource)
+ *
+ * Search all the shares in the specified group for a share with a
+ * resource name matching the one specified.
+ *
+ * In the future, it may be advantageous to allow group to be NULL and
+ * search all groups but that isn't needed at present.
+ */
+
+sa_resource_t
+sa_get_resource(sa_group_t group, char *resource)
+{
+ sa_share_t share = NULL;
+ sa_resource_t res = NULL;
+
+ if (resource != NULL) {
+ for (share = sa_get_share(group, NULL);
+ share != NULL && res == NULL;
+ share = sa_get_next_share(share)) {
+ res = sa_get_share_resource(share, resource);
+ }
+ }
+ return (res);
+}
+
+/*
+ * sa_enable_resource, protocol)
+ * Disable the specified share to the specified protocol.
+ * If protocol is NULL, then all protocols.
+ */
+int
+sa_enable_resource(sa_resource_t resource, char *protocol)
+{
+ int ret = SA_OK;
+ char **protocols;
+ int numproto;
+
+ if (protocol != NULL) {
+ ret = sa_proto_share_resource(protocol, resource);
+ } else {
+ /* need to do all protocols */
+ if ((numproto = sa_get_protocols(&protocols)) >= 0) {
+ int i, err;
+ for (i = 0; i < numproto; i++) {
+ err = sa_proto_share_resource(
+ protocols[i], resource);
+ if (err != SA_OK)
+ ret = err;
+ }
+ free(protocols);
+ }
+ }
+ if (ret == SA_OK)
+ (void) sa_set_resource_attr(resource, "shared", NULL);
+
+ return (ret);
+}
+
+/*
+ * sa_disable_resource(resource, protocol)
+ *
+ * Disable the specified share for the specified protocol. If
+ * protocol is NULL, then all protocols. If the underlying
+ * protocol doesn't implement disable at the resource level, we
+ * disable at the share level.
+ */
+int
+sa_disable_resource(sa_resource_t resource, char *protocol)
+{
+ int ret = SA_OK;
+ char **protocols;
+ int numproto;
+
+ if (protocol != NULL) {
+ ret = sa_proto_unshare_resource(protocol, resource);
+ if (ret == SA_NOT_IMPLEMENTED) {
+ sa_share_t parent;
+ /*
+ * The protocol doesn't implement unshare
+ * resource. That implies that resource names are
+ * simple aliases for this protocol so we need to
+ * unshare the share.
+ */
+ parent = sa_get_resource_parent(resource);
+ if (parent != NULL)
+ ret = sa_disable_share(parent, protocol);
+ else
+ ret = SA_CONFIG_ERR;
+ }
+ } else {
+ /* need to do all protocols */
+ if ((numproto = sa_get_protocols(&protocols)) >= 0) {
+ int i, err;
+ for (i = 0; i < numproto; i++) {
+ err = sa_proto_unshare_resource(protocols[i],
+ resource);
+ if (err == SA_NOT_SUPPORTED) {
+ sa_share_t parent;
+ parent = sa_get_resource_parent(
+ resource);
+ if (parent != NULL)
+ err = sa_disable_share(parent,
+ protocols[i]);
+ else
+ err = SA_CONFIG_ERR;
+ }
+ if (err != SA_OK)
+ ret = err;
+ }
+ free(protocols);
+ }
+ }
+ if (ret == SA_OK)
+ (void) sa_set_resource_attr(resource, "shared", NULL);
+
+ return (ret);
+}
+
+/*
+ * sa_set_resource_description(resource, content)
+ *
+ * Set the description of share to content.
+ */
+
+int
+sa_set_resource_description(sa_resource_t resource, char *content)
+{
+ xmlNodePtr node;
+ sa_group_t group;
+ sa_share_t share;
+ int ret = SA_OK;
+
+ for (node = ((xmlNodePtr)resource)->children;
+ node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
+ break;
+ }
+ }
+
+ /* no existing description but want to add */
+ if (node == NULL && content != NULL) {
+ /* add a description */
+ node = _sa_set_share_description(resource, content);
+ } else if (node != NULL && content != NULL) {
+ /* update a description */
+ xmlNodeSetContent(node, (xmlChar *)content);
+ } else if (node != NULL && content == NULL) {
+ /* remove an existing description */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ }
+ share = sa_get_resource_parent(resource);
+ group = sa_get_parent_group(share);
+ if (group != NULL && sa_is_persistent(share)) {
+ sa_handle_impl_t impl_handle;
+ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+ if (impl_handle != NULL)
+ ret = sa_commit_share(impl_handle->scfhandle,
+ group, share);
+ else
+ ret = SA_SYSTEM_ERR;
+ }
+ return (ret);
+}
+
+/*
+ * sa_get_resource_description(share)
+ *
+ * Return the description text for the specified share if it
+ * exists. NULL if no description exists.
+ */
+
+char *
+sa_get_resource_description(sa_resource_t resource)
+{
+ xmlChar *description = NULL;
+ xmlNodePtr node;
+
+ for (node = ((xmlNodePtr)resource)->children; node != NULL;
+ node = node->next) {
+ if (xmlStrcmp(node->name, (xmlChar *)"description") == 0)
+ break;
+ }
+ if (node != NULL) {
+ description = xmlNodeGetContent(node);
+ fixproblemchars((char *)description);
+ }
+ return ((char *)description);
+}
diff --git a/usr/src/lib/libshare/common/libshare.h b/usr/src/lib/libshare/common/libshare.h
index c78b0822c6..bdac6a6d64 100644
--- a/usr/src/lib/libshare/common/libshare.h
+++ b/usr/src/lib/libshare/common/libshare.h
@@ -37,6 +37,8 @@
extern "C" {
#endif
+#include <sys/types.h>
+
/*
* Basic datatypes for most functions
*/
@@ -46,6 +48,7 @@ typedef void *sa_property_t;
typedef void *sa_optionset_t;
typedef void *sa_security_t;
typedef void *sa_protocol_properties_t;
+typedef void *sa_resource_t;
typedef void *sa_handle_t; /* opaque handle to access core functions */
@@ -77,6 +80,11 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
#define SA_NOT_SUPPORTED 21 /* operation not supported for proto */
#define SA_PROP_SHARE_ONLY 22 /* property valid on share only */
#define SA_NOT_SHARED 23 /* path is not shared */
+#define SA_NO_SUCH_RESOURCE 24 /* resource not found */
+#define SA_RESOURCE_REQUIRED 25 /* resource name is required */
+#define SA_MULTIPLE_ERROR 26 /* multiple protocols reported error */
+#define SA_PATH_IS_SUBDIR 27 /* check_path found path is subdir */
+#define SA_PATH_IS_PARENTDIR 28 /* check_path found path is parent */
/* API Initialization */
#define SA_INIT_SHARE_API 0x0001 /* init share specific interface */
@@ -90,8 +98,9 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
*/
#define SA_MAX_NAME_LEN 100 /* must fit service instance name */
+#define SA_MAX_RESOURCE_NAME 255 /* Maximum length of resource name */
-/* Used in calls to sa_add_share() */
+/* Used in calls to sa_add_share() and sa_add_resource() */
#define SA_SHARE_TRANSIENT 0 /* shared but not across reboot */
#define SA_SHARE_LEGACY 1 /* share is in dfstab only */
#define SA_SHARE_PERMANENT 2 /* share goes to repository */
@@ -105,6 +114,16 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */
#define SA_RBAC_VALUE "solaris.smf.value.shares"
/*
+ * Feature set bit definitions
+ */
+
+#define SA_FEATURE_NONE 0x0000 /* no feature flags set */
+#define SA_FEATURE_RESOURCE 0x0001 /* resource names are required */
+#define SA_FEATURE_DFSTAB 0x0002 /* need to manage in dfstab */
+#define SA_FEATURE_ALLOWSUBDIRS 0x0004 /* allow subdirs to be shared */
+#define SA_FEATURE_ALLOWPARDIRS 0x0008 /* allow parent dirs to be shared */
+
+/*
* legacy files
*/
@@ -143,7 +162,6 @@ extern int sa_check_path(sa_group_t, char *, int);
extern int sa_move_share(sa_group_t, sa_share_t);
extern int sa_remove_share(sa_share_t);
extern sa_share_t sa_get_share(sa_group_t, char *);
-extern sa_share_t sa_get_resource(sa_group_t, char *);
extern sa_share_t sa_find_share(sa_handle_t, char *);
extern sa_share_t sa_get_next_share(sa_share_t);
extern char *sa_get_share_attr(sa_share_t, char *);
@@ -152,9 +170,26 @@ extern sa_group_t sa_get_parent_group(sa_share_t);
extern int sa_set_share_attr(sa_share_t, char *, char *);
extern int sa_set_share_description(sa_share_t, char *);
extern int sa_enable_share(sa_group_t, char *);
-extern int sa_disable_share(sa_group_t, char *);
+extern int sa_disable_share(sa_share_t, char *);
extern int sa_is_share(void *);
+/* resource name related */
+extern sa_resource_t sa_find_resource(sa_handle_t, char *);
+extern sa_resource_t sa_get_resource(sa_group_t, char *);
+extern sa_resource_t sa_get_next_resource(sa_resource_t);
+extern sa_share_t sa_get_resource_parent(sa_resource_t);
+extern sa_resource_t sa_get_share_resource(sa_share_t, char *);
+extern sa_resource_t sa_add_resource(sa_share_t, char *, int, int *);
+extern int sa_remove_resource(sa_resource_t);
+extern char *sa_get_resource_attr(sa_resource_t, char *);
+extern int sa_set_resource_attr(sa_resource_t, char *, char *);
+extern int sa_set_resource_description(sa_resource_t, char *);
+extern char *sa_get_resource_description(sa_resource_t);
+extern int sa_enable_resource(sa_resource_t, char *);
+extern int sa_disable_resource(sa_resource_t, char *);
+extern int sa_rename_resource(sa_resource_t, char *);
+extern void sa_fix_resource_name(char *);
+
/* data structure free calls */
extern void sa_free_attr_string(char *);
extern void sa_free_share_description(char *);
@@ -179,6 +214,7 @@ extern int sa_update_property(sa_property_t, char *);
extern int sa_remove_property(sa_property_t);
extern int sa_commit_properties(sa_optionset_t, int);
extern int sa_valid_property(void *, char *, sa_property_t);
+extern int sa_is_persistent(void *);
/* security control */
extern sa_security_t sa_get_security(sa_group_t, char *, char *);
@@ -196,6 +232,7 @@ extern int sa_parse_legacy_options(sa_group_t, char *, char *);
extern char *sa_proto_legacy_format(char *, sa_group_t, int);
extern int sa_is_security(char *, char *);
extern sa_protocol_properties_t sa_proto_get_properties(char *);
+extern uint64_t sa_proto_get_featureset(char *);
extern sa_property_t sa_get_protocol_property(sa_protocol_properties_t, char *);
extern sa_property_t sa_get_next_protocol_property(sa_property_t);
extern int sa_set_protocol_property(sa_property_t, char *);
@@ -206,9 +243,12 @@ extern int sa_add_protocol_property(sa_protocol_properties_t, sa_property_t);
extern int sa_proto_valid_prop(char *, sa_property_t, sa_optionset_t);
extern int sa_proto_valid_space(char *, char *);
extern char *sa_proto_space_alias(char *, char *);
+extern int sa_proto_get_transients(sa_handle_t, char *);
+extern int sa_proto_notify_resource(sa_resource_t, char *);
+extern int sa_proto_change_notify(sa_share_t, char *);
/* handle legacy (dfstab/sharetab) files */
-extern int sa_delete_legacy(sa_share_t);
+extern int sa_delete_legacy(sa_share_t, char *);
extern int sa_update_legacy(sa_share_t, char *);
extern int sa_update_sharetab(sa_share_t, char *);
extern int sa_delete_sharetab(char *, char *);
diff --git a/usr/src/lib/libshare/common/libshare_impl.h b/usr/src/lib/libshare/common/libshare_impl.h
index a454e3ef75..ab661e432f 100644
--- a/usr/src/lib/libshare/common/libshare_impl.h
+++ b/usr/src/lib/libshare/common/libshare_impl.h
@@ -72,6 +72,13 @@ struct sa_plugin_ops {
char *(*sa_space_alias)(char *);
int (*sa_update_legacy)(sa_share_t);
int (*sa_delete_legacy)(sa_share_t);
+ int (*sa_change_notify)(sa_share_t);
+ int (*sa_enable_resource)(sa_resource_t);
+ int (*sa_disable_resource)(sa_resource_t);
+ uint64_t (*sa_features)(void);
+ int (*sa_get_transient_shares)(sa_handle_t); /* add transients */
+ int (*sa_notify_resource)(sa_resource_t);
+ int (*sa_rename_resource)(sa_handle_t, sa_resource_t, char *);
int (*sa_run_command)(int, int, char **); /* proto specific */
int (*sa_command_help)();
};
@@ -97,6 +104,8 @@ 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 *);
+extern int sa_proto_share_resource(char *, sa_resource_t);
+extern int sa_proto_unshare_resource(char *, sa_resource_t);
/* internal utility functions */
extern sa_optionset_t sa_get_derived_optionset(sa_group_t, char *, int);
@@ -121,7 +130,7 @@ 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_share_zfs(sa_share_t, char *, share_t *, void *, zfs_share_op_t);
extern int sa_sharetab_fill_zfs(sa_share_t share, struct share *sh,
char *proto);
@@ -131,6 +140,8 @@ extern void proto_plugin_fini();
extern int sa_proto_set_property(char *, sa_property_t);
extern int sa_proto_delete_legacy(char *, sa_share_t);
extern int sa_proto_update_legacy(char *, sa_share_t);
+extern int sa_proto_rename_resource(sa_handle_t, char *,
+ sa_resource_t, char *);
#define PL_TYPE_PROPERTY 0
#define PL_TYPE_SECURITY 1
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);
diff --git a/usr/src/lib/libshare/common/libsharecore.c b/usr/src/lib/libshare/common/libsharecore.c
index 503a424cc6..2e39594fc3 100644
--- a/usr/src/lib/libshare/common/libsharecore.c
+++ b/usr/src/lib/libshare/common/libsharecore.c
@@ -51,6 +51,7 @@
#include <sys/param.h>
#include <signal.h>
#include <libintl.h>
+#include <dirent.h>
#include <sharefs/share.h>
#include "sharetab.h"
@@ -88,7 +89,7 @@ extern char *get_token(char *);
static void dfs_free_list(xfs_sharelist_t *);
/* prototypes */
void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
-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_group(sa_handle_impl_t, char *);
static void outdfstab(FILE *, xfs_sharelist_t *);
extern int _sa_remove_optionset(sa_optionset_t);
@@ -563,13 +564,13 @@ sa_comment_line(char *line, char *err)
}
/*
- * sa_delete_legacy(share)
+ * sa_delete_legacy(share, protocol)
*
* Delete the specified share from the legacy config file.
*/
int
-sa_delete_legacy(sa_share_t share)
+sa_delete_legacy(sa_share_t share, char *protocol)
{
FILE *dfstab;
int err;
@@ -580,39 +581,54 @@ sa_delete_legacy(sa_share_t share)
sa_group_t parent;
sigset_t old;
+ /*
+ * Protect against shares that don't have paths. This is not
+ * really an error at this point.
+ */
+ path = sa_get_share_attr(share, "path");
+ if (path == NULL)
+ return (ret);
+
dfstab = open_dfstab(SA_LEGACY_DFSTAB);
if (dfstab != NULL) {
(void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8);
sablocksigs(&old);
- path = sa_get_share_attr(share, "path");
parent = sa_get_parent_group(share);
if (parent != NULL) {
(void) lockf(fileno(dfstab), F_LOCK, 0);
list = getdfstab(dfstab);
rewind(dfstab);
- for (optionset = sa_get_optionset(parent, NULL);
- optionset != NULL;
- optionset = sa_get_next_optionset(optionset)) {
- char *proto = sa_get_optionset_attr(optionset,
- "type");
- if (list != NULL && proto != NULL)
+ if (protocol != NULL) {
+ if (list != NULL)
list = remdfsentry(list, path,
- proto);
- if (proto == NULL)
- ret = SA_NO_MEMORY;
- /*
- * May want to only do the dfstab if
- * this call returns NOT IMPLEMENTED
- * but it shouldn't hurt.
- */
- if (ret == SA_OK) {
- err = sa_proto_delete_legacy(proto,
- share);
- if (err != SA_NOT_IMPLEMENTED)
- ret = err;
+ protocol);
+ } else {
+ for (optionset = sa_get_optionset(parent, NULL);
+ optionset != NULL;
+ optionset =
+ sa_get_next_optionset(optionset)) {
+ char *proto = sa_get_optionset_attr(
+ optionset, "type");
+
+ if (list != NULL && proto != NULL)
+ list = remdfsentry(list, path,
+ proto);
+ if (proto == NULL)
+ ret = SA_NO_MEMORY;
+ /*
+ * may want to only do the dfstab if
+ * this call returns NOT IMPLEMENTED
+ * but it shouldn't hurt.
+ */
+ if (ret == SA_OK) {
+ err = sa_proto_delete_legacy(
+ proto, share);
+ if (err != SA_NOT_IMPLEMENTED)
+ ret = err;
+ }
+ if (proto != NULL)
+ sa_free_attr_string(proto);
}
- if (proto != NULL)
- sa_free_attr_string(proto);
}
outdfstab(dfstab, list);
if (list != NULL)
@@ -623,13 +639,16 @@ sa_delete_legacy(sa_share_t share)
(void) fsync(fileno(dfstab));
saunblocksigs(&old);
(void) fclose(dfstab);
- sa_free_attr_string(path);
} else {
if (errno == EACCES || errno == EPERM)
ret = SA_NO_PERMISSION;
else
ret = SA_CONFIG_ERR;
}
+
+ if (path != NULL)
+ sa_free_attr_string(path);
+
return (ret);
}
@@ -639,7 +658,7 @@ sa_delete_legacy(sa_share_t share)
* There is an assumption that dfstab will be the most common form of
* legacy configuration file for shares, but not the only one. Because
* of that, dfstab handling is done in the main code with calls to
- * this function and protocol specific calls to deal with formating
+ * this function and protocol specific calls to deal with formatting
* options into dfstab/share compatible syntax. Since not everything
* will be dfstab, there is a provision for calling a protocol
* specific plugin interface that allows the protocol plugin to do its
@@ -655,10 +674,16 @@ sa_update_legacy(sa_share_t share, char *proto)
char *path;
sigset_t old;
char *persist;
+ uint64_t features;
ret = sa_proto_update_legacy(proto, share);
if (ret != SA_NOT_IMPLEMENTED)
return (ret);
+
+ features = sa_proto_get_featureset(proto);
+ if (!(features & SA_FEATURE_DFSTAB))
+ return (ret);
+
/* do the dfstab format */
persist = sa_get_share_attr(share, "type");
/*
@@ -748,6 +773,21 @@ sa_is_share(void *object)
}
return (0);
}
+/*
+ * sa_is_resource(object)
+ *
+ * returns true of the object is of type "share".
+ */
+
+int
+sa_is_resource(void *object)
+{
+ if (object != NULL) {
+ if (strcmp((char *)((xmlNodePtr)object)->name, "resource") == 0)
+ return (1);
+ }
+ return (0);
+}
/*
* _sa_remove_property(property)
@@ -1392,6 +1432,7 @@ parse_sharetab(sa_handle_t handle)
sa_group_t lgroup;
char *groupname;
int legacy = 0;
+ char shareopts[MAXNAMLEN];
list = get_share_list(&err);
if (list == NULL)
@@ -1410,7 +1451,9 @@ parse_sharetab(sa_handle_t handle)
* share with no arguments.
*/
set_node_attr(share, "shared", "true");
- set_node_attr(share, "shareopts", tmplist->options);
+ (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s",
+ tmplist->fstype);
+ set_node_attr(share, shareopts, tmplist->options);
continue;
}
@@ -1426,9 +1469,9 @@ parse_sharetab(sa_handle_t handle)
*groupname++ = '\0';
group = sa_get_group(handle, groupname);
if (group != NULL) {
- share = _sa_add_share(group,
- tmplist->path,
- SA_SHARE_TRANSIENT, &err);
+ share = _sa_add_share(group, tmplist->path,
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
} else {
/*
* While this case shouldn't
@@ -1447,7 +1490,7 @@ parse_sharetab(sa_handle_t handle)
*/
share = _sa_add_share(lgroup,
tmplist->path, SA_SHARE_TRANSIENT,
- &err);
+ &err, (uint64_t)SA_FEATURE_NONE);
}
} else {
if (sa_zfs_is_shared(handle, tmplist->path)) {
@@ -1472,11 +1515,12 @@ parse_sharetab(sa_handle_t handle)
if (group != NULL) {
share = _sa_add_share(group,
tmplist->path, SA_SHARE_TRANSIENT,
- &err);
+ &err, (uint64_t)SA_FEATURE_NONE);
}
} else {
share = _sa_add_share(lgroup, tmplist->path,
- SA_SHARE_TRANSIENT, &err);
+ SA_SHARE_TRANSIENT, &err,
+ (uint64_t)SA_FEATURE_NONE);
}
}
if (share == NULL)
@@ -1517,12 +1561,22 @@ int
gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root)
{
int legacy = 0;
+ int numproto;
+ char **protocols = NULL;
+ int i;
if (root != NULL) {
if (*root == NULL)
*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
- if (*root != NULL)
+ if (*root != NULL) {
legacy = parse_sharetab(ihandle);
+ numproto = sa_get_protocols(&protocols);
+ for (i = 0; i < numproto; i++)
+ legacy |= sa_proto_get_transients(
+ (sa_handle_t)ihandle, protocols[i]);
+ if (protocols != NULL)
+ free(protocols);
+ }
}
return (legacy);
}
@@ -1630,7 +1684,7 @@ sa_free_fstype(char *type)
* Work backward to the top of the share object tree and start
* copying protocol specific optionsets into a newly created
* optionset that doesn't have a parent (it will be freed
- * later). This provides for the property inheritence model. That
+ * later). This provides for the property inheritance model. That
* is, properties closer to the share take precedence over group
* level. This also provides for groups of groups in the future.
*/
@@ -1719,7 +1773,7 @@ sa_free_derived_optionset(sa_optionset_t optionset)
* Find all the security types set for this object. This is
* preliminary to getting a derived security set. The return value is an
* optionset containg properties which are the sectype values found by
- * walking up the XML document struture. The returned optionset
+ * walking up the XML document structure. The returned optionset
* is a derived optionset.
*
* If hier is 0, only look at object. If non-zero, walk up the tree.
@@ -1885,6 +1939,19 @@ sa_fillshare(sa_share_t share, char *proto, struct share *sh)
sa_group_t group;
char *buff;
char *zfs;
+ sa_resource_t resource;
+ char *rsrcname = NULL;
+ char *defprop;
+
+ /*
+ * We only want to deal with the path level shares for the
+ * sharetab file. If a resource, get the parent.
+ */
+ if (sa_is_resource(share)) {
+ resource = (sa_resource_t)share;
+ share = sa_get_resource_parent(resource);
+ rsrcname = sa_get_resource_attr(resource, "name");
+ }
group = sa_get_parent_group(share);
if (group != NULL) {
@@ -1912,41 +1979,48 @@ sa_fillshare(sa_share_t share, char *proto, struct share *sh)
sa_free_attr_string(value);
}
- value = sa_get_share_attr(share, "resource");
- if (value != NULL || groupname != NULL) {
+ if (rsrcname != NULL || groupname != NULL) {
int len = 0;
- if (value != NULL)
- len += strlen(value);
+ if (rsrcname != NULL)
+ len += strlen(rsrcname);
if (groupname != NULL)
len += strlen(groupname);
len += 3; /* worst case */
buff = malloc(len);
(void) snprintf(buff, len, "%s%s%s",
- (value != NULL && strlen(value) > 0) ? value : "-",
+ (rsrcname != NULL &&
+ strlen(rsrcname) > 0) ? rsrcname : "-",
groupname != NULL ? "@" : "",
groupname != NULL ? groupname : "");
sh->sh_res = buff;
- if (value != NULL)
- sa_free_attr_string(value);
- if (groupname != NULL) {
+ if (rsrcname != NULL)
+ sa_free_attr_string(rsrcname);
+ if (groupname != NULL)
sa_free_attr_string(groupname);
- groupname = NULL;
- }
} else {
sh->sh_res = strdup("-");
}
+ /*
+ * Get correct default prop string. NFS uses "rw", others use
+ * "".
+ */
+ if (strcmp(proto, "nfs") != 0)
+ defprop = "\"\"";
+ else
+ defprop = "rw";
+
sh->sh_fstype = strdup(proto);
value = sa_proto_legacy_format(proto, share, 1);
if (value != NULL) {
if (strlen(value) > 0)
sh->sh_opts = strdup(value);
else
- sh->sh_opts = strdup("rw");
+ sh->sh_opts = strdup(defprop);
free(value);
} else {
- sh->sh_opts = strdup("rw");
+ sh->sh_opts = strdup(defprop);
}
value = sa_get_share_description(share);
@@ -2041,3 +2115,67 @@ sa_delete_sharetab(char *path, char *proto)
return (ret);
}
+/*
+ * sa_fix_resource_name(path)
+ *
+ * change all illegal characters to something else. For now, all get
+ * converted to '_' and the leading '/' is stripped off. This is used
+ * to construct an resource name (SMB share name) that is valid.
+ * Caller must pass a valid path.
+ */
+void
+sa_fix_resource_name(char *path)
+{
+ char *cp;
+ size_t len;
+
+ assert(path != NULL);
+
+ /* make sure we are appropriate length */
+ cp = path;
+ if (*cp == '/')
+ cp++; /* skip leading slash */
+ while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
+ cp = strchr(cp, '/');
+ if (cp != NULL)
+ cp++;
+ }
+ /* two cases - cp == NULL and cp is substring of path */
+ if (cp == NULL) {
+ /* just take last SA_MAX_RESOURCE_NAME chars */
+ len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
+ (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
+ path[SA_MAX_RESOURCE_NAME] = '\0';
+ } else {
+ len = strlen(cp) + 1;
+ (void) memmove(path, cp, len);
+ }
+
+ /*
+ * Don't want any of the characters that are not allowed
+ * in an SMB share name. Replace them with '_'.
+ */
+ while (*path) {
+ switch (*path) {
+ case '/':
+ case '"':
+ case '\\':
+ case '[':
+ case ']':
+ case ':':
+ case '|':
+ case '<':
+ case '>':
+ case '+':
+ case ';':
+ case ',':
+ case '?':
+ case '*':
+ case '=':
+ case '\t':
+ *path = '_';
+ break;
+ }
+ path++;
+ }
+}
diff --git a/usr/src/lib/libshare/common/mapfile-vers b/usr/src/lib/libshare/common/mapfile-vers
index 317623b3b4..f7dfde5730 100644
--- a/usr/src/lib/libshare/common/mapfile-vers
+++ b/usr/src/lib/libshare/common/mapfile-vers
@@ -106,9 +106,28 @@ SUNWprivate {
sa_delete_legacy;
sa_free_derived_security;
sa_enable_share;
+ sa_enable_resource;
sa_create_group;
sa_valid_protocol;
sa_find_group_handle;
+ sa_add_resource;
+ sa_remove_resource;
+ sa_rename_resource;
+ sa_get_resource;
+ sa_get_next_resource;
+ sa_get_resource_attr;
+ sa_set_resource_attr;
+ sa_get_share_resource;
+ sa_get_resource_parent;
+ sa_find_resource;
+ sa_proto_change_notify;
+ sa_proto_notify_resource;
+ sa_disable_resource;
+ sa_proto_get_featureset;
+ sa_is_persistent;
+ sa_set_resource_description;
+ sa_get_resource_description;
+ sa_fix_resource_name;
local:
*;
};
diff --git a/usr/src/lib/libshare/common/plugin.c b/usr/src/lib/libshare/common/plugin.c
index 4079e24ff7..08856a8951 100644
--- a/usr/src/lib/libshare/common/plugin.c
+++ b/usr/src/lib/libshare/common/plugin.c
@@ -64,7 +64,7 @@ void proto_plugin_fini();
* /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory
* would have a modules with name libshare_<proto>.so. If one is
* found, initialize it and add to the internal list of
- * protocols. These are used for protocol specifici operations.
+ * protocols. These are used for protocol specific operations.
*/
int
@@ -242,9 +242,9 @@ sa_proto_share(char *proto, sa_share_t share)
}
/*
- * sa_proto_unshare(proto, path)
+ * sa_proto_unshare(proto, share)
*
- * Deactivate (unshare) the path for this protocol.
+ * Deactivate (unshare) the share for this protocol.
*/
int
@@ -259,6 +259,52 @@ sa_proto_unshare(sa_share_t share, char *proto, char *path)
}
/*
+ * sa_proto_share_resource(char *proto, sa_resource_t resource)
+ *
+ * For protocols that actually enable at the resource level, do the
+ * protocol specific resource enable. If it doesn't, return an error.
+ * Note that the resource functions are optional so can return
+ * SA_NOT_SUPPORTED.
+ */
+
+int
+sa_proto_share_resource(char *proto, sa_resource_t resource)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_INVALID_PROTOCOL;
+
+ if (ops != NULL) {
+ if (ops->sa_enable_resource != NULL)
+ ret = ops->sa_enable_resource(resource);
+ else
+ ret = SA_NOT_SUPPORTED;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_unshare_resource(char *proto, sa_resource_t resource)
+ *
+ * For protocols that actually disable at the resource level, do the
+ * protocol specific resource disable. If it doesn't, return an error.
+ */
+
+int
+sa_proto_unshare_resource(char *proto, sa_resource_t resource)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_INVALID_PROTOCOL;
+
+ if (ops != NULL) {
+ if (ops->sa_disable_resource != NULL)
+ ret = ops->sa_disable_resource(resource);
+ else
+ ret = SA_NOT_SUPPORTED;
+ }
+ return (ret);
+}
+
+/*
* sa_proto_valid_prop(proto, prop, opt)
*
* Check to see if the specified prop is valid for this protocol.
@@ -395,7 +441,7 @@ sa_proto_get_properties(char *proto)
/*
* sa_proto_set_property(proto, prop)
*
- * Update the protocol specifiec property.
+ * Update the protocol specific property.
*/
int
@@ -467,16 +513,127 @@ int
sa_proto_delete_legacy(char *proto, sa_share_t share)
{
struct sa_plugin_ops *ops = find_protocol(proto);
- int ret = SA_OK;
+ int ret = SA_NOT_IMPLEMENTED;
if (ops != NULL) {
if (ops->sa_delete_legacy != NULL)
ret = ops->sa_delete_legacy(share);
- } else {
- if (proto != NULL)
- ret = SA_NOT_IMPLEMENTED;
- else
+ } else if (proto == NULL) {
+ ret = SA_INVALID_PROTOCOL;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_change_notify(share, char *protocol)
+ *
+ * Notify the protocol that a change has been made to the share
+ */
+
+int
+sa_proto_change_notify(sa_share_t share, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_NOT_IMPLEMENTED;
+
+ if (ops != NULL) {
+ if (ops->sa_change_notify != NULL)
+ ret = ops->sa_change_notify(share);
+ } else if (proto == NULL) {
ret = SA_INVALID_PROTOCOL;
}
return (ret);
}
+
+/*
+ * sa_proto_notify_resource(resource, char *protocol)
+ *
+ * Notify the protocol that a change has been made to the share
+ */
+
+int
+sa_proto_notify_resource(sa_resource_t resource, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_NOT_IMPLEMENTED;
+
+ if (ops != NULL) {
+ if (ops->sa_notify_resource != NULL)
+ ret = ops->sa_notify_resource(resource);
+ } else if (proto == NULL) {
+ ret = SA_INVALID_PROTOCOL;
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_get_featureset(protocol)
+ *
+ * Get bitmask of defined features of the protocol. These are
+ * primarily things like SA_FEATURE_RESOURCE (shares are by resource
+ * name rather than path) and other operational features that affect
+ * behavior.
+ */
+
+uint64_t
+sa_proto_get_featureset(char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ uint64_t ret = 0;
+
+ if (ops != NULL) {
+ if (ops->sa_features != NULL)
+ ret = ops->sa_features();
+ }
+ /* if not implemented, zero is valid */
+ return (ret);
+}
+
+/*
+ * sa_proto_get_transients(sa_handle_t)
+ *
+ * Called to get any protocol specific transient shares. NFS doesn't
+ * use this since the info is in sharetab which is processed as a
+ * common transient store.
+ *
+ * The protocol plugin should verify that the share isn't in the
+ * repository and then add it as a transient.
+ *
+ * Not having an entry is not a problem. It returns 0 in that case.
+ */
+
+int
+sa_proto_get_transients(sa_handle_t handle, char *proto)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = 0;
+
+ if (ops != NULL) {
+ if (ops->sa_get_transient_shares != NULL)
+ ret = ops->sa_get_transient_shares(handle);
+ }
+ return (ret);
+}
+
+/*
+ * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname)
+ *
+ * Protocols may need to know when a resource has changed names in
+ * order to notify clients. This must be done "before" the name in the
+ * resource has been changed. Not being implemented is not a problem.
+ */
+
+int
+sa_proto_rename_resource(sa_handle_t handle, char *proto,
+ sa_resource_t resource, char *newname)
+{
+ struct sa_plugin_ops *ops = find_protocol(proto);
+ int ret = SA_OK;
+
+ if (ops != NULL) {
+ if (ops->sa_rename_resource != NULL)
+ ret = ops->sa_rename_resource(handle, resource,
+ newname);
+ }
+ return (ret);
+}
diff --git a/usr/src/lib/libshare/common/scfutil.c b/usr/src/lib/libshare/common/scfutil.c
index 05421d605b..344d3729bb 100644
--- a/usr/src/lib/libshare/common/scfutil.c
+++ b/usr/src/lib/libshare/common/scfutil.c
@@ -35,6 +35,7 @@
#include "libshare_impl.h"
#include "scfutil.h"
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <uuid/uuid.h>
#include <sys/param.h>
@@ -396,7 +397,8 @@ out:
static char *share_attr[] = {
"path",
"id",
- "resource",
+ "drive-letter",
+ "exclude",
NULL,
};
@@ -411,6 +413,52 @@ is_share_attr(char *name)
}
/*
+ * _sa_make_resource(node, valuestr)
+ *
+ * Make a resource node on the share node. The valusestr will either
+ * be old format (SMF acceptable string) or new format (pretty much an
+ * arbitrary string with "nnn:" prefixing in order to persist
+ * mapping). The input valuestr will get modified in place. This is
+ * only used in SMF repository parsing. A possible third field will be
+ * a "description" string.
+ */
+
+static void
+_sa_make_resource(xmlNodePtr node, char *valuestr)
+{
+ char *idx;
+ char *name;
+ char *description = NULL;
+
+ idx = valuestr;
+ name = strchr(valuestr, ':');
+ if (name == NULL) {
+ /* this is old form so give an index of "0" */
+ idx = "0";
+ name = valuestr;
+ } else {
+ /* NUL the ':' and move past it */
+ *name++ = '\0';
+ /* There could also be a description string */
+ description = strchr(name, ':');
+ if (description != NULL)
+ *description++ = '\0';
+ }
+ node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
+ if (node != NULL) {
+ xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
+ xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
+ /* SMF values are always persistent */
+ xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
+ if (description != NULL && strlen(description) > 0) {
+ (void) xmlNewChild(node, NULL, (xmlChar *)"description",
+ (xmlChar *)description);
+ }
+ }
+}
+
+
+/*
* sa_share_from_pgroup
*
* Extract the share definition from the share property group. We do
@@ -490,34 +538,70 @@ sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
vallen) >= 0) {
ret = SA_OK;
}
+ } else if (strcmp(name, "resource") == 0) {
+ ret = SA_OK;
}
}
- if (ret == SA_OK) {
+ if (ret != SA_OK)
+ continue;
+ /*
+ * Check that we have the "path" property in
+ * name. The string in name will always be nul
+ * terminated if scf_property_get_name()
+ * succeeded.
+ */
+ if (strcmp(name, "path") == 0)
+ have_path = 1;
+ if (is_share_attr(name)) {
/*
- * Check that we have the "path" property in
- * name. The string in name will always be nul
- * terminated if scf_property_get_name()
- * succeeded.
+ * If a share attr, then simple -
+ * usually path and id name
*/
- if (strcmp(name, "path") == 0)
- have_path = 1;
- if (is_share_attr(name)) {
- /*
- * If a share attr, then simple -
- * usually path and resource name
- */
- xmlSetProp(node, (xmlChar *)name,
- (xmlChar *)valuestr);
- } else {
- if (strcmp(name, "description") == 0) {
- /* We have a description node */
- xmlNodePtr desc;
- desc = xmlNewChild(node, NULL,
- (xmlChar *)"description", NULL);
- if (desc != NULL)
- xmlNodeSetContent(desc,
- (xmlChar *)valuestr);
+ xmlSetProp(node, (xmlChar *)name,
+ (xmlChar *)valuestr);
+ } else if (strcmp(name, "resource") == 0) {
+ /*
+ * Resource names handled differently since
+ * there can be multiple on each share. The
+ * "resource" id must be preserved since this
+ * will be used by some protocols in mapping
+ * "property spaces" to names and is always
+ * used to create SMF property groups specific
+ * to resources. CIFS needs this. The first
+ * value is present so add and then loop for
+ * any additional. Since this is new and
+ * previous values may exist, handle
+ * conversions.
+ */
+ scf_iter_t *viter;
+ viter = scf_iter_create(handle->handle);
+ if (viter != NULL &&
+ scf_iter_property_values(viter, prop) == 0) {
+ while (scf_iter_next_value(viter, value) > 0) {
+ /* Have a value so process it */
+ if (scf_value_get_ustring(value,
+ valuestr, vallen) >= 0) {
+ /* have a ustring */
+ _sa_make_resource(node,
+ valuestr);
+ } else if (scf_value_get_astring(value,
+ valuestr, vallen) >= 0) {
+ /* have an astring */
+ _sa_make_resource(node,
+ valuestr);
+ }
}
+ scf_iter_destroy(viter);
+ }
+ } else {
+ if (strcmp(name, "description") == 0) {
+ /* We have a description node */
+ xmlNodePtr desc;
+ desc = xmlNewChild(node, NULL,
+ (xmlChar *)"description", NULL);
+ if (desc != NULL)
+ xmlNodeSetContent(desc,
+ (xmlChar *)valuestr);
}
}
}
@@ -583,7 +667,34 @@ find_share_by_id(sa_handle_t handle, char *shareid)
}
/*
- * sa_share_props_from_pgroup(root, handle, pg, id)
+ * find_resource_by_index(share, index)
+ *
+ * Search the resource records on the share for the id index.
+ */
+static sa_resource_t
+find_resource_by_index(sa_share_t share, char *index)
+{
+ sa_resource_t resource;
+ sa_resource_t found = NULL;
+ char *id;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL && found == NULL;
+ resource = sa_get_next_resource(resource)) {
+ id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
+ if (id != NULL) {
+ if (strcmp(id, index) == 0) {
+ /* found it so save in "found" */
+ found = resource;
+ }
+ sa_free_attr_string(id);
+ }
+ }
+ return (found);
+}
+
+/*
+ * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
*
* Extract share properties from the SMF property group. More sanity
* checks are done and the share object is created. We ignore some
@@ -639,6 +750,7 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
/* not a valid proto (null) */
return (ret);
}
+
sectype = strchr(proto, '_');
if (sectype != NULL)
*sectype++ = '\0';
@@ -664,10 +776,35 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
if (sectype == NULL)
node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
else {
- node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
- if (node != NULL)
- xmlSetProp(node, (xmlChar *)"sectype",
- (xmlChar *)sectype);
+ if (isdigit((int)*sectype)) {
+ sa_resource_t resource;
+ /*
+ * If sectype[0] is a digit, then it is an index into
+ * the resource names. We need to find a resource
+ * record and then get the properties into an
+ * optionset. The optionset becomes the "node" and the
+ * rest is hung off of the share.
+ */
+ resource = find_resource_by_index(share, sectype);
+ if (resource != NULL) {
+ node = xmlNewChild(resource, NULL,
+ (xmlChar *)"optionset", NULL);
+ } else {
+ /* this shouldn't happen */
+ ret = SA_SYSTEM_ERR;
+ }
+ } else {
+ /*
+ * If not a digit, then it is a security type
+ * (alternate option space). Security types start with
+ * an alphabetic.
+ */
+ node = xmlNewChild(root, NULL, (xmlChar *)"security",
+ NULL);
+ if (node != NULL)
+ xmlSetProp(node, (xmlChar *)"sectype",
+ (xmlChar *)sectype);
+ }
}
if (node == NULL) {
ret = SA_NO_MEMORY;
@@ -685,7 +822,7 @@ sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
if (iter == NULL || value == NULL || prop == NULL || name == NULL)
goto out;
- /* Iterate over the share pg properties */
+ /* iterate over the share pg properties */
if (scf_iter_pg_properties(iter, pg) == 0) {
while (scf_iter_next_property(iter, prop) > 0) {
ret = SA_SYSTEM_ERR; /* assume the worst */
@@ -897,7 +1034,7 @@ out:
* sa_extract_defaults(root, handle, instance)
*
* Local function to find the default properties that live in the
- * default instance's "operation" proprerty group.
+ * default instance's "operation" property group.
*/
static void
@@ -946,7 +1083,7 @@ out:
/*
- * sa_get_config(handle, root, doc, sahandlec)
+ * sa_get_config(handle, root, doc, sahandle)
*
* Walk the SMF repository for /network/shares/group and find all the
* instances. These become group names. Then add the XML structure
@@ -1276,6 +1413,147 @@ sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
}
/*
+ * check_resource(share)
+ *
+ * Check to see if share has any persistent resources. We don't want
+ * to save if they are all transient.
+ */
+static int
+check_resource(sa_share_t share)
+{
+ sa_resource_t resource;
+ int ret = B_FALSE;
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL && ret == B_FALSE;
+ resource = sa_get_next_resource(resource)) {
+ char *type;
+ type = sa_get_resource_attr(resource, "type");
+ if (type != NULL) {
+ if (strcmp(type, "transient") != 0) {
+ ret = B_TRUE;
+ }
+ sa_free_attr_string(type);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * sa_set_resource_property(handle, prop, value)
+ *
+ * set a property transaction entry into the pending SMF
+ * transaction. We don't want to include any transient resources
+ */
+
+static int
+sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
+{
+ int ret = SA_OK;
+ scf_value_t *value;
+ scf_transaction_entry_t *entry;
+ sa_resource_t resource;
+ char *valstr;
+ char *idstr;
+ char *description;
+ char *propstr = NULL;
+ size_t strsize;
+
+ /* don't bother if no persistent resources */
+ if (check_resource(share) == B_FALSE)
+ return (ret);
+
+ /*
+ * properties must be set in transactions and don't take
+ * effect until the transaction has been ended/committed.
+ */
+ entry = scf_entry_create(handle->handle);
+ if (entry == NULL)
+ return (SA_SYSTEM_ERR);
+
+ if (scf_transaction_property_change(handle->trans, entry,
+ "resource", SCF_TYPE_ASTRING) != 0 &&
+ scf_transaction_property_new(handle->trans, entry,
+ "resource", SCF_TYPE_ASTRING) != 0) {
+ scf_entry_destroy(entry);
+ return (SA_SYSTEM_ERR);
+
+ }
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL;
+ resource = sa_get_next_resource(resource)) {
+ value = scf_value_create(handle->handle);
+ if (value == NULL) {
+ ret = SA_NO_MEMORY;
+ break;
+ }
+ /* Get size of complete string */
+ valstr = sa_get_resource_attr(resource, "name");
+ idstr = sa_get_resource_attr(resource, "id");
+ description = sa_get_resource_description(resource);
+ strsize = (valstr != NULL) ? strlen(valstr) : 0;
+ strsize += (idstr != NULL) ? strlen(idstr) : 0;
+ strsize += (description != NULL) ? strlen(description) : 0;
+ if (strsize > 0) {
+ strsize += 3; /* add nul and ':' */
+ propstr = (char *)malloc(strsize);
+ if (propstr == NULL) {
+ scf_value_destroy(value);
+ ret = SA_NO_MEMORY;
+ goto err;
+ }
+ if (idstr == NULL)
+ (void) snprintf(propstr, strsize, "%s",
+ valstr ? valstr : "");
+ else
+ (void) snprintf(propstr, strsize, "%s:%s:%s",
+ idstr ? idstr : "", valstr ? valstr : "",
+ description ? description : "");
+ if (scf_value_set_astring(value, propstr) != 0) {
+ ret = SA_SYSTEM_ERR;
+ free(propstr);
+ scf_value_destroy(value);
+ break;
+ }
+ if (scf_entry_add_value(entry, value) != 0) {
+ ret = SA_SYSTEM_ERR;
+ free(propstr);
+ scf_value_destroy(value);
+ break;
+ }
+ /* the value is in the transaction */
+ value = NULL;
+ free(propstr);
+ }
+err:
+ if (valstr != NULL)
+ sa_free_attr_string(valstr);
+ if (idstr != NULL)
+ sa_free_attr_string(idstr);
+ if (description != NULL)
+ sa_free_share_description(description);
+ }
+ /* the entry is in the transaction */
+ entry = NULL;
+
+ if (ret == SA_SYSTEM_ERR) {
+ switch (scf_error()) {
+ case SCF_ERROR_PERMISSION_DENIED:
+ ret = SA_NO_PERMISSION;
+ break;
+ }
+ }
+ /*
+ * cleanup if there were any errors that didn't leave
+ * these values where they would be cleaned up later.
+ */
+ if (entry != NULL)
+ scf_entry_destroy(entry);
+
+ return (ret);
+}
+
+/*
* sa_commit_share(handle, group, share)
*
* Commit this share to the repository.
@@ -1288,7 +1566,6 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
int ret = SA_OK;
char *groupname;
char *name;
- char *resource;
char *description;
char *sharename;
ssize_t proplen;
@@ -1371,15 +1648,35 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
}
if (ret == SA_OK) {
- resource = sa_get_share_attr(share,
- "resource");
- if (resource != NULL) {
+ name = sa_get_share_attr(share, "drive-letter");
+ if (name != NULL) {
+ /* A drive letter may exist for SMB */
+ ret = sa_set_property(handle,
+ "drive-letter", name);
+ sa_free_attr_string(name);
+ }
+ }
+ if (ret == SA_OK) {
+ name = sa_get_share_attr(share, "exclude");
+ if (name != NULL) {
+ /*
+ * In special cases need to
+ * exclude proto enable.
+ */
ret = sa_set_property(handle,
- "resource", resource);
- sa_free_attr_string(resource);
+ "exclude", name);
+ sa_free_attr_string(name);
}
}
if (ret == SA_OK) {
+ /*
+ * If there are resource names, bundle them up
+ * and save appropriately.
+ */
+ ret = sa_set_resource_property(handle, share);
+ }
+
+ if (ret == SA_OK) {
description = sa_get_share_description(share);
if (description != NULL) {
ret = sa_set_property(handle,
@@ -1414,6 +1711,49 @@ sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
/*
+ * remove_resources(handle, share, shareid)
+ *
+ * If the share has resources, remove all of them and their
+ * optionsets.
+ */
+static int
+remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
+{
+ sa_resource_t resource;
+ sa_optionset_t opt;
+ char *proto;
+ char *id;
+ ssize_t proplen;
+ char *propstring;
+ int ret = SA_OK;
+
+ proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
+ propstring = malloc(proplen);
+ if (propstring == NULL)
+ return (SA_NO_MEMORY);
+
+ for (resource = sa_get_share_resource(share, NULL);
+ resource != NULL; resource = sa_get_next_resource(resource)) {
+ id = sa_get_resource_attr(resource, "id");
+ if (id == NULL)
+ continue;
+ for (opt = sa_get_optionset(resource, NULL);
+ opt != NULL; opt = sa_get_next_optionset(resource)) {
+ proto = sa_get_optionset_attr(opt, "type");
+ if (proto != NULL) {
+ (void) snprintf(propstring, proplen,
+ "%s_%s_%s", shareid, proto, id);
+ ret = sa_delete_pgroup(handle, propstring);
+ sa_free_attr_string(proto);
+ }
+ }
+ sa_free_attr_string(id);
+ }
+ free(propstring);
+ return (ret);
+}
+
+/*
* sa_delete_share(handle, group, share)
*
* Remove the specified share from the group (and service instance).
@@ -1444,6 +1784,8 @@ sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
}
ret = sa_get_instance(handle, groupname);
if (ret == SA_OK) {
+ /* If a share has resources, remove them */
+ ret = remove_resources(handle, share, shareid);
/* If a share has properties, remove them */
ret = sa_delete_pgroup(handle, shareid);
for (opt = sa_get_optionset(share, NULL);