/*
 * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset,
 *     grouperr)
 *
 * handle case where this is the top of a sub-group in ZFS. Pulled out
 * of sa_get_zfs_shares for readability. We need the grouperr from the
 * creation of the subgroup to know whether to add the public
 * property, etc. to the specific share.
 */
static int
zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
    char *shareopts, char *proto, char *dataset, int grouperr)
{
	int err = SA_OK;
	sa_resource_t resource;
	uint64_t features;

	set_node_attr(group, "zfs", "true");
	if (share == NULL)
		share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
		    &err, (uint64_t)SA_FEATURE_NONE);

	if (err != SA_OK)
		return (err);

	if (strcmp(shareopts, "on") == 0)
		shareopts = "";
	if (shareopts != NULL) {
		char *options;
		if (grouperr == SA_PROP_SHARE_ONLY) {
			/*
			 * 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);
		}
	}
	return (err);
}
static sa_group_t
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;
	char *name;
	char *options;

	/* start with the top-level "zfs" group */
	zfs = sa_get_group(handle, "zfs");
	*err = SA_OK;
	if (zfs != NULL) {
		for (group = sa_get_sub_group(zfs); group != NULL;
		    group = sa_get_next_group(group)) {
			name = sa_get_group_attr(group, "name");
			if (name != NULL && strcmp(name, groupname) == 0) {
				/* have the group so break out of here */
				sa_free_attr_string(name);
				break;
			}
			if (name != NULL)
				sa_free_attr_string(name);
		}

		if (group == NULL) {
			/*
			 * Need to create the sub-group since it doesn't exist
			 */
			group = _sa_create_zfs_group(zfs, groupname);
			if (group == NULL) {
				*err = SA_NO_MEMORY;
				return (NULL);
			}
			set_node_attr(group, "zfs", "true");
		}
		if (strcmp(optstring, "on") == 0)
			optstring = "rw";
		options = strdup(optstring);
		if (options != NULL) {
			*err = sa_parse_legacy_options(group, 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;
		}
	}
	return (group);
}
/*
 * zfs_parse_options(options, proto)
 *
 * Call the legacy parse interface to get the protocol specific
 * options using the NULL arg to indicate that this is a "parse" only.
 */
int
zfs_parse_options(char *options, zfs_share_proto_t proto)
{
	return (sa_parse_legacy_options(NULL, options,
	    proto_table[proto].p_name));
}
/*
 * zfs_inherited(handle, source, sourcestr)
 *
 * 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 *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
	 * mounted, but it was identified in the "sourcestr"
	 * variable. The real parent not mounted can occur if
	 * "canmount=off and sharenfs=on".
	 */
	group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
	    shareopts, &doshopt);
	if (group != NULL) {
		/*
		 * 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
		 * share.
		 */
		if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) {
			char *options;
			options = strdup(shareopts);
			if (options != NULL) {
				set_node_attr(share, "dataset", dataset);
				err = sa_parse_legacy_options(share, options,
				    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;
	}
	return (err);
}