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 /*
252*4241Sdougm  * isenabled(group)
253*4241Sdougm  *
254*4241Sdougm  * Returns B_TRUE if the group is enabled or B_FALSE if it isn't.
255*4241Sdougm  * Moved to separate function to reduce clutter in the code.
256*4241Sdougm  */
257*4241Sdougm 
258*4241Sdougm static int
259*4241Sdougm isenabled(sa_group_t group)
260*4241Sdougm {
261*4241Sdougm 	char *state;
262*4241Sdougm 	int ret = B_FALSE;
263*4241Sdougm 
264*4241Sdougm 	if (group != NULL) {
265*4241Sdougm 	    state = sa_get_group_attr(group, "state");
266*4241Sdougm 	    if (state != NULL) {
267*4241Sdougm 		if (strcmp(state, "enabled") == 0)
268*4241Sdougm 		    ret = B_TRUE;
269*4241Sdougm 		sa_free_attr_string(state);
270*4241Sdougm 	    }
271*4241Sdougm 	}
272*4241Sdougm 	return (ret);
273*4241Sdougm }
274*4241Sdougm 
275*4241Sdougm /*
2763082Sdougm  * enable_all_groups(list, setstate, online, updateproto)
2773082Sdougm  *	Given a list of groups, enable each one found.  If updateproto
2783082Sdougm  *	is not NULL, then update all the shares for the protocol that
2793082Sdougm  *	was passed in.
2803034Sdougm  */
2813034Sdougm static int
2823910Sdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
2833910Sdougm 	int online, char *updateproto)
2843034Sdougm {
285*4241Sdougm 	int ret;
2863034Sdougm 	char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
2873034Sdougm 	char *state;
2883034Sdougm 	char *name;
2893034Sdougm 	char *zfs = NULL;
2903034Sdougm 	sa_group_t group;
2913082Sdougm 	sa_group_t subgroup;
2923034Sdougm 
293*4241Sdougm 	for (ret = SA_OK; work != NULL;	work = work->next) {
2943034Sdougm 	    group = (sa_group_t)work->item;
295*4241Sdougm 
296*4241Sdougm 		/*
297*4241Sdougm 		 * If setstate == TRUE, then make sure to set
298*4241Sdougm 		 * enabled. This needs to be done here in order for
299*4241Sdougm 		 * the isenabled check to succeed on a newly enabled
300*4241Sdougm 		 * group.
301*4241Sdougm 		 */
302*4241Sdougm 	    if (setstate == B_TRUE) {
303*4241Sdougm 		ret = sa_set_group_attr(group, "state",	"enabled");
304*4241Sdougm 		if (ret != SA_OK)
305*4241Sdougm 		    break;
306*4241Sdougm 	    }
307*4241Sdougm 
308*4241Sdougm 		/*
309*4241Sdougm 		 * Check to see if group is enabled. If it isn't, skip
310*4241Sdougm 		 * the rest.  We don't want shares starting if the
311*4241Sdougm 		 * group is disabled. The properties may have been
312*4241Sdougm 		 * updated, but there won't be a change until the
313*4241Sdougm 		 * group is enabled.
314*4241Sdougm 		 */
315*4241Sdougm 	    if (!isenabled(group))
316*4241Sdougm 		continue;
317*4241Sdougm 
3183034Sdougm 	    /* if itemdata != NULL then a single share */
3193034Sdougm 	    if (work->itemdata != NULL) {
3203034Sdougm 		ret = sa_enable_share((sa_share_t)work->itemdata, NULL);
3213034Sdougm 	    }
322*4241Sdougm 	    if (ret != SA_OK)
323*4241Sdougm 		break;
324*4241Sdougm 
325*4241Sdougm 	    /* if itemdata == NULL then the whole group */
326*4241Sdougm 	    if (work->itemdata == NULL) {
327*4241Sdougm 		zfs = sa_get_group_attr(group, "zfs");
328*4241Sdougm 		/*
329*4241Sdougm 		 * if the share is managed by ZFS, don't
330*4241Sdougm 		 * update any of the protocols since ZFS is
331*4241Sdougm 		 * handling this.  updateproto will contain
332*4241Sdougm 		 * the name of the protocol that we want to
333*4241Sdougm 		 * update legacy files for.
334*4241Sdougm 		 */
335*4241Sdougm 		enable_group(group, zfs == NULL ? updateproto : NULL);
336*4241Sdougm 		for (subgroup = sa_get_sub_group(group); subgroup != NULL;
3373082Sdougm 			subgroup = sa_get_next_group(subgroup)) {
3383082Sdougm 			/* never update legacy for ZFS subgroups */
3393082Sdougm 			enable_group(subgroup, NULL);
3403034Sdougm 		}
341*4241Sdougm 	    }
342*4241Sdougm 	    if (online) {
343*4241Sdougm 		zfs = sa_get_group_attr(group, "zfs");
344*4241Sdougm 		name = sa_get_group_attr(group, "name");
345*4241Sdougm 		if (name != NULL) {
3463034Sdougm 			if (zfs == NULL) {
3473034Sdougm 			    (void) snprintf(instance, sizeof (instance),
3483034Sdougm 						"%s:%s",
3493034Sdougm 						SA_SVC_FMRI_BASE, name);
3503034Sdougm 			    state = smf_get_state(instance);
3513034Sdougm 			    if (state == NULL ||
3523034Sdougm 				strcmp(state, "online") != 0) {
3533034Sdougm 				(void) smf_enable_instance(instance, 0);
3543034Sdougm 				free(state);
3553034Sdougm 			    }
3563034Sdougm 			} else {
3573034Sdougm 			    sa_free_attr_string(zfs);
3583034Sdougm 			    zfs = NULL;
3593034Sdougm 			}
3603034Sdougm 			if (name != NULL)
3613034Sdougm 			    sa_free_attr_string(name);
3623034Sdougm 		}
3633034Sdougm 	    }
3643034Sdougm 	}
3653034Sdougm 	if (ret == SA_OK) {
3663910Sdougm 	    ret = sa_update_config(handle);
3673034Sdougm 	}
3683034Sdougm 	return (ret);
3693034Sdougm }
3703034Sdougm 
3713034Sdougm /*
3723034Sdougm  * chk_opt(optlistp, security, proto)
3733034Sdougm  *
3743034Sdougm  * Do a sanity check on the optlist provided for the protocol.  This
3753034Sdougm  * is a syntax check and verification that the property is either a
3763034Sdougm  * general or specific to a names optionset.
3773034Sdougm  */
3783034Sdougm 
3793034Sdougm static int
3803034Sdougm chk_opt(struct options *optlistp, int security, char *proto)
3813034Sdougm {
3823034Sdougm 	struct options *optlist;
3833034Sdougm 	char *sep = "";
3843034Sdougm 	int notfirst = 0;
3853034Sdougm 	int ret;
3863034Sdougm 
3873034Sdougm 	for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
3883034Sdougm 	    char *optname;
3893034Sdougm 
3903034Sdougm 	    optname = optlist->optname;
3913034Sdougm 	    ret = OPT_ADD_OK;
3923034Sdougm 	    /* extract property/value pair */
3933034Sdougm 	    if (sa_is_security(optname, proto)) {
3943034Sdougm 		if (!security)
3953034Sdougm 		    ret = OPT_ADD_SECURITY;
3963034Sdougm 	    } else {
3973034Sdougm 		if (security)
3983034Sdougm 		    ret = OPT_ADD_PROPERTY;
3993034Sdougm 	    }
4003034Sdougm 	    if (ret != OPT_ADD_OK) {
4013034Sdougm 		if (notfirst == 0)
4023034Sdougm 		    (void) printf(gettext("Property syntax error: "));
4033034Sdougm 		switch (ret) {
4043034Sdougm 		case OPT_ADD_SYNTAX:
4053034Sdougm 		    (void) printf(gettext("%ssyntax error: %s"),
4063034Sdougm 				    sep, optname);
4073034Sdougm 		    sep = ", ";
4083034Sdougm 		    break;
4093034Sdougm 		case OPT_ADD_SECURITY:
4103034Sdougm 		    (void) printf(gettext("%s%s requires -S"),
4113034Sdougm 				    optname, sep);
4123034Sdougm 		    sep = ", ";
4133034Sdougm 		    break;
4143034Sdougm 		case OPT_ADD_PROPERTY:
4153034Sdougm 		    (void) printf(gettext("%s%s not supported with -S"),
4163034Sdougm 				    optname, sep);
4173034Sdougm 		    sep = ", ";
4183034Sdougm 		    break;
4193034Sdougm 		}
4203034Sdougm 		notfirst++;
4213034Sdougm 	    }
4223034Sdougm 	}
4233034Sdougm 	if (notfirst) {
4243034Sdougm 	    (void) printf("\n");
4253034Sdougm 	    ret = SA_SYNTAX_ERR;
4263034Sdougm 	}
4273034Sdougm 	return (ret);
4283034Sdougm }
4293034Sdougm 
4303034Sdougm /*
4313034Sdougm  * free_opt(optlist)
4323034Sdougm  *	Free the specified option list.
4333034Sdougm  */
4343034Sdougm static void
4353034Sdougm free_opt(struct options *optlist)
4363034Sdougm {
4373034Sdougm 	struct options *nextopt;
4383034Sdougm 	while (optlist != NULL) {
4393034Sdougm 		nextopt = optlist->next;
4403034Sdougm 		free(optlist);
4413034Sdougm 		optlist = nextopt;
4423034Sdougm 	}
4433034Sdougm }
4443034Sdougm 
4453034Sdougm /*
4463034Sdougm  * check property list for valid properties
4473034Sdougm  * A null value is a remove which is always valid.
4483034Sdougm  */
4493034Sdougm static int
4503034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec)
4513034Sdougm {
4523034Sdougm 	int ret = SA_OK;
4533034Sdougm 	struct options *cur;
4543034Sdougm 	sa_property_t prop;
4553034Sdougm 	sa_optionset_t parent = NULL;
4563034Sdougm 
4573034Sdougm 	if (object != NULL) {
4583034Sdougm 	    if (sec == NULL)
4593034Sdougm 		parent = sa_get_optionset(object, proto);
4603034Sdougm 	    else
4613034Sdougm 		parent = sa_get_security(object, sec, proto);
4623034Sdougm 	}
4633034Sdougm 
4643034Sdougm 	for (cur = optlist; cur != NULL; cur = cur->next) {
4653034Sdougm 	    if (cur->optvalue != NULL) {
4663034Sdougm 		prop = sa_create_property(cur->optname, cur->optvalue);
4673034Sdougm 		if (prop == NULL)
4683034Sdougm 		    ret = SA_NO_MEMORY;
4693034Sdougm 		if (ret != SA_OK ||
4703034Sdougm 		    (ret = sa_valid_property(parent, proto, prop)) != SA_OK) {
4713034Sdougm 		    (void) printf(gettext("Could not add property %s: %s\n"),
4723034Sdougm 					cur->optname,
4733034Sdougm 					sa_errorstr(ret));
4743034Sdougm 		}
4753034Sdougm 		(void) sa_remove_property(prop);
4763034Sdougm 	    }
4773034Sdougm 	}
4783034Sdougm 	return (ret);
4793034Sdougm }
4803034Sdougm 
4813034Sdougm /*
4823034Sdougm  * add_optionset(group, optlist, protocol, *err)
4833034Sdougm  *	Add the options in optlist to an optionset and then add the optionset
4843034Sdougm  *	to the group.
4853034Sdougm  *
4863034Sdougm  *	The return value indicates if there was a "change" while errors are
4873034Sdougm  *	returned via the *err parameters.
4883034Sdougm  */
4893034Sdougm static int
4903034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
4913034Sdougm {
4923034Sdougm 	sa_optionset_t optionset;
4933034Sdougm 	int ret = SA_OK;
4943034Sdougm 	int result = 0;
4953034Sdougm 
4963034Sdougm 	optionset = sa_get_optionset(group, proto);
4973034Sdougm 	if (optionset == NULL) {
4983034Sdougm 	    optionset = sa_create_optionset(group, proto);
4993034Sdougm 	    result = 1; /* adding a protocol is a change */
5003034Sdougm 	}
5013034Sdougm 	if (optionset != NULL) {
5023034Sdougm 	    while (optlist != NULL) {
5033034Sdougm 		sa_property_t prop;
5043034Sdougm 		prop = sa_get_property(optionset, optlist->optname);
5053034Sdougm 		if (prop == NULL) {
5063034Sdougm 			/*
5073034Sdougm 			 * add the property, but only if it is
5083034Sdougm 			 * a non-NULL or non-zero length value
5093034Sdougm 			 */
5103034Sdougm 		    if (optlist->optvalue != NULL) {
5113034Sdougm 			prop = sa_create_property(optlist->optname,
5123034Sdougm 						    optlist->optvalue);
5133034Sdougm 			if (prop != NULL) {
5143034Sdougm 			    ret = sa_valid_property(optionset, proto, prop);
5153034Sdougm 			    if (ret != SA_OK) {
5163034Sdougm 				(void) sa_remove_property(prop);
5173034Sdougm 				(void) printf(gettext("Could not add property "
5183034Sdougm 							"%s: %s\n"),
5193034Sdougm 						optlist->optname,
5203034Sdougm 						sa_errorstr(ret));
5213034Sdougm 			    }
5223034Sdougm 			}
5233034Sdougm 			if (ret == SA_OK) {
5243034Sdougm 			    ret = sa_add_property(optionset, prop);
5253034Sdougm 			    if (ret != SA_OK) {
5263034Sdougm 				(void) printf(gettext("Could not add property"
5273034Sdougm 							" %s: %s\n"),
5283034Sdougm 						optlist->optname,
5293034Sdougm 						sa_errorstr(ret));
5303034Sdougm 			    } else {
5313034Sdougm 				/* there was a change */
5323034Sdougm 				result = 1;
5333034Sdougm 			    }
5343034Sdougm 			}
5353034Sdougm 		    }
5363034Sdougm 		} else {
5373034Sdougm 		    ret = sa_update_property(prop, optlist->optvalue);
5383034Sdougm 		    /* should check to see if value changed */
5393034Sdougm 		    if (ret != SA_OK) {
5403034Sdougm 			(void) printf(gettext("Could not update "
5413034Sdougm 						"property %s: %s\n"),
5423034Sdougm 					optlist->optname,
5433034Sdougm 					sa_errorstr(ret));
5443034Sdougm 		    } else {
5453034Sdougm 			result = 1;
5463034Sdougm 		    }
5473034Sdougm 		}
5483034Sdougm 		optlist = optlist->next;
5493034Sdougm 	    }
5503034Sdougm 	    ret = sa_commit_properties(optionset, 0);
5513034Sdougm 	}
5523034Sdougm 	if (err != NULL)
5533034Sdougm 	    *err = ret;
5543034Sdougm 	return (result);
5553034Sdougm }
5563034Sdougm 
5573034Sdougm /*
5583034Sdougm  * sa_create(flags, argc, argv)
5593034Sdougm  *	create a new group
5603034Sdougm  *	this may or may not have a protocol associated with it.
5613034Sdougm  *	No protocol means "all" protocols in this case.
5623034Sdougm  */
5633034Sdougm static int
5643910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
5653034Sdougm {
5663034Sdougm 	char *groupname;
5673034Sdougm 
5683034Sdougm 	sa_group_t group;
5693034Sdougm 	int verbose = 0;
5703034Sdougm 	int dryrun = 0;
5713034Sdougm 	int c;
5723034Sdougm 	char *protocol = NULL;
5733034Sdougm 	int ret = SA_OK;
5743034Sdougm 	struct options *optlist = NULL;
5753034Sdougm 	int err = 0;
5763034Sdougm 	int auth;
5773034Sdougm 
5783034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) {
5793034Sdougm 	    switch (c) {
5803034Sdougm 	    case 'v':
5813034Sdougm 		verbose++;
5823034Sdougm 		break;
5833034Sdougm 	    case 'n':
5843034Sdougm 		dryrun++;
5853034Sdougm 		break;
5863034Sdougm 	    case 'P':
5873034Sdougm 		protocol = optarg;
5883034Sdougm 		if (!sa_valid_protocol(protocol)) {
5893034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
5903034Sdougm 					protocol);
5913034Sdougm 		    return (SA_INVALID_PROTOCOL);
5923034Sdougm 		}
5933034Sdougm 		break;
5943034Sdougm 	    case 'p':
5953034Sdougm 		ret = add_opt(&optlist, optarg, 0);
5963034Sdougm 		switch (ret) {
5973034Sdougm 		case OPT_ADD_SYNTAX:
5983034Sdougm 		    (void) printf(gettext("Property syntax error for "
5993034Sdougm 						"property: %s\n"),
6003034Sdougm 				    optarg);
6013034Sdougm 		    return (SA_SYNTAX_ERR);
6023034Sdougm 		case OPT_ADD_SECURITY:
6033034Sdougm 		    (void) printf(gettext("Security properties need "
6043034Sdougm 					"to be set with set-security: %s\n"),
6053034Sdougm 				    optarg);
6063034Sdougm 		    return (SA_SYNTAX_ERR);
6073034Sdougm 		default:
6083034Sdougm 		    break;
6093034Sdougm 		}
6103034Sdougm 
6113034Sdougm 		break;
6123034Sdougm 	    default:
6133034Sdougm 	    case 'h':
6143034Sdougm 	    case '?':
6153034Sdougm 		(void) printf(gettext("usage: %s\n"),
6163034Sdougm 				sa_get_usage(USAGE_CREATE));
6173034Sdougm 		return (0);
6183034Sdougm 	    }
6193034Sdougm 	}
6203034Sdougm 
6213034Sdougm 	if (optind >= argc) {
6223034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
6233034Sdougm 	    (void) printf(gettext("\tgroup must be specified.\n"));
6243034Sdougm 	    return (SA_BAD_PATH);
6253034Sdougm 	}
6263034Sdougm 
6273034Sdougm 	if ((optind + 1) < argc) {
6283034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
6293034Sdougm 	    (void) printf(gettext("\textraneous group(s) at end\n"));
6303034Sdougm 	    return (SA_SYNTAX_ERR);
6313034Sdougm 	}
6323034Sdougm 
6333034Sdougm 	if (protocol == NULL && optlist != NULL) {
6343034Sdougm 	    /* lookup default protocol */
6353034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
6363034Sdougm 	    (void) printf(gettext("\tprotocol must be specified "
6373034Sdougm 				"with properties\n"));
6383034Sdougm 	    return (SA_INVALID_PROTOCOL);
6393034Sdougm 	}
6403034Sdougm 
6413034Sdougm 	if (optlist != NULL)
6423034Sdougm 	    ret = chk_opt(optlist, 0, protocol);
6433034Sdougm 	if (ret == OPT_ADD_SECURITY) {
6443034Sdougm 	    (void) printf(gettext("Security properties not "
6453034Sdougm 				"supported with create\n"));
6463034Sdougm 	    return (SA_SYNTAX_ERR);
6473034Sdougm 	}
6483034Sdougm 
6493034Sdougm 	/*
6503034Sdougm 	 * if a group already exists, we can only add a new protocol
6513034Sdougm 	 * to it and not create a new one or add the same protocol
6523034Sdougm 	 * again.
6533034Sdougm 	 */
6543034Sdougm 
6553034Sdougm 	groupname = argv[optind];
6563034Sdougm 
6573034Sdougm 	auth = check_authorizations(groupname, flags);
6583034Sdougm 
6593910Sdougm 	group = sa_get_group(handle, groupname);
6603034Sdougm 	if (group != NULL) {
6613034Sdougm 	    /* group exists so must be a protocol add */
6623034Sdougm 	    if (protocol != NULL) {
6633034Sdougm 		if (has_protocol(group, protocol)) {
6643034Sdougm 		    (void) printf(gettext("Group \"%s\" already exists"
6653034Sdougm 						" with protocol %s\n"),
6663034Sdougm 					groupname, protocol);
6673034Sdougm 		    ret = SA_DUPLICATE_NAME;
6683034Sdougm 		}
6693034Sdougm 	    } else {
6703034Sdougm 		/* must add new protocol */
6713034Sdougm 		(void) printf(gettext("Group already exists and no protocol"
6723034Sdougm 					" specified.\n"));
6733034Sdougm 		ret = SA_DUPLICATE_NAME;
6743034Sdougm 	    }
6753034Sdougm 	} else {
6763034Sdougm 		/*
6773034Sdougm 		 * is it a valid name? Must comply with SMF instance
6783034Sdougm 		 * name restrictions.
6793034Sdougm 		 */
6803034Sdougm 	    if (!sa_valid_group_name(groupname)) {
6813034Sdougm 		ret = SA_INVALID_NAME;
6823034Sdougm 		(void) printf(gettext("Invalid group name: %s\n"), groupname);
6833034Sdougm 	    }
6843034Sdougm 	}
6853034Sdougm 	if (ret == SA_OK) {
6863034Sdougm 	    /* check protocol vs optlist */
6873034Sdougm 	    if (optlist != NULL) {
6883034Sdougm 		/* check options, if any, for validity */
6893034Sdougm 		ret = valid_options(optlist, protocol, group, NULL);
6903034Sdougm 	    }
6913034Sdougm 	}
6923034Sdougm 	if (ret == SA_OK && !dryrun) {
6933034Sdougm 	    if (group == NULL) {
6943910Sdougm 		group = sa_create_group(handle, (char *)groupname, &err);
6953034Sdougm 	    }
6963034Sdougm 	    if (group != NULL) {
6973034Sdougm 		sa_optionset_t optionset;
6983034Sdougm 		if (optlist != NULL) {
6993034Sdougm 		    (void) add_optionset(group, optlist, protocol, &ret);
7003034Sdougm 		} else if (protocol != NULL) {
7013034Sdougm 		    optionset = sa_create_optionset(group, protocol);
7023034Sdougm 		    if (optionset == NULL)
7033034Sdougm 			ret = SA_NO_MEMORY;
7043034Sdougm 		} else if (protocol == NULL) {
7053034Sdougm 		    char **protolist;
7063034Sdougm 		    int numprotos, i;
7073034Sdougm 		    numprotos = sa_get_protocols(&protolist);
7083034Sdougm 		    for (i = 0; i < numprotos; i++) {
7093034Sdougm 			optionset = sa_create_optionset(group, protolist[i]);
7103034Sdougm 		    }
7113034Sdougm 		    if (protolist != NULL)
7123034Sdougm 			free(protolist);
7133034Sdougm 		}
7143034Sdougm 		/*
7153034Sdougm 		 * we have a group and legal additions
7163034Sdougm 		 */
7173034Sdougm 		if (ret == SA_OK) {
7183034Sdougm 			/*
7193034Sdougm 			 * commit to configuration for protocols that
7203034Sdougm 			 * need to do block updates. For NFS, this
7213034Sdougm 			 * doesn't do anything but it will be run for
7223034Sdougm 			 * all protocols that implement the
7233034Sdougm 			 * appropriate plugin.
7243034Sdougm 			 */
7253910Sdougm 		    ret = sa_update_config(handle);
7263034Sdougm 		} else {
7273034Sdougm 		    if (group != NULL)
7283034Sdougm 			(void) sa_remove_group(group);
7293034Sdougm 		}
7303034Sdougm 	    } else {
7313034Sdougm 		ret = err;
7323034Sdougm 		(void) printf(gettext("Could not create group: %s\n"),
7333034Sdougm 			sa_errorstr(ret));
7343034Sdougm 	    }
7353034Sdougm 	}
7363034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
7373034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
7383034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
7393034Sdougm 	    ret = SA_NO_PERMISSION;
7403034Sdougm 	}
7413034Sdougm 	free_opt(optlist);
7423034Sdougm 	return (ret);
7433034Sdougm }
7443034Sdougm 
7453034Sdougm /*
7463034Sdougm  * group_status(group)
7473034Sdougm  *
7483034Sdougm  * return the current status (enabled/disabled) of the group.
7493034Sdougm  */
7503034Sdougm 
7513034Sdougm static char *
7523034Sdougm group_status(sa_group_t group)
7533034Sdougm {
7543034Sdougm 	char *state;
7553034Sdougm 	int enabled = 0;
7563034Sdougm 
7573034Sdougm 	state = sa_get_group_attr(group, "state");
7583034Sdougm 	if (state != NULL) {
7593034Sdougm 	    if (strcmp(state, "enabled") == 0) {
7603034Sdougm 		enabled = 1;
7613034Sdougm 	    }
7623034Sdougm 	    sa_free_attr_string(state);
7633034Sdougm 	}
7643034Sdougm 	return (enabled ? gettext("enabled") : gettext("disabled"));
7653034Sdougm }
7663034Sdougm 
7673034Sdougm /*
7683034Sdougm  * sa_delete(flags, argc, argv)
7693034Sdougm  *
7703034Sdougm  *	Delete a group.
7713034Sdougm  */
7723034Sdougm 
7733034Sdougm static int
7743910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
7753034Sdougm {
7763034Sdougm 	char *groupname;
7773034Sdougm 	sa_group_t group;
7783034Sdougm 	sa_share_t share;
7793034Sdougm 	int verbose = 0;
7803034Sdougm 	int dryrun = 0;
7813034Sdougm 	int force = 0;
7823034Sdougm 	int c;
7833034Sdougm 	char *protocol = NULL;
7843034Sdougm 	char *sectype = NULL;
7853034Sdougm 	int ret = SA_OK;
7863034Sdougm 	int auth;
7873034Sdougm 
7883034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
7893034Sdougm 	    switch (c) {
7903034Sdougm 	    case 'v':
7913034Sdougm 		verbose++;
7923034Sdougm 		break;
7933034Sdougm 	    case 'n':
7943034Sdougm 		dryrun++;
7953034Sdougm 		break;
7963034Sdougm 	    case 'P':
7973034Sdougm 		protocol = optarg;
7983034Sdougm 		if (!sa_valid_protocol(protocol)) {
7993034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
8003034Sdougm 				    protocol);
8013034Sdougm 		    return (SA_INVALID_PROTOCOL);
8023034Sdougm 		}
8033034Sdougm 		break;
8043034Sdougm 	    case 'S':
8053034Sdougm 		sectype = optarg;
8063034Sdougm 		break;
8073034Sdougm 	    case 'f':
8083034Sdougm 		force++;
8093034Sdougm 		break;
8103034Sdougm 	    default:
8113034Sdougm 	    case 'h':
8123034Sdougm 	    case '?':
8133034Sdougm 		(void) printf(gettext("usage: %s\n"),
8143034Sdougm 				sa_get_usage(USAGE_DELETE));
8153034Sdougm 		return (0);
8163034Sdougm 	    }
8173034Sdougm 	}
8183034Sdougm 
8193034Sdougm 	if (optind >= argc) {
8203034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
8213034Sdougm 	    (void) printf(gettext("\tgroup must be specified.\n"));
8223034Sdougm 	    return (SA_SYNTAX_ERR);
8233034Sdougm 	}
8243034Sdougm 
8253034Sdougm 	if ((optind + 1) < argc) {
8263034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
8273034Sdougm 	    (void) printf(gettext("\textraneous group(s) at end\n"));
8283034Sdougm 	    return (SA_SYNTAX_ERR);
8293034Sdougm 	}
8303034Sdougm 
8313034Sdougm 	if (sectype != NULL && protocol == NULL) {
8323034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
8333034Sdougm 	    (void) printf(gettext("\tsecurity requires protocol to be "
8343034Sdougm 					"specified.\n"));
8353034Sdougm 	    return (SA_SYNTAX_ERR);
8363034Sdougm 	}
8373034Sdougm 
8383034Sdougm 	/*
8393034Sdougm 	 * Determine if the group already exists since it must in
8403034Sdougm 	 * order to be removed.
8413034Sdougm 	 *
8423034Sdougm 	 * We can delete when:
8433034Sdougm 	 *
8443034Sdougm 	 *	- group is empty
8453034Sdougm 	 *	- force flag is set
8463034Sdougm 	 *	- if protocol specified, only delete the protocol
8473034Sdougm 	 */
8483034Sdougm 
8493034Sdougm 	groupname = argv[optind];
8503910Sdougm 	group = sa_get_group(handle, groupname);
8513034Sdougm 	if (group == NULL) {
8523034Sdougm 		ret = SA_NO_SUCH_GROUP;
8533034Sdougm 	} else {
8543034Sdougm 	    auth = check_authorizations(groupname, flags);
8553034Sdougm 	    if (protocol == NULL) {
8563034Sdougm 		share = sa_get_share(group, NULL);
8573034Sdougm 		if (share != NULL)
8583034Sdougm 		    ret = SA_BUSY;
8593034Sdougm 		if (share == NULL || (share != NULL && force == 1)) {
8603034Sdougm 		    ret = SA_OK;
8613034Sdougm 		    if (!dryrun) {
8623034Sdougm 			while (share != NULL) {
8633034Sdougm 			    sa_share_t next_share;
8643034Sdougm 			    next_share = sa_get_next_share(share);
8653034Sdougm 				/*
8663034Sdougm 				 * need to do the disable of each
8673034Sdougm 				 * share, but don't actually do
8683034Sdougm 				 * anything on a dryrun.
8693034Sdougm 				 */
8703034Sdougm 			    ret = sa_disable_share(share, NULL);
8713034Sdougm 			    ret = sa_remove_share(share);
8723034Sdougm 			    share = next_share;
8733034Sdougm 			}
8743034Sdougm 			ret = sa_remove_group(group);
8753034Sdougm 		    }
8763034Sdougm 		}
8773034Sdougm 		/* commit to configuration if not a dryrun */
8783034Sdougm 		if (!dryrun && ret == SA_OK) {
8793910Sdougm 		    ret = sa_update_config(handle);
8803034Sdougm 		}
8813034Sdougm 	    } else {
8823034Sdougm 		/* a protocol delete */
8833034Sdougm 		sa_optionset_t optionset;
8843034Sdougm 		sa_security_t security;
8853034Sdougm 		if (sectype != NULL) {
8863034Sdougm 		    /* only delete specified security */
8873034Sdougm 		    security = sa_get_security(group, sectype, protocol);
8883034Sdougm 		    if (security != NULL && !dryrun) {
8893034Sdougm 			ret = sa_destroy_security(security);
8903034Sdougm 		    } else {
8913034Sdougm 			ret = SA_INVALID_PROTOCOL;
8923034Sdougm 		    }
8933034Sdougm 		} else {
8943034Sdougm 		    optionset = sa_get_optionset(group, protocol);
8953034Sdougm 		    if (optionset != NULL && !dryrun) {
8963034Sdougm 			/* have an optionset with protocol to delete */
8973034Sdougm 			ret = sa_destroy_optionset(optionset);
8983034Sdougm 			/*
8993034Sdougm 			 * now find all security sets for the protocol
9003034Sdougm 			 * and remove them. Don't remove other
9013034Sdougm 			 * protocols.
9023034Sdougm 			 */
9033034Sdougm 			for (security = sa_get_security(group, NULL, NULL);
9043034Sdougm 			    ret == SA_OK && security != NULL;
9053034Sdougm 			    security = sa_get_next_security(security)) {
9063034Sdougm 			    char *secprot;
9073034Sdougm 
9083034Sdougm 			    secprot = sa_get_security_attr(security, "type");
9093034Sdougm 			    if (secprot != NULL &&
9103034Sdougm 				strcmp(secprot, protocol) == 0)
9113034Sdougm 				ret = sa_destroy_security(security);
9123034Sdougm 			    if (secprot != NULL)
9133034Sdougm 				sa_free_attr_string(secprot);
9143034Sdougm 			}
9153034Sdougm 		    } else {
9163034Sdougm 			if (!dryrun)
9173034Sdougm 			    ret = SA_INVALID_PROTOCOL;
9183034Sdougm 		    }
9193034Sdougm 		}
9203034Sdougm 	    }
9213034Sdougm 	}
9223034Sdougm 	if (ret != SA_OK) {
9233034Sdougm 	    (void) printf(gettext("Could not delete group: %s\n"),
9243034Sdougm 				sa_errorstr(ret));
9253034Sdougm 	} else if (dryrun && !auth && verbose) {
9263034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
9273034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
9283034Sdougm 	}
9293034Sdougm 	return (ret);
9303034Sdougm }
9313034Sdougm 
9323034Sdougm /*
9333034Sdougm  * strndupr(*buff, str, buffsize)
9343034Sdougm  *
9353034Sdougm  * used with small strings to duplicate and possibly increase the
9363034Sdougm  * buffer size of a string.
9373034Sdougm  */
9383034Sdougm static char *
9393034Sdougm strndupr(char *buff, char *str, int *buffsize)
9403034Sdougm {
9413034Sdougm 	int limit;
9423034Sdougm 	char *orig_buff = buff;
9433034Sdougm 
9443034Sdougm 	if (buff == NULL) {
9453034Sdougm 	    buff = (char *)malloc(64);
9463034Sdougm 	    if (buff == NULL)
9473034Sdougm 		return (NULL);
9483034Sdougm 	    *buffsize = 64;
9493034Sdougm 	    buff[0] = '\0';
9503034Sdougm 	}
9513034Sdougm 	limit = strlen(buff) + strlen(str) + 1;
9523034Sdougm 	if (limit > *buffsize) {
9533034Sdougm 	    limit = *buffsize = *buffsize + ((limit / 64) + 64);
9543034Sdougm 	    buff = realloc(buff, limit);
9553034Sdougm 	}
9563034Sdougm 	if (buff != NULL) {
9573034Sdougm 	    (void) strcat(buff, str);
9583034Sdougm 	} else {
9593034Sdougm 	    /* if it fails, fail it hard */
9603034Sdougm 	    if (orig_buff != NULL)
9613034Sdougm 		free(orig_buff);
9623034Sdougm 	}
9633034Sdougm 	return (buff);
9643034Sdougm }
9653034Sdougm 
9663034Sdougm /*
9673034Sdougm  * group_proto(group)
9683034Sdougm  *
9693034Sdougm  * return a string of all the protocols (space separated) associated
9703034Sdougm  * with this group.
9713034Sdougm  */
9723034Sdougm 
9733034Sdougm static char *
9743034Sdougm group_proto(sa_group_t group)
9753034Sdougm {
9763034Sdougm 	sa_optionset_t optionset;
9773034Sdougm 	char *proto;
9783034Sdougm 	char *buff = NULL;
9793034Sdougm 	int buffsize = 0;
9803034Sdougm 	int addspace = 0;
9813034Sdougm 	/*
9823034Sdougm 	 * get the protocol list by finding the optionsets on this
9833034Sdougm 	 * group and extracting the type value. The initial call to
9843034Sdougm 	 * strndupr() initailizes buff.
9853034Sdougm 	 */
9863034Sdougm 	buff = strndupr(buff, "", &buffsize);
9873034Sdougm 	if (buff != NULL) {
9883034Sdougm 	    for (optionset = sa_get_optionset(group, NULL);
9893034Sdougm 		optionset != NULL && buff != NULL;
9903034Sdougm 		optionset = sa_get_next_optionset(optionset)) {
9913034Sdougm 		/*
9923034Sdougm 		 * extract out the protocol type from this optionset
9933034Sdougm 		 * and append it to the buffer "buff". strndupr() will
9943034Sdougm 		 * reallocate space as necessay.
9953034Sdougm 		 */
9963034Sdougm 		proto = sa_get_optionset_attr(optionset, "type");
9973034Sdougm 		if (proto != NULL) {
9983034Sdougm 		    if (addspace++)
9993034Sdougm 			buff = strndupr(buff, " ", &buffsize);
10003034Sdougm 		    buff = strndupr(buff, proto, &buffsize);
10013034Sdougm 		    sa_free_attr_string(proto);
10023034Sdougm 		}
10033034Sdougm 	    }
10043034Sdougm 	}
10053034Sdougm 	return (buff);
10063034Sdougm }
10073034Sdougm 
10083034Sdougm /*
10093034Sdougm  * sa_list(flags, argc, argv)
10103034Sdougm  *
10113034Sdougm  * implements the "list" subcommand to list groups and optionally
10123034Sdougm  * their state and protocols.
10133034Sdougm  */
10143034Sdougm 
10153034Sdougm static int
10163910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
10173034Sdougm {
10183034Sdougm 	sa_group_t group;
10193034Sdougm 	int verbose = 0;
10203034Sdougm 	int c;
10213034Sdougm 	char *protocol = NULL;
10223034Sdougm #ifdef lint
10233034Sdougm 	flags = flags;
10243034Sdougm #endif
10253034Sdougm 
10263034Sdougm 	while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
10273034Sdougm 	    switch (c) {
10283034Sdougm 	    case 'v':
10293034Sdougm 		verbose++;
10303034Sdougm 		break;
10313034Sdougm 	    case 'P':
10323034Sdougm 		protocol = optarg;
10333034Sdougm 		if (!sa_valid_protocol(protocol)) {
10343034Sdougm 		    (void) printf(gettext("Invalid protocol specified:"
10353034Sdougm 					    "%s\n"),
10363034Sdougm 					protocol);
10373034Sdougm 		    return (SA_INVALID_PROTOCOL);
10383034Sdougm 		}
10393034Sdougm 		break;
10403034Sdougm 	    default:
10413034Sdougm 	    case 'h':
10423034Sdougm 	    case '?':
10433034Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_LIST));
10443034Sdougm 		return (0);
10453034Sdougm 	    }
10463034Sdougm 	}
10473034Sdougm 
10483910Sdougm 	for (group = sa_get_group(handle, NULL); group != NULL;
10493034Sdougm 	    group = sa_get_next_group(group)) {
10503034Sdougm 	    char *name;
10513034Sdougm 	    char *proto;
10523034Sdougm 	    if (protocol == NULL || has_protocol(group, protocol)) {
10533034Sdougm 		name = sa_get_group_attr(group, "name");
10543034Sdougm 		if (name != NULL && (verbose > 1 || name[0] != '#')) {
10553034Sdougm 		    (void) printf("%s", (char *)name);
10563034Sdougm 		    if (verbose) {
10573034Sdougm 			/*
10583034Sdougm 			 * need the list of protocols
10593034Sdougm 			 * and current status once
10603034Sdougm 			 * available.
10613034Sdougm 			 */
10623034Sdougm 			(void) printf("\t%s", group_status(group));
10633034Sdougm 			proto = group_proto(group);
10643034Sdougm 			if (proto != NULL) {
10653034Sdougm 			    (void) printf("\t%s", (char *)proto);
10663034Sdougm 			    free(proto);
10673034Sdougm 			}
10683034Sdougm 		    }
10693034Sdougm 		    (void) printf("\n");
10703034Sdougm 		}
10713034Sdougm 		if (name != NULL)
10723034Sdougm 		    sa_free_attr_string(name);
10733034Sdougm 	    }
10743034Sdougm 	}
10753034Sdougm 	return (0);
10763034Sdougm }
10773034Sdougm 
10783034Sdougm /*
10793034Sdougm  * out_properties(optionset, proto, sec)
10803034Sdougm  *
10813034Sdougm  * Format the properties and encode the protocol and optional named
10823034Sdougm  * optionset into the string.
10833034Sdougm  *
10843034Sdougm  * format is protocol[:name]=(property-list)
10853034Sdougm  */
10863034Sdougm 
10873034Sdougm static void
10883034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec)
10893034Sdougm {
10903034Sdougm 	char *type;
10913034Sdougm 	char *value;
10923034Sdougm 	int spacer;
10933034Sdougm 	sa_property_t prop;
10943034Sdougm 
10953034Sdougm 	if (sec == NULL) {
10963034Sdougm 	    (void) printf(" %s=(", proto ? proto : gettext("all"));
10973034Sdougm 	} else {
10983034Sdougm 	    (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
10993034Sdougm 	}
11003034Sdougm 
11013034Sdougm 	for (spacer = 0, prop = sa_get_property(optionset, NULL);
11023034Sdougm 	    prop != NULL; prop = sa_get_next_property(prop)) {
11033034Sdougm 
11043034Sdougm 		/*
11053034Sdougm 		 * extract the property name/value and output with
11063034Sdougm 		 * appropriate spacing. I.e. no prefixed space the
11073034Sdougm 		 * first time through but a space on subsequent
11083034Sdougm 		 * properties.
11093034Sdougm 		 */
11103034Sdougm 	    type = sa_get_property_attr(prop, "type");
11113034Sdougm 	    value = sa_get_property_attr(prop, "value");
11123034Sdougm 	    if (type != NULL) {
11133034Sdougm 		(void) printf("%s%s=", spacer ? " " : "",	type);
11143034Sdougm 		spacer = 1;
11153034Sdougm 		if (value != NULL)
11163034Sdougm 		    (void) printf("\"%s\"", value);
11173034Sdougm 		else
11183034Sdougm 		    (void) printf("\"\"");
11193034Sdougm 	    }
11203034Sdougm 	    if (type != NULL)
11213034Sdougm 		sa_free_attr_string(type);
11223034Sdougm 	    if (value != NULL)
11233034Sdougm 		sa_free_attr_string(value);
11243034Sdougm 	}
11253034Sdougm 	(void) printf(")");
11263034Sdougm }
11273034Sdougm 
11283034Sdougm /*
11293034Sdougm  * show_properties(group, protocol, prefix)
11303034Sdougm  *
11313034Sdougm  * print the properties for a group. If protocol is NULL, do all
11323034Sdougm  * protocols otherwise only the specified protocol. All security
11333034Sdougm  * (named groups specific to the protocol) are included.
11343034Sdougm  *
11353034Sdougm  * The "prefix" is always applied. The caller knows whether it wants
11363034Sdougm  * some type of prefix string (white space) or not.  Once the prefix
11373034Sdougm  * has been output, it is reduced to the zero length string for the
11383034Sdougm  * remainder of the property output.
11393034Sdougm  */
11403034Sdougm 
11413034Sdougm static void
11423034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix)
11433034Sdougm {
11443034Sdougm 	sa_optionset_t optionset;
11453034Sdougm 	sa_security_t security;
11463034Sdougm 	char *value;
11473034Sdougm 	char *secvalue;
11483034Sdougm 
11493034Sdougm 	if (protocol != NULL) {
11503034Sdougm 	    optionset = sa_get_optionset(group, protocol);
11513034Sdougm 	    if (optionset != NULL) {
11523034Sdougm 		(void) printf("%s", prefix);
11533034Sdougm 		prefix = "";
11543034Sdougm 		out_properties(optionset, protocol, NULL);
11553034Sdougm 	    }
11563034Sdougm 	    security = sa_get_security(group, protocol, NULL);
11573034Sdougm 	    if (security != NULL) {
11583034Sdougm 		(void) printf("%s", prefix);
11593034Sdougm 		prefix = "";
11603034Sdougm 		out_properties(security, protocol, NULL);
11613034Sdougm 	    }
11623034Sdougm 	} else {
11633034Sdougm 	    for (optionset = sa_get_optionset(group, protocol);
11643034Sdougm 		optionset != NULL;
11653034Sdougm 		optionset = sa_get_next_optionset(optionset)) {
11663034Sdougm 
11673034Sdougm 		value = sa_get_optionset_attr(optionset, "type");
11683034Sdougm 		(void) printf("%s", prefix);
11693034Sdougm 		prefix = "";
11703034Sdougm 		out_properties(optionset, value, 0);
11713034Sdougm 		if (value != NULL)
11723034Sdougm 		    sa_free_attr_string(value);
11733034Sdougm 	    }
11743034Sdougm 	    for (security = sa_get_security(group, NULL, protocol);
11753034Sdougm 		security != NULL;
11763034Sdougm 		security = sa_get_next_security(security)) {
11773034Sdougm 
11783034Sdougm 		value = sa_get_security_attr(security, "type");
11793034Sdougm 		secvalue = sa_get_security_attr(security, "sectype");
11803034Sdougm 		(void) printf("%s", prefix);
11813034Sdougm 		prefix = "";
11823034Sdougm 		out_properties(security, value, secvalue);
11833034Sdougm 		if (value != NULL)
11843034Sdougm 		    sa_free_attr_string(value);
11853034Sdougm 		if (secvalue != NULL)
11863034Sdougm 		    sa_free_attr_string(secvalue);
11873034Sdougm 	    }
11883034Sdougm 	}
11893034Sdougm }
11903034Sdougm 
11913034Sdougm /*
11923034Sdougm  * show_group(group, verbose, properties, proto, subgroup)
11933034Sdougm  *
11943034Sdougm  * helper function to show the contents of a group.
11953034Sdougm  */
11963034Sdougm 
11973034Sdougm static void
11983034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto,
11993034Sdougm 		char *subgroup)
12003034Sdougm {
12013034Sdougm 	sa_share_t share;
12023034Sdougm 	char *groupname;
12033034Sdougm 	char *sharepath;
12043034Sdougm 	char *resource;
12053034Sdougm 	char *description;
12063034Sdougm 	char *type;
12073034Sdougm 	char *zfs = NULL;
12083034Sdougm 	int iszfs = 0;
12093034Sdougm 
12103034Sdougm 	groupname = sa_get_group_attr(group, "name");
12113034Sdougm 	if (groupname != NULL) {
12123034Sdougm 	    if (proto != NULL && !has_protocol(group, proto)) {
12133034Sdougm 		sa_free_attr_string(groupname);
12143034Sdougm 		return;
12153034Sdougm 	    }
12163034Sdougm 		/*
12173034Sdougm 		 * check to see if the group is managed by ZFS. If
12183034Sdougm 		 * there is an attribute, then it is. A non-NULL zfs
12193034Sdougm 		 * variable will trigger the different way to display
12203034Sdougm 		 * and will remove the transient property indicator
12213034Sdougm 		 * from the output.
12223034Sdougm 		 */
12233034Sdougm 	    zfs = sa_get_group_attr(group, "zfs");
12243034Sdougm 	    if (zfs != NULL) {
12253034Sdougm 		iszfs = 1;
12263034Sdougm 		sa_free_attr_string(zfs);
12273034Sdougm 	    }
12283034Sdougm 	    share = sa_get_share(group, NULL);
12293034Sdougm 	    if (subgroup == NULL)
12303034Sdougm 		(void) printf("%s", groupname);
12313034Sdougm 	    else
12323034Sdougm 		(void) printf("    %s/%s", subgroup, groupname);
12333034Sdougm 	    if (properties) {
12343034Sdougm 		show_properties(group, proto, "");
12353034Sdougm 	    }
12363034Sdougm 	    (void) printf("\n");
12373034Sdougm 	    if (strcmp(groupname, "zfs") == 0) {
12383034Sdougm 		sa_group_t zgroup;
12393034Sdougm 
12403034Sdougm 		for (zgroup = sa_get_sub_group(group); zgroup != NULL;
12413034Sdougm 		    zgroup = sa_get_next_group(zgroup)) {
12423034Sdougm 		    show_group(zgroup, verbose, properties, proto, "zfs");
12433034Sdougm 		}
12443034Sdougm 		sa_free_attr_string(groupname);
12453034Sdougm 		return;
12463034Sdougm 	    }
12473034Sdougm 		/*
12483034Sdougm 		 * have a group, so list the contents. Resource and
12493034Sdougm 		 * description are only listed if verbose is set.
12503034Sdougm 		 */
12513034Sdougm 	    for (share = sa_get_share(group, NULL); share != NULL;
12523034Sdougm 		share = sa_get_next_share(share)) {
12533034Sdougm 		sharepath = sa_get_share_attr(share, "path");
12543034Sdougm 		if (sharepath != NULL) {
12553034Sdougm 		    if (verbose) {
12563034Sdougm 			resource = sa_get_share_attr(share, "resource");
12573034Sdougm 			description = sa_get_share_description(share);
12583034Sdougm 			type = sa_get_share_attr(share, "type");
12593034Sdougm 			if (type != NULL && !iszfs &&
12603034Sdougm 				strcmp(type, "transient") == 0)
12613034Sdougm 			    (void) printf("\t* ");
12623034Sdougm 			else
12633034Sdougm 			    (void) printf("\t  ");
12643034Sdougm 			if (resource != NULL && strlen(resource) > 0) {
12653034Sdougm 			    (void) printf("%s=%s", resource, sharepath);
12663034Sdougm 			} else {
12673034Sdougm 			    (void) printf("%s", sharepath);
12683034Sdougm 			}
12693034Sdougm 			if (resource != NULL)
12703034Sdougm 			    sa_free_attr_string(resource);
12713034Sdougm 			if (properties)
12723034Sdougm 			    show_properties(share, NULL, "\t");
12733034Sdougm 			if (description != NULL) {
12743034Sdougm 			    if (strlen(description) > 0) {
12753034Sdougm 				(void) printf("\t\"%s\"", description);
12763034Sdougm 			    }
12773034Sdougm 			    sa_free_share_description(description);
12783034Sdougm 			}
12793034Sdougm 			if (type != NULL)
12803034Sdougm 			    sa_free_attr_string(type);
12813034Sdougm 		    } else {
12823034Sdougm 			(void) printf("\t%s", sharepath);
12833034Sdougm 			if (properties)
12843034Sdougm 			    show_properties(share, NULL, "\t");
12853034Sdougm 		    }
12863034Sdougm 		    (void) printf("\n");
12873034Sdougm 		    sa_free_attr_string(sharepath);
12883034Sdougm 		}
12893034Sdougm 	    }
12903034Sdougm 	}
12913034Sdougm 	if (groupname != NULL) {
12923034Sdougm 		sa_free_attr_string(groupname);
12933034Sdougm 	}
12943034Sdougm }
12953034Sdougm 
12963034Sdougm /*
12973034Sdougm  * show_group_xml_init()
12983034Sdougm  *
12993034Sdougm  * Create an XML document that will be used to display config info via
13003034Sdougm  * XML format.
13013034Sdougm  */
13023034Sdougm 
13033034Sdougm xmlDocPtr
13043034Sdougm show_group_xml_init()
13053034Sdougm {
13063034Sdougm 	xmlDocPtr doc;
13073034Sdougm 	xmlNodePtr root;
13083034Sdougm 
13093034Sdougm 	doc = xmlNewDoc((xmlChar *)"1.0");
13103034Sdougm 	if (doc != NULL) {
13113034Sdougm 	    root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
13123034Sdougm 	    if (root != NULL)
13133034Sdougm 		xmlDocSetRootElement(doc, root);
13143034Sdougm 	}
13153034Sdougm 	return (doc);
13163034Sdougm }
13173034Sdougm 
13183034Sdougm /*
13193034Sdougm  * show_group_xml(doc, group)
13203034Sdougm  *
13213034Sdougm  * Copy the group info into the XML doc.
13223034Sdougm  */
13233034Sdougm 
13243034Sdougm static void
13253034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group)
13263034Sdougm {
13273034Sdougm 	xmlNodePtr node;
13283034Sdougm 	xmlNodePtr root;
13293034Sdougm 
13303034Sdougm 	root = xmlDocGetRootElement(doc);
13313034Sdougm 	node = xmlCopyNode((xmlNodePtr)group, 1);
13323034Sdougm 	if (node != NULL && root != NULL) {
13333034Sdougm 	    xmlAddChild(root, node);
13343034Sdougm 		/*
13353034Sdougm 		 * In the future, we may have interally used tags that
13363034Sdougm 		 * should not appear in the XML output. Remove
13373034Sdougm 		 * anything we don't want to show here.
13383034Sdougm 		 */
13393034Sdougm 	}
13403034Sdougm }
13413034Sdougm 
13423034Sdougm /*
13433034Sdougm  * sa_show(flags, argc, argv)
13443034Sdougm  *
13453034Sdougm  * Implements the show subcommand.
13463034Sdougm  */
13473034Sdougm 
13483034Sdougm int
13493910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
13503034Sdougm {
13513034Sdougm 	sa_group_t group;
13523034Sdougm 	int verbose = 0;
13533034Sdougm 	int properties = 0;
13543034Sdougm 	int c;
13553034Sdougm 	int ret = SA_OK;
13563034Sdougm 	char *protocol = NULL;
13573034Sdougm 	int xml = 0;
13583034Sdougm 	xmlDocPtr doc;
13593034Sdougm #ifdef lint
13603034Sdougm 	flags = flags;
13613034Sdougm #endif
13623034Sdougm 
13633034Sdougm 	while ((c = getopt(argc, argv, "?hvP:px")) !=	EOF) {
13643034Sdougm 	    switch (c) {
13653034Sdougm 	    case 'v':
13663034Sdougm 		verbose++;
13673034Sdougm 		break;
13683034Sdougm 	    case 'p':
13693034Sdougm 		properties++;
13703034Sdougm 		break;
13713034Sdougm 	    case 'P':
13723034Sdougm 		protocol = optarg;
13733034Sdougm 		if (!sa_valid_protocol(protocol)) {
13743034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
13753034Sdougm 					protocol);
13763034Sdougm 		    return (SA_INVALID_PROTOCOL);
13773034Sdougm 		}
13783034Sdougm 		break;
13793034Sdougm 	    case 'x':
13803034Sdougm 		xml++;
13813034Sdougm 		break;
13823034Sdougm 	    default:
13833034Sdougm 	    case 'h':
13843034Sdougm 	    case '?':
13853034Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SHOW));
13863034Sdougm 		return (0);
13873034Sdougm 	    }
13883034Sdougm 	}
13893034Sdougm 
13903034Sdougm 	if (xml) {
13913034Sdougm 	    doc = show_group_xml_init();
13923034Sdougm 	    if (doc == NULL)
13933034Sdougm 		ret = SA_NO_MEMORY;
13943034Sdougm 	}
13953034Sdougm 
13963034Sdougm 	if (optind == argc) {
13973034Sdougm 	    /* no group specified so go through them all */
13983910Sdougm 	    for (group = sa_get_group(handle, NULL); group != NULL;
13993034Sdougm 		group = sa_get_next_group(group)) {
14003034Sdougm 		/*
14013034Sdougm 		 * have a group so check if one we want and then list
14023034Sdougm 		 * contents with appropriate options.
14033034Sdougm 		 */
14043034Sdougm 		if (xml)
14053034Sdougm 		    show_group_xml(doc, group);
14063034Sdougm 		else
14073034Sdougm 		    show_group(group, verbose, properties, protocol, NULL);
14083034Sdougm 	    }
14093034Sdougm 	} else {
14103034Sdougm 	    /* have a specified list of groups */
14113034Sdougm 	    for (; optind < argc; optind++) {
14123910Sdougm 		group = sa_get_group(handle, argv[optind]);
14133034Sdougm 		if (group != NULL) {
14143034Sdougm 		    if (xml)
14153034Sdougm 			show_group_xml(doc, group);
14163034Sdougm 		    else
14173034Sdougm 			show_group(group, verbose, properties, protocol, NULL);
14183034Sdougm 		} else {
14193034Sdougm 		    (void) printf(gettext("%s: not found\n"), argv[optind]);
14203034Sdougm 		    ret = SA_NO_SUCH_GROUP;
14213034Sdougm 		}
14223034Sdougm 	    }
14233034Sdougm 	}
14243034Sdougm 	if (xml && ret == SA_OK) {
14253034Sdougm 	    xmlDocFormatDump(stdout, doc, 1);
14263034Sdougm 	    xmlFreeDoc(doc);
14273034Sdougm 	}
14283034Sdougm 	return (ret);
14293034Sdougm 
14303034Sdougm }
14313034Sdougm 
14323034Sdougm /*
14333034Sdougm  * enable_share(group, share, update_legacy)
14343034Sdougm  *
14353034Sdougm  * helper function to enable a share if the group is enabled.
14363034Sdougm  */
14373034Sdougm 
14383034Sdougm static int
14393910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
14403910Sdougm 		int update_legacy)
14413034Sdougm {
14423034Sdougm 	char *value;
14433034Sdougm 	int enabled;
14443034Sdougm 	sa_optionset_t optionset;
14453034Sdougm 	int ret = SA_OK;
14463034Sdougm 	char *zfs = NULL;
14473034Sdougm 	int iszfs = 0;
14483034Sdougm 
14493034Sdougm 	/*
14503034Sdougm 	 * need to enable this share if the group is enabled but not
14513034Sdougm 	 * otherwise. The enable is also done on each protocol
14523034Sdougm 	 * represented in the group.
14533034Sdougm 	 */
14543034Sdougm 	value = sa_get_group_attr(group, "state");
14553034Sdougm 	enabled = value != NULL && strcmp(value, "enabled") == 0;
14563034Sdougm 	if (value != NULL)
14573034Sdougm 	    sa_free_attr_string(value);
14583034Sdougm 	/* remove legacy config if necessary */
14593034Sdougm 	if (update_legacy)
14603034Sdougm 	    ret = sa_delete_legacy(share);
14613034Sdougm 	zfs = sa_get_group_attr(group, "zfs");
14623034Sdougm 	if (zfs != NULL) {
14633034Sdougm 	    iszfs++;
14643034Sdougm 	    sa_free_attr_string(zfs);
14653034Sdougm 	}
14663034Sdougm 
14673034Sdougm 	/*
14683034Sdougm 	 * Step through each optionset at the group level and
14693034Sdougm 	 * enable the share based on the protocol type. This
14703034Sdougm 	 * works because protocols must be set on the group
14713034Sdougm 	 * for the protocol to be enabled.
14723034Sdougm 	 */
14733034Sdougm 	for (optionset = sa_get_optionset(group, NULL);
14743034Sdougm 	    optionset != NULL && ret == SA_OK;
14753034Sdougm 	    optionset = sa_get_next_optionset(optionset)) {
14763034Sdougm 	    value = sa_get_optionset_attr(optionset, "type");
14773034Sdougm 	    if (value != NULL) {
14783034Sdougm 		if (enabled)
14793034Sdougm 		    ret = sa_enable_share(share, value);
14803034Sdougm 		if (update_legacy && !iszfs)
14813034Sdougm 		    (void) sa_update_legacy(share, value);
14823034Sdougm 		sa_free_attr_string(value);
14833034Sdougm 	    }
14843034Sdougm 	}
14853034Sdougm 	if (ret == SA_OK)
14863910Sdougm 	    (void) sa_update_config(handle);
14873034Sdougm 	return (ret);
14883034Sdougm }
14893034Sdougm 
14903034Sdougm /*
14913034Sdougm  * sa_addshare(flags, argc, argv)
14923034Sdougm  *
14933034Sdougm  * implements add-share subcommand.
14943034Sdougm  */
14953034Sdougm 
14963034Sdougm int
14973910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
14983034Sdougm {
14993034Sdougm 	int verbose = 0;
15003034Sdougm 	int dryrun = 0;
15013034Sdougm 	int c;
15023034Sdougm 	int ret = SA_OK;
15033034Sdougm 	sa_group_t group;
15043034Sdougm 	sa_share_t share;
15053034Sdougm 	char *sharepath = NULL;
15063034Sdougm 	char *description = NULL;
15073034Sdougm 	char *resource = NULL;
15083034Sdougm 	int persist = SA_SHARE_PERMANENT; /* default to persist */
15093034Sdougm 	int auth;
15103034Sdougm 	char dir[MAXPATHLEN];
15113034Sdougm 
15123034Sdougm 	while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
15133034Sdougm 	    switch (c) {
15143034Sdougm 	    case 'n':
15153034Sdougm 		dryrun++;
15163034Sdougm 		break;
15173034Sdougm 	    case 'v':
15183034Sdougm 		verbose++;
15193034Sdougm 		break;
15203034Sdougm 	    case 'd':
15213034Sdougm 		description = optarg;
15223034Sdougm 		break;
15233034Sdougm 	    case 'r':
15243034Sdougm 		resource = optarg;
15253034Sdougm 		break;
15263034Sdougm 	    case 's':
15273034Sdougm 		/*
15283034Sdougm 		 * save share path into group. Currently limit
15293034Sdougm 		 * to one share per command.
15303034Sdougm 		 */
15313034Sdougm 		if (sharepath != NULL) {
15323034Sdougm 		    (void) printf(gettext("Adding multiple shares not"
15333034Sdougm 				    "supported\n"));
15343034Sdougm 		    return (1);
15353034Sdougm 		}
15363034Sdougm 		sharepath = optarg;
15373034Sdougm 		break;
15383034Sdougm 	    case 't':
15393034Sdougm 		persist = SA_SHARE_TRANSIENT;
15403034Sdougm 		break;
15413034Sdougm 	    default:
15423034Sdougm 	    case 'h':
15433034Sdougm 	    case '?':
15443034Sdougm 		(void) printf(gettext("usage: %s\n"),
15453034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15463034Sdougm 		return (0);
15473034Sdougm 	    }
15483034Sdougm 	}
15493034Sdougm 
15503034Sdougm 	if (optind >= argc) {
15513034Sdougm 	    (void) printf(gettext("usage: %s\n"),
15523034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15533034Sdougm 	    if (dryrun || sharepath != NULL || description != NULL ||
15543034Sdougm 		resource != NULL || verbose || persist) {
15553034Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
15563034Sdougm 		ret = SA_NO_SUCH_GROUP;
15573034Sdougm 	    } else {
15583034Sdougm 		ret = SA_OK;
15593034Sdougm 	    }
15603034Sdougm 	} else {
15613034Sdougm 	    if (sharepath == NULL) {
15623034Sdougm 		(void) printf(gettext("usage: %s\n"),
15633034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15643034Sdougm 		(void) printf(gettext("\t-s sharepath must be specified\n"));
15653034Sdougm 		ret = SA_BAD_PATH;
15663034Sdougm 	    }
15673034Sdougm 	    if (ret == SA_OK) {
15683034Sdougm 		if (realpath(sharepath, dir) == NULL) {
15693034Sdougm 		    ret = SA_BAD_PATH;
15703034Sdougm 		    (void) printf(gettext("Path is not valid: %s\n"),
15713034Sdougm 					sharepath);
15723034Sdougm 		} else {
15733034Sdougm 		    sharepath = dir;
15743034Sdougm 		}
15753034Sdougm 	    }
15763034Sdougm 	    if (ret == SA_OK && resource != NULL) {
15773034Sdougm 		/* check for valid syntax */
15783034Sdougm 		if (strpbrk(resource, " \t/") != NULL) {
15793034Sdougm 		    (void) printf(gettext("usage: %s\n"),
15803034Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
15813034Sdougm 		    (void) printf(gettext("\tresource must not contain white"
15823034Sdougm 				    "space or '/' characters\n"));
15833034Sdougm 		    ret = SA_BAD_PATH;
15843034Sdougm 		}
15853034Sdougm 	    }
15863034Sdougm 	    if (ret == SA_OK) {
15873910Sdougm 		group = sa_get_group(handle, argv[optind]);
15883034Sdougm 		if (group != NULL) {
15893034Sdougm 		    auth = check_authorizations(argv[optind], flags);
15903910Sdougm 		    share = sa_find_share(handle, sharepath);
15913034Sdougm 		    if (share != NULL) {
15923034Sdougm 			group = sa_get_parent_group(share);
15933034Sdougm 			if (group != NULL) {
15943034Sdougm 			    char *groupname;
15953034Sdougm 			    groupname = sa_get_group_attr(group, "name");
15963034Sdougm 			    if (groupname != NULL) {
15973034Sdougm 				(void) printf(gettext("Share path already "
15983034Sdougm 							"shared in group "
15993034Sdougm 							"\"%s\": %s\n"),
16003034Sdougm 						groupname, sharepath);
16013034Sdougm 				sa_free_attr_string(groupname);
16023034Sdougm 			    } else {
16033034Sdougm 				(void) printf(gettext("Share path already"
16043034Sdougm 							"shared: %s\n"),
16053034Sdougm 						groupname, sharepath);
16063034Sdougm 			    }
16073034Sdougm 			} else {
16083034Sdougm 			    (void) printf(gettext("Share path %s already "
16093034Sdougm 							"shared\n"),
16103034Sdougm 				    sharepath);
16113034Sdougm 			}
16123034Sdougm 			ret = SA_DUPLICATE_NAME;
16133034Sdougm 		    } else {
16143034Sdougm 			/*
16153034Sdougm 			 * need to check that resource name is unique
16163348Sdougm 			 * at some point. Path checking should use the
16173348Sdougm 			 * "normal" rules which don't check the repository.
16183034Sdougm 			 */
16193034Sdougm 			if (dryrun)
16203348Sdougm 			    ret = sa_check_path(group, sharepath,
16213348Sdougm 						SA_CHECK_NORMAL);
16223034Sdougm 			else
16233034Sdougm 			    share = sa_add_share(group, sharepath,
16243034Sdougm 							persist, &ret);
16253034Sdougm 			if (!dryrun && share == NULL) {
16263034Sdougm 				(void) printf(gettext("Could not add share: "
16273034Sdougm 							"%s\n"),
16283034Sdougm 					sa_errorstr(ret));
16293034Sdougm 			} else {
16303034Sdougm 			    if (!dryrun && ret == SA_OK) {
16313034Sdougm 				if (resource != NULL) {
16323034Sdougm 				    if (strpbrk(resource, " \t/") == NULL) {
16333034Sdougm 					ret = sa_set_share_attr(share,
16343034Sdougm 								"resource",
16353034Sdougm 								resource);
16363034Sdougm 				    }
16373034Sdougm 				}
16383034Sdougm 				if (ret == SA_OK && description != NULL) {
16393034Sdougm 				    ret = sa_set_share_description(share,
16403034Sdougm 							    description);
16413034Sdougm 				}
16423034Sdougm 				if (ret == SA_OK) {
16433034Sdougm 				    /* now enable the share(s) */
16443910Sdougm 				    ret = enable_share(handle, group, share, 1);
16453910Sdougm 				    ret = sa_update_config(handle);
16463034Sdougm 				}
16473034Sdougm 				switch (ret) {
16483034Sdougm 				case SA_DUPLICATE_NAME:
16493034Sdougm 				    (void) printf(gettext("Resource name in"
16503034Sdougm 						    "use: %s\n"),
16513034Sdougm 					    resource);
16523034Sdougm 				    break;
16533034Sdougm 				default:
16543034Sdougm 				    (void) printf(gettext("Could not set "
16553034Sdougm 						    "attribute: %s\n"),
16563034Sdougm 					    sa_errorstr(ret));
16573034Sdougm 				    break;
16583034Sdougm 				case SA_OK:
16593034Sdougm 				    break;
16603034Sdougm 				}
16613034Sdougm 			    } else if (dryrun && ret == SA_OK &&
16623034Sdougm 					!auth && verbose) {
16633034Sdougm 				(void) printf(gettext("Command would fail: "
16643034Sdougm 							"%s\n"),
16653034Sdougm 					sa_errorstr(SA_NO_PERMISSION));
16663034Sdougm 				ret = SA_NO_PERMISSION;
16673034Sdougm 			    }
16683034Sdougm 			}
16693034Sdougm 		    }
16703034Sdougm 		} else {
16713034Sdougm 		    (void) printf(gettext("Group \"%s\" not found\n"),
16723034Sdougm 					argv[optind]);
16733034Sdougm 		    ret = SA_NO_SUCH_GROUP;
16743034Sdougm 		}
16753034Sdougm 	    }
16763034Sdougm 	}
16773034Sdougm 	return (ret);
16783034Sdougm }
16793034Sdougm 
16803034Sdougm /*
16813034Sdougm  * sa_moveshare(flags, argc, argv)
16823034Sdougm  *
16833034Sdougm  * implements move-share subcommand.
16843034Sdougm  */
16853034Sdougm 
16863034Sdougm int
16873910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
16883034Sdougm {
16893034Sdougm 	int verbose = 0;
16903034Sdougm 	int dryrun = 0;
16913034Sdougm 	int c;
16923034Sdougm 	int ret = SA_OK;
16933034Sdougm 	sa_group_t group;
16943034Sdougm 	sa_share_t share;
16953034Sdougm 	char *sharepath = NULL;
16963034Sdougm 	int authsrc = 0, authdst = 0;
16973034Sdougm 
16983034Sdougm 	while ((c = getopt(argc, argv, "?hvns:")) != EOF) {
16993034Sdougm 	    switch (c) {
17003034Sdougm 	    case 'n':
17013034Sdougm 		dryrun++;
17023034Sdougm 		break;
17033034Sdougm 	    case 'v':
17043034Sdougm 		verbose++;
17053034Sdougm 		break;
17063034Sdougm 	    case 's':
17073034Sdougm 		/*
17083034Sdougm 		 * remove share path from group. Currently limit
17093034Sdougm 		 * to one share per command.
17103034Sdougm 		 */
17113034Sdougm 		if (sharepath != NULL) {
17123034Sdougm 		    (void) printf(gettext("Moving multiple shares not"
17133034Sdougm 				    "supported\n"));
17143034Sdougm 		    return (SA_BAD_PATH);
17153034Sdougm 		}
17163034Sdougm 		sharepath = optarg;
17173034Sdougm 		break;
17183034Sdougm 	    default:
17193034Sdougm 	    case 'h':
17203034Sdougm 	    case '?':
17213034Sdougm 		(void) printf(gettext("usage: %s\n"),
17223034Sdougm 				sa_get_usage(USAGE_MOVE_SHARE));
17233034Sdougm 		return (0);
17243034Sdougm 	    }
17253034Sdougm 	}
17263034Sdougm 
17273034Sdougm 	if (optind >= argc || sharepath == NULL) {
17283034Sdougm 			(void) printf(gettext("usage: %s\n"),
17293034Sdougm 				sa_get_usage(USAGE_MOVE_SHARE));
17303034Sdougm 	    if (dryrun || verbose || sharepath != NULL) {
17313034Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
17323034Sdougm 		ret = SA_NO_SUCH_GROUP;
17333034Sdougm 	    } else {
17343034Sdougm 		if (sharepath == NULL) {
17353034Sdougm 		    ret = SA_SYNTAX_ERR;
17363034Sdougm 		    (void) printf(gettext("\tsharepath must be specified\n"));
17373034Sdougm 		} else
17383034Sdougm 		    ret = SA_OK;
17393034Sdougm 	    }
17403034Sdougm 	} else {
17413034Sdougm 	    if (sharepath == NULL) {
17423034Sdougm 		(void) printf(gettext("sharepath must be specified with "
17433034Sdougm 				"the -s option\n"));
17443034Sdougm 		ret = SA_BAD_PATH;
17453034Sdougm 	    } else {
17463910Sdougm 		group = sa_get_group(handle, argv[optind]);
17473034Sdougm 		if (group != NULL) {
17483910Sdougm 		    share = sa_find_share(handle, sharepath);
17493034Sdougm 		    authdst = check_authorizations(argv[optind], flags);
17503034Sdougm 		    if (share == NULL) {
17513034Sdougm 			(void) printf(gettext("Share not found: %s\n"),
17523034Sdougm 					sharepath);
17533034Sdougm 			ret = SA_NO_SUCH_PATH;
17543034Sdougm 		    } else {
17553034Sdougm 			sa_group_t parent;
17563034Sdougm 			char *zfsold;
17573034Sdougm 			char *zfsnew;
17583034Sdougm 
17593034Sdougm 			parent = sa_get_parent_group(share);
17603034Sdougm 			if (parent != NULL) {
17613034Sdougm 			    char *pname;
17623034Sdougm 			    pname = sa_get_group_attr(parent, "name");
17633034Sdougm 			    if (pname != NULL) {
17643034Sdougm 				authsrc = check_authorizations(pname, flags);
17653034Sdougm 				sa_free_attr_string(pname);
17663034Sdougm 			    }
17673034Sdougm 			    zfsold = sa_get_group_attr(parent, "zfs");
17683034Sdougm 			    zfsnew = sa_get_group_attr(group, "zfs");
17693034Sdougm 			    if ((zfsold != NULL && zfsnew == NULL) ||
17703034Sdougm 				(zfsold == NULL && zfsnew != NULL)) {
17713034Sdougm 				ret = SA_NOT_ALLOWED;
17723034Sdougm 			    }
17733034Sdougm 			    if (zfsold != NULL)
17743034Sdougm 				sa_free_attr_string(zfsold);
17753034Sdougm 			    if (zfsnew != NULL)
17763034Sdougm 				sa_free_attr_string(zfsnew);
17773034Sdougm 			}
17783034Sdougm 			if (!dryrun && ret == SA_OK) {
17793034Sdougm 			    ret = sa_move_share(group, share);
17803034Sdougm 			}
17813034Sdougm 			if (ret == SA_OK && parent != group && !dryrun) {
17823034Sdougm 			    char *oldstate;
17833910Sdougm 			    ret = sa_update_config(handle);
17843034Sdougm 				/*
17853034Sdougm 				 * note that the share may need to be
17863034Sdougm 				 * "unshared" if the new group is
17873034Sdougm 				 * disabled and the old was enabled or
17883034Sdougm 				 * it may need to be share to update
17893034Sdougm 				 * if the new group is enabled.
17903034Sdougm 				 */
17913034Sdougm 			    oldstate = sa_get_group_attr(parent, "state");
17923034Sdougm 			    /* enable_share determines what to do */
17933034Sdougm 			    if (strcmp(oldstate, "enabled") == 0) {
17943034Sdougm 				(void) sa_disable_share(share, NULL);
17953034Sdougm 			    }
17963910Sdougm 			    (void) enable_share(handle, group, share, 1);
17973034Sdougm 			    if (oldstate != NULL)
17983034Sdougm 				sa_free_attr_string(oldstate);
17993034Sdougm 			}
18003034Sdougm 			if (ret != SA_OK) {
18013034Sdougm 			    (void) printf(gettext("Could not move share: %s\n"),
18023034Sdougm 				    sa_errorstr(ret));
18033034Sdougm 			}
18043034Sdougm 			if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
18053034Sdougm 			    verbose) {
18063034Sdougm 			    (void) printf(gettext("Command would fail: %s\n"),
18073034Sdougm 					sa_errorstr(SA_NO_PERMISSION));
18083034Sdougm 			}
18093034Sdougm 		    }
18103034Sdougm 		} else {
18113034Sdougm 		    (void) printf(gettext("Group \"%s\" not found\n"),
18123034Sdougm 					argv[optind]);
18133034Sdougm 		    ret = SA_NO_SUCH_GROUP;
18143034Sdougm 		}
18153034Sdougm 	    }
18163034Sdougm 	}
18173034Sdougm 	return (ret);
18183034Sdougm }
18193034Sdougm 
18203034Sdougm /*
18213034Sdougm  * sa_removeshare(flags, argc, argv)
18223034Sdougm  *
18233034Sdougm  * implements remove-share subcommand.
18243034Sdougm  */
18253034Sdougm 
18263034Sdougm int
18273910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
18283034Sdougm {
18293034Sdougm 	int verbose = 0;
18303034Sdougm 	int dryrun = 0;
18313034Sdougm 	int force = 0;
18323034Sdougm 	int c;
18333034Sdougm 	int ret = SA_OK;
18343034Sdougm 	sa_group_t group;
18353034Sdougm 	sa_share_t share;
18363034Sdougm 	char *sharepath = NULL;
18373034Sdougm 	char dir[MAXPATHLEN];
18383034Sdougm 	int auth;
18393034Sdougm 
18403034Sdougm 	while ((c = getopt(argc, argv, "?hfns:v")) != EOF) {
18413034Sdougm 	    switch (c) {
18423034Sdougm 	    case 'n':
18433034Sdougm 		dryrun++;
18443034Sdougm 		break;
18453034Sdougm 	    case 'v':
18463034Sdougm 		verbose++;
18473034Sdougm 		break;
18483034Sdougm 	    case 'f':
18493034Sdougm 		force++;
18503034Sdougm 		break;
18513034Sdougm 	    case 's':
18523034Sdougm 		/*
18533034Sdougm 		 * remove share path from group. Currently limit
18543034Sdougm 		 * to one share per command.
18553034Sdougm 		 */
18563034Sdougm 		if (sharepath != NULL) {
18573034Sdougm 		    (void) printf(gettext("Removing multiple shares not"
18583034Sdougm 				    "supported\n"));
18593034Sdougm 		    return (SA_SYNTAX_ERR);
18603034Sdougm 		}
18613034Sdougm 		sharepath = optarg;
18623034Sdougm 		break;
18633034Sdougm 	    default:
18643034Sdougm 	    case 'h':
18653034Sdougm 	    case '?':
18663034Sdougm 		(void) printf(gettext("usage: %s\n"),
18673034Sdougm 				sa_get_usage(USAGE_REMOVE_SHARE));
18683034Sdougm 		return (0);
18693034Sdougm 	    }
18703034Sdougm 	}
18713034Sdougm 
18723034Sdougm 	if (optind >= argc || sharepath == NULL) {
18733034Sdougm 	    if (sharepath == NULL) {
18743034Sdougm 			(void) printf(gettext("usage: %s\n"),
18753034Sdougm 				sa_get_usage(USAGE_REMOVE_SHARE));
18763034Sdougm 		(void) printf(gettext("\t-s sharepath must be specified\n"));
18773034Sdougm 		ret = SA_BAD_PATH;
18783034Sdougm 	    } else {
18793034Sdougm 		ret = SA_OK;
18803034Sdougm 	    }
18813034Sdougm 	}
18823034Sdougm 	if (ret == SA_OK) {
18833034Sdougm 	    if (optind < argc) {
18843034Sdougm 		if ((optind + 1) < argc) {
18853034Sdougm 		    (void) printf(gettext("Extraneous group(s) at end of "
18863034Sdougm 						"command\n"));
18873034Sdougm 		    ret = SA_SYNTAX_ERR;
18883034Sdougm 		} else {
18893910Sdougm 		    group = sa_get_group(handle, argv[optind]);
18903034Sdougm 		    if (group == NULL) {
18913034Sdougm 			(void) printf(gettext("Group \"%s\" not found\n"),
18923034Sdougm 					argv[optind]);
18933034Sdougm 			ret = SA_NO_SUCH_GROUP;
18943034Sdougm 		    }
18953034Sdougm 		}
18963034Sdougm 	    } else {
18973034Sdougm 		group = NULL;
18983034Sdougm 	    }
18993663Sdougm 
19003663Sdougm 		/*
19013663Sdougm 		 * Lookup the path in the internal configuration. Care
19023663Sdougm 		 * must be taken to handle the case where the
19033663Sdougm 		 * underlying path has been removed since we need to
19043663Sdougm 		 * be able to deal with that as well.
19053663Sdougm 		 */
19063034Sdougm 	    if (ret == SA_OK) {
19073034Sdougm 		if (group != NULL)
19083034Sdougm 		    share = sa_get_share(group, sharepath);
19093034Sdougm 		else
19103910Sdougm 		    share = sa_find_share(handle, sharepath);
19113663Sdougm 		/*
19123663Sdougm 		 * If we didn't find the share with the provided path,
19133663Sdougm 		 * it may be a symlink so attempt to resolve it using
19143663Sdougm 		 * realpath and try again. Realpath will resolve any
19153663Sdougm 		 * symlinks and place them in "dir". Note that
19163663Sdougm 		 * sharepath is only used for the lookup the first
19173663Sdougm 		 * time and later for error messages. dir will be used
19183663Sdougm 		 * on the second attempt. Once a share is found, all
19193663Sdougm 		 * operations are based off of the share variable.
19203663Sdougm 		 */
19213663Sdougm 		if (share == NULL) {
19223663Sdougm 		    if (realpath(sharepath, dir) == NULL) {
19233663Sdougm 			ret = SA_BAD_PATH;
19243663Sdougm 			(void) printf(gettext("Path is not valid: %s\n"),
19253663Sdougm 						sharepath);
19263663Sdougm 		    } else {
19273663Sdougm 			if (group != NULL)
19283663Sdougm 			    share = sa_get_share(group, dir);
19293663Sdougm 			else
19303910Sdougm 			    share = sa_find_share(handle, dir);
19313663Sdougm 		    }
19323663Sdougm 		}
19333663Sdougm 	    }
19343663Sdougm 
19353663Sdougm 		/*
19363663Sdougm 		 * If there hasn't been an error, there was likely a
19373663Sdougm 		 * path found. If not, give the appropriate error
19383663Sdougm 		 * message and set the return error. If it was found,
19393663Sdougm 		 * then disable the share and then remove it from the
19403663Sdougm 		 * configuration.
19413663Sdougm 		 */
19423663Sdougm 	    if (ret == SA_OK) {
19433034Sdougm 		if (share == NULL) {
19443034Sdougm 		    if (group != NULL)
19453034Sdougm 			(void) printf(gettext("Share not found in group %s:"
19463663Sdougm 						" %s\n"),
19473034Sdougm 					argv[optind], sharepath);
19483034Sdougm 		    else
19493034Sdougm 			(void) printf(gettext("Share not found: %s\n"),
19503034Sdougm 					sharepath);
19513034Sdougm 		    ret = SA_NO_SUCH_PATH;
19523034Sdougm 		} else {
19533034Sdougm 		    if (group == NULL)
19543034Sdougm 			group = sa_get_parent_group(share);
19553034Sdougm 		    if (!dryrun) {
19563034Sdougm 			if (ret == SA_OK) {
19573034Sdougm 			    ret = sa_disable_share(share, NULL);
19583034Sdougm 				/*
19593034Sdougm 				 * we don't care if it fails since it
19603663Sdougm 				 * could be disabled already. Some
19613663Sdougm 				 * unexpected errors could occur that
19623663Sdougm 				 * prevent removal, so also check for
19633663Sdougm 				 * force being set.
19643034Sdougm 				 */
19653034Sdougm 			    if (ret == SA_OK || ret == SA_NO_SUCH_PATH ||
19663663Sdougm 					ret == SA_NOT_SUPPORTED ||
19673663Sdougm 					ret == SA_SYSTEM_ERR || force) {
19683034Sdougm 				ret = sa_remove_share(share);
19693034Sdougm 			    }
19703034Sdougm 			    if (ret == SA_OK)
19713910Sdougm 				ret = sa_update_config(handle);
19723034Sdougm 			}
19733034Sdougm 			if (ret != SA_OK) {
19743034Sdougm 			    (void) printf(gettext("Could not remove share:"
19753034Sdougm 							" %s\n"),
19763034Sdougm 					sa_errorstr(ret));
19773034Sdougm 			}
19783034Sdougm 		    } else if (ret == SA_OK) {
19793034Sdougm 			char *pname;
19803034Sdougm 			pname = sa_get_group_attr(group, "name");
19813034Sdougm 			if (pname != NULL) {
19823034Sdougm 			    auth = check_authorizations(pname, flags);
19833034Sdougm 			    sa_free_attr_string(pname);
19843034Sdougm 			}
19853034Sdougm 			if (!auth && verbose) {
19863034Sdougm 			    (void) printf(gettext("Command would fail: %s\n"),
19873034Sdougm 					sa_errorstr(SA_NO_PERMISSION));
19883034Sdougm 			}
19893034Sdougm 		    }
19903034Sdougm 		}
19913034Sdougm 	    }
19923034Sdougm 	}
19933034Sdougm 	return (ret);
19943034Sdougm }
19953034Sdougm 
19963034Sdougm /*
19973034Sdougm  * sa_set_share(flags, argc, argv)
19983034Sdougm  *
19993034Sdougm  * implements set-share subcommand.
20003034Sdougm  */
20013034Sdougm 
20023034Sdougm int
20033910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
20043034Sdougm {
20053034Sdougm 	int dryrun = 0;
20063034Sdougm 	int c;
20073034Sdougm 	int ret = SA_OK;
20083034Sdougm 	sa_group_t group, sharegroup;
20093034Sdougm 	sa_share_t share;
20103034Sdougm 	char *sharepath = NULL;
20113034Sdougm 	char *description = NULL;
20123034Sdougm 	char *resource = NULL;
20133034Sdougm 	int auth;
20143034Sdougm 	int verbose = 0;
20153034Sdougm 
20163034Sdougm 	while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
20173034Sdougm 	    switch (c) {
20183034Sdougm 	    case 'n':
20193034Sdougm 		dryrun++;
20203034Sdougm 		break;
20213034Sdougm 	    case 'd':
20223034Sdougm 		description = optarg;
20233034Sdougm 		break;
20243034Sdougm 	    case 'r':
20253034Sdougm 		resource = optarg;
20263034Sdougm 		break;
20273034Sdougm 	    case 'v':
20283034Sdougm 		verbose++;
20293034Sdougm 		break;
20303034Sdougm 	    case 's':
20313034Sdougm 		/*
20323034Sdougm 		 * save share path into group. Currently limit
20333034Sdougm 		 * to one share per command.
20343034Sdougm 		 */
20353034Sdougm 		if (sharepath != NULL) {
20363034Sdougm 		    (void) printf(gettext("Updating multiple shares not"
20373034Sdougm 				    "supported\n"));
20383034Sdougm 		    return (SA_BAD_PATH);
20393034Sdougm 		}
20403034Sdougm 		sharepath = optarg;
20413034Sdougm 		break;
20423034Sdougm 	    default:
20433034Sdougm 	    case 'h':
20443034Sdougm 	    case '?':
20453034Sdougm 		(void) printf(gettext("usage: %s\n"),
20463034Sdougm 				sa_get_usage(USAGE_SET_SHARE));
20473034Sdougm 		return (SA_OK);
20483034Sdougm 	    }
20493034Sdougm 	}
20503034Sdougm 	if (optind >= argc || sharepath == NULL) {
20513034Sdougm 	    if (sharepath == NULL) {
20523034Sdougm 		(void) printf(gettext("usage: %s\n"),
20533034Sdougm 				sa_get_usage(USAGE_SET_SHARE));
20543034Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
20553034Sdougm 	    ret = SA_BAD_PATH;
20563034Sdougm 	    } else {
20573034Sdougm 		ret = SA_OK;
20583034Sdougm 	    }
20593034Sdougm 	}
20603034Sdougm 	if ((optind + 1) < argc) {
20613034Sdougm 	    (void) printf(gettext("usage: %s\n"),
20623034Sdougm 				sa_get_usage(USAGE_SET_SHARE));
20633034Sdougm 	    (void) printf(gettext("\tExtraneous group(s) at end\n"));
20643034Sdougm 	    ret = SA_SYNTAX_ERR;
20653034Sdougm 	}
20663034Sdougm 	if (ret == SA_OK) {
20673034Sdougm 	    char *groupname;
20683034Sdougm 	    if (optind < argc) {
20693034Sdougm 		groupname = argv[optind];
20703910Sdougm 		group = sa_get_group(handle, groupname);
20713034Sdougm 	    } else {
20723034Sdougm 		group = NULL;
20733034Sdougm 		groupname = NULL;
20743034Sdougm 	    }
20753910Sdougm 	    share = sa_find_share(handle, sharepath);
20763034Sdougm 	    if (share != NULL) {
20773034Sdougm 		sharegroup = sa_get_parent_group(share);
20783034Sdougm 		if (group != NULL && group != sharegroup) {
20793034Sdougm 		    (void) printf(gettext("Group \"%s\" does not contain "
20803034Sdougm 						"share %s\n"),
20813034Sdougm 			    argv[optind], sharepath);
20823034Sdougm 		    ret = SA_BAD_PATH;
20833034Sdougm 		} else {
20843034Sdougm 		    int delgroupname = 0;
20853034Sdougm 		    if (groupname == NULL) {
20863034Sdougm 			groupname = sa_get_group_attr(sharegroup, "name");
20873034Sdougm 			delgroupname = 1;
20883034Sdougm 		    }
20893034Sdougm 		    if (groupname != NULL) {
20903034Sdougm 			auth = check_authorizations(groupname, flags);
20913034Sdougm 			if (delgroupname) {
20923034Sdougm 			    sa_free_attr_string(groupname);
20933034Sdougm 			    groupname = NULL;
20943034Sdougm 			}
20953034Sdougm 		    } else {
20963034Sdougm 			ret = SA_NO_MEMORY;
20973034Sdougm 		    }
20983034Sdougm 		    if (resource != NULL) {
20993034Sdougm 			if (strpbrk(resource, " \t/") == NULL) {
21003034Sdougm 			    if (!dryrun) {
21013034Sdougm 				ret = sa_set_share_attr(share, "resource",
21023034Sdougm 						    resource);
21033034Sdougm 			    } else {
21043034Sdougm 				sa_share_t resshare;
21053034Sdougm 				resshare = sa_get_resource(sharegroup,
21063034Sdougm 							    resource);
21073034Sdougm 				if (resshare != NULL && resshare != share)
21083034Sdougm 				    ret = SA_DUPLICATE_NAME;
21093034Sdougm 			    }
21103034Sdougm 			} else {
21113034Sdougm 			    ret = SA_BAD_PATH;
21123034Sdougm 			    (void) printf(gettext("Resource must not contain "
21133034Sdougm 						"white space or '/'\n"));
21143034Sdougm 			}
21153034Sdougm 		    }
21163034Sdougm 		    if (ret == SA_OK && description != NULL) {
21173034Sdougm 			ret = sa_set_share_description(share, description);
21183034Sdougm 		    }
21193034Sdougm 		}
21203034Sdougm 		if (!dryrun && ret == SA_OK) {
21213910Sdougm 		    ret = sa_update_config(handle);
21223034Sdougm 		}
21233034Sdougm 		switch (ret) {
21243034Sdougm 		case SA_DUPLICATE_NAME:
21253034Sdougm 		    (void) printf(gettext("Resource name in use: %s\n"),
21263034Sdougm 					resource);
21273034Sdougm 		    break;
21283034Sdougm 		default:
21293034Sdougm 		    (void) printf(gettext("Could not set attribute: %s\n"),
21303034Sdougm 			    sa_errorstr(ret));
21313034Sdougm 		    break;
21323034Sdougm 		case SA_OK:
21333034Sdougm 		    if (dryrun && !auth && verbose) {
21343034Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
21353034Sdougm 				sa_errorstr(SA_NO_PERMISSION));
21363034Sdougm 		    }
21373034Sdougm 		    break;
21383034Sdougm 		}
21393034Sdougm 	    } else {
21403034Sdougm 		(void) printf(gettext("Share path \"%s\" not found\n"),
21413034Sdougm 				sharepath);
21423034Sdougm 		ret = SA_NO_SUCH_PATH;
21433034Sdougm 	    }
21443034Sdougm 	}
21453034Sdougm 	return (ret);
21463034Sdougm }
21473034Sdougm 
21483034Sdougm /*
21493034Sdougm  * add_security(group, sectype, optlist, proto, *err)
21503034Sdougm  *
21513034Sdougm  * Helper function to add a security option (named optionset) to the
21523034Sdougm  * group.
21533034Sdougm  */
21543034Sdougm 
21553034Sdougm static int
21563034Sdougm add_security(sa_group_t group, char *sectype,
21573034Sdougm 		struct options *optlist, char *proto, int *err)
21583034Sdougm {
21593034Sdougm 	sa_security_t security;
21603034Sdougm 	int ret = SA_OK;
21613034Sdougm 	int result = 0;
21623034Sdougm 
21633034Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
21643034Sdougm 	security = sa_get_security(group, sectype, proto);
21653034Sdougm 	if (security == NULL) {
21663034Sdougm 	    security = sa_create_security(group, sectype, proto);
21673034Sdougm 	}
21683034Sdougm 	if (sectype != NULL)
21693034Sdougm 	    sa_free_attr_string(sectype);
21703034Sdougm 	if (security != NULL) {
21713034Sdougm 	    while (optlist != NULL) {
21723034Sdougm 		sa_property_t prop;
21733034Sdougm 		prop = sa_get_property(security, optlist->optname);
21743034Sdougm 		if (prop == NULL) {
21753034Sdougm 			/*
21763034Sdougm 			 * add the property, but only if it is
21773034Sdougm 			 * a non-NULL or non-zero length value
21783034Sdougm 			 */
21793034Sdougm 		    if (optlist->optvalue != NULL) {
21803034Sdougm 			prop = sa_create_property(optlist->optname,
21813034Sdougm 							optlist->optvalue);
21823034Sdougm 			if (prop != NULL) {
21833034Sdougm 			    ret = sa_valid_property(security, proto, prop);
21843034Sdougm 			    if (ret != SA_OK) {
21853034Sdougm 				(void) sa_remove_property(prop);
21863034Sdougm 				(void) printf(gettext("Could not add "
21873034Sdougm 							"property %s: %s\n"),
21883034Sdougm 							optlist->optname,
21893034Sdougm 						sa_errorstr(ret));
21903034Sdougm 			    }
21913034Sdougm 			    if (ret == SA_OK) {
21923034Sdougm 				ret = sa_add_property(security, prop);
21933034Sdougm 				if (ret != SA_OK) {
21943034Sdougm 				    (void) printf(gettext("Could not add "
21953034Sdougm 						    "property (%s=%s): %s\n"),
21963034Sdougm 						optlist->optname,
21973034Sdougm 						optlist->optvalue,
21983034Sdougm 						sa_errorstr(ret));
21993034Sdougm 				} else {
22003034Sdougm 				    result = 1;
22013034Sdougm 				}
22023034Sdougm 			    }
22033034Sdougm 			}
22043034Sdougm 		    }
22053034Sdougm 		} else {
22063034Sdougm 		    ret = sa_update_property(prop, optlist->optvalue);
22073034Sdougm 		    result = 1; /* should check if really changed */
22083034Sdougm 		}
22093034Sdougm 		optlist = optlist->next;
22103034Sdougm 	    }
22113034Sdougm 		/*
22123034Sdougm 		 * when done, properties may have all been removed but
22133034Sdougm 		 * we need to keep the security type itself until
22143034Sdougm 		 * explicitly removed.
22153034Sdougm 		 */
22163034Sdougm 	    if (result)
22173034Sdougm 		ret = sa_commit_properties(security, 0);
22183034Sdougm 	}
22193034Sdougm 	*err = ret;
22203034Sdougm 	return (result);
22213034Sdougm }
22223034Sdougm 
22233034Sdougm /*
22243034Sdougm  * basic_set(groupname, optlist, protocol, sharepath, dryrun)
22253034Sdougm  *
22263034Sdougm  * This function implements "set" when a name space (-S) is not
22273034Sdougm  * specified. It is a basic set. Options and other CLI parsing has
22283034Sdougm  * already been done.
22293034Sdougm  */
22303034Sdougm 
22313034Sdougm static int
22323910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
22333910Sdougm 		char *protocol,	char *sharepath, int dryrun)
22343034Sdougm {
22353034Sdougm 	sa_group_t group;
22363034Sdougm 	int ret = SA_OK;
22373034Sdougm 	int change = 0;
22383034Sdougm 	struct list *worklist = NULL;
22393034Sdougm 
22403910Sdougm 	group = sa_get_group(handle, groupname);
22413034Sdougm 	if (group != NULL) {
22423034Sdougm 	    sa_share_t share = NULL;
22433034Sdougm 	    if (sharepath != NULL) {
22443034Sdougm 		share = sa_get_share(group, sharepath);
22453034Sdougm 		if (share == NULL) {
22463034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
22473034Sdougm 				groupname, sharepath);
22483034Sdougm 		    ret = SA_NO_SUCH_PATH;
22493034Sdougm 		}
22503034Sdougm 	    }
22513034Sdougm 	    if (ret == SA_OK) {
22523034Sdougm 		/* group must exist */
22533034Sdougm 		ret = valid_options(optlist, protocol,
22543034Sdougm 				    share == NULL ? group : share, NULL);
22553034Sdougm 		if (ret == SA_OK && !dryrun) {
22563034Sdougm 		    if (share != NULL)
22573034Sdougm 			change |= add_optionset(share, optlist, protocol,
22583034Sdougm 						&ret);
22593034Sdougm 		    else
22603034Sdougm 			change |= add_optionset(group, optlist, protocol,
22613034Sdougm 						&ret);
22623034Sdougm 		    if (ret == SA_OK && change) {
22633034Sdougm 			worklist = add_list(worklist, group, share);
22643034Sdougm 		    }
22653034Sdougm 		}
22663034Sdougm 	    }
22673034Sdougm 	    free_opt(optlist);
22683034Sdougm 	} else {
22693034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
22703034Sdougm 		ret = SA_NO_SUCH_GROUP;
22713034Sdougm 	}
22723034Sdougm 	/*
22733034Sdougm 	 * we have a group and potentially legal additions
22743034Sdougm 	 */
22753034Sdougm 
22763034Sdougm 	/* commit to configuration if not a dryrun */
22773034Sdougm 	if (!dryrun && ret == SA_OK) {
22783034Sdougm 	    if (change && worklist != NULL) {
22793034Sdougm 		/* properties changed, so update all shares */
22803910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
22813034Sdougm 	    }
22823034Sdougm 	}
22833034Sdougm 	if (worklist != NULL)
22843034Sdougm 	    free_list(worklist);
22853034Sdougm 	return (ret);
22863034Sdougm }
22873034Sdougm 
22883034Sdougm /*
22893034Sdougm  * space_set(groupname, optlist, protocol, sharepath, dryrun)
22903034Sdougm  *
22913034Sdougm  * This function implements "set" when a name space (-S) is
22923034Sdougm  * specified. It is a namespace set. Options and other CLI parsing has
22933034Sdougm  * already been done.
22943034Sdougm  */
22953034Sdougm 
22963034Sdougm static int
22973910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist,
22983910Sdougm 		char *protocol,	char *sharepath, int dryrun, char *sectype)
22993034Sdougm {
23003034Sdougm 	sa_group_t group;
23013034Sdougm 	int ret = SA_OK;
23023034Sdougm 	int change = 0;
23033034Sdougm 	struct list *worklist = NULL;
23043034Sdougm 
23053034Sdougm 	/*
23063034Sdougm 	 * make sure protcol and sectype are valid
23073034Sdougm 	 */
23083034Sdougm 
23093034Sdougm 	if (sa_proto_valid_space(protocol, sectype) == 0) {
23103034Sdougm 	    (void) printf(gettext("Option space \"%s\" not valid "
23113034Sdougm 					"for protocol.\n"),
23123034Sdougm 				sectype);
23133034Sdougm 	    return (SA_INVALID_SECURITY);
23143034Sdougm 	}
23153034Sdougm 
23163910Sdougm 	group = sa_get_group(handle, groupname);
23173034Sdougm 	if (group != NULL) {
23183034Sdougm 	    sa_share_t share = NULL;
23193034Sdougm 	    if (sharepath != NULL) {
23203034Sdougm 		share = sa_get_share(group, sharepath);
23213034Sdougm 		if (share == NULL) {
23223034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
23233034Sdougm 				groupname, sharepath);
23243034Sdougm 		    ret = SA_NO_SUCH_PATH;
23253034Sdougm 		}
23263034Sdougm 	    }
23273034Sdougm 	    if (ret == SA_OK) {
23283034Sdougm 		/* group must exist */
23293034Sdougm 		ret = valid_options(optlist, protocol,
23303034Sdougm 				    share == NULL ? group : share, sectype);
23313034Sdougm 		if (ret == SA_OK && !dryrun) {
23323034Sdougm 		    if (share != NULL)
23333034Sdougm 			change = add_security(share, sectype, optlist,
23343034Sdougm 						protocol,
23353034Sdougm 						&ret);
23363034Sdougm 		    else
23373034Sdougm 			change = add_security(group, sectype, optlist,
23383034Sdougm 						protocol,
23393034Sdougm 						&ret);
23403034Sdougm 		    if (ret != SA_OK)
23413034Sdougm 			(void) printf(gettext("Could not set property: %s\n"),
23423034Sdougm 				sa_errorstr(ret));
23433034Sdougm 		}
23443034Sdougm 		if (ret == SA_OK && change)
23453034Sdougm 		    worklist = add_list(worklist, group, share);
23463034Sdougm 	    }
23473034Sdougm 	    free_opt(optlist);
23483034Sdougm 	} else {
23493034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
23503034Sdougm 		ret = SA_NO_SUCH_GROUP;
23513034Sdougm 	}
23523034Sdougm 	/*
23533034Sdougm 	 * we have a group and potentially legal additions
23543034Sdougm 	 */
23553034Sdougm 
23563034Sdougm 	/* commit to configuration if not a dryrun */
23573034Sdougm 	if (!dryrun && ret == 0) {
23583034Sdougm 	    if (change && worklist != NULL) {
23593034Sdougm 		/* properties changed, so update all shares */
23603910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
23613034Sdougm 	    }
23623910Sdougm 	    ret = sa_update_config(handle);
23633034Sdougm 	}
23643034Sdougm 	if (worklist != NULL)
23653034Sdougm 	    free_list(worklist);
23663034Sdougm 	return (ret);
23673034Sdougm }
23683034Sdougm 
23693034Sdougm /*
23703034Sdougm  * sa_set(flags, argc, argv)
23713034Sdougm  *
23723034Sdougm  * Implements the set subcommand. It keys off of -S to determine which
23733034Sdougm  * set of operations to actually do.
23743034Sdougm  */
23753034Sdougm 
23763034Sdougm int
23773910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
23783034Sdougm {
23793034Sdougm 	char *groupname;
23803034Sdougm 	int verbose = 0;
23813034Sdougm 	int dryrun = 0;
23823034Sdougm 	int c;
23833034Sdougm 	char *protocol = NULL;
23843034Sdougm 	int ret = SA_OK;
23853034Sdougm 	struct options *optlist = NULL;
23863034Sdougm 	char *sharepath = NULL;
23873034Sdougm 	char *optset = NULL;
23883034Sdougm 	int auth;
23893034Sdougm 
23903034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
23913034Sdougm 	    switch (c) {
23923034Sdougm 	    case 'v':
23933034Sdougm 		verbose++;
23943034Sdougm 		break;
23953034Sdougm 	    case 'n':
23963034Sdougm 		dryrun++;
23973034Sdougm 		break;
23983034Sdougm 	    case 'P':
23993034Sdougm 		protocol = optarg;
24003034Sdougm 		if (!sa_valid_protocol(protocol)) {
24013034Sdougm 		    (void) printf(gettext("Invalid protocol specified:"
24023034Sdougm 				    "%s\n"),
24033034Sdougm 					protocol);
24043034Sdougm 		    return (SA_INVALID_PROTOCOL);
24053034Sdougm 		}
24063034Sdougm 		break;
24073034Sdougm 	    case 'p':
24083034Sdougm 		ret = add_opt(&optlist, optarg, 0);
24093034Sdougm 		switch (ret) {
24103034Sdougm 		case OPT_ADD_SYNTAX:
24113034Sdougm 		    (void) printf(gettext("Property syntax error: %s\n"),
24123034Sdougm 					optarg);
24133034Sdougm 		    return (SA_SYNTAX_ERR);
24143034Sdougm 		case OPT_ADD_MEMORY:
24153034Sdougm 		    (void) printf(gettext("No memory to set property: %s\n"),
24163034Sdougm 					optarg);
24173034Sdougm 		    return (SA_NO_MEMORY);
24183034Sdougm 		default:
24193034Sdougm 		    break;
24203034Sdougm 		}
24213034Sdougm 		break;
24223034Sdougm 	    case 's':
24233034Sdougm 		sharepath = optarg;
24243034Sdougm 		break;
24253034Sdougm 	    case 'S':
24263034Sdougm 		optset = optarg;
24273034Sdougm 		break;
24283034Sdougm 	    default:
24293034Sdougm 	    case 'h':
24303034Sdougm 	    case '?':
24313034Sdougm 		(void) printf(gettext("usage: %s\n"),
24323034Sdougm 				sa_get_usage(USAGE_SET));
24333034Sdougm 		return (SA_OK);
24343034Sdougm 	    }
24353034Sdougm 	}
24363034Sdougm 
24373034Sdougm 	if (optlist != NULL)
24383034Sdougm 	    ret = chk_opt(optlist, optset != NULL, protocol);
24393034Sdougm 
24403034Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
24413034Sdougm 	    protocol == NULL ||
24423034Sdougm 	    ret != OPT_ADD_OK) {
24433034Sdougm 	    char *sep = "\t";
24443034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
24453034Sdougm 	    if (optind >= argc) {
24463034Sdougm 		(void) printf(gettext("%sgroup must be specified"), sep);
24473034Sdougm 		sep = ", ";
24483034Sdougm 	    }
24493034Sdougm 	    if (optlist == NULL) {
24503034Sdougm 		(void) printf(gettext("%sat least one property must be"
24513034Sdougm 				" specified"), sep);
24523034Sdougm 		sep = ", ";
24533034Sdougm 	    }
24543034Sdougm 	    if (protocol == NULL) {
24553034Sdougm 		(void) printf(gettext("%sprotocol must be specified"), sep);
24563034Sdougm 		sep = ", ";
24573034Sdougm 	    }
24583034Sdougm 	    (void) printf("\n");
24593034Sdougm 	    ret = SA_SYNTAX_ERR;
24603034Sdougm 	} else {
24613034Sdougm 		/*
24623034Sdougm 		 * if a group already exists, we can only add a new
24633034Sdougm 		 * protocol to it and not create a new one or add the
24643034Sdougm 		 * same protocol again.
24653034Sdougm 		 */
24663034Sdougm 
24673034Sdougm 	    groupname = argv[optind];
24683034Sdougm 	    auth = check_authorizations(groupname, flags);
24693034Sdougm 	    if (optset == NULL)
24703910Sdougm 		ret = basic_set(handle, groupname, optlist, protocol,
24713034Sdougm 				sharepath, dryrun);
24723034Sdougm 	    else
24733910Sdougm 		ret = space_set(handle, groupname, optlist, protocol,
24743034Sdougm 				sharepath, dryrun, optset);
24753034Sdougm 	    if (dryrun && ret == SA_OK && !auth && verbose) {
24763034Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
24773034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
24783034Sdougm 	    }
24793034Sdougm 	}
24803034Sdougm 	return (ret);
24813034Sdougm }
24823034Sdougm 
24833034Sdougm /*
24843034Sdougm  * remove_options(group, optlist, proto, *err)
24853034Sdougm  *
24863034Sdougm  * helper function to actually remove options from a group after all
24873034Sdougm  * preprocessing is done.
24883034Sdougm  */
24893034Sdougm 
24903034Sdougm static int
24913034Sdougm remove_options(sa_group_t group, struct options *optlist,
24923034Sdougm 		char *proto, int *err)
24933034Sdougm {
24943034Sdougm 	struct options *cur;
24953034Sdougm 	sa_optionset_t optionset;
24963034Sdougm 	sa_property_t prop;
24973034Sdougm 	int change = 0;
24983034Sdougm 	int ret = SA_OK;
24993034Sdougm 
25003034Sdougm 	optionset = sa_get_optionset(group, proto);
25013034Sdougm 	if (optionset != NULL) {
25023034Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
25033034Sdougm 		prop = sa_get_property(optionset, cur->optname);
25043034Sdougm 		if (prop != NULL) {
25053034Sdougm 		    ret = sa_remove_property(prop);
25063034Sdougm 		    if (ret != SA_OK)
25073034Sdougm 			break;
25083034Sdougm 		    change = 1;
25093034Sdougm 		}
25103034Sdougm 	    }
25113034Sdougm 	}
25123034Sdougm 	if (ret == SA_OK && change)
25133034Sdougm 	    ret = sa_commit_properties(optionset, 0);
25143034Sdougm 
25153034Sdougm 	if (err != NULL)
25163034Sdougm 	    *err = ret;
25173034Sdougm 	return (change);
25183034Sdougm }
25193034Sdougm 
25203034Sdougm /*
25213034Sdougm  * valid_unset(group, optlist, proto)
25223034Sdougm  *
25233034Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
25243034Sdougm  * error if a property doesn't exist.
25253034Sdougm  */
25263034Sdougm 
25273034Sdougm static int
25283034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto)
25293034Sdougm {
25303034Sdougm 	struct options *cur;
25313034Sdougm 	sa_optionset_t optionset;
25323034Sdougm 	sa_property_t prop;
25333034Sdougm 	int ret = SA_OK;
25343034Sdougm 
25353034Sdougm 	optionset = sa_get_optionset(group, proto);
25363034Sdougm 	if (optionset != NULL) {
25373034Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
25383034Sdougm 		prop = sa_get_property(optionset, cur->optname);
25393034Sdougm 		if (prop == NULL) {
25403034Sdougm 		    (void) printf(gettext("Could not unset property %s:"
25413034Sdougm 						" not set\n"),
25423034Sdougm 			    cur->optname);
25433034Sdougm 		    ret = SA_NO_SUCH_PROP;
25443034Sdougm 		}
25453034Sdougm 	    }
25463034Sdougm 	}
25473034Sdougm 	return (ret);
25483034Sdougm }
25493034Sdougm 
25503034Sdougm /*
25513034Sdougm  * valid_unset_security(group, optlist, proto)
25523034Sdougm  *
25533034Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
25543034Sdougm  * error if a property doesn't exist.
25553034Sdougm  */
25563034Sdougm 
25573034Sdougm static int
25583034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
25593034Sdougm 	    char *sectype)
25603034Sdougm {
25613034Sdougm 	struct options *cur;
25623034Sdougm 	sa_security_t security;
25633034Sdougm 	sa_property_t prop;
25643034Sdougm 	int ret = SA_OK;
25653034Sdougm 	char *sec;
25663034Sdougm 
25673034Sdougm 	sec = sa_proto_space_alias(proto, sectype);
25683034Sdougm 	security = sa_get_security(group, sec, proto);
25693034Sdougm 	if (security != NULL) {
25703034Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
25713034Sdougm 		prop = sa_get_property(security, cur->optname);
25723034Sdougm 		if (prop == NULL) {
25733034Sdougm 		    (void) printf(gettext("Could not unset property %s:"
25743034Sdougm 						" not set\n"),
25753034Sdougm 					cur->optname);
25763034Sdougm 		    ret = SA_NO_SUCH_PROP;
25773034Sdougm 		}
25783034Sdougm 	    }
25793034Sdougm 	} else {
25803034Sdougm 	    (void) printf(gettext("Could not unset %s: space not defined\n"),
25813034Sdougm 			    sectype);
25823034Sdougm 	    ret = SA_NO_SUCH_SECURITY;
25833034Sdougm 	}
25843034Sdougm 	if (sec != NULL)
25853034Sdougm 	    sa_free_attr_string(sec);
25863034Sdougm 	return (ret);
25873034Sdougm }
25883034Sdougm 
25893034Sdougm /*
25903034Sdougm  * remove_security(group, optlist, proto)
25913034Sdougm  *
25923034Sdougm  * Remove the properties since they were checked as valid.
25933034Sdougm  */
25943034Sdougm 
25953034Sdougm static int
25963034Sdougm remove_security(sa_group_t group, char *sectype,
25973034Sdougm 		struct options *optlist, char *proto, int *err)
25983034Sdougm {
25993034Sdougm 	sa_security_t security;
26003034Sdougm 	int ret = SA_OK;
26013034Sdougm 	int change = 0;
26023034Sdougm 
26033034Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
26043034Sdougm 	security = sa_get_security(group, sectype, proto);
26053034Sdougm 	if (sectype != NULL)
26063034Sdougm 	    sa_free_attr_string(sectype);
26073034Sdougm 
26083034Sdougm 	if (security != NULL) {
26093034Sdougm 	    while (optlist != NULL) {
26103034Sdougm 		sa_property_t prop;
26113034Sdougm 		prop = sa_get_property(security, optlist->optname);
26123034Sdougm 		if (prop != NULL) {
26133034Sdougm 		    ret = sa_remove_property(prop);
26143034Sdougm 		    if (ret != SA_OK)
26153034Sdougm 			break;
26163034Sdougm 		    change = 1;
26173034Sdougm 		}
26183034Sdougm 		optlist = optlist->next;
26193034Sdougm 	    }
26203034Sdougm 		/*
26213034Sdougm 		 * when done, properties may have all been removed but
26223034Sdougm 		 * we need to keep the security type itself until
26233034Sdougm 		 * explicitly removed.
26243034Sdougm 		 */
26253034Sdougm 	    if (ret == SA_OK && change)
26263034Sdougm 		ret = sa_commit_properties(security, 0);
26273034Sdougm 	} else {
26283034Sdougm 	    ret = SA_NO_SUCH_PROP;
26293034Sdougm 	}
26303034Sdougm 	if (err != NULL)
26313034Sdougm 	    *err = ret;
26323034Sdougm 	return (change);
26333034Sdougm }
26343034Sdougm 
26353034Sdougm /*
26363034Sdougm  * basic_unset(groupname, optlist, protocol, sharepath, dryrun)
26373034Sdougm  *
26383034Sdougm  * unset non-named optionset properties.
26393034Sdougm  */
26403034Sdougm 
26413034Sdougm static int
26423910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
26433910Sdougm 		char *protocol,	char *sharepath, int dryrun)
26443034Sdougm {
26453034Sdougm 	sa_group_t group;
26463034Sdougm 	int ret = SA_OK;
26473034Sdougm 	int change = 0;
26483034Sdougm 	struct list *worklist = NULL;
26493034Sdougm 
26503910Sdougm 	group = sa_get_group(handle, groupname);
26513034Sdougm 	if (group != NULL) {
26523034Sdougm 	    sa_share_t share = NULL;
26533034Sdougm 	    if (sharepath != NULL) {
26543034Sdougm 		share = sa_get_share(group, sharepath);
26553034Sdougm 		if (share == NULL) {
26563034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
26573034Sdougm 				groupname, sharepath);
26583034Sdougm 		    ret = SA_NO_SUCH_PATH;
26593034Sdougm 		}
26603034Sdougm 	    }
26613034Sdougm 	    if (ret == SA_OK) {
26623034Sdougm 		/* group must exist */
26633034Sdougm 		ret = valid_unset(share != NULL ? share : group,
26643034Sdougm 					optlist, protocol);
26653034Sdougm 		if (ret == SA_OK && !dryrun) {
26663034Sdougm 		    if (share != NULL) {
26673034Sdougm 			sa_optionset_t optionset;
26683034Sdougm 			sa_property_t prop;
26693034Sdougm 			change |= remove_options(share, optlist, protocol,
26703034Sdougm 							&ret);
26713034Sdougm 			/* if a share optionset is empty, remove it */
26723034Sdougm 			optionset = sa_get_optionset((sa_share_t)share,
26733034Sdougm 							protocol);
26743034Sdougm 			if (optionset != NULL) {
26753034Sdougm 			    prop = sa_get_property(optionset, NULL);
26763034Sdougm 			    if (prop == NULL)
26773034Sdougm 				(void) sa_destroy_optionset(optionset);
26783034Sdougm 			}
26793034Sdougm 		    } else {
26803034Sdougm 			change |= remove_options(group, optlist, protocol,
26813034Sdougm 							&ret);
26823034Sdougm 		    }
26833034Sdougm 		    if (ret == SA_OK && change)
26843034Sdougm 			worklist = add_list(worklist, group, share);
26853034Sdougm 		    if (ret != SA_OK)
26863034Sdougm 			(void) printf(gettext("Could not remove properties:"
26873034Sdougm 						"%s\n"),
26883034Sdougm 				sa_errorstr(ret));
26893034Sdougm 		}
26903034Sdougm 	    } else {
26913034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
26923034Sdougm 		ret = SA_NO_SUCH_GROUP;
26933034Sdougm 	    }
26943034Sdougm 	    free_opt(optlist);
26953034Sdougm 	}
26963034Sdougm 
26973034Sdougm 	/*
26983034Sdougm 	 * we have a group and potentially legal additions
26993034Sdougm 	 */
27003034Sdougm 	/* commit to configuration if not a dryrun */
27013034Sdougm 	if (!dryrun && ret == SA_OK) {
27023034Sdougm 	    if (change && worklist != NULL) {
27033034Sdougm 		/* properties changed, so update all shares */
27043910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
27053034Sdougm 	    }
27063034Sdougm 	}
27073034Sdougm 	if (worklist != NULL)
27083034Sdougm 	    free_list(worklist);
27093034Sdougm 	return (ret);
27103034Sdougm }
27113034Sdougm 
27123034Sdougm /*
27133034Sdougm  * space_unset(groupname, optlist, protocol, sharepath, dryrun)
27143034Sdougm  *
27153034Sdougm  * unset named optionset properties.
27163034Sdougm  */
27173034Sdougm static int
27183910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
27193910Sdougm 		char *protocol, char *sharepath, int dryrun, char *sectype)
27203034Sdougm {
27213034Sdougm 	sa_group_t group;
27223034Sdougm 	int ret = SA_OK;
27233034Sdougm 	int change = 0;
27243034Sdougm 	struct list *worklist = NULL;
27253034Sdougm 
27263910Sdougm 	group = sa_get_group(handle, groupname);
27273034Sdougm 	if (group != NULL) {
27283034Sdougm 	    sa_share_t share = NULL;
27293034Sdougm 	    if (sharepath != NULL) {
27303034Sdougm 		share = sa_get_share(group, sharepath);
27313034Sdougm 		if (share == NULL) {
27323034Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
27333034Sdougm 				groupname, sharepath);
27343034Sdougm 		    ret = SA_NO_SUCH_PATH;
27353034Sdougm 		}
27363034Sdougm 	    }
27373034Sdougm 	    if (ret == SA_OK) {
27383034Sdougm 		ret = valid_unset_security(share != NULL ? share : group,
27393034Sdougm 						optlist, protocol, sectype);
27403034Sdougm 		if (ret == SA_OK && !dryrun) {
27413034Sdougm 		    if (optlist != NULL) {
27423034Sdougm 			if (share != NULL) {
27433034Sdougm 			    sa_security_t optionset;
27443034Sdougm 			    sa_property_t prop;
27453034Sdougm 			    change = remove_security(share, sectype,
27463034Sdougm 							optlist, protocol,
27473034Sdougm 							&ret);
27483034Sdougm 			    /* if a share security is empty, remove it */
27493034Sdougm 			    optionset = sa_get_security((sa_group_t)share,
27503034Sdougm 							sectype,
27513034Sdougm 							protocol);
27523034Sdougm 			    if (optionset != NULL) {
27533034Sdougm 				prop = sa_get_property(optionset, NULL);
27543034Sdougm 				if (prop == NULL)
27553034Sdougm 				    ret = sa_destroy_security(optionset);
27563034Sdougm 			    }
27573034Sdougm 			} else {
27583034Sdougm 			    change = remove_security(group, sectype,
27593034Sdougm 							optlist, protocol,
27603034Sdougm 							&ret);
27613034Sdougm 			}
27623034Sdougm 		    } else {
27633034Sdougm 			sa_security_t security;
27643034Sdougm 			char *sec;
27653034Sdougm 			sec = sa_proto_space_alias(protocol, sectype);
27663034Sdougm 			security = sa_get_security(group, sec, protocol);
27673034Sdougm 			if (sec != NULL)
27683034Sdougm 			    sa_free_attr_string(sec);
27693034Sdougm 			if (security != NULL) {
27703034Sdougm 			    ret = sa_destroy_security(security);
27713034Sdougm 			    if (ret == SA_OK)
27723034Sdougm 				change = 1;
27733034Sdougm 			} else {
27743034Sdougm 			    ret = SA_NO_SUCH_PROP;
27753034Sdougm 			}
27763034Sdougm 		    }
27773034Sdougm 		    if (ret != SA_OK)
27783034Sdougm 			(void) printf(gettext("Could not unset property: %s\n"),
27793034Sdougm 				sa_errorstr(ret));
27803034Sdougm 		}
27813034Sdougm 
27823034Sdougm 		if (ret == SA_OK && change)
27833034Sdougm 		    worklist = add_list(worklist, group, 0);
27843034Sdougm 	    }
27853034Sdougm 	} else {
27863034Sdougm 	    (void) printf(gettext("Group \"%s\" not found\n"), groupname);
27873034Sdougm 	    ret = SA_NO_SUCH_GROUP;
27883034Sdougm 	}
27893034Sdougm 	free_opt(optlist);
27903034Sdougm 	/*
27913034Sdougm 	 * we have a group and potentially legal additions
27923034Sdougm 	 */
27933034Sdougm 
27943034Sdougm 	/* commit to configuration if not a dryrun */
27953034Sdougm 	if (!dryrun && ret == 0) {
27963034Sdougm 	    if (change && worklist != NULL) {
27973034Sdougm 		/* properties changed, so update all shares */
27983910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
27993034Sdougm 	    }
28003910Sdougm 	    ret = sa_update_config(handle);
28013034Sdougm 	}
28023034Sdougm 	if (worklist != NULL)
28033034Sdougm 	    free_list(worklist);
28043034Sdougm 	return (ret);
28053034Sdougm }
28063034Sdougm 
28073034Sdougm /*
28083034Sdougm  * sa_unset(flags, argc, argv)
28093034Sdougm  *
28103034Sdougm  * implements the unset subcommand. Parsing done here and then basic
28113034Sdougm  * or space versions of the real code are called.
28123034Sdougm  */
28133034Sdougm 
28143034Sdougm int
28153910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
28163034Sdougm {
28173034Sdougm 	char *groupname;
28183034Sdougm 	int verbose = 0;
28193034Sdougm 	int dryrun = 0;
28203034Sdougm 	int c;
28213034Sdougm 	char *protocol = NULL;
28223034Sdougm 	int ret = SA_OK;
28233034Sdougm 	struct options *optlist = NULL;
28243034Sdougm 	char *sharepath = NULL;
28253034Sdougm 	char *optset = NULL;
28263034Sdougm 	int auth;
28273034Sdougm 
28283034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
28293034Sdougm 	    switch (c) {
28303034Sdougm 	    case 'v':
28313034Sdougm 		verbose++;
28323034Sdougm 		break;
28333034Sdougm 	    case 'n':
28343034Sdougm 		dryrun++;
28353034Sdougm 		break;
28363034Sdougm 	    case 'P':
28373034Sdougm 		protocol = optarg;
28383034Sdougm 		if (!sa_valid_protocol(protocol)) {
28393034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
28403034Sdougm 					protocol);
28413034Sdougm 		    return (SA_INVALID_PROTOCOL);
28423034Sdougm 		}
28433034Sdougm 		break;
28443034Sdougm 	    case 'p':
28453034Sdougm 		ret = add_opt(&optlist, optarg, 1);
28463034Sdougm 		switch (ret) {
28473034Sdougm 		case OPT_ADD_SYNTAX:
28483034Sdougm 		    (void) printf(gettext("Property syntax error for "
28493034Sdougm 						"property %s\n"),
28503034Sdougm 					optarg);
28513034Sdougm 		    return (SA_SYNTAX_ERR);
28523034Sdougm 		case OPT_ADD_PROPERTY:
28533034Sdougm 		    (void) printf(gettext("Properties need to be set"
28543034Sdougm 						" with set command: %s\n"),
28553034Sdougm 					optarg);
28563034Sdougm 		    return (SA_SYNTAX_ERR);
28573034Sdougm 		default:
28583034Sdougm 		    break;
28593034Sdougm 		}
28603034Sdougm 		break;
28613034Sdougm 	    case 's':
28623034Sdougm 		sharepath = optarg;
28633034Sdougm 		break;
28643034Sdougm 	    case 'S':
28653034Sdougm 		optset = optarg;
28663034Sdougm 		break;
28673034Sdougm 	    default:
28683034Sdougm 	    case 'h':
28693034Sdougm 	    case '?':
28703034Sdougm 		(void) printf(gettext("usage: %s\n"),
28713034Sdougm 				sa_get_usage(USAGE_UNSET));
28723034Sdougm 		return (SA_OK);
28733034Sdougm 	    }
28743034Sdougm 	}
28753034Sdougm 
28763034Sdougm 	if (optlist != NULL)
28773034Sdougm 	    ret = chk_opt(optlist, optset != NULL, protocol);
28783034Sdougm 
28793034Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
28803034Sdougm 	    protocol == NULL) {
28813034Sdougm 	    char *sep = "\t";
28823034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET));
28833034Sdougm 	    if (optind >= argc) {
28843034Sdougm 		(void) printf(gettext("%sgroup must be specified"), sep);
28853034Sdougm 		sep = ", ";
28863034Sdougm 	    }
28873034Sdougm 	    if (optlist == NULL) {
28883034Sdougm 		(void) printf(gettext("%sat least one property must be "
28893034Sdougm 					"specified"),
28903034Sdougm 			sep);
28913034Sdougm 		sep = ", ";
28923034Sdougm 	    }
28933034Sdougm 	    if (protocol == NULL) {
28943034Sdougm 		(void) printf(gettext("%sprotocol must be specified"), sep);
28953034Sdougm 		sep = ", ";
28963034Sdougm 	    }
28973034Sdougm 	    (void) printf("\n");
28983034Sdougm 	    ret = SA_SYNTAX_ERR;
28993034Sdougm 	} else {
29003034Sdougm 
29013034Sdougm 		/*
29023034Sdougm 		 * if a group already exists, we can only add a new
29033034Sdougm 		 * protocol to it and not create a new one or add the
29043034Sdougm 		 * same protocol again.
29053034Sdougm 		 */
29063034Sdougm 
29073034Sdougm 	    groupname = argv[optind];
29083034Sdougm 	    auth = check_authorizations(groupname, flags);
29093034Sdougm 	    if (optset == NULL)
29103910Sdougm 		ret = basic_unset(handle, groupname, optlist, protocol,
29113034Sdougm 					sharepath, dryrun);
29123034Sdougm 	    else
29133910Sdougm 		ret = space_unset(handle, groupname, optlist, protocol,
29143034Sdougm 					sharepath, dryrun, optset);
29153034Sdougm 
29163034Sdougm 	    if (dryrun && ret == SA_OK && !auth && verbose) {
29173034Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
29183034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
29193034Sdougm 	    }
29203034Sdougm 	}
29213034Sdougm 	return (ret);
29223034Sdougm }
29233034Sdougm 
29243034Sdougm /*
29253034Sdougm  * sa_enable_group(flags, argc, argv)
29263034Sdougm  *
29273034Sdougm  * Implements the enable subcommand
29283034Sdougm  */
29293034Sdougm 
29303034Sdougm int
29313910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
29323034Sdougm {
29333034Sdougm 	int verbose = 0;
29343034Sdougm 	int dryrun = 0;
29353034Sdougm 	int all = 0;
29363034Sdougm 	int c;
29373034Sdougm 	int ret = SA_OK;
29383034Sdougm 	char *protocol = NULL;
29393034Sdougm 	char *state;
29403034Sdougm 	struct list *worklist = NULL;
29413034Sdougm 	int auth = 1;
29423034Sdougm 
29433034Sdougm 	while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
29443034Sdougm 	    switch (c) {
29453034Sdougm 	    case 'a':
29463034Sdougm 		all = 1;
29473034Sdougm 		break;
29483034Sdougm 	    case 'n':
29493034Sdougm 		dryrun++;
29503034Sdougm 		break;
29513034Sdougm 	    case 'P':
29523034Sdougm 		protocol = optarg;
29533034Sdougm 		if (!sa_valid_protocol(protocol)) {
29543034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
29553034Sdougm 				    protocol);
29563034Sdougm 		    return (SA_INVALID_PROTOCOL);
29573034Sdougm 		}
29583034Sdougm 		break;
29593034Sdougm 	    case 'v':
29603034Sdougm 		verbose++;
29613034Sdougm 		break;
29623034Sdougm 	    default:
29633034Sdougm 	    case 'h':
29643034Sdougm 	    case '?':
29653034Sdougm 		(void) printf(gettext("usage: %s\n"),
29663034Sdougm 				sa_get_usage(USAGE_ENABLE));
29673034Sdougm 		return (0);
29683034Sdougm 	    }
29693034Sdougm 	}
29703034Sdougm 
29713034Sdougm 	if (optind == argc && !all) {
29723034Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE));
29733034Sdougm 	    (void) printf(gettext("\tmust specify group\n"));
29743034Sdougm 	    ret = SA_NO_SUCH_PATH;
29753034Sdougm 	} else {
29763034Sdougm 	    sa_group_t group;
29773034Sdougm 	    if (!all) {
29783034Sdougm 		while (optind < argc) {
29793910Sdougm 		    group = sa_get_group(handle, argv[optind]);
29803034Sdougm 		    if (group != NULL) {
29813034Sdougm 			auth &= check_authorizations(argv[optind], flags);
29823034Sdougm 			state = sa_get_group_attr(group, "state");
29833034Sdougm 			if (state != NULL &&
29843034Sdougm 			    strcmp(state, "enabled") == 0) {
29853034Sdougm 			    /* already enabled */
29863034Sdougm 			    if (verbose)
29873034Sdougm 				(void) printf(gettext("Group \"%s\" is already "
29883034Sdougm 						"enabled\n"),
29893034Sdougm 					argv[optind]);
29903034Sdougm 			    ret = SA_BUSY; /* already enabled */
29913034Sdougm 			} else {
29923034Sdougm 			    worklist = add_list(worklist, group, 0);
29933034Sdougm 			    if (verbose)
29943034Sdougm 				(void) printf(gettext("Enabling group "
29953034Sdougm 							"\"%s\"\n"),
29963034Sdougm 					argv[optind]);
29973034Sdougm 			}
29983034Sdougm 			if (state != NULL)
29993034Sdougm 			    sa_free_attr_string(state);
30003034Sdougm 		    } else {
30013034Sdougm 			ret = SA_NO_SUCH_GROUP;
30023034Sdougm 		    }
30033034Sdougm 		    optind++;
30043034Sdougm 		}
30053034Sdougm 	    } else {
30063910Sdougm 		for (group = sa_get_group(handle, NULL); group != NULL;
30073034Sdougm 		    group = sa_get_next_group(group)) {
30083034Sdougm 		    worklist = add_list(worklist, group, 0);
30093034Sdougm 		}
30103034Sdougm 	    }
30113034Sdougm 	    if (!dryrun && ret == SA_OK) {
30123910Sdougm 		ret = enable_all_groups(handle, worklist, 1, 0, NULL);
30133034Sdougm 	    }
30143034Sdougm 	    if (ret != SA_OK && ret != SA_BUSY)
30153034Sdougm 		(void) printf(gettext("Could not enable group: %s\n"),
30163034Sdougm 			sa_errorstr(ret));
30173034Sdougm 	    if (ret == SA_BUSY)
30183034Sdougm 		ret = SA_OK;
30193034Sdougm 	}
30203034Sdougm 	if (worklist != NULL)
30213034Sdougm 	    free_list(worklist);
30223034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
30233034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
30243034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
30253034Sdougm 	}
30263034Sdougm 	return (ret);
30273034Sdougm }
30283034Sdougm 
30293034Sdougm /*
30303034Sdougm  * disable_group(group, setstate)
30313034Sdougm  *
30323034Sdougm  * disable all the shares in the specified group honoring the setstate
30333034Sdougm  * argument. This is a helper for disable_all_groups in order to
30343034Sdougm  * simplify regular and subgroup (zfs) disabling. Group has already
30353034Sdougm  * been checked for non-NULL.
30363034Sdougm  */
30373034Sdougm 
30383034Sdougm static int
30393034Sdougm disable_group(sa_group_t group)
30403034Sdougm {
30413034Sdougm 	sa_share_t share;
30423034Sdougm 	int ret = SA_OK;
30433034Sdougm 
30443034Sdougm 	for (share = sa_get_share(group, NULL);
30453034Sdougm 	    share != NULL && ret == SA_OK;
30463034Sdougm 	    share = sa_get_next_share(share)) {
30473034Sdougm 	    ret = sa_disable_share(share, NULL);
30483034Sdougm 	    if (ret == SA_NO_SUCH_PATH) {
30493034Sdougm 		/*
30503034Sdougm 		 * this is OK since the path is gone. we can't
30513034Sdougm 		 * re-share it anyway so no error.
30523034Sdougm 		 */
30533034Sdougm 		ret = SA_OK;
30543034Sdougm 	    }
30553034Sdougm 	}
30563034Sdougm 	return (ret);
30573034Sdougm }
30583034Sdougm 
30593034Sdougm 
30603034Sdougm /*
30613034Sdougm  * disable_all_groups(work, setstate)
30623034Sdougm  *
30633034Sdougm  * helper function that disables the shares in the list of groups
30643034Sdougm  * provided. It optionally marks the group as disabled. Used by both
30653034Sdougm  * enable and start subcommands.
30663034Sdougm  */
30673034Sdougm 
30683034Sdougm static int
30693910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
30703034Sdougm {
30713034Sdougm 	int ret = SA_OK;
30723034Sdougm 	sa_group_t subgroup, group;
30733034Sdougm 
30743034Sdougm 	while (work != NULL && ret == SA_OK) {
30753034Sdougm 	    group = (sa_group_t)work->item;
30763034Sdougm 	    if (setstate)
30773034Sdougm 		ret = sa_set_group_attr(group, "state", "disabled");
30783034Sdougm 	    if (ret == SA_OK) {
30793034Sdougm 		char *name;
30803034Sdougm 		name = sa_get_group_attr(group, "name");
30813034Sdougm 		if (name != NULL && strcmp(name, "zfs") == 0) {
30823034Sdougm 		    /* need to get the sub-groups for stopping */
30833034Sdougm 		    for (subgroup = sa_get_sub_group(group); subgroup != NULL;
30843034Sdougm 			subgroup = sa_get_next_group(subgroup)) {
30853034Sdougm 			ret = disable_group(subgroup);
30863034Sdougm 		    }
30873034Sdougm 		} else {
30883034Sdougm 		    ret = disable_group(group);
30893034Sdougm 		}
30903034Sdougm 		/*
30913034Sdougm 		 * we don't want to "disable" since it won't come
30923034Sdougm 		 * up after a reboot.  The SMF framework should do
30933034Sdougm 		 * the right thing. On enable we do want to do
30943034Sdougm 		 * something.
30953034Sdougm 		 */
30963034Sdougm 	    }
30973034Sdougm 	    work = work->next;
30983034Sdougm 	}
30993034Sdougm 	if (ret == SA_OK)
31003910Sdougm 	    ret = sa_update_config(handle);
31013034Sdougm 	return (ret);
31023034Sdougm }
31033034Sdougm 
31043034Sdougm /*
31053034Sdougm  * sa_disable_group(flags, argc, argv)
31063034Sdougm  *
31073034Sdougm  * Implements the disable subcommand
31083034Sdougm  */
31093034Sdougm 
31103034Sdougm int
31113910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
31123034Sdougm {
31133034Sdougm 	int verbose = 0;
31143034Sdougm 	int dryrun = 0;
31153034Sdougm 	int all = 0;
31163034Sdougm 	int c;
31173034Sdougm 	int ret = SA_OK;
31183034Sdougm 	char *protocol;
31193034Sdougm 	char *state;
31203034Sdougm 	struct list *worklist = NULL;
31213034Sdougm 	int auth = 1;
31223034Sdougm 
31233034Sdougm 	while ((c = getopt(argc, argv, "?havn")) != EOF) {
31243034Sdougm 	    switch (c) {
31253034Sdougm 	    case 'a':
31263034Sdougm 		all = 1;
31273034Sdougm 		break;
31283034Sdougm 	    case 'n':
31293034Sdougm 		dryrun++;
31303034Sdougm 		break;
31313034Sdougm 	    case 'P':
31323034Sdougm 		protocol = optarg;
31333034Sdougm 		if (!sa_valid_protocol(protocol)) {
31343034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
31353034Sdougm 					protocol);
31363034Sdougm 		    return (SA_INVALID_PROTOCOL);
31373034Sdougm 		}
31383034Sdougm 		break;
31393034Sdougm 	    case 'v':
31403034Sdougm 		verbose++;
31413034Sdougm 		break;
31423034Sdougm 	    default:
31433034Sdougm 	    case 'h':
31443034Sdougm 	    case '?':
31453034Sdougm 		(void) printf(gettext("usage: %s\n"),
31463034Sdougm 				sa_get_usage(USAGE_DISABLE));
31473034Sdougm 		return (0);
31483034Sdougm 	    }
31493034Sdougm 	}
31503034Sdougm 
31513034Sdougm 	if (optind == argc && !all) {
31523034Sdougm 		(void) printf(gettext("usage: %s\n"),
31533034Sdougm 				sa_get_usage(USAGE_DISABLE));
31543034Sdougm 		(void) printf(gettext("\tmust specify group\n"));
31553034Sdougm 		ret = SA_NO_SUCH_PATH;
31563034Sdougm 	} else {
31573034Sdougm 		sa_group_t group;
31583034Sdougm 		if (!all) {
31593034Sdougm 		    while (optind < argc) {
31603910Sdougm 			group = sa_get_group(handle, argv[optind]);
31613034Sdougm 			if (group != NULL) {
31623034Sdougm 			    auth &= check_authorizations(argv[optind], flags);
31633034Sdougm 			    state = sa_get_group_attr(group, "state");
31643034Sdougm 			    if (state == NULL ||
31653034Sdougm 				strcmp(state, "disabled") == 0) {
31663034Sdougm 				/* already disabled */
31673034Sdougm 				if (verbose)
31683034Sdougm 				    (void) printf(gettext("Group \"%s\" is "
31693034Sdougm 							"already disabled\n"),
31703034Sdougm 					    argv[optind]);
31713034Sdougm 				ret = SA_BUSY; /* already disable */
31723034Sdougm 			    } else {
31733034Sdougm 				worklist = add_list(worklist, group, 0);
31743034Sdougm 				if (verbose)
31753034Sdougm 				    (void) printf(gettext("Disabling group "
31763034Sdougm 							    "\"%s\"\n"),
31773034Sdougm 					    argv[optind]);
31783034Sdougm 			    }
31793034Sdougm 			    if (state != NULL)
31803034Sdougm 				sa_free_attr_string(state);
31813034Sdougm 			} else {
31823034Sdougm 			    ret = SA_NO_SUCH_GROUP;
31833034Sdougm 			}
31843034Sdougm 			optind++;
31853034Sdougm 		    }
31863034Sdougm 		} else {
31873910Sdougm 		    for (group = sa_get_group(handle, NULL); group != NULL;
31883034Sdougm 			    group = sa_get_next_group(group)) {
31893034Sdougm 			worklist = add_list(worklist, group, 0);
31903034Sdougm 		    }
31913034Sdougm 		}
31923034Sdougm 		if (ret == SA_OK && !dryrun) {
31933910Sdougm 			ret = disable_all_groups(handle, worklist, 1);
31943034Sdougm 		}
31953034Sdougm 		if (ret != SA_OK && ret != SA_BUSY)
31963034Sdougm 		    (void) printf(gettext("Could not disable group: %s\n"),
31973034Sdougm 				sa_errorstr(ret));
31983034Sdougm 		if (ret == SA_BUSY)
31993034Sdougm 		    ret = SA_OK;
32003034Sdougm 	}
32013034Sdougm 	if (worklist != NULL)
32023034Sdougm 	    free_list(worklist);
32033034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
32043034Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
32053034Sdougm 			sa_errorstr(SA_NO_PERMISSION));
32063034Sdougm 	}
32073034Sdougm 	return (ret);
32083034Sdougm }
32093034Sdougm 
32103034Sdougm /*
32113034Sdougm  * sa_start_group(flags, argc, argv)
32123034Sdougm  *
32133034Sdougm  * Implements the start command.
32143034Sdougm  * This is similar to enable except it doesn't change the state
32153034Sdougm  * of the group(s) and only enables shares if the group is already
32163034Sdougm  * enabled.
32173034Sdougm  */
32183034Sdougm 
32193034Sdougm int
32203910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
32213034Sdougm {
32223034Sdougm 	int verbose = 0;
32233034Sdougm 	int all = 0;
32243034Sdougm 	int c;
32253034Sdougm 	int ret = SMF_EXIT_OK;
32263034Sdougm 	char *protocol = NULL;
32273034Sdougm 	char *state;
32283034Sdougm 	struct list *worklist = NULL;
32293034Sdougm #ifdef lint
32303034Sdougm 	flags = flags;
32313034Sdougm #endif
32323034Sdougm 
32333034Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
32343034Sdougm 	    switch (c) {
32353034Sdougm 	    case 'a':
32363034Sdougm 		all = 1;
32373034Sdougm 		break;
32383034Sdougm 	    case 'P':
32393034Sdougm 		protocol = optarg;
32403034Sdougm 		if (!sa_valid_protocol(protocol)) {
32413034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
32423034Sdougm 				    protocol);
32433034Sdougm 		    return (SA_INVALID_PROTOCOL);
32443034Sdougm 		}
32453034Sdougm 		break;
32463034Sdougm 	    case 'v':
32473034Sdougm 		verbose++;
32483034Sdougm 		break;
32493034Sdougm 	    default:
32503034Sdougm 	    case 'h':
32513034Sdougm 	    case '?':
32523034Sdougm 		(void) printf(gettext("usage: %s\n"),
32533034Sdougm 				sa_get_usage(USAGE_START));
32543034Sdougm 		return (SA_OK);
32553034Sdougm 	    }
32563034Sdougm 	}
32573034Sdougm 
32583034Sdougm 	if (optind == argc && !all) {
32593034Sdougm 		(void) printf(gettext("usage: %s\n"),
32603034Sdougm 				sa_get_usage(USAGE_START));
32613034Sdougm 		ret = SMF_EXIT_ERR_FATAL;
32623034Sdougm 	} else {
32633034Sdougm 		sa_group_t group;
32643034Sdougm 
32653034Sdougm 		if (!all) {
32663034Sdougm 		    while (optind < argc) {
32673910Sdougm 			group = sa_get_group(handle, argv[optind]);
32683034Sdougm 			if (group != NULL) {
32693034Sdougm 			    state = sa_get_group_attr(group, "state");
32703034Sdougm 			    if (state == NULL ||
32713034Sdougm 				strcmp(state, "enabled") == 0) {
32723034Sdougm 				worklist = add_list(worklist, group, 0);
32733034Sdougm 				if (verbose)
32743034Sdougm 				    (void) printf(gettext("Starting group "
32753034Sdougm 								"\"%s\"\n"),
32763034Sdougm 					    argv[optind]);
32773034Sdougm 			    } else {
32783034Sdougm 				/*
32793034Sdougm 				 * determine if there are any
32803034Sdougm 				 * protocols.  if there aren't any,
32813034Sdougm 				 * then there isn't anything to do in
32823034Sdougm 				 * any case so no error.
32833034Sdougm 				 */
32843034Sdougm 				if (sa_get_optionset(group, protocol) != NULL) {
32853034Sdougm 				    ret = SMF_EXIT_OK;
32863034Sdougm 				}
32873034Sdougm 			    }
32883034Sdougm 			    if (state != NULL)
32893034Sdougm 				sa_free_attr_string(state);
32903034Sdougm 			}
32913034Sdougm 			optind++;
32923034Sdougm 		    }
32933034Sdougm 		} else {
32943910Sdougm 		    for (group = sa_get_group(handle, NULL); group != NULL;
32953034Sdougm 			    group = sa_get_next_group(group)) {
32963034Sdougm 			state = sa_get_group_attr(group, "state");
32973034Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
32983034Sdougm 			    worklist = add_list(worklist, group, 0);
32993034Sdougm 			if (state != NULL)
33003034Sdougm 			    sa_free_attr_string(state);
33013034Sdougm 		    }
33023034Sdougm 		}
33033910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 1, NULL);
33043034Sdougm 	}
33053034Sdougm 	if (worklist != NULL)
33063034Sdougm 	    free_list(worklist);
33073034Sdougm 	return (ret);
33083034Sdougm }
33093034Sdougm 
33103034Sdougm /*
33113034Sdougm  * sa_stop_group(flags, argc, argv)
33123034Sdougm  *
33133034Sdougm  * Implements the stop command.
33143034Sdougm  * This is similar to disable except it doesn't change the state
33153034Sdougm  * of the group(s) and only disables shares if the group is already
33163034Sdougm  * enabled.
33173034Sdougm  */
33183034Sdougm 
33193034Sdougm int
33203910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
33213034Sdougm {
33223034Sdougm 	int verbose = 0;
33233034Sdougm 	int all = 0;
33243034Sdougm 	int c;
33253034Sdougm 	int ret = SMF_EXIT_OK;
33263034Sdougm 	char *protocol = NULL;
33273034Sdougm 	char *state;
33283034Sdougm 	struct list *worklist = NULL;
33293034Sdougm #ifdef lint
33303034Sdougm 	flags = flags;
33313034Sdougm #endif
33323034Sdougm 
33333034Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
33343034Sdougm 	    switch (c) {
33353034Sdougm 	    case 'a':
33363034Sdougm 		all = 1;
33373034Sdougm 		break;
33383034Sdougm 	    case 'P':
33393034Sdougm 		protocol = optarg;
33403034Sdougm 		if (!sa_valid_protocol(protocol)) {
33413034Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
33423034Sdougm 					protocol);
33433034Sdougm 		    return (SA_INVALID_PROTOCOL);
33443034Sdougm 		}
33453034Sdougm 		break;
33463034Sdougm 	    case 'v':
33473034Sdougm 		verbose++;
33483034Sdougm 		break;
33493034Sdougm 	    default:
33503034Sdougm 	    case 'h':
33513034Sdougm 	    case '?':
33523034Sdougm 		(void) printf(gettext("usage: %s\n"),
33533034Sdougm 				sa_get_usage(USAGE_STOP));
33543034Sdougm 		return (0);
33553034Sdougm 	    }
33563034Sdougm 	}
33573034Sdougm 
33583034Sdougm 	if (optind == argc && !all) {
33593034Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP));
33603034Sdougm 		ret = SMF_EXIT_ERR_FATAL;
33613034Sdougm 	} else {
33623034Sdougm 		sa_group_t group;
33633034Sdougm 		if (!all) {
33643034Sdougm 		    while (optind < argc) {
33653910Sdougm 			group = sa_get_group(handle, argv[optind]);
33663034Sdougm 			if (group != NULL) {
33673034Sdougm 			    state = sa_get_group_attr(group, "state");
33683034Sdougm 			    if (state == NULL ||
33693034Sdougm 				strcmp(state, "enabled") == 0) {
33703034Sdougm 				worklist = add_list(worklist, group, 0);
33713034Sdougm 				if (verbose)
33723034Sdougm 				    (void) printf(gettext("Stopping group "
33733034Sdougm 								"\"%s\"\n"),
33743034Sdougm 					    argv[optind]);
33753034Sdougm 			    } else {
33763034Sdougm 				ret = SMF_EXIT_OK;
33773034Sdougm 			    }
33783034Sdougm 			    if (state != NULL)
33793034Sdougm 				sa_free_attr_string(state);
33803034Sdougm 			}
33813034Sdougm 			optind++;
33823034Sdougm 		    }
33833034Sdougm 		} else {
33843910Sdougm 		    for (group = sa_get_group(handle, NULL); group != NULL;
33853034Sdougm 			    group = sa_get_next_group(group)) {
33863034Sdougm 			state = sa_get_group_attr(group, "state");
33873034Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
33883034Sdougm 			    worklist = add_list(worklist, group, 0);
33893034Sdougm 			if (state != NULL)
33903034Sdougm 			    sa_free_attr_string(state);
33913034Sdougm 		    }
33923034Sdougm 		}
33933910Sdougm 		(void) disable_all_groups(handle, worklist, 0);
33943910Sdougm 		ret = sa_update_config(handle);
33953034Sdougm 	}
33963034Sdougm 	if (worklist != NULL)
33973034Sdougm 	    free_list(worklist);
33983034Sdougm 	return (ret);
33993034Sdougm }
34003034Sdougm 
34013034Sdougm /*
34023034Sdougm  * remove_all_options(share, proto)
34033034Sdougm  *
34043034Sdougm  * Removes all options on a share.
34053034Sdougm  */
34063034Sdougm 
34073034Sdougm static void
34083034Sdougm remove_all_options(sa_share_t share, char *proto)
34093034Sdougm {
34103034Sdougm 	sa_optionset_t optionset;
34113034Sdougm 	sa_security_t security;
34123034Sdougm 	sa_security_t prevsec = NULL;
34133034Sdougm 
34143034Sdougm 	optionset = sa_get_optionset(share, proto);
34153034Sdougm 	if (optionset != NULL)
34163034Sdougm 	    (void) sa_destroy_optionset(optionset);
34173034Sdougm 	for (security = sa_get_security(share, NULL, NULL);
34183034Sdougm 	    security != NULL;
34193034Sdougm 	    security = sa_get_next_security(security)) {
34203034Sdougm 	    char *type;
34213034Sdougm 		/*
34223034Sdougm 		 * we walk through the list.  prevsec keeps the
34233034Sdougm 		 * previous security so we can delete it without
34243034Sdougm 		 * destroying the list.
34253034Sdougm 		 */
34263034Sdougm 	    if (prevsec != NULL) {
34273034Sdougm 		/* remove the previously seen security */
34283034Sdougm 		(void) sa_destroy_security(prevsec);
34293034Sdougm 		/* set to NULL so we don't try multiple times */
34303034Sdougm 		prevsec = NULL;
34313034Sdougm 	    }
34323034Sdougm 	    type = sa_get_security_attr(security, "type");
34333034Sdougm 	    if (type != NULL) {
34343034Sdougm 		/*
34353034Sdougm 		 * if the security matches the specified protocol, we
34363034Sdougm 		 * want to remove it. prevsec holds it until either
34373034Sdougm 		 * the next pass or we fall out of the loop.
34383034Sdougm 		 */
34393034Sdougm 		if (strcmp(type, proto) == 0)
34403034Sdougm 		    prevsec = security;
34413034Sdougm 		sa_free_attr_string(type);
34423034Sdougm 	    }
34433034Sdougm 	}
34443034Sdougm 	/* in case there is one left */
34453034Sdougm 	if (prevsec != NULL)
34463034Sdougm 	    (void) sa_destroy_security(prevsec);
34473034Sdougm }
34483034Sdougm 
34493034Sdougm 
34503034Sdougm /*
34513034Sdougm  * for legacy support, we need to handle the old syntax. This is what
34523034Sdougm  * we get if sharemgr is called with the name "share" rather than
34533034Sdougm  * sharemgr.
34543034Sdougm  */
34553034Sdougm 
34563034Sdougm static int
34573034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
34583034Sdougm {
34593034Sdougm 	int err;
34603034Sdougm 
34613034Sdougm 	err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
34623034Sdougm 	if (err > buffsize)
34633034Sdougm 	    return (-1);
34643034Sdougm 	return (0);
34653034Sdougm }
34663034Sdougm 
34673034Sdougm 
34683034Sdougm /*
34693034Sdougm  * check_legacy_cmd(proto, cmd)
34703034Sdougm  *
34713034Sdougm  * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
34723034Sdougm  * executable.
34733034Sdougm  */
34743034Sdougm 
34753034Sdougm static int
34763034Sdougm check_legacy_cmd(char *path)
34773034Sdougm {
34783034Sdougm 	struct stat st;
34793034Sdougm 	int ret = 0;
34803034Sdougm 
34813034Sdougm 	if (stat(path, &st) == 0) {
34823034Sdougm 	    if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
34833034Sdougm 		ret = 1;
34843034Sdougm 	}
34853034Sdougm 	return (ret);
34863034Sdougm }
34873034Sdougm 
34883034Sdougm /*
34893034Sdougm  * run_legacy_command(proto, cmd, argv)
34903034Sdougm  *
34913034Sdougm  * we know the command exists, so attempt to execute it with all the
34923034Sdougm  * arguments. This implements full legacy share support for those
34933034Sdougm  * protocols that don't have plugin providers.
34943034Sdougm  */
34953034Sdougm 
34963034Sdougm static int
34973034Sdougm run_legacy_command(char *path, char *argv[])
34983034Sdougm {
34993034Sdougm 	int ret;
35003034Sdougm 
35013034Sdougm 	ret = execv(path, argv);
35023034Sdougm 	if (ret < 0) {
35033034Sdougm 	    switch (errno) {
35043034Sdougm 	    case EACCES:
35053034Sdougm 		ret = SA_NO_PERMISSION;
35063034Sdougm 		break;
35073034Sdougm 	    default:
35083034Sdougm 		ret = SA_SYSTEM_ERR;
35093034Sdougm 		break;
35103034Sdougm 	    }
35113034Sdougm 	}
35123034Sdougm 	return (ret);
35133034Sdougm }
35143034Sdougm 
35153034Sdougm /*
35163348Sdougm  * out_share(out, group, proto)
35173034Sdougm  *
35183034Sdougm  * Display the share information in the format that the "share"
35193034Sdougm  * command has traditionally used.
35203034Sdougm  */
35213034Sdougm 
35223034Sdougm static void
35233348Sdougm out_share(FILE *out, sa_group_t group, char *proto)
35243034Sdougm {
35253034Sdougm 	sa_share_t share;
35263034Sdougm 	char resfmt[128];
35273034Sdougm 
35283034Sdougm 	for (share = sa_get_share(group, NULL); share != NULL;
35293034Sdougm 		share = sa_get_next_share(share)) {
35303034Sdougm 	    char *path;
35313034Sdougm 	    char *type;
35323034Sdougm 	    char *resource;
35333034Sdougm 	    char *description;
35343034Sdougm 	    char *groupname;
35353034Sdougm 	    char *sharedstate;
35363034Sdougm 	    int shared = 1;
35373034Sdougm 	    char *soptions;
35383034Sdougm 
35393034Sdougm 	    sharedstate = sa_get_share_attr(share, "shared");
35403034Sdougm 	    path = sa_get_share_attr(share, "path");
35413034Sdougm 	    type = sa_get_share_attr(share, "type");
35423034Sdougm 	    resource = sa_get_share_attr(share, "resource");
35433034Sdougm 	    groupname = sa_get_group_attr(group, "name");
35443034Sdougm 
35453034Sdougm 	    if (groupname != NULL && strcmp(groupname, "default") == 0) {
35463034Sdougm 		sa_free_attr_string(groupname);
35473034Sdougm 		groupname = NULL;
35483034Sdougm 	    }
35493034Sdougm 	    description = sa_get_share_description(share);
35503348Sdougm 
35513348Sdougm 	    /* want the sharetab version if it exists */
35523348Sdougm 	    soptions = sa_get_share_attr(share, "shareopts");
35533034Sdougm 
35543034Sdougm 	    if (sharedstate == NULL)
35553034Sdougm 		shared = 0;
35563034Sdougm 
35573348Sdougm 	    if (soptions == NULL)
35583348Sdougm 		soptions = sa_proto_legacy_format(proto, share, 1);
35593034Sdougm 
35603034Sdougm 	    if (shared) {
35613348Sdougm 		/* only active shares go here */
35623034Sdougm 		(void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
35633034Sdougm 			resource != NULL ? resource : "-",
35643034Sdougm 			groupname != NULL ? "@" : "",
35653034Sdougm 			groupname != NULL ? groupname : "");
35663034Sdougm 		(void) fprintf(out, "%-14.14s  %s   %s   \"%s\"  \n",
35673034Sdougm 			resfmt,
35683034Sdougm 			path,
35693034Sdougm 			(soptions != NULL && strlen(soptions) > 0) ?
35703034Sdougm 					soptions : "rw",
35713034Sdougm 			(description != NULL) ? description : "");
35723034Sdougm 	    }
35733034Sdougm 
35743034Sdougm 	    if (path != NULL)
35753034Sdougm 		sa_free_attr_string(path);
35763034Sdougm 	    if (type != NULL)
35773034Sdougm 		sa_free_attr_string(type);
35783034Sdougm 	    if (resource != NULL)
35793034Sdougm 		sa_free_attr_string(resource);
35803034Sdougm 	    if (groupname != NULL)
35813034Sdougm 		sa_free_attr_string(groupname);
35823034Sdougm 	    if (description != NULL)
35833034Sdougm 		sa_free_share_description(description);
35843034Sdougm 	    if (sharedstate != NULL)
35853034Sdougm 		sa_free_attr_string(sharedstate);
35863348Sdougm 	    if (soptions != NULL)
35873034Sdougm 		sa_format_free(soptions);
35883034Sdougm 	}
35893034Sdougm }
35903034Sdougm 
35913034Sdougm /*
35923034Sdougm  * output_legacy_file(out, proto)
35933034Sdougm  *
35943034Sdougm  * Walk all of the groups for the specified protocol and call
35953034Sdougm  * out_share() to format and write in the format displayed by the
35963034Sdougm  * "share" command with no arguments.
35973034Sdougm  */
35983034Sdougm 
35993034Sdougm static void
36003910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
36013034Sdougm {
36023034Sdougm 	sa_group_t group;
36033034Sdougm 
36043910Sdougm 	for (group = sa_get_group(handle, NULL); group != NULL;
36053034Sdougm 		group = sa_get_next_group(group)) {
36063034Sdougm 	    char *options;
36073034Sdougm 	    char *zfs;
36083034Sdougm 
36093034Sdougm 		/*
36103034Sdougm 		 * get default options preformated, being careful to
36113034Sdougm 		 * handle legacy shares differently from new style
36123034Sdougm 		 * shares. Legacy share have options on the share.
36133034Sdougm 		 */
36143034Sdougm 
36153034Sdougm 	    zfs = sa_get_group_attr(group, "zfs");
36163034Sdougm 	    if (zfs != NULL) {
36173034Sdougm 		sa_group_t zgroup;
36183034Sdougm 		sa_free_attr_string(zfs);
36193034Sdougm 		options = sa_proto_legacy_format(proto, group, 1);
36203034Sdougm 		for (zgroup = sa_get_sub_group(group); zgroup != NULL;
36213034Sdougm 		    zgroup = sa_get_next_group(zgroup)) {
36223034Sdougm 
36233034Sdougm 		    /* got a group, so display it */
36243348Sdougm 		    out_share(out, zgroup, proto);
36253034Sdougm 		}
36263034Sdougm 	    } else {
36273034Sdougm 		options = sa_proto_legacy_format(proto, group, 1);
36283348Sdougm 		out_share(out, group, proto);
36293034Sdougm 	    }
36303034Sdougm 	    if (options != NULL)
36313034Sdougm 		free(options);
36323034Sdougm 	}
36333034Sdougm }
36343034Sdougm 
36353034Sdougm int
36363910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
36373034Sdougm {
36383034Sdougm 	char *protocol = "nfs";
36393034Sdougm 	char *options = NULL;
36403034Sdougm 	char *description = NULL;
36413034Sdougm 	char *groupname = NULL;
36423034Sdougm 	char *sharepath = NULL;
36433034Sdougm 	char *resource = NULL;
36443034Sdougm 	char *groupstatus = NULL;
36453034Sdougm 	int persist = SA_SHARE_TRANSIENT;
36463034Sdougm 	int argsused = 0;
36473034Sdougm 	int c;
36483034Sdougm 	int ret = SA_OK;
36493034Sdougm 	int zfs = 0;
36503034Sdougm 	int true_legacy = 0;
36513034Sdougm 	int curtype = SA_SHARE_TRANSIENT;
36523034Sdougm 	char cmd[MAXPATHLEN];
36533034Sdougm #ifdef lint
36543034Sdougm 	flags = flags;
36553034Sdougm #endif
36563034Sdougm 
36573034Sdougm 	while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
36583034Sdougm 	    switch (c) {
36593034Sdougm 	    case 'd':
36603034Sdougm 		description = optarg;
36613034Sdougm 		argsused++;
36623034Sdougm 		break;
36633034Sdougm 	    case 'F':
36643034Sdougm 		protocol = optarg;
36653034Sdougm 		if (!sa_valid_protocol(protocol)) {
36663034Sdougm 		    if (format_legacy_path(cmd, MAXPATHLEN,
36673034Sdougm 			    protocol, "share") == 0 && check_legacy_cmd(cmd)) {
36683034Sdougm 			true_legacy++;
36693034Sdougm 		    } else {
36703034Sdougm 			(void) fprintf(stderr,
36713034Sdougm 					gettext("Invalid protocol specified:"
36723034Sdougm 						"%s\n"),
36733034Sdougm 				protocol);
36743034Sdougm 			return (SA_INVALID_PROTOCOL);
36753034Sdougm 		    }
36763034Sdougm 		}
36773034Sdougm 		break;
36783034Sdougm 	    case 'o':
36793034Sdougm 		options = optarg;
36803034Sdougm 		argsused++;
36813034Sdougm 		break;
36823034Sdougm 	    case 'p':
36833034Sdougm 		persist = SA_SHARE_PERMANENT;
36843034Sdougm 		argsused++;
36853034Sdougm 		break;
36863034Sdougm 	    case 'h':
36873034Sdougm 	    case '?':
36883034Sdougm 	    default:
36893034Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
36903034Sdougm 						sa_get_usage(USAGE_SHARE));
36913034Sdougm 		return (SA_OK);
36923034Sdougm 	    }
36933034Sdougm 	}
36943034Sdougm 
36953034Sdougm 	/* have the info so construct what is needed */
36963034Sdougm 	if (!argsused && optind == argc) {
36973034Sdougm 	    /* display current info in share format */
36983910Sdougm 	    (void) output_legacy_file(stdout, "nfs", handle);
36993034Sdougm 	} else {
37003034Sdougm 	    sa_group_t group = NULL;
37013034Sdougm 	    sa_share_t share;
37023034Sdougm 	    char dir[MAXPATHLEN];
37033034Sdougm 
37043034Sdougm 	    /* we are modifying the configuration */
37053034Sdougm 	    if (optind == argc) {
37063034Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
37073034Sdougm 				sa_get_usage(USAGE_SHARE));
37083034Sdougm 		return (SA_LEGACY_ERR);
37093034Sdougm 	    }
37103034Sdougm 
37113034Sdougm 	    if (true_legacy) {
37123034Sdougm 		/* if still using legacy share/unshare, exec it */
37133034Sdougm 		ret = run_legacy_command(cmd, argv);
37143034Sdougm 		return (ret);
37153034Sdougm 	    }
37163034Sdougm 
37173034Sdougm 	    sharepath = argv[optind++];
37183034Sdougm 	    if (optind < argc) {
37193034Sdougm 		resource = argv[optind];
37203034Sdougm 		groupname = strchr(resource, '@');
37213034Sdougm 		if (groupname != NULL)
37223034Sdougm 		    *groupname++ = '\0';
37233034Sdougm 	    }
37243034Sdougm 	    if (realpath(sharepath, dir) == NULL)
37253034Sdougm 		ret = SA_BAD_PATH;
37263034Sdougm 	    else
37273034Sdougm 		sharepath = dir;
37283034Sdougm 	    if (ret == SA_OK) {
37293910Sdougm 		share = sa_find_share(handle, sharepath);
37303034Sdougm 	    } else {
37313034Sdougm 		share = NULL;
37323034Sdougm 	    }
37333034Sdougm 	    if (groupname != NULL) {
37343034Sdougm 		    ret = SA_NOT_ALLOWED;
37353034Sdougm 	    } else if (ret == SA_OK) {
37363034Sdougm 		char *legacygroup = "default";
37373034Sdougm 		/*
37383034Sdougm 		 * the legacy group is always present and zfs groups
37393034Sdougm 		 * come and go.  zfs shares may be in sub-groups and
37403034Sdougm 		 * the zfs share will already be in that group so it
37413034Sdougm 		 * isn't an error.
37423034Sdougm 		 */
37433034Sdougm 		if (share != NULL) {
37443034Sdougm 		/*
37453034Sdougm 		 * if the share exists, then make sure it is one we
37463034Sdougm 		 * want to handle.
37473034Sdougm 		 */
37483034Sdougm 		    group = sa_get_parent_group(share);
37493034Sdougm 		} else {
37503910Sdougm 		    group = sa_get_group(handle, legacygroup);
37513034Sdougm 		}
37523034Sdougm 		if (group != NULL) {
37533034Sdougm 		    groupstatus = group_status(group);
37543034Sdougm 		    if (share == NULL) {
37553034Sdougm 			share = sa_add_share(group, sharepath, persist, &ret);
37563034Sdougm 			if (share == NULL && ret == SA_DUPLICATE_NAME) {
37573034Sdougm 			    /* could be a ZFS path being started */
37583910Sdougm 			    if (sa_zfs_is_shared(handle, sharepath)) {
37593034Sdougm 				ret = SA_OK;
37603910Sdougm 				group = sa_get_group(handle, "zfs");
37613034Sdougm 				if (group == NULL) {
37623034Sdougm 				    /* this shouldn't happen */
37633034Sdougm 				    ret = SA_CONFIG_ERR;
37643034Sdougm 				}
37653034Sdougm 				if (group != NULL) {
37663034Sdougm 				    share = sa_add_share(group, sharepath,
37673034Sdougm 							    persist, &ret);
37683034Sdougm 				}
37693034Sdougm 			    }
37703034Sdougm 			}
37713034Sdougm 		    } else {
37723108Sdougm 			char *type;
37733034Sdougm 			/*
37743034Sdougm 			 * may want to change persist state, but the
37753108Sdougm 			 * important thing is to change options. We
37763108Sdougm 			 * need to change them regardless of the
37773108Sdougm 			 * source.
37783034Sdougm 			 */
37793910Sdougm 			if (sa_zfs_is_shared(handle, sharepath)) {
37803108Sdougm 			    zfs = 1;
37813108Sdougm 			}
37823108Sdougm 			remove_all_options(share, protocol);
37833108Sdougm 			type = sa_get_share_attr(share, "type");
37843108Sdougm 			if (type != NULL &&
37853108Sdougm 			    strcmp(type, "transient") != 0) {
37863108Sdougm 			    curtype = SA_SHARE_PERMANENT;
37873108Sdougm 			}
37883108Sdougm 			if (type != NULL)
37893108Sdougm 			    sa_free_attr_string(type);
37903108Sdougm 			if (curtype != persist) {
37913108Sdougm 			    (void) sa_set_share_attr(share, "type",
37923034Sdougm 					persist == SA_SHARE_PERMANENT ?
37933034Sdougm 						"persist" : "transient");
37943034Sdougm 			}
37953034Sdougm 		    }
37963108Sdougm 		    /* have a group to hold this share path */
37973108Sdougm 		    if (ret == SA_OK && options != NULL &&
37983108Sdougm 			strlen(options) > 0) {
37993108Sdougm 			ret = sa_parse_legacy_options(share,
38003108Sdougm 							options,
38013108Sdougm 							protocol);
38023108Sdougm 		    }
38033034Sdougm 		    if (!zfs) {
38043108Sdougm 			/*
38053108Sdougm 			 * zfs shares never have resource or
38063108Sdougm 			 * description and we can't store the values
38073108Sdougm 			 * so don't try.
38083108Sdougm 			 */
38093034Sdougm 			if (ret == SA_OK && description != NULL)
38103034Sdougm 			    ret = sa_set_share_description(share, description);
38113034Sdougm 			if (ret == SA_OK && resource != NULL)
38123034Sdougm 			    ret = sa_set_share_attr(share, "resource",
38133034Sdougm 						    resource);
38143034Sdougm 		    }
38153034Sdougm 		    if (ret == SA_OK) {
38163034Sdougm 			if (strcmp(groupstatus, "enabled") == 0)
38173034Sdougm 			    ret = sa_enable_share(share, protocol);
38183034Sdougm 			if (ret == SA_OK && persist == SA_SHARE_PERMANENT) {
38193034Sdougm 			    (void) sa_update_legacy(share, protocol);
38203034Sdougm 			}
38213034Sdougm 			if (ret == SA_OK)
38223910Sdougm 			    ret = sa_update_config(handle);
38233034Sdougm 		    }
38243034Sdougm 		} else {
38253034Sdougm 		    ret = SA_SYSTEM_ERR;
38263034Sdougm 		}
38273034Sdougm 	    }
38283034Sdougm 	}
38293034Sdougm 	if (ret != SA_OK) {
38303034Sdougm 	    (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
38313034Sdougm 				sharepath, sa_errorstr(ret));
38323034Sdougm 	    ret = SA_LEGACY_ERR;
38333034Sdougm 
38343034Sdougm 	}
38353034Sdougm 	return (ret);
38363034Sdougm }
38373034Sdougm 
38383034Sdougm /*
38393034Sdougm  * sa_legacy_unshare(flags, argc, argv)
38403034Sdougm  *
38413034Sdougm  * Implements the original unshare command.
38423034Sdougm  */
38433034Sdougm 
38443034Sdougm int
38453910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
38463034Sdougm {
38473034Sdougm 	char *protocol = "nfs"; /* for now */
38483034Sdougm 	char *options = NULL;
38493034Sdougm 	char *sharepath = NULL;
38503034Sdougm 	int persist = SA_SHARE_TRANSIENT;
38513034Sdougm 	int argsused = 0;
38523034Sdougm 	int c;
38533034Sdougm 	int ret = SA_OK;
38543034Sdougm 	int true_legacy = 0;
38553034Sdougm 	char cmd[MAXPATHLEN];
38563034Sdougm #ifdef lint
38573034Sdougm 	flags = flags;
38583034Sdougm 	options = options;
38593034Sdougm #endif
38603034Sdougm 
38613034Sdougm 	while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
38623034Sdougm 	    switch (c) {
38633034Sdougm 	    case 'h':
38643034Sdougm 	    case '?':
38653034Sdougm 		break;
38663034Sdougm 	    case 'F':
38673034Sdougm 		protocol = optarg;
38683034Sdougm 		if (!sa_valid_protocol(protocol)) {
38693034Sdougm 		    if (format_legacy_path(cmd, MAXPATHLEN,
38703034Sdougm 						protocol, "unshare") == 0 &&
38713034Sdougm 			check_legacy_cmd(cmd)) {
38723034Sdougm 			true_legacy++;
38733034Sdougm 		    } else {
38743034Sdougm 			(void) printf(gettext("Invalid file system name\n"));
38753034Sdougm 			return (SA_INVALID_PROTOCOL);
38763034Sdougm 		    }
38773034Sdougm 		}
38783034Sdougm 		break;
38793034Sdougm 	    case 'o':
38803034Sdougm 		options = optarg;
38813034Sdougm 		argsused++;
38823034Sdougm 		break;
38833034Sdougm 	    case 'p':
38843034Sdougm 		persist = SA_SHARE_PERMANENT;
38853034Sdougm 		argsused++;
38863034Sdougm 		break;
38873034Sdougm 	    default:
38883034Sdougm 		(void) printf(gettext("usage: %s\n"),
38893034Sdougm 				sa_get_usage(USAGE_UNSHARE));
38903034Sdougm 		return (SA_OK);
38913034Sdougm 	    }
38923034Sdougm 	}
38933034Sdougm 
38943034Sdougm 	/* have the info so construct what is needed */
38953034Sdougm 	if (optind == argc || (optind + 1) < argc) {
38963034Sdougm 	    ret = SA_SYNTAX_ERR;
38973034Sdougm 	} else {
38983034Sdougm 	    sa_share_t share;
38993034Sdougm 	    char dir[MAXPATHLEN];
39003034Sdougm 	    if (true_legacy) {
39013034Sdougm 		/* if still using legacy share/unshare, exec it */
39023034Sdougm 		ret = run_legacy_command(cmd, argv);
39033034Sdougm 		return (ret);
39043034Sdougm 	    }
39053663Sdougm 		/*
39063663Sdougm 		 * Find the path in the internal configuration. If it
39073663Sdougm 		 * isn't found, attempt to resolve the path via
39083663Sdougm 		 * realpath() and try again.
39093663Sdougm 		 */
39103034Sdougm 	    sharepath = argv[optind++];
39113910Sdougm 	    share = sa_find_share(handle, sharepath);
39123663Sdougm 	    if (share == NULL) {
39133663Sdougm 		if (realpath(sharepath, dir) == NULL) {
39143663Sdougm 		    ret = SA_NO_SUCH_PATH;
39153663Sdougm 		} else {
39163910Sdougm 		    share = sa_find_share(handle, dir);
39173663Sdougm 		}
39183663Sdougm 	    }
39193663Sdougm 	    if (share != NULL) {
39203663Sdougm 		ret = sa_disable_share(share, protocol);
39213663Sdougm 		/*
39223663Sdougm 		 * Errors are ok and removal should still occur. The
39233663Sdougm 		 * legacy unshare is more forgiving of errors than the
39243663Sdougm 		 * remove-share subcommand which may need the force
39253663Sdougm 		 * flag set for some error conditions. That is, the
39263663Sdougm 		 * "unshare" command will always unshare if it can
39273663Sdougm 		 * while "remove-share" might require the force option.
39283663Sdougm 		 */
39293663Sdougm 		if (persist == SA_SHARE_PERMANENT) {
39303663Sdougm 		    ret = sa_remove_share(share);
39313663Sdougm 		    if (ret == SA_OK)
39323910Sdougm 			ret = sa_update_config(handle);
39333663Sdougm 		}
39343034Sdougm 	    } else {
39353663Sdougm 		ret = SA_NOT_SHARED;
39363034Sdougm 	    }
39373034Sdougm 	}
39383034Sdougm 	switch (ret) {
39393034Sdougm 	default:
39403034Sdougm 	    (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
39413034Sdougm 	    ret = SA_LEGACY_ERR;
39423034Sdougm 	    break;
39433034Sdougm 	case SA_SYNTAX_ERR:
39443034Sdougm 	    (void) printf(gettext("usage: %s\n"),
39453034Sdougm 				sa_get_usage(USAGE_UNSHARE));
39463034Sdougm 	    break;
39473034Sdougm 	case SA_OK:
39483034Sdougm 	    break;
39493034Sdougm 	}
39503034Sdougm 	return (ret);
39513034Sdougm }
39523034Sdougm 
39533034Sdougm /*
39543034Sdougm  * common commands that implement the sub-commands used by all
39553034Sdougm  * protcols. The entries are found via the lookup command
39563034Sdougm  */
39573034Sdougm 
39583034Sdougm static sa_command_t commands[] = {
39593034Sdougm 	{"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
39603034Sdougm 	{"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
39613034Sdougm 	{"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
39623034Sdougm 	{"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
39633034Sdougm 	{"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
39643034Sdougm 	{"list", 0, sa_list, USAGE_LIST},
39653034Sdougm 	{"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
39663034Sdougm 	{"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
39673034Sdougm 	{"set", 0, sa_set, USAGE_SET, SVC_SET},
39683034Sdougm 	{"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
39693034Sdougm 	{"show", 0, sa_show, USAGE_SHOW},
39703034Sdougm 	{"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
39713034Sdougm 	{"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
39723034Sdougm 		SVC_SET|SVC_ACTION},
39733034Sdougm 	{"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
39743034Sdougm 	{"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
39753034Sdougm 	{"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
39763034Sdougm 	{NULL, 0, NULL, NULL}
39773034Sdougm };
39783034Sdougm 
39793034Sdougm static char *
39803034Sdougm sa_get_usage(sa_usage_t index)
39813034Sdougm {
39823034Sdougm 	char *ret = NULL;
39833034Sdougm 	switch (index) {
39843034Sdougm 	case USAGE_ADD_SHARE:
39853034Sdougm 	    ret = gettext("add-share [-nth] [-r resource-name] "
39863034Sdougm 			    "[-d \"description text\"] -s sharepath group");
39873034Sdougm 	    break;
39883034Sdougm 	case USAGE_CREATE:
39893034Sdougm 	    ret = gettext("create [-nvh] [-P proto [-p property=value]] group");
39903034Sdougm 	    break;
39913034Sdougm 	case USAGE_DELETE:
39923034Sdougm 	    ret = gettext("delete [-nvh] [-P proto] [-f] group");
39933034Sdougm 	    break;
39943034Sdougm 	case USAGE_DISABLE:
39953034Sdougm 	    ret = gettext("disable [-nvh] {-a | group ...}");
39963034Sdougm 	    break;
39973034Sdougm 	case USAGE_ENABLE:
39983034Sdougm 	    ret = gettext("enable [-nvh] {-a | group ...}");
39993034Sdougm 	    break;
40003034Sdougm 	case USAGE_LIST:
40013034Sdougm 	    ret = gettext("list [-vh] [-P proto]");
40023034Sdougm 	    break;
40033034Sdougm 	case USAGE_MOVE_SHARE:
40043034Sdougm 	    ret = gettext("move-share [-nvh] -s sharepath destination-group");
40053034Sdougm 	    break;
40063034Sdougm 	case USAGE_REMOVE_SHARE:
40073034Sdougm 	    ret = gettext("remove-share [-fnvh] -s sharepath group");
40083034Sdougm 	    break;
40093034Sdougm 	case USAGE_SET:
40103034Sdougm 	    ret = gettext("set [-nvh] -P proto [-S optspace] "
40113034Sdougm 				"[-p property=value]* [-s sharepath] group");
40123034Sdougm 	    break;
40133034Sdougm 	case USAGE_SET_SECURITY:
40143034Sdougm 	    ret = gettext("set-security [-nvh] -P proto -S security-type "
40153034Sdougm 			    "[-p property=value]* group");
40163034Sdougm 	    break;
40173034Sdougm 	case USAGE_SET_SHARE:
40183034Sdougm 	    ret = gettext("set-share [-nh] [-r resource] "
40193034Sdougm 			    "[-d \"description text\"] -s sharepath group");
40203034Sdougm 	    break;
40213034Sdougm 	case USAGE_SHOW:
40223034Sdougm 	    ret = gettext("show [-pvxh] [-P proto] [group ...]");
40233034Sdougm 	    break;
40243034Sdougm 	case USAGE_SHARE:
40253034Sdougm 	    ret = gettext("share [-F fstype] [-p] [-o optionlist]"
40263034Sdougm 			    "[-d description] [pathname [resourcename]]");
40273034Sdougm 	    break;
40283034Sdougm 	case USAGE_START:
40293034Sdougm 	    ret = gettext("start [-vh] [-P proto] {-a | group ...}");
40303034Sdougm 	    break;
40313034Sdougm 	case USAGE_STOP:
40323034Sdougm 	    ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
40333034Sdougm 	    break;
40343034Sdougm 	case USAGE_UNSET:
40353034Sdougm 	    ret = gettext("unset [-nvh] -P proto [-S optspace] "
40363034Sdougm 			    "[-p property]* group");
40373034Sdougm 	    break;
40383034Sdougm 	case USAGE_UNSET_SECURITY:
40393034Sdougm 	    ret = gettext("unset-security [-nvh] -P proto -S security-type "
40403034Sdougm 				"[-p property]* group");
40413034Sdougm 	    break;
40423034Sdougm 	case USAGE_UNSHARE:
40433034Sdougm 	    ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath");
40443034Sdougm 	    break;
40453034Sdougm 	}
40463034Sdougm 	return (ret);
40473034Sdougm }
40483034Sdougm 
40493034Sdougm /*
40503034Sdougm  * sa_lookup(cmd, proto)
40513034Sdougm  *
40523034Sdougm  * Lookup the sub-command. proto isn't currently used, but it may
40533034Sdougm  * eventually provide a way to provide protocol specific sub-commands.
40543034Sdougm  */
40553034Sdougm 
40563034Sdougm sa_command_t *
40573034Sdougm sa_lookup(char *cmd, char *proto)
40583034Sdougm {
40593034Sdougm 	int i;
40603034Sdougm 	size_t len;
40613034Sdougm #ifdef lint
40623034Sdougm 	proto = proto;
40633034Sdougm #endif
40643034Sdougm 
40653034Sdougm 	len = strlen(cmd);
40663034Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
40673034Sdougm 	    if (strncmp(cmd, commands[i].cmdname, len) == 0)
40683034Sdougm 		return (&commands[i]);
40693034Sdougm 	}
40703034Sdougm 	return (NULL);
40713034Sdougm }
40723034Sdougm 
40733034Sdougm void
40743034Sdougm sub_command_help(char *proto)
40753034Sdougm {
40763034Sdougm 	int i;
40773034Sdougm #ifdef lint
40783034Sdougm 	proto = proto;
40793034Sdougm #endif
40803034Sdougm 
40813034Sdougm 	(void) printf(gettext("\tsub-commands:\n"));
40823034Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
40833034Sdougm 	    if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
40843034Sdougm 		(void) printf("\t%s\n",
40853034Sdougm 				sa_get_usage((sa_usage_t)commands[i].cmdidx));
40863034Sdougm 	}
40873034Sdougm }
4088