13034Sdougm /*
23034Sdougm  * CDDL HEADER START
33034Sdougm  *
43034Sdougm  * The contents of this file are subject to the terms of the
53034Sdougm  * Common Development and Distribution License (the "License").
63034Sdougm  * You may not use this file except in compliance with the License.
73034Sdougm  *
83034Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm  * or http://www.opensolaris.org/os/licensing.
103034Sdougm  * See the License for the specific language governing permissions
113034Sdougm  * and limitations under the License.
123034Sdougm  *
133034Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm  * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm  *
193034Sdougm  * CDDL HEADER END
203034Sdougm  */
213034Sdougm 
223034Sdougm /*
233348Sdougm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
243034Sdougm  * Use is subject to license terms.
253034Sdougm  */
263034Sdougm 
273034Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
283034Sdougm 
293034Sdougm #include <sys/types.h>
303034Sdougm #include <sys/stat.h>
313034Sdougm #include <fcntl.h>
323034Sdougm #include <stdlib.h>
333034Sdougm #include <stdio.h>
343034Sdougm #include <string.h>
353034Sdougm #include <ctype.h>
363034Sdougm #include <unistd.h>
373034Sdougm #include <getopt.h>
383034Sdougm #include <utmpx.h>
393034Sdougm #include <pwd.h>
403034Sdougm #include <auth_attr.h>
413034Sdougm #include <secdb.h>
423034Sdougm #include <sys/param.h>
433034Sdougm #include <sys/stat.h>
443034Sdougm #include <errno.h>
453034Sdougm 
463034Sdougm #include <libshare.h>
473034Sdougm #include "sharemgr.h"
483034Sdougm #include <libscf.h>
493034Sdougm #include <libxml/tree.h>
503034Sdougm #include <libintl.h>
513034Sdougm 
523034Sdougm static char *sa_get_usage(sa_usage_t);
533034Sdougm 
543034Sdougm /*
553034Sdougm  * Implementation of the common sub-commands supported by sharemgr.
563034Sdougm  * A number of helper functions are also included.
573034Sdougm  */
583034Sdougm 
593034Sdougm /*
603034Sdougm  * has_protocol(group, proto)
613034Sdougm  *	If the group has an optionset with the specified protocol,
623034Sdougm  *	return true (1) otherwise false (0).
633034Sdougm  */
643034Sdougm static int
653034Sdougm has_protocol(sa_group_t group, char *protocol)
663034Sdougm {
673034Sdougm 	sa_optionset_t optionset;
683034Sdougm 	int result = 0;
693034Sdougm 
703034Sdougm 	optionset = sa_get_optionset(group, protocol);
713034Sdougm 	if (optionset != NULL) {
723034Sdougm 	    result++;
733034Sdougm 	}
743034Sdougm 	return (result);
753034Sdougm }
763034Sdougm 
773034Sdougm /*
783034Sdougm  * add_list(list, item)
793034Sdougm  *	Adds a new list member that points to item to the list.
803034Sdougm  *	If list is NULL, it starts a new list.  The function returns
813034Sdougm  *	the first member of the list.
823034Sdougm  */
833034Sdougm struct list *
843034Sdougm add_list(struct list *listp, void *item, void *data)
853034Sdougm {
863034Sdougm 	struct list *new, *tmp;
873034Sdougm 
883034Sdougm 	new = malloc(sizeof (struct list));
893034Sdougm 	if (new != NULL) {
903034Sdougm 	    new->next = NULL;
913034Sdougm 	    new->item = item;
923034Sdougm 	    new->itemdata = data;
933034Sdougm 	} else {
943034Sdougm 	    return (listp);
953034Sdougm 	}
963034Sdougm 
973034Sdougm 	if (listp == NULL)
983034Sdougm 	    return (new);
993034Sdougm 
1003034Sdougm 	for (tmp = listp; tmp->next != NULL; tmp = tmp->next) {
1013034Sdougm 		/* get to end of list */
1023034Sdougm 	}
1033034Sdougm 	tmp->next = new;
1043034Sdougm 	return (listp);
1053034Sdougm }
1063034Sdougm 
1073034Sdougm /*
1083034Sdougm  * free_list(list)
1093034Sdougm  *	Given a list, free all the members of the list;
1103034Sdougm  */
1113034Sdougm static void
1123034Sdougm free_list(struct list *listp)
1133034Sdougm {
1143034Sdougm 	struct list *tmp;
1153034Sdougm 	while (listp != NULL) {
1163034Sdougm 	    tmp = listp;
1173034Sdougm 	    listp = listp->next;
1183034Sdougm 	    free(tmp);
1193034Sdougm 	}
1203034Sdougm }
1213034Sdougm 
1223034Sdougm /*
1233034Sdougm  * check_authorization(instname, which)
1243034Sdougm  *
1253034Sdougm  * Checks to see if the specific type of authorization in which is
1263034Sdougm  * enabled for the user in this SMF service instance.
1273034Sdougm  */
1283034Sdougm 
1293034Sdougm static int
1303034Sdougm check_authorization(char *instname, int which)
1313034Sdougm {
1323034Sdougm 	scf_handle_t *handle = NULL;
1333034Sdougm 	scf_simple_prop_t *prop = NULL;
1343034Sdougm 	char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
1353034Sdougm 	char *authstr = NULL;
1363034Sdougm 	ssize_t numauths;
1373034Sdougm 	int ret = 1;
1383034Sdougm 	uid_t uid;
1393034Sdougm 	struct passwd *pw = NULL;
1403034Sdougm 
1413034Sdougm 	uid = getuid();
1423034Sdougm 	pw = getpwuid(uid);
1433034Sdougm 	if (pw == NULL)
1443034Sdougm 	    ret = 0;
1453034Sdougm 
1463034Sdougm 	if (ret == 1) {
1473034Sdougm 	    /* since names  are restricted to SA_MAX_NAME_LEN won't overflow */
1483034Sdougm 	    (void) snprintf(svcstring, sizeof (svcstring),
1493034Sdougm 				"%s:%s", SA_SVC_FMRI_BASE, instname);
1503034Sdougm 	    handle = scf_handle_create(SCF_VERSION);
1513034Sdougm 	    if (handle != NULL) {
1523034Sdougm 		if (scf_handle_bind(handle) == 0) {
1533034Sdougm 		    switch (which) {
1543034Sdougm 		    case SVC_SET:
1553034Sdougm 			prop = scf_simple_prop_get(handle, svcstring,
1563034Sdougm 							"general",
1573034Sdougm 							SVC_AUTH_VALUE);
1583034Sdougm 			break;
1593034Sdougm 		    case SVC_ACTION:
1603034Sdougm 			prop = scf_simple_prop_get(handle, svcstring,
1613034Sdougm 							"general",
1623034Sdougm 							SVC_AUTH_ACTION);
1633034Sdougm 			break;
1643034Sdougm 		    }
1653034Sdougm 		}
1663034Sdougm 	    }
1673034Sdougm 	}
1683034Sdougm 	/* make sure we have an authorization string property */
1693034Sdougm 	if (prop != NULL) {
1703034Sdougm 	    int i;
1713034Sdougm 	    numauths = scf_simple_prop_numvalues(prop);
1723034Sdougm 	    for (ret = 0, i = 0; i < numauths; i++) {
1733034Sdougm 		authstr = scf_simple_prop_next_astring(prop);
1743034Sdougm 		if (authstr != NULL) {
1753034Sdougm 		    /* check if this user has one of the strings */
1763034Sdougm 		    if (chkauthattr(authstr, pw->pw_name)) {
1773034Sdougm 			ret = 1;
1783034Sdougm 			break;
1793034Sdougm 		    }
1803034Sdougm 		}
1813034Sdougm 	    }
1823034Sdougm 	    endauthattr();
1833034Sdougm 	    scf_simple_prop_free(prop);
1843034Sdougm 	} else {
1853034Sdougm 	    /* no authorization string defined */
1863034Sdougm 	    ret = 0;
1873034Sdougm 	}
1883034Sdougm 	if (handle != NULL)
1893034Sdougm 	    scf_handle_destroy(handle);
1903034Sdougm 	return (ret);
1913034Sdougm }
1923034Sdougm 
1933034Sdougm /*
1943034Sdougm  * check_authorizations(instname, flags)
1953034Sdougm  *
1963034Sdougm  * check all the needed authorizations for the user in this service
1973034Sdougm  * instance. Return value of 1(true) or 0(false) indicates whether
1983034Sdougm  * there are authorizations for the user or not.
1993034Sdougm  */
2003034Sdougm 
2013034Sdougm static int
2023034Sdougm check_authorizations(char *instname, int flags)
2033034Sdougm {
2043034Sdougm 	int ret1 = 0;
2053034Sdougm 	int ret2 = 0;
2063034Sdougm 	int ret;
2073034Sdougm 
2083034Sdougm 	if (flags & SVC_SET)
2093034Sdougm 	    ret1 = check_authorization(instname, SVC_SET);
2103034Sdougm 	if (flags & SVC_ACTION)
2113034Sdougm 	    ret2 = check_authorization(instname, SVC_ACTION);
2123034Sdougm 	switch (flags) {
2133034Sdougm 	case SVC_ACTION:
2143034Sdougm 	    ret = ret2;
2153034Sdougm 	    break;
2163034Sdougm 	case SVC_SET:
2173034Sdougm 	    ret = ret1;
2183034Sdougm 	    break;
2193034Sdougm 	case SVC_ACTION|SVC_SET:
2203034Sdougm 	    ret = ret1 & ret2;
2213034Sdougm 	    break;
2223034Sdougm 	default:
2233034Sdougm 	    /* if not flags set, we assume we don't need authorizations */
2243034Sdougm 	    ret = 1;
2253034Sdougm 	}
2263034Sdougm 	return (ret);
2273034Sdougm }
2283034Sdougm 
2293034Sdougm /*
2303082Sdougm  * enable_group(group, updateproto)
2313082Sdougm  *
2323082Sdougm  * enable all the shares in the specified group. This is a helper for
2333082Sdougm  * enable_all_groups in order to simplify regular and subgroup (zfs)
2343082Sdougm  * disabling. Group has already been checked for non-NULL.
2353082Sdougm  */
2363082Sdougm 
2373082Sdougm static void
2383082Sdougm enable_group(sa_group_t group, char *updateproto)
2393082Sdougm {
2403082Sdougm 	sa_share_t share;
2413082Sdougm 
2423082Sdougm 	for (share = sa_get_share(group, NULL);
2433082Sdougm 	    share != NULL;
2443082Sdougm 	    share = sa_get_next_share(share)) {
2453082Sdougm 	    if (updateproto != NULL)
2463082Sdougm 		(void) sa_update_legacy(share, updateproto);
2473082Sdougm 	    (void) sa_enable_share(share, NULL);
2483082Sdougm 	}
2493082Sdougm }
2503082Sdougm 
2513082Sdougm /*
2523082Sdougm  * enable_all_groups(list, setstate, online, updateproto)
2533082Sdougm  *	Given a list of groups, enable each one found.  If updateproto
2543082Sdougm  *	is not NULL, then update all the shares for the protocol that
2553082Sdougm  *	was passed in.
2563034Sdougm  */
2573034Sdougm static int
258*3910Sdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
259*3910Sdougm 	int online, char *updateproto)
2603034Sdougm {
2613034Sdougm 	int ret = SA_OK;
2623034Sdougm 	char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
2633034Sdougm 	char *state;
2643034Sdougm 	char *name;
2653034Sdougm 	char *zfs = NULL;
2663034Sdougm 	sa_group_t group;
2673082Sdougm 	sa_group_t subgroup;
2683034Sdougm 
2693034Sdougm 	while (work != NULL && ret == SA_OK) {
2703034Sdougm 	    group = (sa_group_t)work->item;
2713034Sdougm 	    /* if itemdata != NULL then a single share */
2723034Sdougm 	    if (work->itemdata != NULL) {
2733034Sdougm 		ret = sa_enable_share((sa_share_t)work->itemdata, NULL);
2743034Sdougm 	    }
2753034Sdougm 	    if (setstate)
2763034Sdougm 		ret = sa_set_group_attr(group, "state",
2773034Sdougm 					"enabled");
2783034Sdougm 	    if (ret == SA_OK) {
2793034Sdougm 		/* if itemdata == NULL then the whole group */
2803034Sdougm 		if (work->itemdata == NULL) {
2813082Sdougm 		    zfs = sa_get_group_attr(group, "zfs");
2823082Sdougm 			/*
2833082Sdougm 			 * if the share is managed by ZFS, don't
2843082Sdougm 			 * update any of the protocols since ZFS is
2853082Sdougm 			 * handling this.  updateproto will contain
2863082Sdougm 			 * the name of the protocol that we want to
2873082Sdougm 			 * update legacy files for.
2883082Sdougm 			 */
2893082Sdougm 		    enable_group(group, zfs == NULL ? updateproto : NULL);
2903082Sdougm 		    for (subgroup = sa_get_sub_group(group); subgroup != NULL;
2913082Sdougm 			subgroup = sa_get_next_group(subgroup)) {
2923082Sdougm 			/* never update legacy for ZFS subgroups */
2933082Sdougm 			enable_group(subgroup, NULL);
2943034Sdougm 		    }
2953034Sdougm 		}
2963034Sdougm 		if (online) {
2973082Sdougm 		    zfs = sa_get_group_attr(group, "zfs");
2983034Sdougm 		    name = sa_get_group_attr(group, "name");
2993034Sdougm 		    if (name != NULL) {
3003034Sdougm 			if (zfs == NULL) {
3013034Sdougm 			    (void) snprintf(instance, sizeof (instance),
3023034Sdougm 						"%s:%s",
3033034Sdougm 						SA_SVC_FMRI_BASE, name);
3043034Sdougm 			    state = smf_get_state(instance);
3053034Sdougm 			    if (state == NULL ||
3063034Sdougm 				strcmp(state, "online") != 0) {
3073034Sdougm 				(void) smf_enable_instance(instance, 0);
3083034Sdougm 				free(state);
3093034Sdougm 			    }
3103034Sdougm 			} else {
3113034Sdougm 			    sa_free_attr_string(zfs);
3123034Sdougm 			    zfs = NULL;
3133034Sdougm 			}
3143034Sdougm 			if (name != NULL)
3153034Sdougm 			    sa_free_attr_string(name);
3163034Sdougm 		    }
3173034Sdougm 		}
3183034Sdougm 		work = work->next;
3193034Sdougm 	    }
3203034Sdougm 	}
3213034Sdougm 	if (ret == SA_OK) {
322*3910Sdougm 	    ret = sa_update_config(handle);
3233034Sdougm 	}
3243034Sdougm 	return (ret);
3253034Sdougm }
3263034Sdougm 
3273034Sdougm /*
3283034Sdougm  * chk_opt(optlistp, security, proto)
3293034Sdougm  *
3303034Sdougm  * Do a sanity check on the optlist provided for the protocol.  This
3313034Sdougm  * is a syntax check and verification that the property is either a
3323034Sdougm  * general or specific to a names optionset.
3333034Sdougm  */
3343034Sdougm 
3353034Sdougm static int
3363034Sdougm chk_opt(struct options *optlistp, int security, char *proto)
3373034Sdougm {
3383034Sdougm 	struct options *optlist;
3393034Sdougm 	char *sep = "";
3403034Sdougm 	int notfirst = 0;
3413034Sdougm 	int ret;
3423034Sdougm 
3433034Sdougm 	for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
3443034Sdougm 	    char *optname;
3453034Sdougm 
3463034Sdougm 	    optname = optlist->optname;
3473034Sdougm 	    ret = OPT_ADD_OK;
3483034Sdougm 	    /* extract property/value pair */
3493034Sdougm 	    if (sa_is_security(optname, proto)) {
3503034Sdougm 		if (!security)
3513034Sdougm 		    ret = OPT_ADD_SECURITY;
3523034Sdougm 	    } else {
3533034Sdougm 		if (security)
3543034Sdougm 		    ret = OPT_ADD_PROPERTY;
3553034Sdougm 	    }
3563034Sdougm 	    if (ret != OPT_ADD_OK) {
3573034Sdougm 		if (notfirst == 0)
3583034Sdougm 		    (void) printf(gettext("Property syntax error: "));
3593034Sdougm 		switch (ret) {
3603034Sdougm 		case OPT_ADD_SYNTAX:
3613034Sdougm 		    (void) printf(gettext("%ssyntax error: %s"),
3623034Sdougm 				    sep, optname);
3633034Sdougm 		    sep = ", ";
3643034Sdougm 		    break;
3653034Sdougm 		case OPT_ADD_SECURITY:
3663034Sdougm 		    (void) printf(gettext("%s%s requires -S"),
3673034Sdougm 				    optname, sep);
3683034Sdougm 		    sep = ", ";
3693034Sdougm 		    break;
3703034Sdougm 		case OPT_ADD_PROPERTY:
3713034Sdougm 		    (void) printf(gettext("%s%s not supported with -S"),
3723034Sdougm 				    optname, sep);
3733034Sdougm 		    sep = ", ";
3743034Sdougm 		    break;
3753034Sdougm 		}
3763034Sdougm 		notfirst++;
3773034Sdougm 	    }
3783034Sdougm 	}
3793034Sdougm 	if (notfirst) {
3803034Sdougm 	    (void) printf("\n");
3813034Sdougm 	    ret = SA_SYNTAX_ERR;
3823034Sdougm 	}
3833034Sdougm 	return (ret);
3843034Sdougm }
3853034Sdougm 
3863034Sdougm /*
3873034Sdougm  * free_opt(optlist)
3883034Sdougm  *	Free the specified option list.
3893034Sdougm  */
3903034Sdougm static void
3913034Sdougm free_opt(struct options *optlist)
3923034Sdougm {
3933034Sdougm 	struct options *nextopt;
3943034Sdougm 	while (optlist != NULL) {
3953034Sdougm 		nextopt = optlist->next;
3963034Sdougm 		free(optlist);
3973034Sdougm 		optlist = nextopt;
3983034Sdougm 	}
3993034Sdougm }
4003034Sdougm 
4013034Sdougm /*
4023034Sdougm  * check property list for valid properties
4033034Sdougm  * A null value is a remove which is always valid.
4043034Sdougm  */
4053034Sdougm static int
4063034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec)
4073034Sdougm {
4083034Sdougm 	int ret = SA_OK;
4093034Sdougm 	struct options *cur;
4103034Sdougm 	sa_property_t prop;
4113034Sdougm 	sa_optionset_t parent = NULL;
4123034Sdougm 
4133034Sdougm 	if (object != NULL) {
4143034Sdougm 	    if (sec == NULL)
4153034Sdougm 		parent = sa_get_optionset(object, proto);
4163034Sdougm 	    else
4173034Sdougm 		parent = sa_get_security(object, sec, proto);
4183034Sdougm 	}
4193034Sdougm 
4203034Sdougm 	for (cur = optlist; cur != NULL; cur = cur->next) {
4213034Sdougm 	    if (cur->optvalue != NULL) {
4223034Sdougm 		prop = sa_create_property(cur->optname, cur->optvalue);
4233034Sdougm 		if (prop == NULL)
4243034Sdougm 		    ret = SA_NO_MEMORY;
4253034Sdougm 		if (ret != SA_OK ||
4263034Sdougm 		    (ret = sa_valid_property(parent, proto, prop)) != SA_OK) {
4273034Sdougm 		    (void) printf(gettext("Could not add property %s: %s\n"),
4283034Sdougm 					cur->optname,
4293034Sdougm 					sa_errorstr(ret));
4303034Sdougm 		}
4313034Sdougm 		(void) sa_remove_property(prop);
4323034Sdougm 	    }
4333034Sdougm 	}
4343034Sdougm 	return (ret);
4353034Sdougm }
4363034Sdougm 
4373034Sdougm /*
4383034Sdougm  * add_optionset(group, optlist, protocol, *err)
4393034Sdougm  *	Add the options in optlist to an optionset and then add the optionset
4403034Sdougm  *	to the group.
4413034Sdougm  *
4423034Sdougm  *	The return value indicates if there was a "change" while errors are
4433034Sdougm  *	returned via the *err parameters.
4443034Sdougm  */
4453034Sdougm static int
4463034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
4473034Sdougm {
4483034Sdougm 	sa_optionset_t optionset;
4493034Sdougm 	int ret = SA_OK;
4503034Sdougm 	int result = 0;
4513034Sdougm 
4523034Sdougm 	optionset = sa_get_optionset(group, proto);
4533034Sdougm 	if (optionset == NULL) {
4543034Sdougm 	    optionset = sa_create_optionset(group, proto);
4553034Sdougm 	    result = 1; /* adding a protocol is a change */
4563034Sdougm 	}
4573034Sdougm 	if (optionset != NULL) {
4583034Sdougm 	    while (optlist != NULL) {
4593034Sdougm 		sa_property_t prop;
4603034Sdougm 		prop = sa_get_property(optionset, optlist->optname);
4613034Sdougm 		if (prop == NULL) {
4623034Sdougm 			/*
4633034Sdougm 			 * add the property, but only if it is
4643034Sdougm 			 * a non-NULL or non-zero length value
4653034Sdougm 			 */
4663034Sdougm 		    if (optlist->optvalue != NULL) {
4673034Sdougm 			prop = sa_create_property(optlist->optname,
4683034Sdougm 						    optlist->optvalue);
4693034Sdougm 			if (prop != NULL) {
4703034Sdougm 			    ret = sa_valid_property(optionset, proto, prop);
4713034Sdougm 			    if (ret != SA_OK) {
4723034Sdougm 				(void) sa_remove_property(prop);
4733034Sdougm 				(void) printf(gettext("Could not add property "
4743034Sdougm 							"%s: %s\n"),
4753034Sdougm 						optlist->optname,
4763034Sdougm 						sa_errorstr(ret));
4773034Sdougm 			    }
4783034Sdougm 			}
4793034Sdougm 			if (ret == SA_OK) {
4803034Sdougm 			    ret = sa_add_property(optionset, prop);
4813034Sdougm 			    if (ret != SA_OK) {
4823034Sdougm 				(void) printf(gettext("Could not add property"
4833034Sdougm 							" %s: %s\n"),
4843034Sdougm 						optlist->optname,
4853034Sdougm 						sa_errorstr(ret));
4863034Sdougm 			    } else {
4873034Sdougm 				/* there was a change */
4883034Sdougm 				result = 1;
4893034Sdougm 			    }
4903034Sdougm 			}
4913034Sdougm 		    }
4923034Sdougm 		} else {
4933034Sdougm 		    ret = sa_update_property(prop, optlist->optvalue);
4943034Sdougm 		    /* should check to see if value changed */
4953034Sdougm 		    if (ret != SA_OK) {
4963034Sdougm 			(void) printf(gettext("Could not update "
4973034Sdougm 						"property %s: %s\n"),
4983034Sdougm 					optlist->optname,
4993034Sdougm 					sa_errorstr(ret));
5003034Sdougm 		    } else {
5013034Sdougm 			result = 1;
5023034Sdougm 		    }
5033034Sdougm 		}
5043034Sdougm 		optlist = optlist->next;
5053034Sdougm 	    }
5063034Sdougm 	    ret = sa_commit_properties(optionset, 0);
5073034Sdougm 	}
5083034Sdougm 	if (err != NULL)
5093034Sdougm 	    *err = ret;
5103034Sdougm 	return (result);
5113034Sdougm }
5123034Sdougm 
5133034Sdougm /*
5143034Sdougm  * sa_create(flags, argc, argv)
5153034Sdougm  *	create a new group
5163034Sdougm  *	this may or may not have a protocol associated with it.
5173034Sdougm  *	No protocol means "all" protocols in this case.
5183034Sdougm  */
5193034Sdougm static int
520*3910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
5213034Sdougm {
5223034Sdougm 	char *groupname;
5233034Sdougm 
5243034Sdougm 	sa_group_t group;
5253034Sdougm 	int verbose = 0;
5263034Sdougm 	int dryrun = 0;
5273034Sdougm 	int c;
5283034Sdougm 	char *protocol = NULL;
5293034Sdougm 	int ret = SA_OK;
5303034Sdougm 	struct options *optlist = NULL;
5313034Sdougm 	int err = 0;
5323034Sdougm 	int auth;
5333034Sdougm 
5343034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) {
5353034Sdougm 	    switch (c) {
5363034Sdougm 	    case 'v':
5373034Sdougm 		verbose++;
5383034Sdougm 		break;
5393034Sdougm 	    case 'n':
5403034Sdougm 		dryrun++;
5413034Sdougm 		break;
5423034Sdougm 	    case 'P':
5433034Sdougm 		protocol = optarg;
5443034Sdougm 		if (!sa_valid_protocol(protocol)) {
5453034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
5463034Sdougm 					protocol);
5473034Sdougm 		    return (SA_INVALID_PROTOCOL);
5483034Sdougm 		}
5493034Sdougm 		break;
5503034Sdougm 	    case 'p':
5513034Sdougm 		ret = add_opt(&optlist, optarg, 0);
5523034Sdougm 		switch (ret) {
5533034Sdougm 		case OPT_ADD_SYNTAX:
5543034Sdougm 		    (void) printf(gettext("Property syntax error for "
5553034Sdougm 						"property: %s\n"),
5563034Sdougm 				    optarg);
5573034Sdougm 		    return (SA_SYNTAX_ERR);
5583034Sdougm 		case OPT_ADD_SECURITY:
5593034Sdougm 		    (void) printf(gettext("Security properties need "
5603034Sdougm 					"to be set with set-security: %s\n"),
5613034Sdougm 				    optarg);
5623034Sdougm 		    return (SA_SYNTAX_ERR);
5633034Sdougm 		default:
5643034Sdougm 		    break;
5653034Sdougm 		}
5663034Sdougm 
5673034Sdougm 		break;
5683034Sdougm 	    default:
5693034Sdougm 	    case 'h':
5703034Sdougm 	    case '?':
5713034Sdougm 		(void) printf(gettext("usage: %s\n"),
5723034Sdougm 				sa_get_usage(USAGE_CREATE));
5733034Sdougm 		return (0);
5743034Sdougm 	    }
5753034Sdougm 	}
5763034Sdougm 
5773034Sdougm 	if (optind >= argc) {
5783034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
5793034Sdougm 	    (void) printf(gettext("\tgroup must be specified.\n"));
5803034Sdougm 	    return (SA_BAD_PATH);
5813034Sdougm 	}
5823034Sdougm 
5833034Sdougm 	if ((optind + 1) < argc) {
5843034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
5853034Sdougm 	    (void) printf(gettext("\textraneous group(s) at end\n"));
5863034Sdougm 	    return (SA_SYNTAX_ERR);
5873034Sdougm 	}
5883034Sdougm 
5893034Sdougm 	if (protocol == NULL && optlist != NULL) {
5903034Sdougm 	    /* lookup default protocol */
5913034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
5923034Sdougm 	    (void) printf(gettext("\tprotocol must be specified "
5933034Sdougm 				"with properties\n"));
5943034Sdougm 	    return (SA_INVALID_PROTOCOL);
5953034Sdougm 	}
5963034Sdougm 
5973034Sdougm 	if (optlist != NULL)
5983034Sdougm 	    ret = chk_opt(optlist, 0, protocol);
5993034Sdougm 	if (ret == OPT_ADD_SECURITY) {
6003034Sdougm 	    (void) printf(gettext("Security properties not "
6013034Sdougm 				"supported with create\n"));
6023034Sdougm 	    return (SA_SYNTAX_ERR);
6033034Sdougm 	}
6043034Sdougm 
6053034Sdougm 	/*
6063034Sdougm 	 * if a group already exists, we can only add a new protocol
6073034Sdougm 	 * to it and not create a new one or add the same protocol
6083034Sdougm 	 * again.
6093034Sdougm 	 */
6103034Sdougm 
6113034Sdougm 	groupname = argv[optind];
6123034Sdougm 
6133034Sdougm 	auth = check_authorizations(groupname, flags);
6143034Sdougm 
615*3910Sdougm 	group = sa_get_group(handle, groupname);
6163034Sdougm 	if (group != NULL) {
6173034Sdougm 	    /* group exists so must be a protocol add */
6183034Sdougm 	    if (protocol != NULL) {
6193034Sdougm 		if (has_protocol(group, protocol)) {
6203034Sdougm 		    (void) printf(gettext("Group \"%s\" already exists"
6213034Sdougm 						" with protocol %s\n"),
6223034Sdougm 					groupname, protocol);
6233034Sdougm 		    ret = SA_DUPLICATE_NAME;
6243034Sdougm 		}
6253034Sdougm 	    } else {
6263034Sdougm 		/* must add new protocol */
6273034Sdougm 		(void) printf(gettext("Group already exists and no protocol"
6283034Sdougm 					" specified.\n"));
6293034Sdougm 		ret = SA_DUPLICATE_NAME;
6303034Sdougm 	    }
6313034Sdougm 	} else {
6323034Sdougm 		/*
6333034Sdougm 		 * is it a valid name? Must comply with SMF instance
6343034Sdougm 		 * name restrictions.
6353034Sdougm 		 */
6363034Sdougm 	    if (!sa_valid_group_name(groupname)) {
6373034Sdougm 		ret = SA_INVALID_NAME;
6383034Sdougm 		(void) printf(gettext("Invalid group name: %s\n"), groupname);
6393034Sdougm 	    }
6403034Sdougm 	}
6413034Sdougm 	if (ret == SA_OK) {
6423034Sdougm 	    /* check protocol vs optlist */
6433034Sdougm 	    if (optlist != NULL) {
6443034Sdougm 		/* check options, if any, for validity */
6453034Sdougm 		ret = valid_options(optlist, protocol, group, NULL);
6463034Sdougm 	    }
6473034Sdougm 	}
6483034Sdougm 	if (ret == SA_OK && !dryrun) {
6493034Sdougm 	    if (group == NULL) {
650*3910Sdougm 		group = sa_create_group(handle, (char *)groupname, &err);
6513034Sdougm 	    }
6523034Sdougm 	    if (group != NULL) {
6533034Sdougm 		sa_optionset_t optionset;
6543034Sdougm 		if (optlist != NULL) {
6553034Sdougm 		    (void) add_optionset(group, optlist, protocol, &ret);
6563034Sdougm 		} else if (protocol != NULL) {
6573034Sdougm 		    optionset = sa_create_optionset(group, protocol);
6583034Sdougm 		    if (optionset == NULL)
6593034Sdougm 			ret = SA_NO_MEMORY;
6603034Sdougm 		} else if (protocol == NULL) {
6613034Sdougm 		    char **protolist;
6623034Sdougm 		    int numprotos, i;
6633034Sdougm 		    numprotos = sa_get_protocols(&protolist);
6643034Sdougm 		    for (i = 0; i < numprotos; i++) {
6653034Sdougm 			optionset = sa_create_optionset(group, protolist[i]);
6663034Sdougm 		    }
6673034Sdougm 		    if (protolist != NULL)
6683034Sdougm 			free(protolist);
6693034Sdougm 		}
6703034Sdougm 		/*
6713034Sdougm 		 * we have a group and legal additions
6723034Sdougm 		 */
6733034Sdougm 		if (ret == SA_OK) {
6743034Sdougm 			/*
6753034Sdougm 			 * commit to configuration for protocols that
6763034Sdougm 			 * need to do block updates. For NFS, this
6773034Sdougm 			 * doesn't do anything but it will be run for
6783034Sdougm 			 * all protocols that implement the
6793034Sdougm 			 * appropriate plugin.
6803034Sdougm 			 */
681*3910Sdougm 		    ret = sa_update_config(handle);
6823034Sdougm 		} else {
6833034Sdougm 		    if (group != NULL)
6843034Sdougm 			(void) sa_remove_group(group);
6853034Sdougm 		}
6863034Sdougm 	    } else {
6873034Sdougm 		ret = err;
6883034Sdougm 		(void) printf(gettext("Could not create group: %s\n"),
6893034Sdougm 			sa_errorstr(ret));
6903034Sdougm 	    }
6913034Sdougm 	}
6923034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
6933034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
6943034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
6953034Sdougm 	    ret = SA_NO_PERMISSION;
6963034Sdougm 	}
6973034Sdougm 	free_opt(optlist);
6983034Sdougm 	return (ret);
6993034Sdougm }
7003034Sdougm 
7013034Sdougm /*
7023034Sdougm  * group_status(group)
7033034Sdougm  *
7043034Sdougm  * return the current status (enabled/disabled) of the group.
7053034Sdougm  */
7063034Sdougm 
7073034Sdougm static char *
7083034Sdougm group_status(sa_group_t group)
7093034Sdougm {
7103034Sdougm 	char *state;
7113034Sdougm 	int enabled = 0;
7123034Sdougm 
7133034Sdougm 	state = sa_get_group_attr(group, "state");
7143034Sdougm 	if (state != NULL) {
7153034Sdougm 	    if (strcmp(state, "enabled") == 0) {
7163034Sdougm 		enabled = 1;
7173034Sdougm 	    }
7183034Sdougm 	    sa_free_attr_string(state);
7193034Sdougm 	}
7203034Sdougm 	return (enabled ? gettext("enabled") : gettext("disabled"));
7213034Sdougm }
7223034Sdougm 
7233034Sdougm /*
7243034Sdougm  * sa_delete(flags, argc, argv)
7253034Sdougm  *
7263034Sdougm  *	Delete a group.
7273034Sdougm  */
7283034Sdougm 
7293034Sdougm static int
730*3910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
7313034Sdougm {
7323034Sdougm 	char *groupname;
7333034Sdougm 	sa_group_t group;
7343034Sdougm 	sa_share_t share;
7353034Sdougm 	int verbose = 0;
7363034Sdougm 	int dryrun = 0;
7373034Sdougm 	int force = 0;
7383034Sdougm 	int c;
7393034Sdougm 	char *protocol = NULL;
7403034Sdougm 	char *sectype = NULL;
7413034Sdougm 	int ret = SA_OK;
7423034Sdougm 	int auth;
7433034Sdougm 
7443034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
7453034Sdougm 	    switch (c) {
7463034Sdougm 	    case 'v':
7473034Sdougm 		verbose++;
7483034Sdougm 		break;
7493034Sdougm 	    case 'n':
7503034Sdougm 		dryrun++;
7513034Sdougm 		break;
7523034Sdougm 	    case 'P':
7533034Sdougm 		protocol = optarg;
7543034Sdougm 		if (!sa_valid_protocol(protocol)) {
7553034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
7563034Sdougm 				    protocol);
7573034Sdougm 		    return (SA_INVALID_PROTOCOL);
7583034Sdougm 		}
7593034Sdougm 		break;
7603034Sdougm 	    case 'S':
7613034Sdougm 		sectype = optarg;
7623034Sdougm 		break;
7633034Sdougm 	    case 'f':
7643034Sdougm 		force++;
7653034Sdougm 		break;
7663034Sdougm 	    default:
7673034Sdougm 	    case 'h':
7683034Sdougm 	    case '?':
7693034Sdougm 		(void) printf(gettext("usage: %s\n"),
7703034Sdougm 				sa_get_usage(USAGE_DELETE));
7713034Sdougm 		return (0);
7723034Sdougm 	    }
7733034Sdougm 	}
7743034Sdougm 
7753034Sdougm 	if (optind >= argc) {
7763034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
7773034Sdougm 	    (void) printf(gettext("\tgroup must be specified.\n"));
7783034Sdougm 	    return (SA_SYNTAX_ERR);
7793034Sdougm 	}
7803034Sdougm 
7813034Sdougm 	if ((optind + 1) < argc) {
7823034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
7833034Sdougm 	    (void) printf(gettext("\textraneous group(s) at end\n"));
7843034Sdougm 	    return (SA_SYNTAX_ERR);
7853034Sdougm 	}
7863034Sdougm 
7873034Sdougm 	if (sectype != NULL && protocol == NULL) {
7883034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
7893034Sdougm 	    (void) printf(gettext("\tsecurity requires protocol to be "
7903034Sdougm 					"specified.\n"));
7913034Sdougm 	    return (SA_SYNTAX_ERR);
7923034Sdougm 	}
7933034Sdougm 
7943034Sdougm 	/*
7953034Sdougm 	 * Determine if the group already exists since it must in
7963034Sdougm 	 * order to be removed.
7973034Sdougm 	 *
7983034Sdougm 	 * We can delete when:
7993034Sdougm 	 *
8003034Sdougm 	 *	- group is empty
8013034Sdougm 	 *	- force flag is set
8023034Sdougm 	 *	- if protocol specified, only delete the protocol
8033034Sdougm 	 */
8043034Sdougm 
8053034Sdougm 	groupname = argv[optind];
806*3910Sdougm 	group = sa_get_group(handle, groupname);
8073034Sdougm 	if (group == NULL) {
8083034Sdougm 		ret = SA_NO_SUCH_GROUP;
8093034Sdougm 	} else {
8103034Sdougm 	    auth = check_authorizations(groupname, flags);
8113034Sdougm 	    if (protocol == NULL) {
8123034Sdougm 		share = sa_get_share(group, NULL);
8133034Sdougm 		if (share != NULL)
8143034Sdougm 		    ret = SA_BUSY;
8153034Sdougm 		if (share == NULL || (share != NULL && force == 1)) {
8163034Sdougm 		    ret = SA_OK;
8173034Sdougm 		    if (!dryrun) {
8183034Sdougm 			while (share != NULL) {
8193034Sdougm 			    sa_share_t next_share;
8203034Sdougm 			    next_share = sa_get_next_share(share);
8213034Sdougm 				/*
8223034Sdougm 				 * need to do the disable of each
8233034Sdougm 				 * share, but don't actually do
8243034Sdougm 				 * anything on a dryrun.
8253034Sdougm 				 */
8263034Sdougm 			    ret = sa_disable_share(share, NULL);
8273034Sdougm 			    ret = sa_remove_share(share);
8283034Sdougm 			    share = next_share;
8293034Sdougm 			}
8303034Sdougm 			ret = sa_remove_group(group);
8313034Sdougm 		    }
8323034Sdougm 		}
8333034Sdougm 		/* commit to configuration if not a dryrun */
8343034Sdougm 		if (!dryrun && ret == SA_OK) {
835*3910Sdougm 		    ret = sa_update_config(handle);
8363034Sdougm 		}
8373034Sdougm 	    } else {
8383034Sdougm 		/* a protocol delete */
8393034Sdougm 		sa_optionset_t optionset;
8403034Sdougm 		sa_security_t security;
8413034Sdougm 		if (sectype != NULL) {
8423034Sdougm 		    /* only delete specified security */
8433034Sdougm 		    security = sa_get_security(group, sectype, protocol);
8443034Sdougm 		    if (security != NULL && !dryrun) {
8453034Sdougm 			ret = sa_destroy_security(security);
8463034Sdougm 		    } else {
8473034Sdougm 			ret = SA_INVALID_PROTOCOL;
8483034Sdougm 		    }
8493034Sdougm 		} else {
8503034Sdougm 		    optionset = sa_get_optionset(group, protocol);
8513034Sdougm 		    if (optionset != NULL && !dryrun) {
8523034Sdougm 			/* have an optionset with protocol to delete */
8533034Sdougm 			ret = sa_destroy_optionset(optionset);
8543034Sdougm 			/*
8553034Sdougm 			 * now find all security sets for the protocol
8563034Sdougm 			 * and remove them. Don't remove other
8573034Sdougm 			 * protocols.
8583034Sdougm 			 */
8593034Sdougm 			for (security = sa_get_security(group, NULL, NULL);
8603034Sdougm 			    ret == SA_OK && security != NULL;
8613034Sdougm 			    security = sa_get_next_security(security)) {
8623034Sdougm 			    char *secprot;
8633034Sdougm 
8643034Sdougm 			    secprot = sa_get_security_attr(security, "type");
8653034Sdougm 			    if (secprot != NULL &&
8663034Sdougm 				strcmp(secprot, protocol) == 0)
8673034Sdougm 				ret = sa_destroy_security(security);
8683034Sdougm 			    if (secprot != NULL)
8693034Sdougm 				sa_free_attr_string(secprot);
8703034Sdougm 			}
8713034Sdougm 		    } else {
8723034Sdougm 			if (!dryrun)
8733034Sdougm 			    ret = SA_INVALID_PROTOCOL;
8743034Sdougm 		    }
8753034Sdougm 		}
8763034Sdougm 	    }
8773034Sdougm 	}
8783034Sdougm 	if (ret != SA_OK) {
8793034Sdougm 	    (void) printf(gettext("Could not delete group: %s\n"),
8803034Sdougm 				sa_errorstr(ret));
8813034Sdougm 	} else if (dryrun && !auth && verbose) {
8823034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
8833034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
8843034Sdougm 	}
8853034Sdougm 	return (ret);
8863034Sdougm }
8873034Sdougm 
8883034Sdougm /*
8893034Sdougm  * strndupr(*buff, str, buffsize)
8903034Sdougm  *
8913034Sdougm  * used with small strings to duplicate and possibly increase the
8923034Sdougm  * buffer size of a string.
8933034Sdougm  */
8943034Sdougm static char *
8953034Sdougm strndupr(char *buff, char *str, int *buffsize)
8963034Sdougm {
8973034Sdougm 	int limit;
8983034Sdougm 	char *orig_buff = buff;
8993034Sdougm 
9003034Sdougm 	if (buff == NULL) {
9013034Sdougm 	    buff = (char *)malloc(64);
9023034Sdougm 	    if (buff == NULL)
9033034Sdougm 		return (NULL);
9043034Sdougm 	    *buffsize = 64;
9053034Sdougm 	    buff[0] = '\0';
9063034Sdougm 	}
9073034Sdougm 	limit = strlen(buff) + strlen(str) + 1;
9083034Sdougm 	if (limit > *buffsize) {
9093034Sdougm 	    limit = *buffsize = *buffsize + ((limit / 64) + 64);
9103034Sdougm 	    buff = realloc(buff, limit);
9113034Sdougm 	}
9123034Sdougm 	if (buff != NULL) {
9133034Sdougm 	    (void) strcat(buff, str);
9143034Sdougm 	} else {
9153034Sdougm 	    /* if it fails, fail it hard */
9163034Sdougm 	    if (orig_buff != NULL)
9173034Sdougm 		free(orig_buff);
9183034Sdougm 	}
9193034Sdougm 	return (buff);
9203034Sdougm }
9213034Sdougm 
9223034Sdougm /*
9233034Sdougm  * group_proto(group)
9243034Sdougm  *
9253034Sdougm  * return a string of all the protocols (space separated) associated
9263034Sdougm  * with this group.
9273034Sdougm  */
9283034Sdougm 
9293034Sdougm static char *
9303034Sdougm group_proto(sa_group_t group)
9313034Sdougm {
9323034Sdougm 	sa_optionset_t optionset;
9333034Sdougm 	char *proto;
9343034Sdougm 	char *buff = NULL;
9353034Sdougm 	int buffsize = 0;
9363034Sdougm 	int addspace = 0;
9373034Sdougm 	/*
9383034Sdougm 	 * get the protocol list by finding the optionsets on this
9393034Sdougm 	 * group and extracting the type value. The initial call to
9403034Sdougm 	 * strndupr() initailizes buff.
9413034Sdougm 	 */
9423034Sdougm 	buff = strndupr(buff, "", &buffsize);
9433034Sdougm 	if (buff != NULL) {
9443034Sdougm 	    for (optionset = sa_get_optionset(group, NULL);
9453034Sdougm 		optionset != NULL && buff != NULL;
9463034Sdougm 		optionset = sa_get_next_optionset(optionset)) {
9473034Sdougm 		/*
9483034Sdougm 		 * extract out the protocol type from this optionset
9493034Sdougm 		 * and append it to the buffer "buff". strndupr() will
9503034Sdougm 		 * reallocate space as necessay.
9513034Sdougm 		 */
9523034Sdougm 		proto = sa_get_optionset_attr(optionset, "type");
9533034Sdougm 		if (proto != NULL) {
9543034Sdougm 		    if (addspace++)
9553034Sdougm 			buff = strndupr(buff, " ", &buffsize);
9563034Sdougm 		    buff = strndupr(buff, proto, &buffsize);
9573034Sdougm 		    sa_free_attr_string(proto);
9583034Sdougm 		}
9593034Sdougm 	    }
9603034Sdougm 	}
9613034Sdougm 	return (buff);
9623034Sdougm }
9633034Sdougm 
9643034Sdougm /*
9653034Sdougm  * sa_list(flags, argc, argv)
9663034Sdougm  *
9673034Sdougm  * implements the "list" subcommand to list groups and optionally
9683034Sdougm  * their state and protocols.
9693034Sdougm  */
9703034Sdougm 
9713034Sdougm static int
972*3910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
9733034Sdougm {
9743034Sdougm 	sa_group_t group;
9753034Sdougm 	int verbose = 0;
9763034Sdougm 	int c;
9773034Sdougm 	char *protocol = NULL;
9783034Sdougm #ifdef lint
9793034Sdougm 	flags = flags;
9803034Sdougm #endif
9813034Sdougm 
9823034Sdougm 	while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
9833034Sdougm 	    switch (c) {
9843034Sdougm 	    case 'v':
9853034Sdougm 		verbose++;
9863034Sdougm 		break;
9873034Sdougm 	    case 'P':
9883034Sdougm 		protocol = optarg;
9893034Sdougm 		if (!sa_valid_protocol(protocol)) {
9903034Sdougm 		    (void) printf(gettext("Invalid protocol specified:"
9913034Sdougm 					    "%s\n"),
9923034Sdougm 					protocol);
9933034Sdougm 		    return (SA_INVALID_PROTOCOL);
9943034Sdougm 		}
9953034Sdougm 		break;
9963034Sdougm 	    default:
9973034Sdougm 	    case 'h':
9983034Sdougm 	    case '?':
9993034Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_LIST));
10003034Sdougm 		return (0);
10013034Sdougm 	    }
10023034Sdougm 	}
10033034Sdougm 
1004*3910Sdougm 	for (group = sa_get_group(handle, NULL); group != NULL;
10053034Sdougm 	    group = sa_get_next_group(group)) {
10063034Sdougm 	    char *name;
10073034Sdougm 	    char *proto;
10083034Sdougm 	    if (protocol == NULL || has_protocol(group, protocol)) {
10093034Sdougm 		name = sa_get_group_attr(group, "name");
10103034Sdougm 		if (name != NULL && (verbose > 1 || name[0] != '#')) {
10113034Sdougm 		    (void) printf("%s", (char *)name);
10123034Sdougm 		    if (verbose) {
10133034Sdougm 			/*
10143034Sdougm 			 * need the list of protocols
10153034Sdougm 			 * and current status once
10163034Sdougm 			 * available.
10173034Sdougm 			 */
10183034Sdougm 			(void) printf("\t%s", group_status(group));
10193034Sdougm 			proto = group_proto(group);
10203034Sdougm 			if (proto != NULL) {
10213034Sdougm 			    (void) printf("\t%s", (char *)proto);
10223034Sdougm 			    free(proto);
10233034Sdougm 			}
10243034Sdougm 		    }
10253034Sdougm 		    (void) printf("\n");
10263034Sdougm 		}
10273034Sdougm 		if (name != NULL)
10283034Sdougm 		    sa_free_attr_string(name);
10293034Sdougm 	    }
10303034Sdougm 	}
10313034Sdougm 	return (0);
10323034Sdougm }
10333034Sdougm 
10343034Sdougm /*
10353034Sdougm  * out_properties(optionset, proto, sec)
10363034Sdougm  *
10373034Sdougm  * Format the properties and encode the protocol and optional named
10383034Sdougm  * optionset into the string.
10393034Sdougm  *
10403034Sdougm  * format is protocol[:name]=(property-list)
10413034Sdougm  */
10423034Sdougm 
10433034Sdougm static void
10443034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec)
10453034Sdougm {
10463034Sdougm 	char *type;
10473034Sdougm 	char *value;
10483034Sdougm 	int spacer;
10493034Sdougm 	sa_property_t prop;
10503034Sdougm 
10513034Sdougm 	if (sec == NULL) {
10523034Sdougm 	    (void) printf(" %s=(", proto ? proto : gettext("all"));
10533034Sdougm 	} else {
10543034Sdougm 	    (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
10553034Sdougm 	}
10563034Sdougm 
10573034Sdougm 	for (spacer = 0, prop = sa_get_property(optionset, NULL);
10583034Sdougm 	    prop != NULL; prop = sa_get_next_property(prop)) {
10593034Sdougm 
10603034Sdougm 		/*
10613034Sdougm 		 * extract the property name/value and output with
10623034Sdougm 		 * appropriate spacing. I.e. no prefixed space the
10633034Sdougm 		 * first time through but a space on subsequent
10643034Sdougm 		 * properties.
10653034Sdougm 		 */
10663034Sdougm 	    type = sa_get_property_attr(prop, "type");
10673034Sdougm 	    value = sa_get_property_attr(prop, "value");
10683034Sdougm 	    if (type != NULL) {
10693034Sdougm 		(void) printf("%s%s=", spacer ? " " : "",	type);
10703034Sdougm 		spacer = 1;
10713034Sdougm 		if (value != NULL)
10723034Sdougm 		    (void) printf("\"%s\"", value);
10733034Sdougm 		else
10743034Sdougm 		    (void) printf("\"\"");
10753034Sdougm 	    }
10763034Sdougm 	    if (type != NULL)
10773034Sdougm 		sa_free_attr_string(type);
10783034Sdougm 	    if (value != NULL)
10793034Sdougm 		sa_free_attr_string(value);
10803034Sdougm 	}
10813034Sdougm 	(void) printf(")");
10823034Sdougm }
10833034Sdougm 
10843034Sdougm /*
10853034Sdougm  * show_properties(group, protocol, prefix)
10863034Sdougm  *
10873034Sdougm  * print the properties for a group. If protocol is NULL, do all
10883034Sdougm  * protocols otherwise only the specified protocol. All security
10893034Sdougm  * (named groups specific to the protocol) are included.
10903034Sdougm  *
10913034Sdougm  * The "prefix" is always applied. The caller knows whether it wants
10923034Sdougm  * some type of prefix string (white space) or not.  Once the prefix
10933034Sdougm  * has been output, it is reduced to the zero length string for the
10943034Sdougm  * remainder of the property output.
10953034Sdougm  */
10963034Sdougm 
10973034Sdougm static void
10983034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix)
10993034Sdougm {
11003034Sdougm 	sa_optionset_t optionset;
11013034Sdougm 	sa_security_t security;
11023034Sdougm 	char *value;
11033034Sdougm 	char *secvalue;
11043034Sdougm 
11053034Sdougm 	if (protocol != NULL) {
11063034Sdougm 	    optionset = sa_get_optionset(group, protocol);
11073034Sdougm 	    if (optionset != NULL) {
11083034Sdougm 		(void) printf("%s", prefix);
11093034Sdougm 		prefix = "";
11103034Sdougm 		out_properties(optionset, protocol, NULL);
11113034Sdougm 	    }
11123034Sdougm 	    security = sa_get_security(group, protocol, NULL);
11133034Sdougm 	    if (security != NULL) {
11143034Sdougm 		(void) printf("%s", prefix);
11153034Sdougm 		prefix = "";
11163034Sdougm 		out_properties(security, protocol, NULL);
11173034Sdougm 	    }
11183034Sdougm 	} else {
11193034Sdougm 	    for (optionset = sa_get_optionset(group, protocol);
11203034Sdougm 		optionset != NULL;
11213034Sdougm 		optionset = sa_get_next_optionset(optionset)) {
11223034Sdougm 
11233034Sdougm 		value = sa_get_optionset_attr(optionset, "type");
11243034Sdougm 		(void) printf("%s", prefix);
11253034Sdougm 		prefix = "";
11263034Sdougm 		out_properties(optionset, value, 0);
11273034Sdougm 		if (value != NULL)
11283034Sdougm 		    sa_free_attr_string(value);
11293034Sdougm 	    }
11303034Sdougm 	    for (security = sa_get_security(group, NULL, protocol);
11313034Sdougm 		security != NULL;
11323034Sdougm 		security = sa_get_next_security(security)) {
11333034Sdougm 
11343034Sdougm 		value = sa_get_security_attr(security, "type");
11353034Sdougm 		secvalue = sa_get_security_attr(security, "sectype");
11363034Sdougm 		(void) printf("%s", prefix);
11373034Sdougm 		prefix = "";
11383034Sdougm 		out_properties(security, value, secvalue);
11393034Sdougm 		if (value != NULL)
11403034Sdougm 		    sa_free_attr_string(value);
11413034Sdougm 		if (secvalue != NULL)
11423034Sdougm 		    sa_free_attr_string(secvalue);
11433034Sdougm 	    }
11443034Sdougm 	}
11453034Sdougm }
11463034Sdougm 
11473034Sdougm /*
11483034Sdougm  * show_group(group, verbose, properties, proto, subgroup)
11493034Sdougm  *
11503034Sdougm  * helper function to show the contents of a group.
11513034Sdougm  */
11523034Sdougm 
11533034Sdougm static void
11543034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto,
11553034Sdougm 		char *subgroup)
11563034Sdougm {
11573034Sdougm 	sa_share_t share;
11583034Sdougm 	char *groupname;
11593034Sdougm 	char *sharepath;
11603034Sdougm 	char *resource;
11613034Sdougm 	char *description;
11623034Sdougm 	char *type;
11633034Sdougm 	char *zfs = NULL;
11643034Sdougm 	int iszfs = 0;
11653034Sdougm 
11663034Sdougm 	groupname = sa_get_group_attr(group, "name");
11673034Sdougm 	if (groupname != NULL) {
11683034Sdougm 	    if (proto != NULL && !has_protocol(group, proto)) {
11693034Sdougm 		sa_free_attr_string(groupname);
11703034Sdougm 		return;
11713034Sdougm 	    }
11723034Sdougm 		/*
11733034Sdougm 		 * check to see if the group is managed by ZFS. If
11743034Sdougm 		 * there is an attribute, then it is. A non-NULL zfs
11753034Sdougm 		 * variable will trigger the different way to display
11763034Sdougm 		 * and will remove the transient property indicator
11773034Sdougm 		 * from the output.
11783034Sdougm 		 */
11793034Sdougm 	    zfs = sa_get_group_attr(group, "zfs");
11803034Sdougm 	    if (zfs != NULL) {
11813034Sdougm 		iszfs = 1;
11823034Sdougm 		sa_free_attr_string(zfs);
11833034Sdougm 	    }
11843034Sdougm 	    share = sa_get_share(group, NULL);
11853034Sdougm 	    if (subgroup == NULL)
11863034Sdougm 		(void) printf("%s", groupname);
11873034Sdougm 	    else
11883034Sdougm 		(void) printf("    %s/%s", subgroup, groupname);
11893034Sdougm 	    if (properties) {
11903034Sdougm 		show_properties(group, proto, "");
11913034Sdougm 	    }
11923034Sdougm 	    (void) printf("\n");
11933034Sdougm 	    if (strcmp(groupname, "zfs") == 0) {
11943034Sdougm 		sa_group_t zgroup;
11953034Sdougm 
11963034Sdougm 		for (zgroup = sa_get_sub_group(group); zgroup != NULL;
11973034Sdougm 		    zgroup = sa_get_next_group(zgroup)) {
11983034Sdougm 		    show_group(zgroup, verbose, properties, proto, "zfs");
11993034Sdougm 		}
12003034Sdougm 		sa_free_attr_string(groupname);
12013034Sdougm 		return;
12023034Sdougm 	    }
12033034Sdougm 		/*
12043034Sdougm 		 * have a group, so list the contents. Resource and
12053034Sdougm 		 * description are only listed if verbose is set.
12063034Sdougm 		 */
12073034Sdougm 	    for (share = sa_get_share(group, NULL); share != NULL;
12083034Sdougm 		share = sa_get_next_share(share)) {
12093034Sdougm 		sharepath = sa_get_share_attr(share, "path");
12103034Sdougm 		if (sharepath != NULL) {
12113034Sdougm 		    if (verbose) {
12123034Sdougm 			resource = sa_get_share_attr(share, "resource");
12133034Sdougm 			description = sa_get_share_description(share);
12143034Sdougm 			type = sa_get_share_attr(share, "type");
12153034Sdougm 			if (type != NULL && !iszfs &&
12163034Sdougm 				strcmp(type, "transient") == 0)
12173034Sdougm 			    (void) printf("\t* ");
12183034Sdougm 			else
12193034Sdougm 			    (void) printf("\t  ");
12203034Sdougm 			if (resource != NULL && strlen(resource) > 0) {
12213034Sdougm 			    (void) printf("%s=%s", resource, sharepath);
12223034Sdougm 			} else {
12233034Sdougm 			    (void) printf("%s", sharepath);
12243034Sdougm 			}
12253034Sdougm 			if (resource != NULL)
12263034Sdougm 			    sa_free_attr_string(resource);
12273034Sdougm 			if (properties)
12283034Sdougm 			    show_properties(share, NULL, "\t");
12293034Sdougm 			if (description != NULL) {
12303034Sdougm 			    if (strlen(description) > 0) {
12313034Sdougm 				(void) printf("\t\"%s\"", description);
12323034Sdougm 			    }
12333034Sdougm 			    sa_free_share_description(description);
12343034Sdougm 			}
12353034Sdougm 			if (type != NULL)
12363034Sdougm 			    sa_free_attr_string(type);
12373034Sdougm 		    } else {
12383034Sdougm 			(void) printf("\t%s", sharepath);
12393034Sdougm 			if (properties)
12403034Sdougm 			    show_properties(share, NULL, "\t");
12413034Sdougm 		    }
12423034Sdougm 		    (void) printf("\n");
12433034Sdougm 		    sa_free_attr_string(sharepath);
12443034Sdougm 		}
12453034Sdougm 	    }
12463034Sdougm 	}
12473034Sdougm 	if (groupname != NULL) {
12483034Sdougm 		sa_free_attr_string(groupname);
12493034Sdougm 	}
12503034Sdougm }
12513034Sdougm 
12523034Sdougm /*
12533034Sdougm  * show_group_xml_init()
12543034Sdougm  *
12553034Sdougm  * Create an XML document that will be used to display config info via
12563034Sdougm  * XML format.
12573034Sdougm  */
12583034Sdougm 
12593034Sdougm xmlDocPtr
12603034Sdougm show_group_xml_init()
12613034Sdougm {
12623034Sdougm 	xmlDocPtr doc;
12633034Sdougm 	xmlNodePtr root;
12643034Sdougm 
12653034Sdougm 	doc = xmlNewDoc((xmlChar *)"1.0");
12663034Sdougm 	if (doc != NULL) {
12673034Sdougm 	    root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
12683034Sdougm 	    if (root != NULL)
12693034Sdougm 		xmlDocSetRootElement(doc, root);
12703034Sdougm 	}
12713034Sdougm 	return (doc);
12723034Sdougm }
12733034Sdougm 
12743034Sdougm /*
12753034Sdougm  * show_group_xml(doc, group)
12763034Sdougm  *
12773034Sdougm  * Copy the group info into the XML doc.
12783034Sdougm  */
12793034Sdougm 
12803034Sdougm static void
12813034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group)
12823034Sdougm {
12833034Sdougm 	xmlNodePtr node;
12843034Sdougm 	xmlNodePtr root;
12853034Sdougm 
12863034Sdougm 	root = xmlDocGetRootElement(doc);
12873034Sdougm 	node = xmlCopyNode((xmlNodePtr)group, 1);
12883034Sdougm 	if (node != NULL && root != NULL) {
12893034Sdougm 	    xmlAddChild(root, node);
12903034Sdougm 		/*
12913034Sdougm 		 * In the future, we may have interally used tags that
12923034Sdougm 		 * should not appear in the XML output. Remove
12933034Sdougm 		 * anything we don't want to show here.
12943034Sdougm 		 */
12953034Sdougm 	}
12963034Sdougm }
12973034Sdougm 
12983034Sdougm /*
12993034Sdougm  * sa_show(flags, argc, argv)
13003034Sdougm  *
13013034Sdougm  * Implements the show subcommand.
13023034Sdougm  */
13033034Sdougm 
13043034Sdougm int
1305*3910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
13063034Sdougm {
13073034Sdougm 	sa_group_t group;
13083034Sdougm 	int verbose = 0;
13093034Sdougm 	int properties = 0;
13103034Sdougm 	int c;
13113034Sdougm 	int ret = SA_OK;
13123034Sdougm 	char *protocol = NULL;
13133034Sdougm 	int xml = 0;
13143034Sdougm 	xmlDocPtr doc;
13153034Sdougm #ifdef lint
13163034Sdougm 	flags = flags;
13173034Sdougm #endif
13183034Sdougm 
13193034Sdougm 	while ((c = getopt(argc, argv, "?hvP:px")) !=	EOF) {
13203034Sdougm 	    switch (c) {
13213034Sdougm 	    case 'v':
13223034Sdougm 		verbose++;
13233034Sdougm 		break;
13243034Sdougm 	    case 'p':
13253034Sdougm 		properties++;
13263034Sdougm 		break;
13273034Sdougm 	    case 'P':
13283034Sdougm 		protocol = optarg;
13293034Sdougm 		if (!sa_valid_protocol(protocol)) {
13303034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
13313034Sdougm 					protocol);
13323034Sdougm 		    return (SA_INVALID_PROTOCOL);
13333034Sdougm 		}
13343034Sdougm 		break;
13353034Sdougm 	    case 'x':
13363034Sdougm 		xml++;
13373034Sdougm 		break;
13383034Sdougm 	    default:
13393034Sdougm 	    case 'h':
13403034Sdougm 	    case '?':
13413034Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SHOW));
13423034Sdougm 		return (0);
13433034Sdougm 	    }
13443034Sdougm 	}
13453034Sdougm 
13463034Sdougm 	if (xml) {
13473034Sdougm 	    doc = show_group_xml_init();
13483034Sdougm 	    if (doc == NULL)
13493034Sdougm 		ret = SA_NO_MEMORY;
13503034Sdougm 	}
13513034Sdougm 
13523034Sdougm 	if (optind == argc) {
13533034Sdougm 	    /* no group specified so go through them all */
1354*3910Sdougm 	    for (group = sa_get_group(handle, NULL); group != NULL;
13553034Sdougm 		group = sa_get_next_group(group)) {
13563034Sdougm 		/*
13573034Sdougm 		 * have a group so check if one we want and then list
13583034Sdougm 		 * contents with appropriate options.
13593034Sdougm 		 */
13603034Sdougm 		if (xml)
13613034Sdougm 		    show_group_xml(doc, group);
13623034Sdougm 		else
13633034Sdougm 		    show_group(group, verbose, properties, protocol, NULL);
13643034Sdougm 	    }
13653034Sdougm 	} else {
13663034Sdougm 	    /* have a specified list of groups */
13673034Sdougm 	    for (; optind < argc; optind++) {
1368*3910Sdougm 		group = sa_get_group(handle, argv[optind]);
13693034Sdougm 		if (group != NULL) {
13703034Sdougm 		    if (xml)
13713034Sdougm 			show_group_xml(doc, group);
13723034Sdougm 		    else
13733034Sdougm 			show_group(group, verbose, properties, protocol, NULL);
13743034Sdougm 		} else {
13753034Sdougm 		    (void) printf(gettext("%s: not found\n"), argv[optind]);
13763034Sdougm 		    ret = SA_NO_SUCH_GROUP;
13773034Sdougm 		}
13783034Sdougm 	    }
13793034Sdougm 	}
13803034Sdougm 	if (xml && ret == SA_OK) {
13813034Sdougm 	    xmlDocFormatDump(stdout, doc, 1);
13823034Sdougm 	    xmlFreeDoc(doc);
13833034Sdougm 	}
13843034Sdougm 	return (ret);
13853034Sdougm 
13863034Sdougm }
13873034Sdougm 
13883034Sdougm /*
13893034Sdougm  * enable_share(group, share, update_legacy)
13903034Sdougm  *
13913034Sdougm  * helper function to enable a share if the group is enabled.
13923034Sdougm  */
13933034Sdougm 
13943034Sdougm static int
1395*3910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
1396*3910Sdougm 		int update_legacy)
13973034Sdougm {
13983034Sdougm 	char *value;
13993034Sdougm 	int enabled;
14003034Sdougm 	sa_optionset_t optionset;
14013034Sdougm 	int ret = SA_OK;
14023034Sdougm 	char *zfs = NULL;
14033034Sdougm 	int iszfs = 0;
14043034Sdougm 
14053034Sdougm 	/*
14063034Sdougm 	 * need to enable this share if the group is enabled but not
14073034Sdougm 	 * otherwise. The enable is also done on each protocol
14083034Sdougm 	 * represented in the group.
14093034Sdougm 	 */
14103034Sdougm 	value = sa_get_group_attr(group, "state");
14113034Sdougm 	enabled = value != NULL && strcmp(value, "enabled") == 0;
14123034Sdougm 	if (value != NULL)
14133034Sdougm 	    sa_free_attr_string(value);
14143034Sdougm 	/* remove legacy config if necessary */
14153034Sdougm 	if (update_legacy)
14163034Sdougm 	    ret = sa_delete_legacy(share);
14173034Sdougm 	zfs = sa_get_group_attr(group, "zfs");
14183034Sdougm 	if (zfs != NULL) {
14193034Sdougm 	    iszfs++;
14203034Sdougm 	    sa_free_attr_string(zfs);
14213034Sdougm 	}
14223034Sdougm 
14233034Sdougm 	/*
14243034Sdougm 	 * Step through each optionset at the group level and
14253034Sdougm 	 * enable the share based on the protocol type. This
14263034Sdougm 	 * works because protocols must be set on the group
14273034Sdougm 	 * for the protocol to be enabled.
14283034Sdougm 	 */
14293034Sdougm 	for (optionset = sa_get_optionset(group, NULL);
14303034Sdougm 	    optionset != NULL && ret == SA_OK;
14313034Sdougm 	    optionset = sa_get_next_optionset(optionset)) {
14323034Sdougm 	    value = sa_get_optionset_attr(optionset, "type");
14333034Sdougm 	    if (value != NULL) {
14343034Sdougm 		if (enabled)
14353034Sdougm 		    ret = sa_enable_share(share, value);
14363034Sdougm 		if (update_legacy && !iszfs)
14373034Sdougm 		    (void) sa_update_legacy(share, value);
14383034Sdougm 		sa_free_attr_string(value);
14393034Sdougm 	    }
14403034Sdougm 	}
14413034Sdougm 	if (ret == SA_OK)
1442*3910Sdougm 	    (void) sa_update_config(handle);
14433034Sdougm 	return (ret);
14443034Sdougm }
14453034Sdougm 
14463034Sdougm /*
14473034Sdougm  * sa_addshare(flags, argc, argv)
14483034Sdougm  *
14493034Sdougm  * implements add-share subcommand.
14503034Sdougm  */
14513034Sdougm 
14523034Sdougm int
1453*3910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
14543034Sdougm {
14553034Sdougm 	int verbose = 0;
14563034Sdougm 	int dryrun = 0;
14573034Sdougm 	int c;
14583034Sdougm 	int ret = SA_OK;
14593034Sdougm 	sa_group_t group;
14603034Sdougm 	sa_share_t share;
14613034Sdougm 	char *sharepath = NULL;
14623034Sdougm 	char *description = NULL;
14633034Sdougm 	char *resource = NULL;
14643034Sdougm 	int persist = SA_SHARE_PERMANENT; /* default to persist */
14653034Sdougm 	int auth;
14663034Sdougm 	char dir[MAXPATHLEN];
14673034Sdougm 
14683034Sdougm 	while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
14693034Sdougm 	    switch (c) {
14703034Sdougm 	    case 'n':
14713034Sdougm 		dryrun++;
14723034Sdougm 		break;
14733034Sdougm 	    case 'v':
14743034Sdougm 		verbose++;
14753034Sdougm 		break;
14763034Sdougm 	    case 'd':
14773034Sdougm 		description = optarg;
14783034Sdougm 		break;
14793034Sdougm 	    case 'r':
14803034Sdougm 		resource = optarg;
14813034Sdougm 		break;
14823034Sdougm 	    case 's':
14833034Sdougm 		/*
14843034Sdougm 		 * save share path into group. Currently limit
14853034Sdougm 		 * to one share per command.
14863034Sdougm 		 */
14873034Sdougm 		if (sharepath != NULL) {
14883034Sdougm 		    (void) printf(gettext("Adding multiple shares not"
14893034Sdougm 				    "supported\n"));
14903034Sdougm 		    return (1);
14913034Sdougm 		}
14923034Sdougm 		sharepath = optarg;
14933034Sdougm 		break;
14943034Sdougm 	    case 't':
14953034Sdougm 		persist = SA_SHARE_TRANSIENT;
14963034Sdougm 		break;
14973034Sdougm 	    default:
14983034Sdougm 	    case 'h':
14993034Sdougm 	    case '?':
15003034Sdougm 		(void) printf(gettext("usage: %s\n"),
15013034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15023034Sdougm 		return (0);
15033034Sdougm 	    }
15043034Sdougm 	}
15053034Sdougm 
15063034Sdougm 	if (optind >= argc) {
15073034Sdougm 	    (void) printf(gettext("usage: %s\n"),
15083034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15093034Sdougm 	    if (dryrun || sharepath != NULL || description != NULL ||
15103034Sdougm 		resource != NULL || verbose || persist) {
15113034Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
15123034Sdougm 		ret = SA_NO_SUCH_GROUP;
15133034Sdougm 	    } else {
15143034Sdougm 		ret = SA_OK;
15153034Sdougm 	    }
15163034Sdougm 	} else {
15173034Sdougm 	    if (sharepath == NULL) {
15183034Sdougm 		(void) printf(gettext("usage: %s\n"),
15193034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15203034Sdougm 		(void) printf(gettext("\t-s sharepath must be specified\n"));
15213034Sdougm 		ret = SA_BAD_PATH;
15223034Sdougm 	    }
15233034Sdougm 	    if (ret == SA_OK) {
15243034Sdougm 		if (realpath(sharepath, dir) == NULL) {
15253034Sdougm 		    ret = SA_BAD_PATH;
15263034Sdougm 		    (void) printf(gettext("Path is not valid: %s\n"),
15273034Sdougm 					sharepath);
15283034Sdougm 		} else {
15293034Sdougm 		    sharepath = dir;
15303034Sdougm 		}
15313034Sdougm 	    }
15323034Sdougm 	    if (ret == SA_OK && resource != NULL) {
15333034Sdougm 		/* check for valid syntax */
15343034Sdougm 		if (strpbrk(resource, " \t/") != NULL) {
15353034Sdougm 		    (void) printf(gettext("usage: %s\n"),
15363034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15373034Sdougm 		    (void) printf(gettext("\tresource must not contain white"
15383034Sdougm 				    "space or '/' characters\n"));
15393034Sdougm 		    ret = SA_BAD_PATH;
15403034Sdougm 		}
15413034Sdougm 	    }
15423034Sdougm 	    if (ret == SA_OK) {
1543*3910Sdougm 		group = sa_get_group(handle, argv[optind]);
15443034Sdougm 		if (group != NULL) {
15453034Sdougm 		    auth = check_authorizations(argv[optind], flags);
1546*3910Sdougm 		    share = sa_find_share(handle, sharepath);
15473034Sdougm 		    if (share != NULL) {
15483034Sdougm 			group = sa_get_parent_group(share);
15493034Sdougm 			if (group != NULL) {
15503034Sdougm 			    char *groupname;
15513034Sdougm 			    groupname = sa_get_group_attr(group, "name");
15523034Sdougm 			    if (groupname != NULL) {
15533034Sdougm 				(void) printf(gettext("Share path already "
15543034Sdougm 							"shared in group "
15553034Sdougm 							"\"%s\": %s\n"),
15563034Sdougm 						groupname, sharepath);
15573034Sdougm 				sa_free_attr_string(groupname);
15583034Sdougm 			    } else {
15593034Sdougm 				(void) printf(gettext("Share path already"
15603034Sdougm 							"shared: %s\n"),
15613034Sdougm 						groupname, sharepath);
15623034Sdougm 			    }
15633034Sdougm 			} else {
15643034Sdougm 			    (void) printf(gettext("Share path %s already "
15653034Sdougm 							"shared\n"),
15663034Sdougm 				    sharepath);
15673034Sdougm 			}
15683034Sdougm 			ret = SA_DUPLICATE_NAME;
15693034Sdougm 		    } else {
15703034Sdougm 			/*
15713034Sdougm 			 * need to check that resource name is unique
15723348Sdougm 			 * at some point. Path checking should use the
15733348Sdougm 			 * "normal" rules which don't check the repository.
15743034Sdougm 			 */
15753034Sdougm 			if (dryrun)
15763348Sdougm 			    ret = sa_check_path(group, sharepath,
15773348Sdougm 						SA_CHECK_NORMAL);
15783034Sdougm 			else
15793034Sdougm 			    share = sa_add_share(group, sharepath,
15803034Sdougm 							persist, &ret);
15813034Sdougm 			if (!dryrun && share == NULL) {
15823034Sdougm 				(void) printf(gettext("Could not add share: "
15833034Sdougm 							"%s\n"),
15843034Sdougm 					sa_errorstr(ret));
15853034Sdougm 			} else {
15863034Sdougm 			    if (!dryrun && ret == SA_OK) {
15873034Sdougm 				if (resource != NULL) {
15883034Sdougm 				    if (strpbrk(resource, " \t/") == NULL) {
15893034Sdougm 					ret = sa_set_share_attr(share,
15903034Sdougm 								"resource",
15913034Sdougm 								resource);
15923034Sdougm 				    }
15933034Sdougm 				}
15943034Sdougm 				if (ret == SA_OK && description != NULL) {
15953034Sdougm 				    ret = sa_set_share_description(share,
15963034Sdougm 							    description);
15973034Sdougm 				}
15983034Sdougm 				if (ret == SA_OK) {
15993034Sdougm 				    /* now enable the share(s) */
1600*3910Sdougm 				    ret = enable_share(handle, group, share, 1);
1601*3910Sdougm 				    ret = sa_update_config(handle);
16023034Sdougm 				}
16033034Sdougm 				switch (ret) {
16043034Sdougm 				case SA_DUPLICATE_NAME:
16053034Sdougm 				    (void) printf(gettext("Resource name in"
16063034Sdougm 						    "use: %s\n"),
16073034Sdougm 					    resource);
16083034Sdougm 				    break;
16093034Sdougm 				default:
16103034Sdougm 				    (void) printf(gettext("Could not set "
16113034Sdougm 						    "attribute: %s\n"),
16123034Sdougm 					    sa_errorstr(ret));
16133034Sdougm 				    break;
16143034Sdougm 				case SA_OK:
16153034Sdougm 				    break;
16163034Sdougm 				}
16173034Sdougm 			    } else if (dryrun && ret == SA_OK &&
16183034Sdougm 					!auth && verbose) {
16193034Sdougm 				(void) printf(gettext("Command would fail: "
16203034Sdougm 							"%s\n"),
16213034Sdougm 					sa_errorstr(SA_NO_PERMISSION));
16223034Sdougm 				ret = SA_NO_PERMISSION;
16233034Sdougm 			    }
16243034Sdougm 			}
16253034Sdougm 		    }
16263034Sdougm 		} else {
16273034Sdougm 		    (void) printf(gettext("Group \"%s\" not found\n"),
16283034Sdougm 					argv[optind]);
16293034Sdougm 		    ret = SA_NO_SUCH_GROUP;
16303034Sdougm 		}
16313034Sdougm 	    }
16323034Sdougm 	}
16333034Sdougm 	return (ret);
16343034Sdougm }
16353034Sdougm 
16363034Sdougm /*
16373034Sdougm  * sa_moveshare(flags, argc, argv)
16383034Sdougm  *
16393034Sdougm  * implements move-share subcommand.
16403034Sdougm  */
16413034Sdougm 
16423034Sdougm int
1643*3910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
16443034Sdougm {
16453034Sdougm 	int verbose = 0;
16463034Sdougm 	int dryrun = 0;
16473034Sdougm 	int c;
16483034Sdougm 	int ret = SA_OK;
16493034Sdougm 	sa_group_t group;
16503034Sdougm 	sa_share_t share;
16513034Sdougm 	char *sharepath = NULL;
16523034Sdougm 	int authsrc = 0, authdst = 0;
16533034Sdougm 
16543034Sdougm 	while ((c = getopt(argc, argv, "?hvns:")) != EOF) {
16553034Sdougm 	    switch (c) {
16563034Sdougm 	    case 'n':
16573034Sdougm 		dryrun++;
16583034Sdougm 		break;
16593034Sdougm 	    case 'v':
16603034Sdougm 		verbose++;
16613034Sdougm 		break;
16623034Sdougm 	    case 's':
16633034Sdougm 		/*
16643034Sdougm 		 * remove share path from group. Currently limit
16653034Sdougm 		 * to one share per command.
16663034Sdougm 		 */
16673034Sdougm 		if (sharepath != NULL) {
16683034Sdougm 		    (void) printf(gettext("Moving multiple shares not"
16693034Sdougm 				    "supported\n"));
16703034Sdougm 		    return (SA_BAD_PATH);
16713034Sdougm 		}
16723034Sdougm 		sharepath = optarg;
16733034Sdougm 		break;
16743034Sdougm 	    default:
16753034Sdougm 	    case 'h':
16763034Sdougm 	    case '?':
16773034Sdougm 		(void) printf(gettext("usage: %s\n"),
16783034Sdougm 				sa_get_usage(USAGE_MOVE_SHARE));
16793034Sdougm 		return (0);
16803034Sdougm 	    }
16813034Sdougm 	}
16823034Sdougm 
16833034Sdougm 	if (optind >= argc || sharepath == NULL) {
16843034Sdougm 			(void) printf(gettext("usage: %s\n"),
16853034Sdougm 				sa_get_usage(USAGE_MOVE_SHARE));
16863034Sdougm 	    if (dryrun || verbose || sharepath != NULL) {
16873034Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
16883034Sdougm 		ret = SA_NO_SUCH_GROUP;
16893034Sdougm 	    } else {
16903034Sdougm 		if (sharepath == NULL) {
16913034Sdougm 		    ret = SA_SYNTAX_ERR;
16923034Sdougm 		    (void) printf(gettext("\tsharepath must be specified\n"));
16933034Sdougm 		} else
16943034Sdougm 		    ret = SA_OK;
16953034Sdougm 	    }
16963034Sdougm 	} else {
16973034Sdougm 	    if (sharepath == NULL) {
16983034Sdougm 		(void) printf(gettext("sharepath must be specified with "
16993034Sdougm 				"the -s option\n"));
17003034Sdougm 		ret = SA_BAD_PATH;
17013034Sdougm 	    } else {
1702*3910Sdougm 		group = sa_get_group(handle, argv[optind]);
17033034Sdougm 		if (group != NULL) {
1704*3910Sdougm 		    share = sa_find_share(handle, sharepath);
17053034Sdougm 		    authdst = check_authorizations(argv[optind], flags);
17063034Sdougm 		    if (share == NULL) {
17073034Sdougm 			(void) printf(gettext("Share not found: %s\n"),
17083034Sdougm 					sharepath);
17093034Sdougm 			ret = SA_NO_SUCH_PATH;
17103034Sdougm 		    } else {
17113034Sdougm 			sa_group_t parent;
17123034Sdougm 			char *zfsold;
17133034Sdougm 			char *zfsnew;
17143034Sdougm 
17153034Sdougm 			parent = sa_get_parent_group(share);
17163034Sdougm 			if (parent != NULL) {
17173034Sdougm 			    char *pname;
17183034Sdougm 			    pname = sa_get_group_attr(parent, "name");
17193034Sdougm 			    if (pname != NULL) {
17203034Sdougm 				authsrc = check_authorizations(pname, flags);
17213034Sdougm 				sa_free_attr_string(pname);
17223034Sdougm 			    }
17233034Sdougm 			    zfsold = sa_get_group_attr(parent, "zfs");
17243034Sdougm 			    zfsnew = sa_get_group_attr(group, "zfs");
17253034Sdougm 			    if ((zfsold != NULL && zfsnew == NULL) ||
17263034Sdougm 				(zfsold == NULL && zfsnew != NULL)) {
17273034Sdougm 				ret = SA_NOT_ALLOWED;
17283034Sdougm 			    }
17293034Sdougm 			    if (zfsold != NULL)
17303034Sdougm 				sa_free_attr_string(zfsold);
17313034Sdougm 			    if (zfsnew != NULL)
17323034Sdougm 				sa_free_attr_string(zfsnew);
17333034Sdougm 			}
17343034Sdougm 			if (!dryrun && ret == SA_OK) {
17353034Sdougm 			    ret = sa_move_share(group, share);
17363034Sdougm 			}
17373034Sdougm 			if (ret == SA_OK && parent != group && !dryrun) {
17383034Sdougm 			    char *oldstate;
1739*3910Sdougm 			    ret = sa_update_config(handle);
17403034Sdougm 				/*
17413034Sdougm 				 * note that the share may need to be
17423034Sdougm 				 * "unshared" if the new group is
17433034Sdougm 				 * disabled and the old was enabled or
17443034Sdougm 				 * it may need to be share to update
17453034Sdougm 				 * if the new group is enabled.
17463034Sdougm 				 */
17473034Sdougm 			    oldstate = sa_get_group_attr(parent, "state");
17483034Sdougm 			    /* enable_share determines what to do */
17493034Sdougm 			    if (strcmp(oldstate, "enabled") == 0) {
17503034Sdougm 				(void) sa_disable_share(share, NULL);
17513034Sdougm 			    }
1752*3910Sdougm 			    (void) enable_share(handle, group, share, 1);
17533034Sdougm 			    if (oldstate != NULL)
17543034Sdougm 				sa_free_attr_string(oldstate);
17553034Sdougm 			}
17563034Sdougm 			if (ret != SA_OK) {
17573034Sdougm 			    (void) printf(gettext("Could not move share: %s\n"),
17583034Sdougm 				    sa_errorstr(ret));
17593034Sdougm 			}
17603034Sdougm 			if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
17613034Sdougm 			    verbose) {
17623034Sdougm 			    (void) printf(gettext("Command would fail: %s\n"),
17633034Sdougm 					sa_errorstr(SA_NO_PERMISSION));
17643034Sdougm 			}
17653034Sdougm 		    }
17663034Sdougm 		} else {
17673034Sdougm 		    (void) printf(gettext("Group \"%s\" not found\n"),
17683034Sdougm 					argv[optind]);
17693034Sdougm 		    ret = SA_NO_SUCH_GROUP;
17703034Sdougm 		}
17713034Sdougm 	    }
17723034Sdougm 	}
17733034Sdougm 	return (ret);
17743034Sdougm }
17753034Sdougm 
17763034Sdougm /*
17773034Sdougm  * sa_removeshare(flags, argc, argv)
17783034Sdougm  *
17793034Sdougm  * implements remove-share subcommand.
17803034Sdougm  */
17813034Sdougm 
17823034Sdougm int
1783*3910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
17843034Sdougm {
17853034Sdougm 	int verbose = 0;
17863034Sdougm 	int dryrun = 0;
17873034Sdougm 	int force = 0;
17883034Sdougm 	int c;
17893034Sdougm 	int ret = SA_OK;
17903034Sdougm 	sa_group_t group;
17913034Sdougm 	sa_share_t share;
17923034Sdougm 	char *sharepath = NULL;
17933034Sdougm 	char dir[MAXPATHLEN];
17943034Sdougm 	int auth;
17953034Sdougm 
17963034Sdougm 	while ((c = getopt(argc, argv, "?hfns:v")) != EOF) {
17973034Sdougm 	    switch (c) {
17983034Sdougm 	    case 'n':
17993034Sdougm 		dryrun++;
18003034Sdougm 		break;
18013034Sdougm 	    case 'v':
18023034Sdougm 		verbose++;
18033034Sdougm 		break;
18043034Sdougm 	    case 'f':
18053034Sdougm 		force++;
18063034Sdougm 		break;
18073034Sdougm 	    case 's':
18083034Sdougm 		/*
18093034Sdougm 		 * remove share path from group. Currently limit
18103034Sdougm 		 * to one share per command.
18113034Sdougm 		 */
18123034Sdougm 		if (sharepath != NULL) {
18133034Sdougm 		    (void) printf(gettext("Removing multiple shares not"
18143034Sdougm 				    "supported\n"));
18153034Sdougm 		    return (SA_SYNTAX_ERR);
18163034Sdougm 		}
18173034Sdougm 		sharepath = optarg;
18183034Sdougm 		break;
18193034Sdougm 	    default:
18203034Sdougm 	    case 'h':
18213034Sdougm 	    case '?':
18223034Sdougm 		(void) printf(gettext("usage: %s\n"),
18233034Sdougm 				sa_get_usage(USAGE_REMOVE_SHARE));
18243034Sdougm 		return (0);
18253034Sdougm 	    }
18263034Sdougm 	}
18273034Sdougm 
18283034Sdougm 	if (optind >= argc || sharepath == NULL) {
18293034Sdougm 	    if (sharepath == NULL) {
18303034Sdougm 			(void) printf(gettext("usage: %s\n"),
18313034Sdougm 				sa_get_usage(USAGE_REMOVE_SHARE));
18323034Sdougm 		(void) printf(gettext("\t-s sharepath must be specified\n"));
18333034Sdougm 		ret = SA_BAD_PATH;
18343034Sdougm 	    } else {
18353034Sdougm 		ret = SA_OK;
18363034Sdougm 	    }
18373034Sdougm 	}
18383034Sdougm 	if (ret == SA_OK) {
18393034Sdougm 	    if (optind < argc) {
18403034Sdougm 		if ((optind + 1) < argc) {
18413034Sdougm 		    (void) printf(gettext("Extraneous group(s) at end of "
18423034Sdougm 						"command\n"));
18433034Sdougm 		    ret = SA_SYNTAX_ERR;
18443034Sdougm 		} else {
1845*3910Sdougm 		    group = sa_get_group(handle, argv[optind]);
18463034Sdougm 		    if (group == NULL) {
18473034Sdougm 			(void) printf(gettext("Group \"%s\" not found\n"),
18483034Sdougm 					argv[optind]);
18493034Sdougm 			ret = SA_NO_SUCH_GROUP;
18503034Sdougm 		    }
18513034Sdougm 		}
18523034Sdougm 	    } else {
18533034Sdougm 		group = NULL;
18543034Sdougm 	    }
18553663Sdougm 
18563663Sdougm 		/*
18573663Sdougm 		 * Lookup the path in the internal configuration. Care
18583663Sdougm 		 * must be taken to handle the case where the
18593663Sdougm 		 * underlying path has been removed since we need to
18603663Sdougm 		 * be able to deal with that as well.
18613663Sdougm 		 */
18623034Sdougm 	    if (ret == SA_OK) {
18633034Sdougm 		if (group != NULL)
18643034Sdougm 		    share = sa_get_share(group, sharepath);
18653034Sdougm 		else
1866*3910Sdougm 		    share = sa_find_share(handle, sharepath);
18673663Sdougm 		/*
18683663Sdougm 		 * If we didn't find the share with the provided path,
18693663Sdougm 		 * it may be a symlink so attempt to resolve it using
18703663Sdougm 		 * realpath and try again. Realpath will resolve any
18713663Sdougm 		 * symlinks and place them in "dir". Note that
18723663Sdougm 		 * sharepath is only used for the lookup the first
18733663Sdougm 		 * time and later for error messages. dir will be used
18743663Sdougm 		 * on the second attempt. Once a share is found, all
18753663Sdougm 		 * operations are based off of the share variable.
18763663Sdougm 		 */
18773663Sdougm 		if (share == NULL) {
18783663Sdougm 		    if (realpath(sharepath, dir) == NULL) {
18793663Sdougm 			ret = SA_BAD_PATH;
18803663Sdougm 			(void) printf(gettext("Path is not valid: %s\n"),
18813663Sdougm 						sharepath);
18823663Sdougm 		    } else {
18833663Sdougm 			if (group != NULL)
18843663Sdougm 			    share = sa_get_share(group, dir);
18853663Sdougm 			else
1886*3910Sdougm 			    share = sa_find_share(handle, dir);
18873663Sdougm 		    }
18883663Sdougm 		}
18893663Sdougm 	    }
18903663Sdougm 
18913663Sdougm 		/*
18923663Sdougm 		 * If there hasn't been an error, there was likely a
18933663Sdougm 		 * path found. If not, give the appropriate error
18943663Sdougm 		 * message and set the return error. If it was found,
18953663Sdougm 		 * then disable the share and then remove it from the
18963663Sdougm 		 * configuration.
18973663Sdougm 		 */
18983663Sdougm 	    if (ret == SA_OK) {
18993034Sdougm 		if (share == NULL) {
19003034Sdougm 		    if (group != NULL)
19013034Sdougm 			(void) printf(gettext("Share not found in group %s:"
19023663Sdougm 						" %s\n"),
19033034Sdougm 					argv[optind], sharepath);
19043034Sdougm 		    else
19053034Sdougm 			(void) printf(gettext("Share not found: %s\n"),
19063034Sdougm 					sharepath);
19073034Sdougm 		    ret = SA_NO_SUCH_PATH;
19083034Sdougm 		} else {
19093034Sdougm 		    if (group == NULL)
19103034Sdougm 			group = sa_get_parent_group(share);
19113034Sdougm 		    if (!dryrun) {
19123034Sdougm 			if (ret == SA_OK) {
19133034Sdougm 			    ret = sa_disable_share(share, NULL);
19143034Sdougm 				/*
19153034Sdougm 				 * we don't care if it fails since it
19163663Sdougm 				 * could be disabled already. Some
19173663Sdougm 				 * unexpected errors could occur that
19183663Sdougm 				 * prevent removal, so also check for
19193663Sdougm 				 * force being set.
19203034Sdougm 				 */
19213034Sdougm 			    if (ret == SA_OK || ret == SA_NO_SUCH_PATH ||
19223663Sdougm 					ret == SA_NOT_SUPPORTED ||
19233663Sdougm 					ret == SA_SYSTEM_ERR || force) {
19243034Sdougm 				ret = sa_remove_share(share);
19253034Sdougm 			    }
19263034Sdougm 			    if (ret == SA_OK)
1927*3910Sdougm 				ret = sa_update_config(handle);
19283034Sdougm 			}
19293034Sdougm 			if (ret != SA_OK) {
19303034Sdougm 			    (void) printf(gettext("Could not remove share:"
19313034Sdougm 							" %s\n"),
19323034Sdougm 					sa_errorstr(ret));
19333034Sdougm 			}
19343034Sdougm 		    } else if (ret == SA_OK) {
19353034Sdougm 			char *pname;
19363034Sdougm 			pname = sa_get_group_attr(group, "name");
19373034Sdougm 			if (pname != NULL) {
19383034Sdougm 			    auth = check_authorizations(pname, flags);
19393034Sdougm 			    sa_free_attr_string(pname);
19403034Sdougm 			}
19413034Sdougm 			if (!auth && verbose) {
19423034Sdougm 			    (void) printf(gettext("Command would fail: %s\n"),
19433034Sdougm 					sa_errorstr(SA_NO_PERMISSION));
19443034Sdougm 			}
19453034Sdougm 		    }
19463034Sdougm 		}
19473034Sdougm 	    }
19483034Sdougm 	}
19493034Sdougm 	return (ret);
19503034Sdougm }
19513034Sdougm 
19523034Sdougm /*
19533034Sdougm  * sa_set_share(flags, argc, argv)
19543034Sdougm  *
19553034Sdougm  * implements set-share subcommand.
19563034Sdougm  */
19573034Sdougm 
19583034Sdougm int
1959*3910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
19603034Sdougm {
19613034Sdougm 	int dryrun = 0;
19623034Sdougm 	int c;
19633034Sdougm 	int ret = SA_OK;
19643034Sdougm 	sa_group_t group, sharegroup;
19653034Sdougm 	sa_share_t share;
19663034Sdougm 	char *sharepath = NULL;
19673034Sdougm 	char *description = NULL;
19683034Sdougm 	char *resource = NULL;
19693034Sdougm 	int auth;
19703034Sdougm 	int verbose = 0;
19713034Sdougm 
19723034Sdougm 	while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
19733034Sdougm 	    switch (c) {
19743034Sdougm 	    case 'n':
19753034Sdougm 		dryrun++;
19763034Sdougm 		break;
19773034Sdougm 	    case 'd':
19783034Sdougm 		description = optarg;
19793034Sdougm 		break;
19803034Sdougm 	    case 'r':
19813034Sdougm 		resource = optarg;
19823034Sdougm 		break;
19833034Sdougm 	    case 'v':
19843034Sdougm 		verbose++;
19853034Sdougm 		break;
19863034Sdougm 	    case 's':
19873034Sdougm 		/*
19883034Sdougm 		 * save share path into group. Currently limit
19893034Sdougm 		 * to one share per command.
19903034Sdougm 		 */
19913034Sdougm 		if (sharepath != NULL) {
19923034Sdougm 		    (void) printf(gettext("Updating multiple shares not"
19933034Sdougm 				    "supported\n"));
19943034Sdougm 		    return (SA_BAD_PATH);
19953034Sdougm 		}
19963034Sdougm 		sharepath = optarg;
19973034Sdougm 		break;
19983034Sdougm 	    default:
19993034Sdougm 	    case 'h':
20003034Sdougm 	    case '?':
20013034Sdougm 		(void) printf(gettext("usage: %s\n"),
20023034Sdougm 				sa_get_usage(USAGE_SET_SHARE));
20033034Sdougm 		return (SA_OK);
20043034Sdougm 	    }
20053034Sdougm 	}
20063034Sdougm 	if (optind >= argc || sharepath == NULL) {
20073034Sdougm 	    if (sharepath == NULL) {
20083034Sdougm 		(void) printf(gettext("usage: %s\n"),
20093034Sdougm 				sa_get_usage(USAGE_SET_SHARE));
20103034Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
20113034Sdougm 	    ret = SA_BAD_PATH;
20123034Sdougm 	    } else {
20133034Sdougm 		ret = SA_OK;
20143034Sdougm 	    }
20153034Sdougm 	}
20163034Sdougm 	if ((optind + 1) < argc) {
20173034Sdougm 	    (void) printf(gettext("usage: %s\n"),
20183034Sdougm 				sa_get_usage(USAGE_SET_SHARE));
20193034Sdougm 	    (void) printf(gettext("\tExtraneous group(s) at end\n"));
20203034Sdougm 	    ret = SA_SYNTAX_ERR;
20213034Sdougm 	}
20223034Sdougm 	if (ret == SA_OK) {
20233034Sdougm 	    char *groupname;
20243034Sdougm 	    if (optind < argc) {
20253034Sdougm 		groupname = argv[optind];
2026*3910Sdougm 		group = sa_get_group(handle, groupname);
20273034Sdougm 	    } else {
20283034Sdougm 		group = NULL;
20293034Sdougm 		groupname = NULL;
20303034Sdougm 	    }
2031*3910Sdougm 	    share = sa_find_share(handle, sharepath);
20323034Sdougm 	    if (share != NULL) {
20333034Sdougm 		sharegroup = sa_get_parent_group(share);
20343034Sdougm 		if (group != NULL && group != sharegroup) {
20353034Sdougm 		    (void) printf(gettext("Group \"%s\" does not contain "
20363034Sdougm 						"share %s\n"),
20373034Sdougm 			    argv[optind], sharepath);
20383034Sdougm 		    ret = SA_BAD_PATH;
20393034Sdougm 		} else {
20403034Sdougm 		    int delgroupname = 0;
20413034Sdougm 		    if (groupname == NULL) {
20423034Sdougm 			groupname = sa_get_group_attr(sharegroup, "name");
20433034Sdougm 			delgroupname = 1;
20443034Sdougm 		    }
20453034Sdougm 		    if (groupname != NULL) {
20463034Sdougm 			auth = check_authorizations(groupname, flags);
20473034Sdougm 			if (delgroupname) {
20483034Sdougm 			    sa_free_attr_string(groupname);
20493034Sdougm 			    groupname = NULL;
20503034Sdougm 			}
20513034Sdougm 		    } else {
20523034Sdougm 			ret = SA_NO_MEMORY;
20533034Sdougm 		    }
20543034Sdougm 		    if (resource != NULL) {
20553034Sdougm 			if (strpbrk(resource, " \t/") == NULL) {
20563034Sdougm 			    if (!dryrun) {
20573034Sdougm 				ret = sa_set_share_attr(share, "resource",
20583034Sdougm 						    resource);
20593034Sdougm 			    } else {
20603034Sdougm 				sa_share_t resshare;
20613034Sdougm 				resshare = sa_get_resource(sharegroup,
20623034Sdougm 							    resource);
20633034Sdougm 				if (resshare != NULL && resshare != share)
20643034Sdougm 				    ret = SA_DUPLICATE_NAME;
20653034Sdougm 			    }
20663034Sdougm 			} else {
20673034Sdougm 			    ret = SA_BAD_PATH;
20683034Sdougm 			    (void) printf(gettext("Resource must not contain "
20693034Sdougm 						"white space or '/'\n"));
20703034Sdougm 			}
20713034Sdougm 		    }
20723034Sdougm 		    if (ret == SA_OK && description != NULL) {
20733034Sdougm 			ret = sa_set_share_description(share, description);
20743034Sdougm 		    }
20753034Sdougm 		}
20763034Sdougm 		if (!dryrun && ret == SA_OK) {
2077*3910Sdougm 		    ret = sa_update_config(handle);
20783034Sdougm 		}
20793034Sdougm 		switch (ret) {
20803034Sdougm 		case SA_DUPLICATE_NAME:
20813034Sdougm 		    (void) printf(gettext("Resource name in use: %s\n"),
20823034Sdougm 					resource);
20833034Sdougm 		    break;
20843034Sdougm 		default:
20853034Sdougm 		    (void) printf(gettext("Could not set attribute: %s\n"),
20863034Sdougm 			    sa_errorstr(ret));
20873034Sdougm 		    break;
20883034Sdougm 		case SA_OK:
20893034Sdougm 		    if (dryrun && !auth && verbose) {
20903034Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
20913034Sdougm 				sa_errorstr(SA_NO_PERMISSION));
20923034Sdougm 		    }
20933034Sdougm 		    break;
20943034Sdougm 		}
20953034Sdougm 	    } else {
20963034Sdougm 		(void) printf(gettext("Share path \"%s\" not found\n"),
20973034Sdougm 				sharepath);
20983034Sdougm 		ret = SA_NO_SUCH_PATH;
20993034Sdougm 	    }
21003034Sdougm 	}
21013034Sdougm 	return (ret);
21023034Sdougm }
21033034Sdougm 
21043034Sdougm /*
21053034Sdougm  * add_security(group, sectype, optlist, proto, *err)
21063034Sdougm  *
21073034Sdougm  * Helper function to add a security option (named optionset) to the
21083034Sdougm  * group.
21093034Sdougm  */
21103034Sdougm 
21113034Sdougm static int
21123034Sdougm add_security(sa_group_t group, char *sectype,
21133034Sdougm 		struct options *optlist, char *proto, int *err)
21143034Sdougm {
21153034Sdougm 	sa_security_t security;
21163034Sdougm 	int ret = SA_OK;
21173034Sdougm 	int result = 0;
21183034Sdougm 
21193034Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
21203034Sdougm 	security = sa_get_security(group, sectype, proto);
21213034Sdougm 	if (security == NULL) {
21223034Sdougm 	    security = sa_create_security(group, sectype, proto);
21233034Sdougm 	}
21243034Sdougm 	if (sectype != NULL)
21253034Sdougm 	    sa_free_attr_string(sectype);
21263034Sdougm 	if (security != NULL) {
21273034Sdougm 	    while (optlist != NULL) {
21283034Sdougm 		sa_property_t prop;
21293034Sdougm 		prop = sa_get_property(security, optlist->optname);
21303034Sdougm 		if (prop == NULL) {
21313034Sdougm 			/*
21323034Sdougm 			 * add the property, but only if it is
21333034Sdougm 			 * a non-NULL or non-zero length value
21343034Sdougm 			 */
21353034Sdougm 		    if (optlist->optvalue != NULL) {
21363034Sdougm 			prop = sa_create_property(optlist->optname,
21373034Sdougm 							optlist->optvalue);
21383034Sdougm 			if (prop != NULL) {
21393034Sdougm 			    ret = sa_valid_property(security, proto, prop);
21403034Sdougm 			    if (ret != SA_OK) {
21413034Sdougm 				(void) sa_remove_property(prop);
21423034Sdougm 				(void) printf(gettext("Could not add "
21433034Sdougm 							"property %s: %s\n"),
21443034Sdougm 							optlist->optname,
21453034Sdougm 						sa_errorstr(ret));
21463034Sdougm 			    }
21473034Sdougm 			    if (ret == SA_OK) {
21483034Sdougm 				ret = sa_add_property(security, prop);
21493034Sdougm 				if (ret != SA_OK) {
21503034Sdougm 				    (void) printf(gettext("Could not add "
21513034Sdougm 						    "property (%s=%s): %s\n"),
21523034Sdougm 						optlist->optname,
21533034Sdougm 						optlist->optvalue,
21543034Sdougm 						sa_errorstr(ret));
21553034Sdougm 				} else {
21563034Sdougm 				    result = 1;
21573034Sdougm 				}
21583034Sdougm 			    }
21593034Sdougm 			}
21603034Sdougm 		    }
21613034Sdougm 		} else {
21623034Sdougm 		    ret = sa_update_property(prop, optlist->optvalue);
21633034Sdougm 		    result = 1; /* should check if really changed */
21643034Sdougm 		}
21653034Sdougm 		optlist = optlist->next;
21663034Sdougm 	    }
21673034Sdougm 		/*
21683034Sdougm 		 * when done, properties may have all been removed but
21693034Sdougm 		 * we need to keep the security type itself until
21703034Sdougm 		 * explicitly removed.
21713034Sdougm 		 */
21723034Sdougm 	    if (result)
21733034Sdougm 		ret = sa_commit_properties(security, 0);
21743034Sdougm 	}
21753034Sdougm 	*err = ret;
21763034Sdougm 	return (result);
21773034Sdougm }
21783034Sdougm 
21793034Sdougm /*
21803034Sdougm  * basic_set(groupname, optlist, protocol, sharepath, dryrun)
21813034Sdougm  *
21823034Sdougm  * This function implements "set" when a name space (-S) is not
21833034Sdougm  * specified. It is a basic set. Options and other CLI parsing has
21843034Sdougm  * already been done.
21853034Sdougm  */
21863034Sdougm 
21873034Sdougm static int
2188*3910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
2189*3910Sdougm 		char *protocol,	char *sharepath, int dryrun)
21903034Sdougm {
21913034Sdougm 	sa_group_t group;
21923034Sdougm 	int ret = SA_OK;
21933034Sdougm 	int change = 0;
21943034Sdougm 	struct list *worklist = NULL;
21953034Sdougm 
2196*3910Sdougm 	group = sa_get_group(handle, groupname);
21973034Sdougm 	if (group != NULL) {
21983034Sdougm 	    sa_share_t share = NULL;
21993034Sdougm 	    if (sharepath != NULL) {
22003034Sdougm 		share = sa_get_share(group, sharepath);
22013034Sdougm 		if (share == NULL) {
22023034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
22033034Sdougm 				groupname, sharepath);
22043034Sdougm 		    ret = SA_NO_SUCH_PATH;
22053034Sdougm 		}
22063034Sdougm 	    }
22073034Sdougm 	    if (ret == SA_OK) {
22083034Sdougm 		/* group must exist */
22093034Sdougm 		ret = valid_options(optlist, protocol,
22103034Sdougm 				    share == NULL ? group : share, NULL);
22113034Sdougm 		if (ret == SA_OK && !dryrun) {
22123034Sdougm 		    if (share != NULL)
22133034Sdougm 			change |= add_optionset(share, optlist, protocol,
22143034Sdougm 						&ret);
22153034Sdougm 		    else
22163034Sdougm 			change |= add_optionset(group, optlist, protocol,
22173034Sdougm 						&ret);
22183034Sdougm 		    if (ret == SA_OK && change) {
22193034Sdougm 			worklist = add_list(worklist, group, share);
22203034Sdougm 		    }
22213034Sdougm 		}
22223034Sdougm 	    }
22233034Sdougm 	    free_opt(optlist);
22243034Sdougm 	} else {
22253034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
22263034Sdougm 		ret = SA_NO_SUCH_GROUP;
22273034Sdougm 	}
22283034Sdougm 	/*
22293034Sdougm 	 * we have a group and potentially legal additions
22303034Sdougm 	 */
22313034Sdougm 
22323034Sdougm 	/* commit to configuration if not a dryrun */
22333034Sdougm 	if (!dryrun && ret == SA_OK) {
22343034Sdougm 	    if (change && worklist != NULL) {
22353034Sdougm 		/* properties changed, so update all shares */
2236*3910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
22373034Sdougm 	    }
22383034Sdougm 	}
22393034Sdougm 	if (worklist != NULL)
22403034Sdougm 	    free_list(worklist);
22413034Sdougm 	return (ret);
22423034Sdougm }
22433034Sdougm 
22443034Sdougm /*
22453034Sdougm  * space_set(groupname, optlist, protocol, sharepath, dryrun)
22463034Sdougm  *
22473034Sdougm  * This function implements "set" when a name space (-S) is
22483034Sdougm  * specified. It is a namespace set. Options and other CLI parsing has
22493034Sdougm  * already been done.
22503034Sdougm  */
22513034Sdougm 
22523034Sdougm static int
2253*3910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist,
2254*3910Sdougm 		char *protocol,	char *sharepath, int dryrun, char *sectype)
22553034Sdougm {
22563034Sdougm 	sa_group_t group;
22573034Sdougm 	int ret = SA_OK;
22583034Sdougm 	int change = 0;
22593034Sdougm 	struct list *worklist = NULL;
22603034Sdougm 
22613034Sdougm 	/*
22623034Sdougm 	 * make sure protcol and sectype are valid
22633034Sdougm 	 */
22643034Sdougm 
22653034Sdougm 	if (sa_proto_valid_space(protocol, sectype) == 0) {
22663034Sdougm 	    (void) printf(gettext("Option space \"%s\" not valid "
22673034Sdougm 					"for protocol.\n"),
22683034Sdougm 				sectype);
22693034Sdougm 	    return (SA_INVALID_SECURITY);
22703034Sdougm 	}
22713034Sdougm 
2272*3910Sdougm 	group = sa_get_group(handle, groupname);
22733034Sdougm 	if (group != NULL) {
22743034Sdougm 	    sa_share_t share = NULL;
22753034Sdougm 	    if (sharepath != NULL) {
22763034Sdougm 		share = sa_get_share(group, sharepath);
22773034Sdougm 		if (share == NULL) {
22783034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
22793034Sdougm 				groupname, sharepath);
22803034Sdougm 		    ret = SA_NO_SUCH_PATH;
22813034Sdougm 		}
22823034Sdougm 	    }
22833034Sdougm 	    if (ret == SA_OK) {
22843034Sdougm 		/* group must exist */
22853034Sdougm 		ret = valid_options(optlist, protocol,
22863034Sdougm 				    share == NULL ? group : share, sectype);
22873034Sdougm 		if (ret == SA_OK && !dryrun) {
22883034Sdougm 		    if (share != NULL)
22893034Sdougm 			change = add_security(share, sectype, optlist,
22903034Sdougm 						protocol,
22913034Sdougm 						&ret);
22923034Sdougm 		    else
22933034Sdougm 			change = add_security(group, sectype, optlist,
22943034Sdougm 						protocol,
22953034Sdougm 						&ret);
22963034Sdougm 		    if (ret != SA_OK)
22973034Sdougm 			(void) printf(gettext("Could not set property: %s\n"),
22983034Sdougm 				sa_errorstr(ret));
22993034Sdougm 		}
23003034Sdougm 		if (ret == SA_OK && change)
23013034Sdougm 		    worklist = add_list(worklist, group, share);
23023034Sdougm 	    }
23033034Sdougm 	    free_opt(optlist);
23043034Sdougm 	} else {
23053034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
23063034Sdougm 		ret = SA_NO_SUCH_GROUP;
23073034Sdougm 	}
23083034Sdougm 	/*
23093034Sdougm 	 * we have a group and potentially legal additions
23103034Sdougm 	 */
23113034Sdougm 
23123034Sdougm 	/* commit to configuration if not a dryrun */
23133034Sdougm 	if (!dryrun && ret == 0) {
23143034Sdougm 	    if (change && worklist != NULL) {
23153034Sdougm 		/* properties changed, so update all shares */
2316*3910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
23173034Sdougm 	    }
2318*3910Sdougm 	    ret = sa_update_config(handle);
23193034Sdougm 	}
23203034Sdougm 	if (worklist != NULL)
23213034Sdougm 	    free_list(worklist);
23223034Sdougm 	return (ret);
23233034Sdougm }
23243034Sdougm 
23253034Sdougm /*
23263034Sdougm  * sa_set(flags, argc, argv)
23273034Sdougm  *
23283034Sdougm  * Implements the set subcommand. It keys off of -S to determine which
23293034Sdougm  * set of operations to actually do.
23303034Sdougm  */
23313034Sdougm 
23323034Sdougm int
2333*3910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
23343034Sdougm {
23353034Sdougm 	char *groupname;
23363034Sdougm 	int verbose = 0;
23373034Sdougm 	int dryrun = 0;
23383034Sdougm 	int c;
23393034Sdougm 	char *protocol = NULL;
23403034Sdougm 	int ret = SA_OK;
23413034Sdougm 	struct options *optlist = NULL;
23423034Sdougm 	char *sharepath = NULL;
23433034Sdougm 	char *optset = NULL;
23443034Sdougm 	int auth;
23453034Sdougm 
23463034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
23473034Sdougm 	    switch (c) {
23483034Sdougm 	    case 'v':
23493034Sdougm 		verbose++;
23503034Sdougm 		break;
23513034Sdougm 	    case 'n':
23523034Sdougm 		dryrun++;
23533034Sdougm 		break;
23543034Sdougm 	    case 'P':
23553034Sdougm 		protocol = optarg;
23563034Sdougm 		if (!sa_valid_protocol(protocol)) {
23573034Sdougm 		    (void) printf(gettext("Invalid protocol specified:"
23583034Sdougm 				    "%s\n"),
23593034Sdougm 					protocol);
23603034Sdougm 		    return (SA_INVALID_PROTOCOL);
23613034Sdougm 		}
23623034Sdougm 		break;
23633034Sdougm 	    case 'p':
23643034Sdougm 		ret = add_opt(&optlist, optarg, 0);
23653034Sdougm 		switch (ret) {
23663034Sdougm 		case OPT_ADD_SYNTAX:
23673034Sdougm 		    (void) printf(gettext("Property syntax error: %s\n"),
23683034Sdougm 					optarg);
23693034Sdougm 		    return (SA_SYNTAX_ERR);
23703034Sdougm 		case OPT_ADD_MEMORY:
23713034Sdougm 		    (void) printf(gettext("No memory to set property: %s\n"),
23723034Sdougm 					optarg);
23733034Sdougm 		    return (SA_NO_MEMORY);
23743034Sdougm 		default:
23753034Sdougm 		    break;
23763034Sdougm 		}
23773034Sdougm 		break;
23783034Sdougm 	    case 's':
23793034Sdougm 		sharepath = optarg;
23803034Sdougm 		break;
23813034Sdougm 	    case 'S':
23823034Sdougm 		optset = optarg;
23833034Sdougm 		break;
23843034Sdougm 	    default:
23853034Sdougm 	    case 'h':
23863034Sdougm 	    case '?':
23873034Sdougm 		(void) printf(gettext("usage: %s\n"),
23883034Sdougm 				sa_get_usage(USAGE_SET));
23893034Sdougm 		return (SA_OK);
23903034Sdougm 	    }
23913034Sdougm 	}
23923034Sdougm 
23933034Sdougm 	if (optlist != NULL)
23943034Sdougm 	    ret = chk_opt(optlist, optset != NULL, protocol);
23953034Sdougm 
23963034Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
23973034Sdougm 	    protocol == NULL ||
23983034Sdougm 	    ret != OPT_ADD_OK) {
23993034Sdougm 	    char *sep = "\t";
24003034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
24013034Sdougm 	    if (optind >= argc) {
24023034Sdougm 		(void) printf(gettext("%sgroup must be specified"), sep);
24033034Sdougm 		sep = ", ";
24043034Sdougm 	    }
24053034Sdougm 	    if (optlist == NULL) {
24063034Sdougm 		(void) printf(gettext("%sat least one property must be"
24073034Sdougm 				" specified"), sep);
24083034Sdougm 		sep = ", ";
24093034Sdougm 	    }
24103034Sdougm 	    if (protocol == NULL) {
24113034Sdougm 		(void) printf(gettext("%sprotocol must be specified"), sep);
24123034Sdougm 		sep = ", ";
24133034Sdougm 	    }
24143034Sdougm 	    (void) printf("\n");
24153034Sdougm 	    ret = SA_SYNTAX_ERR;
24163034Sdougm 	} else {
24173034Sdougm 		/*
24183034Sdougm 		 * if a group already exists, we can only add a new
24193034Sdougm 		 * protocol to it and not create a new one or add the
24203034Sdougm 		 * same protocol again.
24213034Sdougm 		 */
24223034Sdougm 
24233034Sdougm 	    groupname = argv[optind];
24243034Sdougm 	    auth = check_authorizations(groupname, flags);
24253034Sdougm 	    if (optset == NULL)
2426*3910Sdougm 		ret = basic_set(handle, groupname, optlist, protocol,
24273034Sdougm 				sharepath, dryrun);
24283034Sdougm 	    else
2429*3910Sdougm 		ret = space_set(handle, groupname, optlist, protocol,
24303034Sdougm 				sharepath, dryrun, optset);
24313034Sdougm 	    if (dryrun && ret == SA_OK && !auth && verbose) {
24323034Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
24333034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
24343034Sdougm 	    }
24353034Sdougm 	}
24363034Sdougm 	return (ret);
24373034Sdougm }
24383034Sdougm 
24393034Sdougm /*
24403034Sdougm  * remove_options(group, optlist, proto, *err)
24413034Sdougm  *
24423034Sdougm  * helper function to actually remove options from a group after all
24433034Sdougm  * preprocessing is done.
24443034Sdougm  */
24453034Sdougm 
24463034Sdougm static int
24473034Sdougm remove_options(sa_group_t group, struct options *optlist,
24483034Sdougm 		char *proto, int *err)
24493034Sdougm {
24503034Sdougm 	struct options *cur;
24513034Sdougm 	sa_optionset_t optionset;
24523034Sdougm 	sa_property_t prop;
24533034Sdougm 	int change = 0;
24543034Sdougm 	int ret = SA_OK;
24553034Sdougm 
24563034Sdougm 	optionset = sa_get_optionset(group, proto);
24573034Sdougm 	if (optionset != NULL) {
24583034Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
24593034Sdougm 		prop = sa_get_property(optionset, cur->optname);
24603034Sdougm 		if (prop != NULL) {
24613034Sdougm 		    ret = sa_remove_property(prop);
24623034Sdougm 		    if (ret != SA_OK)
24633034Sdougm 			break;
24643034Sdougm 		    change = 1;
24653034Sdougm 		}
24663034Sdougm 	    }
24673034Sdougm 	}
24683034Sdougm 	if (ret == SA_OK && change)
24693034Sdougm 	    ret = sa_commit_properties(optionset, 0);
24703034Sdougm 
24713034Sdougm 	if (err != NULL)
24723034Sdougm 	    *err = ret;
24733034Sdougm 	return (change);
24743034Sdougm }
24753034Sdougm 
24763034Sdougm /*
24773034Sdougm  * valid_unset(group, optlist, proto)
24783034Sdougm  *
24793034Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
24803034Sdougm  * error if a property doesn't exist.
24813034Sdougm  */
24823034Sdougm 
24833034Sdougm static int
24843034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto)
24853034Sdougm {
24863034Sdougm 	struct options *cur;
24873034Sdougm 	sa_optionset_t optionset;
24883034Sdougm 	sa_property_t prop;
24893034Sdougm 	int ret = SA_OK;
24903034Sdougm 
24913034Sdougm 	optionset = sa_get_optionset(group, proto);
24923034Sdougm 	if (optionset != NULL) {
24933034Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
24943034Sdougm 		prop = sa_get_property(optionset, cur->optname);
24953034Sdougm 		if (prop == NULL) {
24963034Sdougm 		    (void) printf(gettext("Could not unset property %s:"
24973034Sdougm 						" not set\n"),
24983034Sdougm 			    cur->optname);
24993034Sdougm 		    ret = SA_NO_SUCH_PROP;
25003034Sdougm 		}
25013034Sdougm 	    }
25023034Sdougm 	}
25033034Sdougm 	return (ret);
25043034Sdougm }
25053034Sdougm 
25063034Sdougm /*
25073034Sdougm  * valid_unset_security(group, optlist, proto)
25083034Sdougm  *
25093034Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
25103034Sdougm  * error if a property doesn't exist.
25113034Sdougm  */
25123034Sdougm 
25133034Sdougm static int
25143034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
25153034Sdougm 	    char *sectype)
25163034Sdougm {
25173034Sdougm 	struct options *cur;
25183034Sdougm 	sa_security_t security;
25193034Sdougm 	sa_property_t prop;
25203034Sdougm 	int ret = SA_OK;
25213034Sdougm 	char *sec;
25223034Sdougm 
25233034Sdougm 	sec = sa_proto_space_alias(proto, sectype);
25243034Sdougm 	security = sa_get_security(group, sec, proto);
25253034Sdougm 	if (security != NULL) {
25263034Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
25273034Sdougm 		prop = sa_get_property(security, cur->optname);
25283034Sdougm 		if (prop == NULL) {
25293034Sdougm 		    (void) printf(gettext("Could not unset property %s:"
25303034Sdougm 						" not set\n"),
25313034Sdougm 					cur->optname);
25323034Sdougm 		    ret = SA_NO_SUCH_PROP;
25333034Sdougm 		}
25343034Sdougm 	    }
25353034Sdougm 	} else {
25363034Sdougm 	    (void) printf(gettext("Could not unset %s: space not defined\n"),
25373034Sdougm 			    sectype);
25383034Sdougm 	    ret = SA_NO_SUCH_SECURITY;
25393034Sdougm 	}
25403034Sdougm 	if (sec != NULL)
25413034Sdougm 	    sa_free_attr_string(sec);
25423034Sdougm 	return (ret);
25433034Sdougm }
25443034Sdougm 
25453034Sdougm /*
25463034Sdougm  * remove_security(group, optlist, proto)
25473034Sdougm  *
25483034Sdougm  * Remove the properties since they were checked as valid.
25493034Sdougm  */
25503034Sdougm 
25513034Sdougm static int
25523034Sdougm remove_security(sa_group_t group, char *sectype,
25533034Sdougm 		struct options *optlist, char *proto, int *err)
25543034Sdougm {
25553034Sdougm 	sa_security_t security;
25563034Sdougm 	int ret = SA_OK;
25573034Sdougm 	int change = 0;
25583034Sdougm 
25593034Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
25603034Sdougm 	security = sa_get_security(group, sectype, proto);
25613034Sdougm 	if (sectype != NULL)
25623034Sdougm 	    sa_free_attr_string(sectype);
25633034Sdougm 
25643034Sdougm 	if (security != NULL) {
25653034Sdougm 	    while (optlist != NULL) {
25663034Sdougm 		sa_property_t prop;
25673034Sdougm 		prop = sa_get_property(security, optlist->optname);
25683034Sdougm 		if (prop != NULL) {
25693034Sdougm 		    ret = sa_remove_property(prop);
25703034Sdougm 		    if (ret != SA_OK)
25713034Sdougm 			break;
25723034Sdougm 		    change = 1;
25733034Sdougm 		}
25743034Sdougm 		optlist = optlist->next;
25753034Sdougm 	    }
25763034Sdougm 		/*
25773034Sdougm 		 * when done, properties may have all been removed but
25783034Sdougm 		 * we need to keep the security type itself until
25793034Sdougm 		 * explicitly removed.
25803034Sdougm 		 */
25813034Sdougm 	    if (ret == SA_OK && change)
25823034Sdougm 		ret = sa_commit_properties(security, 0);
25833034Sdougm 	} else {
25843034Sdougm 	    ret = SA_NO_SUCH_PROP;
25853034Sdougm 	}
25863034Sdougm 	if (err != NULL)
25873034Sdougm 	    *err = ret;
25883034Sdougm 	return (change);
25893034Sdougm }
25903034Sdougm 
25913034Sdougm /*
25923034Sdougm  * basic_unset(groupname, optlist, protocol, sharepath, dryrun)
25933034Sdougm  *
25943034Sdougm  * unset non-named optionset properties.
25953034Sdougm  */
25963034Sdougm 
25973034Sdougm static int
2598*3910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
2599*3910Sdougm 		char *protocol,	char *sharepath, int dryrun)
26003034Sdougm {
26013034Sdougm 	sa_group_t group;
26023034Sdougm 	int ret = SA_OK;
26033034Sdougm 	int change = 0;
26043034Sdougm 	struct list *worklist = NULL;
26053034Sdougm 
2606*3910Sdougm 	group = sa_get_group(handle, groupname);
26073034Sdougm 	if (group != NULL) {
26083034Sdougm 	    sa_share_t share = NULL;
26093034Sdougm 	    if (sharepath != NULL) {
26103034Sdougm 		share = sa_get_share(group, sharepath);
26113034Sdougm 		if (share == NULL) {
26123034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
26133034Sdougm 				groupname, sharepath);
26143034Sdougm 		    ret = SA_NO_SUCH_PATH;
26153034Sdougm 		}
26163034Sdougm 	    }
26173034Sdougm 	    if (ret == SA_OK) {
26183034Sdougm 		/* group must exist */
26193034Sdougm 		ret = valid_unset(share != NULL ? share : group,
26203034Sdougm 					optlist, protocol);
26213034Sdougm 		if (ret == SA_OK && !dryrun) {
26223034Sdougm 		    if (share != NULL) {
26233034Sdougm 			sa_optionset_t optionset;
26243034Sdougm 			sa_property_t prop;
26253034Sdougm 			change |= remove_options(share, optlist, protocol,
26263034Sdougm 							&ret);
26273034Sdougm 			/* if a share optionset is empty, remove it */
26283034Sdougm 			optionset = sa_get_optionset((sa_share_t)share,
26293034Sdougm 							protocol);
26303034Sdougm 			if (optionset != NULL) {
26313034Sdougm 			    prop = sa_get_property(optionset, NULL);
26323034Sdougm 			    if (prop == NULL)
26333034Sdougm 				(void) sa_destroy_optionset(optionset);
26343034Sdougm 			}
26353034Sdougm 		    } else {
26363034Sdougm 			change |= remove_options(group, optlist, protocol,
26373034Sdougm 							&ret);
26383034Sdougm 		    }
26393034Sdougm 		    if (ret == SA_OK && change)
26403034Sdougm 			worklist = add_list(worklist, group, share);
26413034Sdougm 		    if (ret != SA_OK)
26423034Sdougm 			(void) printf(gettext("Could not remove properties:"
26433034Sdougm 						"%s\n"),
26443034Sdougm 				sa_errorstr(ret));
26453034Sdougm 		}
26463034Sdougm 	    } else {
26473034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
26483034Sdougm 		ret = SA_NO_SUCH_GROUP;
26493034Sdougm 	    }
26503034Sdougm 	    free_opt(optlist);
26513034Sdougm 	}
26523034Sdougm 
26533034Sdougm 	/*
26543034Sdougm 	 * we have a group and potentially legal additions
26553034Sdougm 	 */
26563034Sdougm 	/* commit to configuration if not a dryrun */
26573034Sdougm 	if (!dryrun && ret == SA_OK) {
26583034Sdougm 	    if (change && worklist != NULL) {
26593034Sdougm 		/* properties changed, so update all shares */
2660*3910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
26613034Sdougm 	    }
26623034Sdougm 	}
26633034Sdougm 	if (worklist != NULL)
26643034Sdougm 	    free_list(worklist);
26653034Sdougm 	return (ret);
26663034Sdougm }
26673034Sdougm 
26683034Sdougm /*
26693034Sdougm  * space_unset(groupname, optlist, protocol, sharepath, dryrun)
26703034Sdougm  *
26713034Sdougm  * unset named optionset properties.
26723034Sdougm  */
26733034Sdougm static int
2674*3910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
2675*3910Sdougm 		char *protocol, char *sharepath, int dryrun, char *sectype)
26763034Sdougm {
26773034Sdougm 	sa_group_t group;
26783034Sdougm 	int ret = SA_OK;
26793034Sdougm 	int change = 0;
26803034Sdougm 	struct list *worklist = NULL;
26813034Sdougm 
2682*3910Sdougm 	group = sa_get_group(handle, groupname);
26833034Sdougm 	if (group != NULL) {
26843034Sdougm 	    sa_share_t share = NULL;
26853034Sdougm 	    if (sharepath != NULL) {
26863034Sdougm 		share = sa_get_share(group, sharepath);
26873034Sdougm 		if (share == NULL) {
26883034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
26893034Sdougm 				groupname, sharepath);
26903034Sdougm 		    ret = SA_NO_SUCH_PATH;
26913034Sdougm 		}
26923034Sdougm 	    }
26933034Sdougm 	    if (ret == SA_OK) {
26943034Sdougm 		ret = valid_unset_security(share != NULL ? share : group,
26953034Sdougm 						optlist, protocol, sectype);
26963034Sdougm 		if (ret == SA_OK && !dryrun) {
26973034Sdougm 		    if (optlist != NULL) {
26983034Sdougm 			if (share != NULL) {
26993034Sdougm 			    sa_security_t optionset;
27003034Sdougm 			    sa_property_t prop;
27013034Sdougm 			    change = remove_security(share, sectype,
27023034Sdougm 							optlist, protocol,
27033034Sdougm 							&ret);
27043034Sdougm 			    /* if a share security is empty, remove it */
27053034Sdougm 			    optionset = sa_get_security((sa_group_t)share,
27063034Sdougm 							sectype,
27073034Sdougm 							protocol);
27083034Sdougm 			    if (optionset != NULL) {
27093034Sdougm 				prop = sa_get_property(optionset, NULL);
27103034Sdougm 				if (prop == NULL)
27113034Sdougm 				    ret = sa_destroy_security(optionset);
27123034Sdougm 			    }
27133034Sdougm 			} else {
27143034Sdougm 			    change = remove_security(group, sectype,
27153034Sdougm 							optlist, protocol,
27163034Sdougm 							&ret);
27173034Sdougm 			}
27183034Sdougm 		    } else {
27193034Sdougm 			sa_security_t security;
27203034Sdougm 			char *sec;
27213034Sdougm 			sec = sa_proto_space_alias(protocol, sectype);
27223034Sdougm 			security = sa_get_security(group, sec, protocol);
27233034Sdougm 			if (sec != NULL)
27243034Sdougm 			    sa_free_attr_string(sec);
27253034Sdougm 			if (security != NULL) {
27263034Sdougm 			    ret = sa_destroy_security(security);
27273034Sdougm 			    if (ret == SA_OK)
27283034Sdougm 				change = 1;
27293034Sdougm 			} else {
27303034Sdougm 			    ret = SA_NO_SUCH_PROP;
27313034Sdougm 			}
27323034Sdougm 		    }
27333034Sdougm 		    if (ret != SA_OK)
27343034Sdougm 			(void) printf(gettext("Could not unset property: %s\n"),
27353034Sdougm 				sa_errorstr(ret));
27363034Sdougm 		}
27373034Sdougm 
27383034Sdougm 		if (ret == SA_OK && change)
27393034Sdougm 		    worklist = add_list(worklist, group, 0);
27403034Sdougm 	    }
27413034Sdougm 	} else {
27423034Sdougm 	    (void) printf(gettext("Group \"%s\" not found\n"), groupname);
27433034Sdougm 	    ret = SA_NO_SUCH_GROUP;
27443034Sdougm 	}
27453034Sdougm 	free_opt(optlist);
27463034Sdougm 	/*
27473034Sdougm 	 * we have a group and potentially legal additions
27483034Sdougm 	 */
27493034Sdougm 
27503034Sdougm 	/* commit to configuration if not a dryrun */
27513034Sdougm 	if (!dryrun && ret == 0) {
27523034Sdougm 	    if (change && worklist != NULL) {
27533034Sdougm 		/* properties changed, so update all shares */
2754*3910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
27553034Sdougm 	    }
2756*3910Sdougm 	    ret = sa_update_config(handle);
27573034Sdougm 	}
27583034Sdougm 	if (worklist != NULL)
27593034Sdougm 	    free_list(worklist);
27603034Sdougm 	return (ret);
27613034Sdougm }
27623034Sdougm 
27633034Sdougm /*
27643034Sdougm  * sa_unset(flags, argc, argv)
27653034Sdougm  *
27663034Sdougm  * implements the unset subcommand. Parsing done here and then basic
27673034Sdougm  * or space versions of the real code are called.
27683034Sdougm  */
27693034Sdougm 
27703034Sdougm int
2771*3910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
27723034Sdougm {
27733034Sdougm 	char *groupname;
27743034Sdougm 	int verbose = 0;
27753034Sdougm 	int dryrun = 0;
27763034Sdougm 	int c;
27773034Sdougm 	char *protocol = NULL;
27783034Sdougm 	int ret = SA_OK;
27793034Sdougm 	struct options *optlist = NULL;
27803034Sdougm 	char *sharepath = NULL;
27813034Sdougm 	char *optset = NULL;
27823034Sdougm 	int auth;
27833034Sdougm 
27843034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
27853034Sdougm 	    switch (c) {
27863034Sdougm 	    case 'v':
27873034Sdougm 		verbose++;
27883034Sdougm 		break;
27893034Sdougm 	    case 'n':
27903034Sdougm 		dryrun++;
27913034Sdougm 		break;
27923034Sdougm 	    case 'P':
27933034Sdougm 		protocol = optarg;
27943034Sdougm 		if (!sa_valid_protocol(protocol)) {
27953034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
27963034Sdougm 					protocol);
27973034Sdougm 		    return (SA_INVALID_PROTOCOL);
27983034Sdougm 		}
27993034Sdougm 		break;
28003034Sdougm 	    case 'p':
28013034Sdougm 		ret = add_opt(&optlist, optarg, 1);
28023034Sdougm 		switch (ret) {
28033034Sdougm 		case OPT_ADD_SYNTAX:
28043034Sdougm 		    (void) printf(gettext("Property syntax error for "
28053034Sdougm 						"property %s\n"),
28063034Sdougm 					optarg);
28073034Sdougm 		    return (SA_SYNTAX_ERR);
28083034Sdougm 		case OPT_ADD_PROPERTY:
28093034Sdougm 		    (void) printf(gettext("Properties need to be set"
28103034Sdougm 						" with set command: %s\n"),
28113034Sdougm 					optarg);
28123034Sdougm 		    return (SA_SYNTAX_ERR);
28133034Sdougm 		default:
28143034Sdougm 		    break;
28153034Sdougm 		}
28163034Sdougm 		break;
28173034Sdougm 	    case 's':
28183034Sdougm 		sharepath = optarg;
28193034Sdougm 		break;
28203034Sdougm 	    case 'S':
28213034Sdougm 		optset = optarg;
28223034Sdougm 		break;
28233034Sdougm 	    default:
28243034Sdougm 	    case 'h':
28253034Sdougm 	    case '?':
28263034Sdougm 		(void) printf(gettext("usage: %s\n"),
28273034Sdougm 				sa_get_usage(USAGE_UNSET));
28283034Sdougm 		return (SA_OK);
28293034Sdougm 	    }
28303034Sdougm 	}
28313034Sdougm 
28323034Sdougm 	if (optlist != NULL)
28333034Sdougm 	    ret = chk_opt(optlist, optset != NULL, protocol);
28343034Sdougm 
28353034Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
28363034Sdougm 	    protocol == NULL) {
28373034Sdougm 	    char *sep = "\t";
28383034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET));
28393034Sdougm 	    if (optind >= argc) {
28403034Sdougm 		(void) printf(gettext("%sgroup must be specified"), sep);
28413034Sdougm 		sep = ", ";
28423034Sdougm 	    }
28433034Sdougm 	    if (optlist == NULL) {
28443034Sdougm 		(void) printf(gettext("%sat least one property must be "
28453034Sdougm 					"specified"),
28463034Sdougm 			sep);
28473034Sdougm 		sep = ", ";
28483034Sdougm 	    }
28493034Sdougm 	    if (protocol == NULL) {
28503034Sdougm 		(void) printf(gettext("%sprotocol must be specified"), sep);
28513034Sdougm 		sep = ", ";
28523034Sdougm 	    }
28533034Sdougm 	    (void) printf("\n");
28543034Sdougm 	    ret = SA_SYNTAX_ERR;
28553034Sdougm 	} else {
28563034Sdougm 
28573034Sdougm 		/*
28583034Sdougm 		 * if a group already exists, we can only add a new
28593034Sdougm 		 * protocol to it and not create a new one or add the
28603034Sdougm 		 * same protocol again.
28613034Sdougm 		 */
28623034Sdougm 
28633034Sdougm 	    groupname = argv[optind];
28643034Sdougm 	    auth = check_authorizations(groupname, flags);
28653034Sdougm 	    if (optset == NULL)
2866*3910Sdougm 		ret = basic_unset(handle, groupname, optlist, protocol,
28673034Sdougm 					sharepath, dryrun);
28683034Sdougm 	    else
2869*3910Sdougm 		ret = space_unset(handle, groupname, optlist, protocol,
28703034Sdougm 					sharepath, dryrun, optset);
28713034Sdougm 
28723034Sdougm 	    if (dryrun && ret == SA_OK && !auth && verbose) {
28733034Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
28743034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
28753034Sdougm 	    }
28763034Sdougm 	}
28773034Sdougm 	return (ret);
28783034Sdougm }
28793034Sdougm 
28803034Sdougm /*
28813034Sdougm  * sa_enable_group(flags, argc, argv)
28823034Sdougm  *
28833034Sdougm  * Implements the enable subcommand
28843034Sdougm  */
28853034Sdougm 
28863034Sdougm int
2887*3910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
28883034Sdougm {
28893034Sdougm 	int verbose = 0;
28903034Sdougm 	int dryrun = 0;
28913034Sdougm 	int all = 0;
28923034Sdougm 	int c;
28933034Sdougm 	int ret = SA_OK;
28943034Sdougm 	char *protocol = NULL;
28953034Sdougm 	char *state;
28963034Sdougm 	struct list *worklist = NULL;
28973034Sdougm 	int auth = 1;
28983034Sdougm 
28993034Sdougm 	while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
29003034Sdougm 	    switch (c) {
29013034Sdougm 	    case 'a':
29023034Sdougm 		all = 1;
29033034Sdougm 		break;
29043034Sdougm 	    case 'n':
29053034Sdougm 		dryrun++;
29063034Sdougm 		break;
29073034Sdougm 	    case 'P':
29083034Sdougm 		protocol = optarg;
29093034Sdougm 		if (!sa_valid_protocol(protocol)) {
29103034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
29113034Sdougm 				    protocol);
29123034Sdougm 		    return (SA_INVALID_PROTOCOL);
29133034Sdougm 		}
29143034Sdougm 		break;
29153034Sdougm 	    case 'v':
29163034Sdougm 		verbose++;
29173034Sdougm 		break;
29183034Sdougm 	    default:
29193034Sdougm 	    case 'h':
29203034Sdougm 	    case '?':
29213034Sdougm 		(void) printf(gettext("usage: %s\n"),
29223034Sdougm 				sa_get_usage(USAGE_ENABLE));
29233034Sdougm 		return (0);
29243034Sdougm 	    }
29253034Sdougm 	}
29263034Sdougm 
29273034Sdougm 	if (optind == argc && !all) {
29283034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE));
29293034Sdougm 	    (void) printf(gettext("\tmust specify group\n"));
29303034Sdougm 	    ret = SA_NO_SUCH_PATH;
29313034Sdougm 	} else {
29323034Sdougm 	    sa_group_t group;
29333034Sdougm 	    if (!all) {
29343034Sdougm 		while (optind < argc) {
2935*3910Sdougm 		    group = sa_get_group(handle, argv[optind]);
29363034Sdougm 		    if (group != NULL) {
29373034Sdougm 			auth &= check_authorizations(argv[optind], flags);
29383034Sdougm 			state = sa_get_group_attr(group, "state");
29393034Sdougm 			if (state != NULL &&
29403034Sdougm 			    strcmp(state, "enabled") == 0) {
29413034Sdougm 			    /* already enabled */
29423034Sdougm 			    if (verbose)
29433034Sdougm 				(void) printf(gettext("Group \"%s\" is already "
29443034Sdougm 						"enabled\n"),
29453034Sdougm 					argv[optind]);
29463034Sdougm 			    ret = SA_BUSY; /* already enabled */
29473034Sdougm 			} else {
29483034Sdougm 			    worklist = add_list(worklist, group, 0);
29493034Sdougm 			    if (verbose)
29503034Sdougm 				(void) printf(gettext("Enabling group "
29513034Sdougm 							"\"%s\"\n"),
29523034Sdougm 					argv[optind]);
29533034Sdougm 			}
29543034Sdougm 			if (state != NULL)
29553034Sdougm 			    sa_free_attr_string(state);
29563034Sdougm 		    } else {
29573034Sdougm 			ret = SA_NO_SUCH_GROUP;
29583034Sdougm 		    }
29593034Sdougm 		    optind++;
29603034Sdougm 		}
29613034Sdougm 	    } else {
2962*3910Sdougm 		for (group = sa_get_group(handle, NULL); group != NULL;
29633034Sdougm 		    group = sa_get_next_group(group)) {
29643034Sdougm 		    worklist = add_list(worklist, group, 0);
29653034Sdougm 		}
29663034Sdougm 	    }
29673034Sdougm 	    if (!dryrun && ret == SA_OK) {
2968*3910Sdougm 		ret = enable_all_groups(handle, worklist, 1, 0, NULL);
29693034Sdougm 	    }
29703034Sdougm 	    if (ret != SA_OK && ret != SA_BUSY)
29713034Sdougm 		(void) printf(gettext("Could not enable group: %s\n"),
29723034Sdougm 			sa_errorstr(ret));
29733034Sdougm 	    if (ret == SA_BUSY)
29743034Sdougm 		ret = SA_OK;
29753034Sdougm 	}
29763034Sdougm 	if (worklist != NULL)
29773034Sdougm 	    free_list(worklist);
29783034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
29793034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
29803034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
29813034Sdougm 	}
29823034Sdougm 	return (ret);
29833034Sdougm }
29843034Sdougm 
29853034Sdougm /*
29863034Sdougm  * disable_group(group, setstate)
29873034Sdougm  *
29883034Sdougm  * disable all the shares in the specified group honoring the setstate
29893034Sdougm  * argument. This is a helper for disable_all_groups in order to
29903034Sdougm  * simplify regular and subgroup (zfs) disabling. Group has already
29913034Sdougm  * been checked for non-NULL.
29923034Sdougm  */
29933034Sdougm 
29943034Sdougm static int
29953034Sdougm disable_group(sa_group_t group)
29963034Sdougm {
29973034Sdougm 	sa_share_t share;
29983034Sdougm 	int ret = SA_OK;
29993034Sdougm 
30003034Sdougm 	for (share = sa_get_share(group, NULL);
30013034Sdougm 	    share != NULL && ret == SA_OK;
30023034Sdougm 	    share = sa_get_next_share(share)) {
30033034Sdougm 	    ret = sa_disable_share(share, NULL);
30043034Sdougm 	    if (ret == SA_NO_SUCH_PATH) {
30053034Sdougm 		/*
30063034Sdougm 		 * this is OK since the path is gone. we can't
30073034Sdougm 		 * re-share it anyway so no error.
30083034Sdougm 		 */
30093034Sdougm 		ret = SA_OK;
30103034Sdougm 	    }
30113034Sdougm 	}
30123034Sdougm 	return (ret);
30133034Sdougm }
30143034Sdougm 
30153034Sdougm 
30163034Sdougm /*
30173034Sdougm  * disable_all_groups(work, setstate)
30183034Sdougm  *
30193034Sdougm  * helper function that disables the shares in the list of groups
30203034Sdougm  * provided. It optionally marks the group as disabled. Used by both
30213034Sdougm  * enable and start subcommands.
30223034Sdougm  */
30233034Sdougm 
30243034Sdougm static int
3025*3910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
30263034Sdougm {
30273034Sdougm 	int ret = SA_OK;
30283034Sdougm 	sa_group_t subgroup, group;
30293034Sdougm 
30303034Sdougm 	while (work != NULL && ret == SA_OK) {
30313034Sdougm 	    group = (sa_group_t)work->item;
30323034Sdougm 	    if (setstate)
30333034Sdougm 		ret = sa_set_group_attr(group, "state", "disabled");
30343034Sdougm 	    if (ret == SA_OK) {
30353034Sdougm 		char *name;
30363034Sdougm 		name = sa_get_group_attr(group, "name");
30373034Sdougm 		if (name != NULL && strcmp(name, "zfs") == 0) {
30383034Sdougm 		    /* need to get the sub-groups for stopping */
30393034Sdougm 		    for (subgroup = sa_get_sub_group(group); subgroup != NULL;
30403034Sdougm 			subgroup = sa_get_next_group(subgroup)) {
30413034Sdougm 			ret = disable_group(subgroup);
30423034Sdougm 		    }
30433034Sdougm 		} else {
30443034Sdougm 		    ret = disable_group(group);
30453034Sdougm 		}
30463034Sdougm 		/*
30473034Sdougm 		 * we don't want to "disable" since it won't come
30483034Sdougm 		 * up after a reboot.  The SMF framework should do
30493034Sdougm 		 * the right thing. On enable we do want to do
30503034Sdougm 		 * something.
30513034Sdougm 		 */
30523034Sdougm 	    }
30533034Sdougm 	    work = work->next;
30543034Sdougm 	}
30553034Sdougm 	if (ret == SA_OK)
3056*3910Sdougm 	    ret = sa_update_config(handle);
30573034Sdougm 	return (ret);
30583034Sdougm }
30593034Sdougm 
30603034Sdougm /*
30613034Sdougm  * sa_disable_group(flags, argc, argv)
30623034Sdougm  *
30633034Sdougm  * Implements the disable subcommand
30643034Sdougm  */
30653034Sdougm 
30663034Sdougm int
3067*3910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
30683034Sdougm {
30693034Sdougm 	int verbose = 0;
30703034Sdougm 	int dryrun = 0;
30713034Sdougm 	int all = 0;
30723034Sdougm 	int c;
30733034Sdougm 	int ret = SA_OK;
30743034Sdougm 	char *protocol;
30753034Sdougm 	char *state;
30763034Sdougm 	struct list *worklist = NULL;
30773034Sdougm 	int auth = 1;
30783034Sdougm 
30793034Sdougm 	while ((c = getopt(argc, argv, "?havn")) != EOF) {
30803034Sdougm 	    switch (c) {
30813034Sdougm 	    case 'a':
30823034Sdougm 		all = 1;
30833034Sdougm 		break;
30843034Sdougm 	    case 'n':
30853034Sdougm 		dryrun++;
30863034Sdougm 		break;
30873034Sdougm 	    case 'P':
30883034Sdougm 		protocol = optarg;
30893034Sdougm 		if (!sa_valid_protocol(protocol)) {
30903034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
30913034Sdougm 					protocol);
30923034Sdougm 		    return (SA_INVALID_PROTOCOL);
30933034Sdougm 		}
30943034Sdougm 		break;
30953034Sdougm 	    case 'v':
30963034Sdougm 		verbose++;
30973034Sdougm 		break;
30983034Sdougm 	    default:
30993034Sdougm 	    case 'h':
31003034Sdougm 	    case '?':
31013034Sdougm 		(void) printf(gettext("usage: %s\n"),
31023034Sdougm 				sa_get_usage(USAGE_DISABLE));
31033034Sdougm 		return (0);
31043034Sdougm 	    }
31053034Sdougm 	}
31063034Sdougm 
31073034Sdougm 	if (optind == argc && !all) {
31083034Sdougm 		(void) printf(gettext("usage: %s\n"),
31093034Sdougm 				sa_get_usage(USAGE_DISABLE));
31103034Sdougm 		(void) printf(gettext("\tmust specify group\n"));
31113034Sdougm 		ret = SA_NO_SUCH_PATH;
31123034Sdougm 	} else {
31133034Sdougm 		sa_group_t group;
31143034Sdougm 		if (!all) {
31153034Sdougm 		    while (optind < argc) {
3116*3910Sdougm 			group = sa_get_group(handle, argv[optind]);
31173034Sdougm 			if (group != NULL) {
31183034Sdougm 			    auth &= check_authorizations(argv[optind], flags);
31193034Sdougm 			    state = sa_get_group_attr(group, "state");
31203034Sdougm 			    if (state == NULL ||
31213034Sdougm 				strcmp(state, "disabled") == 0) {
31223034Sdougm 				/* already disabled */
31233034Sdougm 				if (verbose)
31243034Sdougm 				    (void) printf(gettext("Group \"%s\" is "
31253034Sdougm 							"already disabled\n"),
31263034Sdougm 					    argv[optind]);
31273034Sdougm 				ret = SA_BUSY; /* already disable */
31283034Sdougm 			    } else {
31293034Sdougm 				worklist = add_list(worklist, group, 0);
31303034Sdougm 				if (verbose)
31313034Sdougm 				    (void) printf(gettext("Disabling group "
31323034Sdougm 							    "\"%s\"\n"),
31333034Sdougm 					    argv[optind]);
31343034Sdougm 			    }
31353034Sdougm 			    if (state != NULL)
31363034Sdougm 				sa_free_attr_string(state);
31373034Sdougm 			} else {
31383034Sdougm 			    ret = SA_NO_SUCH_GROUP;
31393034Sdougm 			}
31403034Sdougm 			optind++;
31413034Sdougm 		    }
31423034Sdougm 		} else {
3143*3910Sdougm 		    for (group = sa_get_group(handle, NULL); group != NULL;
31443034Sdougm 			    group = sa_get_next_group(group)) {
31453034Sdougm 			worklist = add_list(worklist, group, 0);
31463034Sdougm 		    }
31473034Sdougm 		}
31483034Sdougm 		if (ret == SA_OK && !dryrun) {
3149*3910Sdougm 			ret = disable_all_groups(handle, worklist, 1);
31503034Sdougm 		}
31513034Sdougm 		if (ret != SA_OK && ret != SA_BUSY)
31523034Sdougm 		    (void) printf(gettext("Could not disable group: %s\n"),
31533034Sdougm 				sa_errorstr(ret));
31543034Sdougm 		if (ret == SA_BUSY)
31553034Sdougm 		    ret = SA_OK;
31563034Sdougm 	}
31573034Sdougm 	if (worklist != NULL)
31583034Sdougm 	    free_list(worklist);
31593034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
31603034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
31613034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
31623034Sdougm 	}
31633034Sdougm 	return (ret);
31643034Sdougm }
31653034Sdougm 
31663034Sdougm /*
31673034Sdougm  * check_sharetab()
31683034Sdougm  *
31693034Sdougm  * Checks to see if the /etc/dfs/sharetab file is stale (exists from
31703034Sdougm  * before the current boot). If it is, truncate it since nothing is
31713034Sdougm  * really shared.
31723034Sdougm  */
31733034Sdougm 
31743034Sdougm static void
31753034Sdougm check_sharetab()
31763034Sdougm {
31773034Sdougm 	int fd;
31783034Sdougm 	struct utmpx *utmpxp;
31793034Sdougm 	struct stat st;
31803034Sdougm 
31813034Sdougm 	fd = open(SA_LEGACY_SHARETAB, O_RDWR);
31823034Sdougm 	if (fd >= 0) {
31833034Sdougm 		/*
31843034Sdougm 		 * Attempt to get a lock on the file. Whgen we get
31853034Sdougm 		 * one, then check to see if it is older than the boot
31863034Sdougm 		 * time. Truncate if older than boot.
31873034Sdougm 		 */
31883034Sdougm 	    (void) lockf(fd, F_LOCK, 0);
31893034Sdougm 	    if ((fstat(fd, &st) == 0) && /* does sharetab exist? */
31903034Sdougm 		(utmpxp = getutxent()) != NULL && /* does utmpx exist? */
31913034Sdougm 			(utmpxp->ut_xtime > st.st_mtime)) /* sharetab older? */
31923034Sdougm 		(void) ftruncate(fd, 0);
31933034Sdougm 
31943034Sdougm 	    (void) lockf(fd, F_ULOCK, 0);
31953034Sdougm 	    (void) close(fd);
31963034Sdougm 	    endutxent();
31973034Sdougm 	}
31983034Sdougm }
31993034Sdougm 
32003034Sdougm /*
32013034Sdougm  * sa_start_group(flags, argc, argv)
32023034Sdougm  *
32033034Sdougm  * Implements the start command.
32043034Sdougm  * This is similar to enable except it doesn't change the state
32053034Sdougm  * of the group(s) and only enables shares if the group is already
32063034Sdougm  * enabled.
32073034Sdougm  */
32083034Sdougm 
32093034Sdougm int
3210*3910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
32113034Sdougm {
32123034Sdougm 	int verbose = 0;
32133034Sdougm 	int all = 0;
32143034Sdougm 	int c;
32153034Sdougm 	int ret = SMF_EXIT_OK;
32163034Sdougm 	char *protocol = NULL;
32173034Sdougm 	char *state;
32183034Sdougm 	struct list *worklist = NULL;
32193034Sdougm #ifdef lint
32203034Sdougm 	flags = flags;
32213034Sdougm #endif
32223034Sdougm 
32233034Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
32243034Sdougm 	    switch (c) {
32253034Sdougm 	    case 'a':
32263034Sdougm 		all = 1;
32273034Sdougm 		break;
32283034Sdougm 	    case 'P':
32293034Sdougm 		protocol = optarg;
32303034Sdougm 		if (!sa_valid_protocol(protocol)) {
32313034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
32323034Sdougm 				    protocol);
32333034Sdougm 		    return (SA_INVALID_PROTOCOL);
32343034Sdougm 		}
32353034Sdougm 		break;
32363034Sdougm 	    case 'v':
32373034Sdougm 		verbose++;
32383034Sdougm 		break;
32393034Sdougm 	    default:
32403034Sdougm 	    case 'h':
32413034Sdougm 	    case '?':
32423034Sdougm 		(void) printf(gettext("usage: %s\n"),
32433034Sdougm 				sa_get_usage(USAGE_START));
32443034Sdougm 		return (SA_OK);
32453034Sdougm 	    }
32463034Sdougm 	}
32473034Sdougm 
32483034Sdougm 	if (optind == argc && !all) {
32493034Sdougm 		(void) printf(gettext("usage: %s\n"),
32503034Sdougm 				sa_get_usage(USAGE_START));
32513034Sdougm 		ret = SMF_EXIT_ERR_FATAL;
32523034Sdougm 	} else {
32533034Sdougm 		sa_group_t group;
32543034Sdougm 
32553034Sdougm 		check_sharetab();
32563034Sdougm 
32573034Sdougm 		if (!all) {
32583034Sdougm 		    while (optind < argc) {
3259*3910Sdougm 			group = sa_get_group(handle, argv[optind]);
32603034Sdougm 			if (group != NULL) {
32613034Sdougm 			    state = sa_get_group_attr(group, "state");
32623034Sdougm 			    if (state == NULL ||
32633034Sdougm 				strcmp(state, "enabled") == 0) {
32643034Sdougm 				worklist = add_list(worklist, group, 0);
32653034Sdougm 				if (verbose)
32663034Sdougm 				    (void) printf(gettext("Starting group "
32673034Sdougm 								"\"%s\"\n"),
32683034Sdougm 					    argv[optind]);
32693034Sdougm 			    } else {
32703034Sdougm 				/*
32713034Sdougm 				 * determine if there are any
32723034Sdougm 				 * protocols.  if there aren't any,
32733034Sdougm 				 * then there isn't anything to do in
32743034Sdougm 				 * any case so no error.
32753034Sdougm 				 */
32763034Sdougm 				if (sa_get_optionset(group, protocol) != NULL) {
32773034Sdougm 				    ret = SMF_EXIT_OK;
32783034Sdougm 				}
32793034Sdougm 			    }
32803034Sdougm 			    if (state != NULL)
32813034Sdougm 				sa_free_attr_string(state);
32823034Sdougm 			}
32833034Sdougm 			optind++;
32843034Sdougm 		    }
32853034Sdougm 		} else {
3286*3910Sdougm 		    for (group = sa_get_group(handle, NULL); group != NULL;
32873034Sdougm 			    group = sa_get_next_group(group)) {
32883034Sdougm 			state = sa_get_group_attr(group, "state");
32893034Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
32903034Sdougm 			    worklist = add_list(worklist, group, 0);
32913034Sdougm 			if (state != NULL)
32923034Sdougm 			    sa_free_attr_string(state);
32933034Sdougm 		    }
32943034Sdougm 		}
3295*3910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 1, NULL);
32963034Sdougm 	}
32973034Sdougm 	if (worklist != NULL)
32983034Sdougm 	    free_list(worklist);
32993034Sdougm 	return (ret);
33003034Sdougm }
33013034Sdougm 
33023034Sdougm /*
33033034Sdougm  * sa_stop_group(flags, argc, argv)
33043034Sdougm  *
33053034Sdougm  * Implements the stop command.
33063034Sdougm  * This is similar to disable except it doesn't change the state
33073034Sdougm  * of the group(s) and only disables shares if the group is already
33083034Sdougm  * enabled.
33093034Sdougm  */
33103034Sdougm 
33113034Sdougm int
3312*3910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
33133034Sdougm {
33143034Sdougm 	int verbose = 0;
33153034Sdougm 	int all = 0;
33163034Sdougm 	int c;
33173034Sdougm 	int ret = SMF_EXIT_OK;
33183034Sdougm 	char *protocol = NULL;
33193034Sdougm 	char *state;
33203034Sdougm 	struct list *worklist = NULL;
33213034Sdougm #ifdef lint
33223034Sdougm 	flags = flags;
33233034Sdougm #endif
33243034Sdougm 
33253034Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
33263034Sdougm 	    switch (c) {
33273034Sdougm 	    case 'a':
33283034Sdougm 		all = 1;
33293034Sdougm 		break;
33303034Sdougm 	    case 'P':
33313034Sdougm 		protocol = optarg;
33323034Sdougm 		if (!sa_valid_protocol(protocol)) {
33333034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
33343034Sdougm 					protocol);
33353034Sdougm 		    return (SA_INVALID_PROTOCOL);
33363034Sdougm 		}
33373034Sdougm 		break;
33383034Sdougm 	    case 'v':
33393034Sdougm 		verbose++;
33403034Sdougm 		break;
33413034Sdougm 	    default:
33423034Sdougm 	    case 'h':
33433034Sdougm 	    case '?':
33443034Sdougm 		(void) printf(gettext("usage: %s\n"),
33453034Sdougm 				sa_get_usage(USAGE_STOP));
33463034Sdougm 		return (0);
33473034Sdougm 	    }
33483034Sdougm 	}
33493034Sdougm 
33503034Sdougm 	if (optind == argc && !all) {
33513034Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP));
33523034Sdougm 		ret = SMF_EXIT_ERR_FATAL;
33533034Sdougm 	} else {
33543034Sdougm 		sa_group_t group;
33553034Sdougm 		if (!all) {
33563034Sdougm 		    while (optind < argc) {
3357*3910Sdougm 			group = sa_get_group(handle, argv[optind]);
33583034Sdougm 			if (group != NULL) {
33593034Sdougm 			    state = sa_get_group_attr(group, "state");
33603034Sdougm 			    if (state == NULL ||
33613034Sdougm 				strcmp(state, "enabled") == 0) {
33623034Sdougm 				worklist = add_list(worklist, group, 0);
33633034Sdougm 				if (verbose)
33643034Sdougm 				    (void) printf(gettext("Stopping group "
33653034Sdougm 								"\"%s\"\n"),
33663034Sdougm 					    argv[optind]);
33673034Sdougm 			    } else {
33683034Sdougm 				ret = SMF_EXIT_OK;
33693034Sdougm 			    }
33703034Sdougm 			    if (state != NULL)
33713034Sdougm 				sa_free_attr_string(state);
33723034Sdougm 			}
33733034Sdougm 			optind++;
33743034Sdougm 		    }
33753034Sdougm 		} else {
3376*3910Sdougm 		    for (group = sa_get_group(handle, NULL); group != NULL;
33773034Sdougm 			    group = sa_get_next_group(group)) {
33783034Sdougm 			state = sa_get_group_attr(group, "state");
33793034Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
33803034Sdougm 			    worklist = add_list(worklist, group, 0);
33813034Sdougm 			if (state != NULL)
33823034Sdougm 			    sa_free_attr_string(state);
33833034Sdougm 		    }
33843034Sdougm 		}
3385*3910Sdougm 		(void) disable_all_groups(handle, worklist, 0);
3386*3910Sdougm 		ret = sa_update_config(handle);
33873034Sdougm 	}
33883034Sdougm 	if (worklist != NULL)
33893034Sdougm 	    free_list(worklist);
33903034Sdougm 	return (ret);
33913034Sdougm }
33923034Sdougm 
33933034Sdougm /*
33943034Sdougm  * remove_all_options(share, proto)
33953034Sdougm  *
33963034Sdougm  * Removes all options on a share.
33973034Sdougm  */
33983034Sdougm 
33993034Sdougm static void
34003034Sdougm remove_all_options(sa_share_t share, char *proto)
34013034Sdougm {
34023034Sdougm 	sa_optionset_t optionset;
34033034Sdougm 	sa_security_t security;
34043034Sdougm 	sa_security_t prevsec = NULL;
34053034Sdougm 
34063034Sdougm 	optionset = sa_get_optionset(share, proto);
34073034Sdougm 	if (optionset != NULL)
34083034Sdougm 	    (void) sa_destroy_optionset(optionset);
34093034Sdougm 	for (security = sa_get_security(share, NULL, NULL);
34103034Sdougm 	    security != NULL;
34113034Sdougm 	    security = sa_get_next_security(security)) {
34123034Sdougm 	    char *type;
34133034Sdougm 		/*
34143034Sdougm 		 * we walk through the list.  prevsec keeps the
34153034Sdougm 		 * previous security so we can delete it without
34163034Sdougm 		 * destroying the list.
34173034Sdougm 		 */
34183034Sdougm 	    if (prevsec != NULL) {
34193034Sdougm 		/* remove the previously seen security */
34203034Sdougm 		(void) sa_destroy_security(prevsec);
34213034Sdougm 		/* set to NULL so we don't try multiple times */
34223034Sdougm 		prevsec = NULL;
34233034Sdougm 	    }
34243034Sdougm 	    type = sa_get_security_attr(security, "type");
34253034Sdougm 	    if (type != NULL) {
34263034Sdougm 		/*
34273034Sdougm 		 * if the security matches the specified protocol, we
34283034Sdougm 		 * want to remove it. prevsec holds it until either
34293034Sdougm 		 * the next pass or we fall out of the loop.
34303034Sdougm 		 */
34313034Sdougm 		if (strcmp(type, proto) == 0)
34323034Sdougm 		    prevsec = security;
34333034Sdougm 		sa_free_attr_string(type);
34343034Sdougm 	    }
34353034Sdougm 	}
34363034Sdougm 	/* in case there is one left */
34373034Sdougm 	if (prevsec != NULL)
34383034Sdougm 	    (void) sa_destroy_security(prevsec);
34393034Sdougm }
34403034Sdougm 
34413034Sdougm 
34423034Sdougm /*
34433034Sdougm  * for legacy support, we need to handle the old syntax. This is what
34443034Sdougm  * we get if sharemgr is called with the name "share" rather than
34453034Sdougm  * sharemgr.
34463034Sdougm  */
34473034Sdougm 
34483034Sdougm static int
34493034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
34503034Sdougm {
34513034Sdougm 	int err;
34523034Sdougm 
34533034Sdougm 	err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
34543034Sdougm 	if (err > buffsize)
34553034Sdougm 	    return (-1);
34563034Sdougm 	return (0);
34573034Sdougm }
34583034Sdougm 
34593034Sdougm 
34603034Sdougm /*
34613034Sdougm  * check_legacy_cmd(proto, cmd)
34623034Sdougm  *
34633034Sdougm  * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
34643034Sdougm  * executable.
34653034Sdougm  */
34663034Sdougm 
34673034Sdougm static int
34683034Sdougm check_legacy_cmd(char *path)
34693034Sdougm {
34703034Sdougm 	struct stat st;
34713034Sdougm 	int ret = 0;
34723034Sdougm 
34733034Sdougm 	if (stat(path, &st) == 0) {
34743034Sdougm 	    if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
34753034Sdougm 		ret = 1;
34763034Sdougm 	}
34773034Sdougm 	return (ret);
34783034Sdougm }
34793034Sdougm 
34803034Sdougm /*
34813034Sdougm  * run_legacy_command(proto, cmd, argv)
34823034Sdougm  *
34833034Sdougm  * we know the command exists, so attempt to execute it with all the
34843034Sdougm  * arguments. This implements full legacy share support for those
34853034Sdougm  * protocols that don't have plugin providers.
34863034Sdougm  */
34873034Sdougm 
34883034Sdougm static int
34893034Sdougm run_legacy_command(char *path, char *argv[])
34903034Sdougm {
34913034Sdougm 	int ret;
34923034Sdougm 
34933034Sdougm 	ret = execv(path, argv);
34943034Sdougm 	if (ret < 0) {
34953034Sdougm 	    switch (errno) {
34963034Sdougm 	    case EACCES:
34973034Sdougm 		ret = SA_NO_PERMISSION;
34983034Sdougm 		break;
34993034Sdougm 	    default:
35003034Sdougm 		ret = SA_SYSTEM_ERR;
35013034Sdougm 		break;
35023034Sdougm 	    }
35033034Sdougm 	}
35043034Sdougm 	return (ret);
35053034Sdougm }
35063034Sdougm 
35073034Sdougm /*
35083348Sdougm  * out_share(out, group, proto)
35093034Sdougm  *
35103034Sdougm  * Display the share information in the format that the "share"
35113034Sdougm  * command has traditionally used.
35123034Sdougm  */
35133034Sdougm 
35143034Sdougm static void
35153348Sdougm out_share(FILE *out, sa_group_t group, char *proto)
35163034Sdougm {
35173034Sdougm 	sa_share_t share;
35183034Sdougm 	char resfmt[128];
35193034Sdougm 
35203034Sdougm 	for (share = sa_get_share(group, NULL); share != NULL;
35213034Sdougm 		share = sa_get_next_share(share)) {
35223034Sdougm 	    char *path;
35233034Sdougm 	    char *type;
35243034Sdougm 	    char *resource;
35253034Sdougm 	    char *description;
35263034Sdougm 	    char *groupname;
35273034Sdougm 	    char *sharedstate;
35283034Sdougm 	    int shared = 1;
35293034Sdougm 	    char *soptions;
35303034Sdougm 
35313034Sdougm 	    sharedstate = sa_get_share_attr(share, "shared");
35323034Sdougm 	    path = sa_get_share_attr(share, "path");
35333034Sdougm 	    type = sa_get_share_attr(share, "type");
35343034Sdougm 	    resource = sa_get_share_attr(share, "resource");
35353034Sdougm 	    groupname = sa_get_group_attr(group, "name");
35363034Sdougm 
35373034Sdougm 	    if (groupname != NULL && strcmp(groupname, "default") == 0) {
35383034Sdougm 		sa_free_attr_string(groupname);
35393034Sdougm 		groupname = NULL;
35403034Sdougm 	    }
35413034Sdougm 	    description = sa_get_share_description(share);
35423348Sdougm 
35433348Sdougm 	    /* want the sharetab version if it exists */
35443348Sdougm 	    soptions = sa_get_share_attr(share, "shareopts");
35453034Sdougm 
35463034Sdougm 	    if (sharedstate == NULL)
35473034Sdougm 		shared = 0;
35483034Sdougm 
35493348Sdougm 	    if (soptions == NULL)
35503348Sdougm 		soptions = sa_proto_legacy_format(proto, share, 1);
35513034Sdougm 
35523034Sdougm 	    if (shared) {
35533348Sdougm 		/* only active shares go here */
35543034Sdougm 		(void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
35553034Sdougm 			resource != NULL ? resource : "-",
35563034Sdougm 			groupname != NULL ? "@" : "",
35573034Sdougm 			groupname != NULL ? groupname : "");
35583034Sdougm 		(void) fprintf(out, "%-14.14s  %s   %s   \"%s\"  \n",
35593034Sdougm 			resfmt,
35603034Sdougm 			path,
35613034Sdougm 			(soptions != NULL && strlen(soptions) > 0) ?
35623034Sdougm 					soptions : "rw",
35633034Sdougm 			(description != NULL) ? description : "");
35643034Sdougm 	    }
35653034Sdougm 
35663034Sdougm 	    if (path != NULL)
35673034Sdougm 		sa_free_attr_string(path);
35683034Sdougm 	    if (type != NULL)
35693034Sdougm 		sa_free_attr_string(type);
35703034Sdougm 	    if (resource != NULL)
35713034Sdougm 		sa_free_attr_string(resource);
35723034Sdougm 	    if (groupname != NULL)
35733034Sdougm 		sa_free_attr_string(groupname);
35743034Sdougm 	    if (description != NULL)
35753034Sdougm 		sa_free_share_description(description);
35763034Sdougm 	    if (sharedstate != NULL)
35773034Sdougm 		sa_free_attr_string(sharedstate);
35783348Sdougm 	    if (soptions != NULL)
35793034Sdougm 		sa_format_free(soptions);
35803034Sdougm 	}
35813034Sdougm }
35823034Sdougm 
35833034Sdougm /*
35843034Sdougm  * output_legacy_file(out, proto)
35853034Sdougm  *
35863034Sdougm  * Walk all of the groups for the specified protocol and call
35873034Sdougm  * out_share() to format and write in the format displayed by the
35883034Sdougm  * "share" command with no arguments.
35893034Sdougm  */
35903034Sdougm 
35913034Sdougm static void
3592*3910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
35933034Sdougm {
35943034Sdougm 	sa_group_t group;
35953034Sdougm 
3596*3910Sdougm 	for (group = sa_get_group(handle, NULL); group != NULL;
35973034Sdougm 		group = sa_get_next_group(group)) {
35983034Sdougm 	    char *options;
35993034Sdougm 	    char *zfs;
36003034Sdougm 
36013034Sdougm 		/*
36023034Sdougm 		 * get default options preformated, being careful to
36033034Sdougm 		 * handle legacy shares differently from new style
36043034Sdougm 		 * shares. Legacy share have options on the share.
36053034Sdougm 		 */
36063034Sdougm 
36073034Sdougm 	    zfs = sa_get_group_attr(group, "zfs");
36083034Sdougm 	    if (zfs != NULL) {
36093034Sdougm 		sa_group_t zgroup;
36103034Sdougm 		sa_free_attr_string(zfs);
36113034Sdougm 		options = sa_proto_legacy_format(proto, group, 1);
36123034Sdougm 		for (zgroup = sa_get_sub_group(group); zgroup != NULL;
36133034Sdougm 		    zgroup = sa_get_next_group(zgroup)) {
36143034Sdougm 
36153034Sdougm 		    /* got a group, so display it */
36163348Sdougm 		    out_share(out, zgroup, proto);
36173034Sdougm 		}
36183034Sdougm 	    } else {
36193034Sdougm 		options = sa_proto_legacy_format(proto, group, 1);
36203348Sdougm 		out_share(out, group, proto);
36213034Sdougm 	    }
36223034Sdougm 	    if (options != NULL)
36233034Sdougm 		free(options);
36243034Sdougm 	}
36253034Sdougm }
36263034Sdougm 
36273034Sdougm int
3628*3910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
36293034Sdougm {
36303034Sdougm 	char *protocol = "nfs";
36313034Sdougm 	char *options = NULL;
36323034Sdougm 	char *description = NULL;
36333034Sdougm 	char *groupname = NULL;
36343034Sdougm 	char *sharepath = NULL;
36353034Sdougm 	char *resource = NULL;
36363034Sdougm 	char *groupstatus = NULL;
36373034Sdougm 	int persist = SA_SHARE_TRANSIENT;
36383034Sdougm 	int argsused = 0;
36393034Sdougm 	int c;
36403034Sdougm 	int ret = SA_OK;
36413034Sdougm 	int zfs = 0;
36423034Sdougm 	int true_legacy = 0;
36433034Sdougm 	int curtype = SA_SHARE_TRANSIENT;
36443034Sdougm 	char cmd[MAXPATHLEN];
36453034Sdougm #ifdef lint
36463034Sdougm 	flags = flags;
36473034Sdougm #endif
36483034Sdougm 
36493034Sdougm 	while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
36503034Sdougm 	    switch (c) {
36513034Sdougm 	    case 'd':
36523034Sdougm 		description = optarg;
36533034Sdougm 		argsused++;
36543034Sdougm 		break;
36553034Sdougm 	    case 'F':
36563034Sdougm 		protocol = optarg;
36573034Sdougm 		if (!sa_valid_protocol(protocol)) {
36583034Sdougm 		    if (format_legacy_path(cmd, MAXPATHLEN,
36593034Sdougm 			    protocol, "share") == 0 && check_legacy_cmd(cmd)) {
36603034Sdougm 			true_legacy++;
36613034Sdougm 		    } else {
36623034Sdougm 			(void) fprintf(stderr,
36633034Sdougm 					gettext("Invalid protocol specified:"
36643034Sdougm 						"%s\n"),
36653034Sdougm 				protocol);
36663034Sdougm 			return (SA_INVALID_PROTOCOL);
36673034Sdougm 		    }
36683034Sdougm 		}
36693034Sdougm 		break;
36703034Sdougm 	    case 'o':
36713034Sdougm 		options = optarg;
36723034Sdougm 		argsused++;
36733034Sdougm 		break;
36743034Sdougm 	    case 'p':
36753034Sdougm 		persist = SA_SHARE_PERMANENT;
36763034Sdougm 		argsused++;
36773034Sdougm 		break;
36783034Sdougm 	    case 'h':
36793034Sdougm 	    case '?':
36803034Sdougm 	    default:
36813034Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
36823034Sdougm 						sa_get_usage(USAGE_SHARE));
36833034Sdougm 		return (SA_OK);
36843034Sdougm 	    }
36853034Sdougm 	}
36863034Sdougm 
36873034Sdougm 	/* have the info so construct what is needed */
36883034Sdougm 	if (!argsused && optind == argc) {
36893034Sdougm 	    /* display current info in share format */
3690*3910Sdougm 	    (void) output_legacy_file(stdout, "nfs", handle);
36913034Sdougm 	} else {
36923034Sdougm 	    sa_group_t group = NULL;
36933034Sdougm 	    sa_share_t share;
36943034Sdougm 	    char dir[MAXPATHLEN];
36953034Sdougm 
36963034Sdougm 	    /* we are modifying the configuration */
36973034Sdougm 	    if (optind == argc) {
36983034Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
36993034Sdougm 				sa_get_usage(USAGE_SHARE));
37003034Sdougm 		return (SA_LEGACY_ERR);
37013034Sdougm 	    }
37023034Sdougm 
37033034Sdougm 	    if (true_legacy) {
37043034Sdougm 		/* if still using legacy share/unshare, exec it */
37053034Sdougm 		ret = run_legacy_command(cmd, argv);
37063034Sdougm 		return (ret);
37073034Sdougm 	    }
37083034Sdougm 
37093034Sdougm 	    sharepath = argv[optind++];
37103034Sdougm 	    if (optind < argc) {
37113034Sdougm 		resource = argv[optind];
37123034Sdougm 		groupname = strchr(resource, '@');
37133034Sdougm 		if (groupname != NULL)
37143034Sdougm 		    *groupname++ = '\0';
37153034Sdougm 	    }
37163034Sdougm 	    if (realpath(sharepath, dir) == NULL)
37173034Sdougm 		ret = SA_BAD_PATH;
37183034Sdougm 	    else
37193034Sdougm 		sharepath = dir;
37203034Sdougm 	    if (ret == SA_OK) {
3721*3910Sdougm 		share = sa_find_share(handle, sharepath);
37223034Sdougm 	    } else {
37233034Sdougm 		share = NULL;
37243034Sdougm 	    }
37253034Sdougm 	    if (groupname != NULL) {
37263034Sdougm 		    ret = SA_NOT_ALLOWED;
37273034Sdougm 	    } else if (ret == SA_OK) {
37283034Sdougm 		char *legacygroup = "default";
37293034Sdougm 		/*
37303034Sdougm 		 * the legacy group is always present and zfs groups
37313034Sdougm 		 * come and go.  zfs shares may be in sub-groups and
37323034Sdougm 		 * the zfs share will already be in that group so it
37333034Sdougm 		 * isn't an error.
37343034Sdougm 		 */
37353034Sdougm 		if (share != NULL) {
37363034Sdougm 		/*
37373034Sdougm 		 * if the share exists, then make sure it is one we
37383034Sdougm 		 * want to handle.
37393034Sdougm 		 */
37403034Sdougm 		    group = sa_get_parent_group(share);
37413034Sdougm 		} else {
3742*3910Sdougm 		    group = sa_get_group(handle, legacygroup);
37433034Sdougm 		}
37443034Sdougm 		if (group != NULL) {
37453034Sdougm 		    groupstatus = group_status(group);
37463034Sdougm 		    if (share == NULL) {
37473034Sdougm 			share = sa_add_share(group, sharepath, persist, &ret);
37483034Sdougm 			if (share == NULL && ret == SA_DUPLICATE_NAME) {
37493034Sdougm 			    /* could be a ZFS path being started */
3750*3910Sdougm 			    if (sa_zfs_is_shared(handle, sharepath)) {
37513034Sdougm 				ret = SA_OK;
3752*3910Sdougm 				group = sa_get_group(handle, "zfs");
37533034Sdougm 				if (group == NULL) {
37543034Sdougm 				    /* this shouldn't happen */
37553034Sdougm 				    ret = SA_CONFIG_ERR;
37563034Sdougm 				}
37573034Sdougm 				if (group != NULL) {
37583034Sdougm 				    share = sa_add_share(group, sharepath,
37593034Sdougm 							    persist, &ret);
37603034Sdougm 				}
37613034Sdougm 			    }
37623034Sdougm 			}
37633034Sdougm 		    } else {
37643108Sdougm 			char *type;
37653034Sdougm 			/*
37663034Sdougm 			 * may want to change persist state, but the
37673108Sdougm 			 * important thing is to change options. We
37683108Sdougm 			 * need to change them regardless of the
37693108Sdougm 			 * source.
37703034Sdougm 			 */
3771*3910Sdougm 			if (sa_zfs_is_shared(handle, sharepath)) {
37723108Sdougm 			    zfs = 1;
37733108Sdougm 			}
37743108Sdougm 			remove_all_options(share, protocol);
37753108Sdougm 			type = sa_get_share_attr(share, "type");
37763108Sdougm 			if (type != NULL &&
37773108Sdougm 			    strcmp(type, "transient") != 0) {
37783108Sdougm 			    curtype = SA_SHARE_PERMANENT;
37793108Sdougm 			}
37803108Sdougm 			if (type != NULL)
37813108Sdougm 			    sa_free_attr_string(type);
37823108Sdougm 			if (curtype != persist) {
37833108Sdougm 			    (void) sa_set_share_attr(share, "type",
37843034Sdougm 					persist == SA_SHARE_PERMANENT ?
37853034Sdougm 						"persist" : "transient");
37863034Sdougm 			}
37873034Sdougm 		    }
37883108Sdougm 		    /* have a group to hold this share path */
37893108Sdougm 		    if (ret == SA_OK && options != NULL &&
37903108Sdougm 			strlen(options) > 0) {
37913108Sdougm 			ret = sa_parse_legacy_options(share,
37923108Sdougm 							options,
37933108Sdougm 							protocol);
37943108Sdougm 		    }
37953034Sdougm 		    if (!zfs) {
37963108Sdougm 			/*
37973108Sdougm 			 * zfs shares never have resource or
37983108Sdougm 			 * description and we can't store the values
37993108Sdougm 			 * so don't try.
38003108Sdougm 			 */
38013034Sdougm 			if (ret == SA_OK && description != NULL)
38023034Sdougm 			    ret = sa_set_share_description(share, description);
38033034Sdougm 			if (ret == SA_OK && resource != NULL)
38043034Sdougm 			    ret = sa_set_share_attr(share, "resource",
38053034Sdougm 						    resource);
38063034Sdougm 		    }
38073034Sdougm 		    if (ret == SA_OK) {
38083034Sdougm 			if (strcmp(groupstatus, "enabled") == 0)
38093034Sdougm 			    ret = sa_enable_share(share, protocol);
38103034Sdougm 			if (ret == SA_OK && persist == SA_SHARE_PERMANENT) {
38113034Sdougm 			    (void) sa_update_legacy(share, protocol);
38123034Sdougm 			}
38133034Sdougm 			if (ret == SA_OK)
3814*3910Sdougm 			    ret = sa_update_config(handle);
38153034Sdougm 		    }
38163034Sdougm 		} else {
38173034Sdougm 		    ret = SA_SYSTEM_ERR;
38183034Sdougm 		}
38193034Sdougm 	    }
38203034Sdougm 	}
38213034Sdougm 	if (ret != SA_OK) {
38223034Sdougm 	    (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
38233034Sdougm 				sharepath, sa_errorstr(ret));
38243034Sdougm 	    ret = SA_LEGACY_ERR;
38253034Sdougm 
38263034Sdougm 	}
38273034Sdougm 	return (ret);
38283034Sdougm }
38293034Sdougm 
38303034Sdougm /*
38313034Sdougm  * sa_legacy_unshare(flags, argc, argv)
38323034Sdougm  *
38333034Sdougm  * Implements the original unshare command.
38343034Sdougm  */
38353034Sdougm 
38363034Sdougm int
3837*3910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
38383034Sdougm {
38393034Sdougm 	char *protocol = "nfs"; /* for now */
38403034Sdougm 	char *options = NULL;
38413034Sdougm 	char *sharepath = NULL;
38423034Sdougm 	int persist = SA_SHARE_TRANSIENT;
38433034Sdougm 	int argsused = 0;
38443034Sdougm 	int c;
38453034Sdougm 	int ret = SA_OK;
38463034Sdougm 	int true_legacy = 0;
38473034Sdougm 	char cmd[MAXPATHLEN];
38483034Sdougm #ifdef lint
38493034Sdougm 	flags = flags;
38503034Sdougm 	options = options;
38513034Sdougm #endif
38523034Sdougm 
38533034Sdougm 	while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
38543034Sdougm 	    switch (c) {
38553034Sdougm 	    case 'h':
38563034Sdougm 	    case '?':
38573034Sdougm 		break;
38583034Sdougm 	    case 'F':
38593034Sdougm 		protocol = optarg;
38603034Sdougm 		if (!sa_valid_protocol(protocol)) {
38613034Sdougm 		    if (format_legacy_path(cmd, MAXPATHLEN,
38623034Sdougm 						protocol, "unshare") == 0 &&
38633034Sdougm 			check_legacy_cmd(cmd)) {
38643034Sdougm 			true_legacy++;
38653034Sdougm 		    } else {
38663034Sdougm 			(void) printf(gettext("Invalid file system name\n"));
38673034Sdougm 			return (SA_INVALID_PROTOCOL);
38683034Sdougm 		    }
38693034Sdougm 		}
38703034Sdougm 		break;
38713034Sdougm 	    case 'o':
38723034Sdougm 		options = optarg;
38733034Sdougm 		argsused++;
38743034Sdougm 		break;
38753034Sdougm 	    case 'p':
38763034Sdougm 		persist = SA_SHARE_PERMANENT;
38773034Sdougm 		argsused++;
38783034Sdougm 		break;
38793034Sdougm 	    default:
38803034Sdougm 		(void) printf(gettext("usage: %s\n"),
38813034Sdougm 				sa_get_usage(USAGE_UNSHARE));
38823034Sdougm 		return (SA_OK);
38833034Sdougm 	    }
38843034Sdougm 	}
38853034Sdougm 
38863034Sdougm 	/* have the info so construct what is needed */
38873034Sdougm 	if (optind == argc || (optind + 1) < argc) {
38883034Sdougm 	    ret = SA_SYNTAX_ERR;
38893034Sdougm 	} else {
38903034Sdougm 	    sa_share_t share;
38913034Sdougm 	    char dir[MAXPATHLEN];
38923034Sdougm 	    if (true_legacy) {
38933034Sdougm 		/* if still using legacy share/unshare, exec it */
38943034Sdougm 		ret = run_legacy_command(cmd, argv);
38953034Sdougm 		return (ret);
38963034Sdougm 	    }
38973663Sdougm 		/*
38983663Sdougm 		 * Find the path in the internal configuration. If it
38993663Sdougm 		 * isn't found, attempt to resolve the path via
39003663Sdougm 		 * realpath() and try again.
39013663Sdougm 		 */
39023034Sdougm 	    sharepath = argv[optind++];
3903*3910Sdougm 	    share = sa_find_share(handle, sharepath);
39043663Sdougm 	    if (share == NULL) {
39053663Sdougm 		if (realpath(sharepath, dir) == NULL) {
39063663Sdougm 		    ret = SA_NO_SUCH_PATH;
39073663Sdougm 		} else {
3908*3910Sdougm 		    share = sa_find_share(handle, dir);
39093663Sdougm 		}
39103663Sdougm 	    }
39113663Sdougm 	    if (share != NULL) {
39123663Sdougm 		ret = sa_disable_share(share, protocol);
39133663Sdougm 		/*
39143663Sdougm 		 * Errors are ok and removal should still occur. The
39153663Sdougm 		 * legacy unshare is more forgiving of errors than the
39163663Sdougm 		 * remove-share subcommand which may need the force
39173663Sdougm 		 * flag set for some error conditions. That is, the
39183663Sdougm 		 * "unshare" command will always unshare if it can
39193663Sdougm 		 * while "remove-share" might require the force option.
39203663Sdougm 		 */
39213663Sdougm 		if (persist == SA_SHARE_PERMANENT) {
39223663Sdougm 		    ret = sa_remove_share(share);
39233663Sdougm 		    if (ret == SA_OK)
3924*3910Sdougm 			ret = sa_update_config(handle);
39253663Sdougm 		}
39263034Sdougm 	    } else {
39273663Sdougm 		ret = SA_NOT_SHARED;
39283034Sdougm 	    }
39293034Sdougm 	}
39303034Sdougm 	switch (ret) {
39313034Sdougm 	default:
39323034Sdougm 	    (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
39333034Sdougm 	    ret = SA_LEGACY_ERR;
39343034Sdougm 	    break;
39353034Sdougm 	case SA_SYNTAX_ERR:
39363034Sdougm 	    (void) printf(gettext("usage: %s\n"),
39373034Sdougm 				sa_get_usage(USAGE_UNSHARE));
39383034Sdougm 	    break;
39393034Sdougm 	case SA_OK:
39403034Sdougm 	    break;
39413034Sdougm 	}
39423034Sdougm 	return (ret);
39433034Sdougm }
39443034Sdougm 
39453034Sdougm /*
39463034Sdougm  * common commands that implement the sub-commands used by all
39473034Sdougm  * protcols. The entries are found via the lookup command
39483034Sdougm  */
39493034Sdougm 
39503034Sdougm static sa_command_t commands[] = {
39513034Sdougm 	{"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
39523034Sdougm 	{"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
39533034Sdougm 	{"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
39543034Sdougm 	{"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
39553034Sdougm 	{"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
39563034Sdougm 	{"list", 0, sa_list, USAGE_LIST},
39573034Sdougm 	{"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
39583034Sdougm 	{"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
39593034Sdougm 	{"set", 0, sa_set, USAGE_SET, SVC_SET},
39603034Sdougm 	{"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
39613034Sdougm 	{"show", 0, sa_show, USAGE_SHOW},
39623034Sdougm 	{"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
39633034Sdougm 	{"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
39643034Sdougm 		SVC_SET|SVC_ACTION},
39653034Sdougm 	{"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
39663034Sdougm 	{"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
39673034Sdougm 	{"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
39683034Sdougm 	{NULL, 0, NULL, NULL}
39693034Sdougm };
39703034Sdougm 
39713034Sdougm static char *
39723034Sdougm sa_get_usage(sa_usage_t index)
39733034Sdougm {
39743034Sdougm 	char *ret = NULL;
39753034Sdougm 	switch (index) {
39763034Sdougm 	case USAGE_ADD_SHARE:
39773034Sdougm 	    ret = gettext("add-share [-nth] [-r resource-name] "
39783034Sdougm 			    "[-d \"description text\"] -s sharepath group");
39793034Sdougm 	    break;
39803034Sdougm 	case USAGE_CREATE:
39813034Sdougm 	    ret = gettext("create [-nvh] [-P proto [-p property=value]] group");
39823034Sdougm 	    break;
39833034Sdougm 	case USAGE_DELETE:
39843034Sdougm 	    ret = gettext("delete [-nvh] [-P proto] [-f] group");
39853034Sdougm 	    break;
39863034Sdougm 	case USAGE_DISABLE:
39873034Sdougm 	    ret = gettext("disable [-nvh] {-a | group ...}");
39883034Sdougm 	    break;
39893034Sdougm 	case USAGE_ENABLE:
39903034Sdougm 	    ret = gettext("enable [-nvh] {-a | group ...}");
39913034Sdougm 	    break;
39923034Sdougm 	case USAGE_LIST:
39933034Sdougm 	    ret = gettext("list [-vh] [-P proto]");
39943034Sdougm 	    break;
39953034Sdougm 	case USAGE_MOVE_SHARE:
39963034Sdougm 	    ret = gettext("move-share [-nvh] -s sharepath destination-group");
39973034Sdougm 	    break;
39983034Sdougm 	case USAGE_REMOVE_SHARE:
39993034Sdougm 	    ret = gettext("remove-share [-fnvh] -s sharepath group");
40003034Sdougm 	    break;
40013034Sdougm 	case USAGE_SET:
40023034Sdougm 	    ret = gettext("set [-nvh] -P proto [-S optspace] "
40033034Sdougm 				"[-p property=value]* [-s sharepath] group");
40043034Sdougm 	    break;
40053034Sdougm 	case USAGE_SET_SECURITY:
40063034Sdougm 	    ret = gettext("set-security [-nvh] -P proto -S security-type "
40073034Sdougm 			    "[-p property=value]* group");
40083034Sdougm 	    break;
40093034Sdougm 	case USAGE_SET_SHARE:
40103034Sdougm 	    ret = gettext("set-share [-nh] [-r resource] "
40113034Sdougm 			    "[-d \"description text\"] -s sharepath group");
40123034Sdougm 	    break;
40133034Sdougm 	case USAGE_SHOW:
40143034Sdougm 	    ret = gettext("show [-pvxh] [-P proto] [group ...]");
40153034Sdougm 	    break;
40163034Sdougm 	case USAGE_SHARE:
40173034Sdougm 	    ret = gettext("share [-F fstype] [-p] [-o optionlist]"
40183034Sdougm 			    "[-d description] [pathname [resourcename]]");
40193034Sdougm 	    break;
40203034Sdougm 	case USAGE_START:
40213034Sdougm 	    ret = gettext("start [-vh] [-P proto] {-a | group ...}");
40223034Sdougm 	    break;
40233034Sdougm 	case USAGE_STOP:
40243034Sdougm 	    ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
40253034Sdougm 	    break;
40263034Sdougm 	case USAGE_UNSET:
40273034Sdougm 	    ret = gettext("unset [-nvh] -P proto [-S optspace] "
40283034Sdougm 			    "[-p property]* group");
40293034Sdougm 	    break;
40303034Sdougm 	case USAGE_UNSET_SECURITY:
40313034Sdougm 	    ret = gettext("unset-security [-nvh] -P proto -S security-type "
40323034Sdougm 				"[-p property]* group");
40333034Sdougm 	    break;
40343034Sdougm 	case USAGE_UNSHARE:
40353034Sdougm 	    ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath");
40363034Sdougm 	    break;
40373034Sdougm 	}
40383034Sdougm 	return (ret);
40393034Sdougm }
40403034Sdougm 
40413034Sdougm /*
40423034Sdougm  * sa_lookup(cmd, proto)
40433034Sdougm  *
40443034Sdougm  * Lookup the sub-command. proto isn't currently used, but it may
40453034Sdougm  * eventually provide a way to provide protocol specific sub-commands.
40463034Sdougm  */
40473034Sdougm 
40483034Sdougm sa_command_t *
40493034Sdougm sa_lookup(char *cmd, char *proto)
40503034Sdougm {
40513034Sdougm 	int i;
40523034Sdougm 	size_t len;
40533034Sdougm #ifdef lint
40543034Sdougm 	proto = proto;
40553034Sdougm #endif
40563034Sdougm 
40573034Sdougm 	len = strlen(cmd);
40583034Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
40593034Sdougm 	    if (strncmp(cmd, commands[i].cmdname, len) == 0)
40603034Sdougm 		return (&commands[i]);
40613034Sdougm 	}
40623034Sdougm 	return (NULL);
40633034Sdougm }
40643034Sdougm 
40653034Sdougm void
40663034Sdougm sub_command_help(char *proto)
40673034Sdougm {
40683034Sdougm 	int i;
40693034Sdougm #ifdef lint
40703034Sdougm 	proto = proto;
40713034Sdougm #endif
40723034Sdougm 
40733034Sdougm 	(void) printf(gettext("\tsub-commands:\n"));
40743034Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
40753034Sdougm 	    if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
40763034Sdougm 		(void) printf("\t%s\n",
40773034Sdougm 				sa_get_usage((sa_usage_t)commands[i].cmdidx));
40783034Sdougm 	}
40793034Sdougm }
4080