diff options
Diffstat (limited to 'usr/src/lib/libshare/common')
-rw-r--r-- | usr/src/lib/libshare/common/libshare.c | 1194 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/libshare.h | 48 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/libshare_impl.h | 13 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/libshare_zfs.c | 388 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/libsharecore.c | 236 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/mapfile-vers | 19 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/plugin.c | 175 | ||||
-rw-r--r-- | usr/src/lib/libshare/common/scfutil.c | 418 |
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); |