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) {
72*4653Sdougm 		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) {
90*4653Sdougm 		new->next = NULL;
91*4653Sdougm 		new->item = item;
92*4653Sdougm 		new->itemdata = data;
933034Sdougm 	} else {
94*4653Sdougm 		return (listp);
953034Sdougm 	}
963034Sdougm 
973034Sdougm 	if (listp == NULL)
98*4653Sdougm 		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) {
116*4653Sdougm 		tmp = listp;
117*4653Sdougm 		listp = listp->next;
118*4653Sdougm 		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;
137*4653Sdougm 	int ret = B_TRUE;
1383034Sdougm 	uid_t uid;
1393034Sdougm 	struct passwd *pw = NULL;
1403034Sdougm 
1413034Sdougm 	uid = getuid();
1423034Sdougm 	pw = getpwuid(uid);
143*4653Sdougm 	if (pw == NULL) {
144*4653Sdougm 		ret = B_FALSE;
145*4653Sdougm 	} else {
146*4653Sdougm 		/*
147*4653Sdougm 		 * Since names are restricted to SA_MAX_NAME_LEN won't
148*4653Sdougm 		 * overflow.
149*4653Sdougm 		 */
150*4653Sdougm 		(void) snprintf(svcstring, sizeof (svcstring), "%s:%s",
151*4653Sdougm 		    SA_SVC_FMRI_BASE, instname);
152*4653Sdougm 		handle = scf_handle_create(SCF_VERSION);
153*4653Sdougm 		if (handle != NULL) {
154*4653Sdougm 			if (scf_handle_bind(handle) == 0) {
155*4653Sdougm 				switch (which) {
156*4653Sdougm 				case SVC_SET:
157*4653Sdougm 					prop = scf_simple_prop_get(handle,
158*4653Sdougm 					    svcstring, "general",
159*4653Sdougm 					    SVC_AUTH_VALUE);
160*4653Sdougm 					break;
161*4653Sdougm 				case SVC_ACTION:
162*4653Sdougm 					prop = scf_simple_prop_get(handle,
163*4653Sdougm 					    svcstring, "general",
164*4653Sdougm 					    SVC_AUTH_ACTION);
165*4653Sdougm 					break;
166*4653Sdougm 				}
167*4653Sdougm 			}
1683034Sdougm 		}
1693034Sdougm 	}
1703034Sdougm 	/* make sure we have an authorization string property */
1713034Sdougm 	if (prop != NULL) {
172*4653Sdougm 		int i;
173*4653Sdougm 		numauths = scf_simple_prop_numvalues(prop);
174*4653Sdougm 		for (ret = 0, i = 0; i < numauths; i++) {
175*4653Sdougm 			authstr = scf_simple_prop_next_astring(prop);
176*4653Sdougm 			if (authstr != NULL) {
177*4653Sdougm 				/* check if this user has one of the strings */
178*4653Sdougm 				if (chkauthattr(authstr, pw->pw_name)) {
179*4653Sdougm 					ret = 1;
180*4653Sdougm 					break;
181*4653Sdougm 				}
182*4653Sdougm 			}
1833034Sdougm 		}
184*4653Sdougm 		endauthattr();
185*4653Sdougm 		scf_simple_prop_free(prop);
1863034Sdougm 	} else {
187*4653Sdougm 		/* no authorization string defined */
188*4653Sdougm 		ret = 0;
1893034Sdougm 	}
1903034Sdougm 	if (handle != NULL)
191*4653Sdougm 		scf_handle_destroy(handle);
1923034Sdougm 	return (ret);
1933034Sdougm }
1943034Sdougm 
1953034Sdougm /*
1963034Sdougm  * check_authorizations(instname, flags)
1973034Sdougm  *
1983034Sdougm  * check all the needed authorizations for the user in this service
1993034Sdougm  * instance. Return value of 1(true) or 0(false) indicates whether
2003034Sdougm  * there are authorizations for the user or not.
2013034Sdougm  */
2023034Sdougm 
2033034Sdougm static int
2043034Sdougm check_authorizations(char *instname, int flags)
2053034Sdougm {
2063034Sdougm 	int ret1 = 0;
2073034Sdougm 	int ret2 = 0;
2083034Sdougm 	int ret;
2093034Sdougm 
2103034Sdougm 	if (flags & SVC_SET)
211*4653Sdougm 		ret1 = check_authorization(instname, SVC_SET);
2123034Sdougm 	if (flags & SVC_ACTION)
213*4653Sdougm 		ret2 = check_authorization(instname, SVC_ACTION);
2143034Sdougm 	switch (flags) {
2153034Sdougm 	case SVC_ACTION:
216*4653Sdougm 		ret = ret2;
217*4653Sdougm 		break;
2183034Sdougm 	case SVC_SET:
219*4653Sdougm 		ret = ret1;
220*4653Sdougm 		break;
2213034Sdougm 	case SVC_ACTION|SVC_SET:
222*4653Sdougm 		ret = ret1 & ret2;
223*4653Sdougm 		break;
2243034Sdougm 	default:
225*4653Sdougm 		/* if not flags set, we assume we don't need authorizations */
226*4653Sdougm 		ret = 1;
2273034Sdougm 	}
2283034Sdougm 	return (ret);
2293034Sdougm }
2303034Sdougm 
2313034Sdougm /*
2323082Sdougm  * enable_group(group, updateproto)
2333082Sdougm  *
2343082Sdougm  * enable all the shares in the specified group. This is a helper for
2353082Sdougm  * enable_all_groups in order to simplify regular and subgroup (zfs)
2363082Sdougm  * disabling. Group has already been checked for non-NULL.
2373082Sdougm  */
2383082Sdougm 
2393082Sdougm static void
2403082Sdougm enable_group(sa_group_t group, char *updateproto)
2413082Sdougm {
2423082Sdougm 	sa_share_t share;
2433082Sdougm 
2443082Sdougm 	for (share = sa_get_share(group, NULL);
2453082Sdougm 	    share != NULL;
2463082Sdougm 	    share = sa_get_next_share(share)) {
247*4653Sdougm 		if (updateproto != NULL)
248*4653Sdougm 			(void) sa_update_legacy(share, updateproto);
249*4653Sdougm 		(void) sa_enable_share(share, NULL);
2503082Sdougm 	}
2513082Sdougm }
2523082Sdougm 
2533082Sdougm /*
2544241Sdougm  * isenabled(group)
2554241Sdougm  *
2564241Sdougm  * Returns B_TRUE if the group is enabled or B_FALSE if it isn't.
2574241Sdougm  * Moved to separate function to reduce clutter in the code.
2584241Sdougm  */
2594241Sdougm 
2604241Sdougm static int
2614241Sdougm isenabled(sa_group_t group)
2624241Sdougm {
2634241Sdougm 	char *state;
2644241Sdougm 	int ret = B_FALSE;
2654241Sdougm 
2664241Sdougm 	if (group != NULL) {
267*4653Sdougm 		state = sa_get_group_attr(group, "state");
268*4653Sdougm 		if (state != NULL) {
269*4653Sdougm 			if (strcmp(state, "enabled") == 0)
270*4653Sdougm 				ret = B_TRUE;
271*4653Sdougm 			sa_free_attr_string(state);
272*4653Sdougm 		}
2734241Sdougm 	}
2744241Sdougm 	return (ret);
2754241Sdougm }
2764241Sdougm 
2774241Sdougm /*
2783082Sdougm  * enable_all_groups(list, setstate, online, updateproto)
2793082Sdougm  *	Given a list of groups, enable each one found.  If updateproto
2803082Sdougm  *	is not NULL, then update all the shares for the protocol that
2813082Sdougm  *	was passed in.
2823034Sdougm  */
2833034Sdougm static int
2843910Sdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
2853910Sdougm 	int online, char *updateproto)
2863034Sdougm {
2874241Sdougm 	int ret;
2883034Sdougm 	char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
2893034Sdougm 	char *state;
2903034Sdougm 	char *name;
2913034Sdougm 	char *zfs = NULL;
2923034Sdougm 	sa_group_t group;
2933082Sdougm 	sa_group_t subgroup;
2943034Sdougm 
2954241Sdougm 	for (ret = SA_OK; work != NULL;	work = work->next) {
296*4653Sdougm 		group = (sa_group_t)work->item;
2974241Sdougm 
2984241Sdougm 		/*
2994241Sdougm 		 * If setstate == TRUE, then make sure to set
3004241Sdougm 		 * enabled. This needs to be done here in order for
3014241Sdougm 		 * the isenabled check to succeed on a newly enabled
3024241Sdougm 		 * group.
3034241Sdougm 		 */
304*4653Sdougm 		if (setstate == B_TRUE) {
305*4653Sdougm 			ret = sa_set_group_attr(group, "state",	"enabled");
306*4653Sdougm 			if (ret != SA_OK)
307*4653Sdougm 				break;
308*4653Sdougm 		}
3094241Sdougm 
3104241Sdougm 		/*
3114241Sdougm 		 * Check to see if group is enabled. If it isn't, skip
3124241Sdougm 		 * the rest.  We don't want shares starting if the
3134241Sdougm 		 * group is disabled. The properties may have been
3144241Sdougm 		 * updated, but there won't be a change until the
3154241Sdougm 		 * group is enabled.
3164241Sdougm 		 */
317*4653Sdougm 		if (!isenabled(group))
318*4653Sdougm 			continue;
319*4653Sdougm 
320*4653Sdougm 		/* if itemdata != NULL then a single share */
321*4653Sdougm 		if (work->itemdata != NULL) {
322*4653Sdougm 			ret = sa_enable_share((sa_share_t)work->itemdata, NULL);
3233034Sdougm 		}
324*4653Sdougm 		if (ret != SA_OK)
325*4653Sdougm 			break;
326*4653Sdougm 
327*4653Sdougm 		/* if itemdata == NULL then the whole group */
328*4653Sdougm 		if (work->itemdata == NULL) {
329*4653Sdougm 			zfs = sa_get_group_attr(group, "zfs");
330*4653Sdougm 			/*
331*4653Sdougm 			 * if the share is managed by ZFS, don't
332*4653Sdougm 			 * update any of the protocols since ZFS is
333*4653Sdougm 			 * handling this.  updateproto will contain
334*4653Sdougm 			 * the name of the protocol that we want to
335*4653Sdougm 			 * update legacy files for.
336*4653Sdougm 			 */
337*4653Sdougm 			enable_group(group, zfs == NULL ? updateproto : NULL);
338*4653Sdougm 			for (subgroup = sa_get_sub_group(group);
339*4653Sdougm 			    subgroup != NULL;
340*4653Sdougm 			    subgroup = sa_get_next_group(subgroup)) {
341*4653Sdougm 				/* never update legacy for ZFS subgroups */
342*4653Sdougm 				enable_group(subgroup, NULL);
3433034Sdougm 			}
3443034Sdougm 		}
345*4653Sdougm 		if (online) {
346*4653Sdougm 			zfs = sa_get_group_attr(group, "zfs");
347*4653Sdougm 			name = sa_get_group_attr(group, "name");
348*4653Sdougm 			if (name != NULL) {
349*4653Sdougm 				if (zfs == NULL) {
350*4653Sdougm 					(void) snprintf(instance,
351*4653Sdougm 					    sizeof (instance), "%s:%s",
352*4653Sdougm 					    SA_SVC_FMRI_BASE, name);
353*4653Sdougm 					state = smf_get_state(instance);
354*4653Sdougm 					if (state == NULL ||
355*4653Sdougm 					    strcmp(state, "online") != 0) {
356*4653Sdougm 						(void) smf_enable_instance(
357*4653Sdougm 						    instance, 0);
358*4653Sdougm 						free(state);
359*4653Sdougm 					}
360*4653Sdougm 				} else {
361*4653Sdougm 					sa_free_attr_string(zfs);
362*4653Sdougm 					zfs = NULL;
363*4653Sdougm 				}
364*4653Sdougm 				if (name != NULL)
365*4653Sdougm 					sa_free_attr_string(name);
366*4653Sdougm 			}
367*4653Sdougm 		}
3683034Sdougm 	}
3693034Sdougm 	if (ret == SA_OK) {
370*4653Sdougm 		ret = sa_update_config(handle);
3713034Sdougm 	}
3723034Sdougm 	return (ret);
3733034Sdougm }
3743034Sdougm 
3753034Sdougm /*
3763034Sdougm  * chk_opt(optlistp, security, proto)
3773034Sdougm  *
3783034Sdougm  * Do a sanity check on the optlist provided for the protocol.  This
3793034Sdougm  * is a syntax check and verification that the property is either a
3803034Sdougm  * general or specific to a names optionset.
3813034Sdougm  */
3823034Sdougm 
3833034Sdougm static int
3843034Sdougm chk_opt(struct options *optlistp, int security, char *proto)
3853034Sdougm {
3863034Sdougm 	struct options *optlist;
3873034Sdougm 	char *sep = "";
3883034Sdougm 	int notfirst = 0;
3893034Sdougm 	int ret;
3903034Sdougm 
3913034Sdougm 	for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
392*4653Sdougm 		char *optname;
393*4653Sdougm 
394*4653Sdougm 		optname = optlist->optname;
395*4653Sdougm 		ret = OPT_ADD_OK;
396*4653Sdougm 		/* extract property/value pair */
397*4653Sdougm 		if (sa_is_security(optname, proto)) {
398*4653Sdougm 			if (!security)
399*4653Sdougm 				ret = OPT_ADD_SECURITY;
400*4653Sdougm 		} else {
401*4653Sdougm 			if (security)
402*4653Sdougm 				ret = OPT_ADD_PROPERTY;
403*4653Sdougm 		}
404*4653Sdougm 		if (ret != OPT_ADD_OK) {
405*4653Sdougm 			if (notfirst == 0)
406*4653Sdougm 				(void) printf(
407*4653Sdougm 				    gettext("Property syntax error: "));
408*4653Sdougm 			switch (ret) {
409*4653Sdougm 			case OPT_ADD_SYNTAX:
410*4653Sdougm 				(void) printf(gettext("%ssyntax error: %s"),
4113034Sdougm 				    sep, optname);
412*4653Sdougm 				sep = ", ";
413*4653Sdougm 				break;
414*4653Sdougm 			case OPT_ADD_SECURITY:
415*4653Sdougm 				(void) printf(gettext("%s%s requires -S"),
4163034Sdougm 				    optname, sep);
417*4653Sdougm 				sep = ", ";
418*4653Sdougm 				break;
419*4653Sdougm 			case OPT_ADD_PROPERTY:
420*4653Sdougm 				(void) printf(
421*4653Sdougm 				    gettext("%s%s not supported with -S"),
4223034Sdougm 				    optname, sep);
423*4653Sdougm 				sep = ", ";
424*4653Sdougm 				break;
425*4653Sdougm 			}
426*4653Sdougm 			notfirst++;
4273034Sdougm 		}
4283034Sdougm 	}
4293034Sdougm 	if (notfirst) {
430*4653Sdougm 		(void) printf("\n");
431*4653Sdougm 		ret = SA_SYNTAX_ERR;
4323034Sdougm 	}
4333034Sdougm 	return (ret);
4343034Sdougm }
4353034Sdougm 
4363034Sdougm /*
4373034Sdougm  * free_opt(optlist)
4383034Sdougm  *	Free the specified option list.
4393034Sdougm  */
4403034Sdougm static void
4413034Sdougm free_opt(struct options *optlist)
4423034Sdougm {
4433034Sdougm 	struct options *nextopt;
4443034Sdougm 	while (optlist != NULL) {
4453034Sdougm 		nextopt = optlist->next;
4463034Sdougm 		free(optlist);
4473034Sdougm 		optlist = nextopt;
4483034Sdougm 	}
4493034Sdougm }
4503034Sdougm 
4513034Sdougm /*
4523034Sdougm  * check property list for valid properties
4533034Sdougm  * A null value is a remove which is always valid.
4543034Sdougm  */
4553034Sdougm static int
4563034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec)
4573034Sdougm {
4583034Sdougm 	int ret = SA_OK;
4593034Sdougm 	struct options *cur;
4603034Sdougm 	sa_property_t prop;
4613034Sdougm 	sa_optionset_t parent = NULL;
4623034Sdougm 
4633034Sdougm 	if (object != NULL) {
464*4653Sdougm 		if (sec == NULL)
465*4653Sdougm 			parent = sa_get_optionset(object, proto);
466*4653Sdougm 		else
467*4653Sdougm 			parent = sa_get_security(object, sec, proto);
4683034Sdougm 	}
4693034Sdougm 
4703034Sdougm 	for (cur = optlist; cur != NULL; cur = cur->next) {
471*4653Sdougm 		if (cur->optvalue == NULL)
472*4653Sdougm 			continue;
4733034Sdougm 		prop = sa_create_property(cur->optname, cur->optvalue);
4743034Sdougm 		if (prop == NULL)
475*4653Sdougm 			ret = SA_NO_MEMORY;
4763034Sdougm 		if (ret != SA_OK ||
4773034Sdougm 		    (ret = sa_valid_property(parent, proto, prop)) != SA_OK) {
478*4653Sdougm 			(void) printf(
479*4653Sdougm 			    gettext("Could not add property %s: %s\n"),
480*4653Sdougm 			    cur->optname, sa_errorstr(ret));
4813034Sdougm 		}
4823034Sdougm 		(void) sa_remove_property(prop);
4833034Sdougm 	}
4843034Sdougm 	return (ret);
4853034Sdougm }
4863034Sdougm 
4873034Sdougm /*
4883034Sdougm  * add_optionset(group, optlist, protocol, *err)
4893034Sdougm  *	Add the options in optlist to an optionset and then add the optionset
4903034Sdougm  *	to the group.
4913034Sdougm  *
4923034Sdougm  *	The return value indicates if there was a "change" while errors are
4933034Sdougm  *	returned via the *err parameters.
4943034Sdougm  */
4953034Sdougm static int
4963034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
4973034Sdougm {
4983034Sdougm 	sa_optionset_t optionset;
4993034Sdougm 	int ret = SA_OK;
5003034Sdougm 	int result = 0;
5013034Sdougm 
5023034Sdougm 	optionset = sa_get_optionset(group, proto);
5033034Sdougm 	if (optionset == NULL) {
504*4653Sdougm 		optionset = sa_create_optionset(group, proto);
505*4653Sdougm 		result = 1; /* adding a protocol is a change */
5063034Sdougm 	}
507*4653Sdougm 	if (optionset == NULL) {
508*4653Sdougm 		ret = SA_NO_MEMORY;
509*4653Sdougm 		goto out;
510*4653Sdougm 	}
511*4653Sdougm 	while (optlist != NULL) {
5123034Sdougm 		sa_property_t prop;
5133034Sdougm 		prop = sa_get_property(optionset, optlist->optname);
5143034Sdougm 		if (prop == NULL) {
5153034Sdougm 			/*
5163034Sdougm 			 * add the property, but only if it is
5173034Sdougm 			 * a non-NULL or non-zero length value
5183034Sdougm 			 */
519*4653Sdougm 			if (optlist->optvalue != NULL) {
520*4653Sdougm 				prop = sa_create_property(optlist->optname,
521*4653Sdougm 				    optlist->optvalue);
522*4653Sdougm 				if (prop != NULL) {
523*4653Sdougm 					ret = sa_valid_property(optionset,
524*4653Sdougm 					    proto, prop);
525*4653Sdougm 					if (ret != SA_OK) {
526*4653Sdougm 						(void) sa_remove_property(prop);
527*4653Sdougm 						(void) printf(gettext("Could "
528*4653Sdougm 						    "not add property "
529*4653Sdougm 						    "%s: %s\n"),
530*4653Sdougm 						    optlist->optname,
531*4653Sdougm 						    sa_errorstr(ret));
532*4653Sdougm 					}
533*4653Sdougm 				}
534*4653Sdougm 				if (ret == SA_OK) {
535*4653Sdougm 					ret = sa_add_property(optionset, prop);
536*4653Sdougm 					if (ret != SA_OK) {
537*4653Sdougm 						(void) printf(gettext(
538*4653Sdougm 						    "Could not add property "
539*4653Sdougm 						    "%s: %s\n"),
540*4653Sdougm 						    optlist->optname,
541*4653Sdougm 						    sa_errorstr(ret));
542*4653Sdougm 					} else {
543*4653Sdougm 						/* there was a change */
544*4653Sdougm 						result = 1;
545*4653Sdougm 					}
546*4653Sdougm 				}
5473034Sdougm 			}
548*4653Sdougm 		} else {
549*4653Sdougm 			ret = sa_update_property(prop, optlist->optvalue);
550*4653Sdougm 			/* should check to see if value changed */
551*4653Sdougm 			if (ret != SA_OK) {
552*4653Sdougm 				(void) printf(gettext("Could not update "
553*4653Sdougm 				    "property %s: %s\n"), optlist->optname,
554*4653Sdougm 				    sa_errorstr(ret));
555*4653Sdougm 			} else {
5563034Sdougm 				result = 1;
5573034Sdougm 			}
5583034Sdougm 		}
5593034Sdougm 		optlist = optlist->next;
5603034Sdougm 	}
561*4653Sdougm 	ret = sa_commit_properties(optionset, 0);
562*4653Sdougm 
563*4653Sdougm out:
5643034Sdougm 	if (err != NULL)
565*4653Sdougm 		*err = ret;
5663034Sdougm 	return (result);
5673034Sdougm }
5683034Sdougm 
5693034Sdougm /*
5703034Sdougm  * sa_create(flags, argc, argv)
5713034Sdougm  *	create a new group
5723034Sdougm  *	this may or may not have a protocol associated with it.
5733034Sdougm  *	No protocol means "all" protocols in this case.
5743034Sdougm  */
5753034Sdougm static int
5763910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
5773034Sdougm {
5783034Sdougm 	char *groupname;
5793034Sdougm 
5803034Sdougm 	sa_group_t group;
5813034Sdougm 	int verbose = 0;
5823034Sdougm 	int dryrun = 0;
5833034Sdougm 	int c;
5843034Sdougm 	char *protocol = NULL;
5853034Sdougm 	int ret = SA_OK;
5863034Sdougm 	struct options *optlist = NULL;
5873034Sdougm 	int err = 0;
5883034Sdougm 	int auth;
5893034Sdougm 
5903034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) {
591*4653Sdougm 		switch (c) {
592*4653Sdougm 		case 'v':
593*4653Sdougm 			verbose++;
594*4653Sdougm 			break;
595*4653Sdougm 		case 'n':
596*4653Sdougm 			dryrun++;
597*4653Sdougm 			break;
598*4653Sdougm 		case 'P':
599*4653Sdougm 			protocol = optarg;
600*4653Sdougm 			if (sa_valid_protocol(protocol))
601*4653Sdougm 				break;
602*4653Sdougm 			(void) printf(gettext(
603*4653Sdougm 			    "Invalid protocol specified: %s\n"), protocol);
604*4653Sdougm 			return (SA_INVALID_PROTOCOL);
605*4653Sdougm 			break;
606*4653Sdougm 		case 'p':
607*4653Sdougm 			ret = add_opt(&optlist, optarg, 0);
608*4653Sdougm 			switch (ret) {
609*4653Sdougm 			case OPT_ADD_SYNTAX:
610*4653Sdougm 				(void) printf(gettext(
611*4653Sdougm 				    "Property syntax error for property: %s\n"),
612*4653Sdougm 				    optarg);
613*4653Sdougm 				return (SA_SYNTAX_ERR);
614*4653Sdougm 			case OPT_ADD_SECURITY:
615*4653Sdougm 				(void) printf(gettext(
616*4653Sdougm 				    "Security properties need "
617*4653Sdougm 				    "to be set with set-security: %s\n"),
618*4653Sdougm 				    optarg);
619*4653Sdougm 				return (SA_SYNTAX_ERR);
620*4653Sdougm 			default:
621*4653Sdougm 				break;
622*4653Sdougm 			}
623*4653Sdougm 			break;
624*4653Sdougm 		default:
625*4653Sdougm 		case 'h':
626*4653Sdougm 		case '?':
627*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
628*4653Sdougm 			    sa_get_usage(USAGE_CREATE));
629*4653Sdougm 			return (0);
6303034Sdougm 		}
6313034Sdougm 	}
6323034Sdougm 
6333034Sdougm 	if (optind >= argc) {
634*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
635*4653Sdougm 		    sa_get_usage(USAGE_CREATE));
636*4653Sdougm 		(void) printf(gettext("\tgroup must be specified.\n"));
637*4653Sdougm 		return (SA_BAD_PATH);
6383034Sdougm 	}
6393034Sdougm 
6403034Sdougm 	if ((optind + 1) < argc) {
641*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
642*4653Sdougm 		    sa_get_usage(USAGE_CREATE));
643*4653Sdougm 		(void) printf(gettext("\textraneous group(s) at end\n"));
644*4653Sdougm 		return (SA_SYNTAX_ERR);
6453034Sdougm 	}
6463034Sdougm 
6473034Sdougm 	if (protocol == NULL && optlist != NULL) {
648*4653Sdougm 		/* lookup default protocol */
649*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
650*4653Sdougm 		    sa_get_usage(USAGE_CREATE));
651*4653Sdougm 		(void) printf(gettext("\tprotocol must be specified "
652*4653Sdougm 		    "with properties\n"));
653*4653Sdougm 		return (SA_INVALID_PROTOCOL);
6543034Sdougm 	}
6553034Sdougm 
6563034Sdougm 	if (optlist != NULL)
657*4653Sdougm 		ret = chk_opt(optlist, 0, protocol);
6583034Sdougm 	if (ret == OPT_ADD_SECURITY) {
659*4653Sdougm 		(void) printf(gettext("Security properties not "
660*4653Sdougm 		    "supported with create\n"));
661*4653Sdougm 		return (SA_SYNTAX_ERR);
6623034Sdougm 	}
6633034Sdougm 
6643034Sdougm 	/*
665*4653Sdougm 	 * If a group already exists, we can only add a new protocol
6663034Sdougm 	 * to it and not create a new one or add the same protocol
6673034Sdougm 	 * again.
6683034Sdougm 	 */
6693034Sdougm 
6703034Sdougm 	groupname = argv[optind];
6713034Sdougm 
6723034Sdougm 	auth = check_authorizations(groupname, flags);
6733034Sdougm 
6743910Sdougm 	group = sa_get_group(handle, groupname);
6753034Sdougm 	if (group != NULL) {
676*4653Sdougm 		/* group exists so must be a protocol add */
677*4653Sdougm 		if (protocol != NULL) {
678*4653Sdougm 			if (has_protocol(group, protocol)) {
679*4653Sdougm 				(void) printf(gettext(
680*4653Sdougm 				    "Group \"%s\" already exists"
681*4653Sdougm 				    " with protocol %s\n"), groupname,
682*4653Sdougm 				    protocol);
683*4653Sdougm 				ret = SA_DUPLICATE_NAME;
684*4653Sdougm 			}
685*4653Sdougm 		} else {
686*4653Sdougm 			/* must add new protocol */
687*4653Sdougm 			(void) printf(gettext(
688*4653Sdougm 			    "Group already exists and no protocol "
689*4653Sdougm 			    "specified.\n"));
690*4653Sdougm 			ret = SA_DUPLICATE_NAME;
6913034Sdougm 		}
6923034Sdougm 	} else {
6933034Sdougm 		/*
6943034Sdougm 		 * is it a valid name? Must comply with SMF instance
6953034Sdougm 		 * name restrictions.
6963034Sdougm 		 */
697*4653Sdougm 		if (!sa_valid_group_name(groupname)) {
698*4653Sdougm 			ret = SA_INVALID_NAME;
699*4653Sdougm 			(void) printf(gettext("Invalid group name: %s\n"),
700*4653Sdougm 			    groupname);
701*4653Sdougm 		}
7023034Sdougm 	}
7033034Sdougm 	if (ret == SA_OK) {
704*4653Sdougm 		/* check protocol vs optlist */
705*4653Sdougm 		if (optlist != NULL) {
706*4653Sdougm 			/* check options, if any, for validity */
707*4653Sdougm 			ret = valid_options(optlist, protocol, group, NULL);
708*4653Sdougm 		}
7093034Sdougm 	}
7103034Sdougm 	if (ret == SA_OK && !dryrun) {
711*4653Sdougm 		if (group == NULL) {
712*4653Sdougm 			group = sa_create_group(handle, (char *)groupname,
713*4653Sdougm 			    &err);
7143034Sdougm 		}
715*4653Sdougm 		if (group != NULL) {
716*4653Sdougm 			sa_optionset_t optionset;
717*4653Sdougm 			if (optlist != NULL) {
718*4653Sdougm 				(void) add_optionset(group, optlist, protocol,
719*4653Sdougm 				    &ret);
720*4653Sdougm 			} else if (protocol != NULL) {
721*4653Sdougm 				optionset = sa_create_optionset(group,
722*4653Sdougm 				    protocol);
723*4653Sdougm 				if (optionset == NULL)
724*4653Sdougm 					ret = SA_NO_MEMORY;
725*4653Sdougm 			} else if (protocol == NULL) {
726*4653Sdougm 				char **protolist;
727*4653Sdougm 				int numprotos, i;
728*4653Sdougm 				numprotos = sa_get_protocols(&protolist);
729*4653Sdougm 				for (i = 0; i < numprotos; i++) {
730*4653Sdougm 					optionset = sa_create_optionset(group,
731*4653Sdougm 					    protolist[i]);
732*4653Sdougm 				}
733*4653Sdougm 				if (protolist != NULL)
734*4653Sdougm 					free(protolist);
735*4653Sdougm 			}
7363034Sdougm 			/*
737*4653Sdougm 			 * We have a group and legal additions
7383034Sdougm 			 */
739*4653Sdougm 			if (ret == SA_OK) {
740*4653Sdougm 				/*
741*4653Sdougm 				 * Commit to configuration for protocols that
742*4653Sdougm 				 * need to do block updates. For NFS, this
743*4653Sdougm 				 * doesn't do anything but it will be run for
744*4653Sdougm 				 * all protocols that implement the
745*4653Sdougm 				 * appropriate plugin.
746*4653Sdougm 				 */
747*4653Sdougm 				ret = sa_update_config(handle);
748*4653Sdougm 			} else {
749*4653Sdougm 				if (group != NULL)
750*4653Sdougm 					(void) sa_remove_group(group);
751*4653Sdougm 			}
7523034Sdougm 		} else {
753*4653Sdougm 			ret = err;
754*4653Sdougm 			(void) printf(gettext("Could not create group: %s\n"),
755*4653Sdougm 			    sa_errorstr(ret));
7563034Sdougm 		}
7573034Sdougm 	}
7583034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
759*4653Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
760*4653Sdougm 		    sa_errorstr(SA_NO_PERMISSION));
761*4653Sdougm 		ret = SA_NO_PERMISSION;
7623034Sdougm 	}
7633034Sdougm 	free_opt(optlist);
7643034Sdougm 	return (ret);
7653034Sdougm }
7663034Sdougm 
7673034Sdougm /*
7683034Sdougm  * group_status(group)
7693034Sdougm  *
7703034Sdougm  * return the current status (enabled/disabled) of the group.
7713034Sdougm  */
7723034Sdougm 
7733034Sdougm static char *
7743034Sdougm group_status(sa_group_t group)
7753034Sdougm {
7763034Sdougm 	char *state;
7773034Sdougm 	int enabled = 0;
7783034Sdougm 
7793034Sdougm 	state = sa_get_group_attr(group, "state");
7803034Sdougm 	if (state != NULL) {
781*4653Sdougm 		if (strcmp(state, "enabled") == 0) {
782*4653Sdougm 			enabled = 1;
783*4653Sdougm 		}
784*4653Sdougm 		sa_free_attr_string(state);
7853034Sdougm 	}
7864255Sdougm 	return (enabled ? "enabled" : "disabled");
7873034Sdougm }
7883034Sdougm 
7893034Sdougm /*
7903034Sdougm  * sa_delete(flags, argc, argv)
7913034Sdougm  *
7923034Sdougm  *	Delete a group.
7933034Sdougm  */
7943034Sdougm 
7953034Sdougm static int
7963910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
7973034Sdougm {
7983034Sdougm 	char *groupname;
7993034Sdougm 	sa_group_t group;
8003034Sdougm 	sa_share_t share;
8013034Sdougm 	int verbose = 0;
8023034Sdougm 	int dryrun = 0;
8033034Sdougm 	int force = 0;
8043034Sdougm 	int c;
8053034Sdougm 	char *protocol = NULL;
8063034Sdougm 	char *sectype = NULL;
8073034Sdougm 	int ret = SA_OK;
8083034Sdougm 	int auth;
8093034Sdougm 
8103034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
811*4653Sdougm 		switch (c) {
812*4653Sdougm 		case 'v':
813*4653Sdougm 			verbose++;
814*4653Sdougm 			break;
815*4653Sdougm 		case 'n':
816*4653Sdougm 			dryrun++;
817*4653Sdougm 			break;
818*4653Sdougm 		case 'P':
819*4653Sdougm 			protocol = optarg;
820*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
821*4653Sdougm 				(void) printf(gettext("Invalid protocol "
822*4653Sdougm 				    "specified: %s\n"),   protocol);
823*4653Sdougm 				return (SA_INVALID_PROTOCOL);
824*4653Sdougm 			}
825*4653Sdougm 			break;
826*4653Sdougm 		case 'S':
827*4653Sdougm 			sectype = optarg;
828*4653Sdougm 			break;
829*4653Sdougm 		case 'f':
830*4653Sdougm 			force++;
831*4653Sdougm 			break;
832*4653Sdougm 		default:
833*4653Sdougm 		case 'h':
834*4653Sdougm 		case '?':
835*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
836*4653Sdougm 			    sa_get_usage(USAGE_DELETE));
837*4653Sdougm 			return (0);
8383034Sdougm 		}
8393034Sdougm 	}
8403034Sdougm 
8413034Sdougm 	if (optind >= argc) {
842*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
843*4653Sdougm 		    sa_get_usage(USAGE_DELETE));
844*4653Sdougm 		(void) printf(gettext("\tgroup must be specified.\n"));
845*4653Sdougm 		return (SA_SYNTAX_ERR);
8463034Sdougm 	}
8473034Sdougm 
8483034Sdougm 	if ((optind + 1) < argc) {
849*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
850*4653Sdougm 		    sa_get_usage(USAGE_DELETE));
851*4653Sdougm 		(void) printf(gettext("\textraneous group(s) at end\n"));
852*4653Sdougm 		return (SA_SYNTAX_ERR);
8533034Sdougm 	}
8543034Sdougm 
8553034Sdougm 	if (sectype != NULL && protocol == NULL) {
856*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
857*4653Sdougm 		    sa_get_usage(USAGE_DELETE));
858*4653Sdougm 		(void) printf(gettext("\tsecurity requires protocol to be "
859*4653Sdougm 		    "specified.\n"));
860*4653Sdougm 		return (SA_SYNTAX_ERR);
8613034Sdougm 	}
8623034Sdougm 
8633034Sdougm 	/*
8643034Sdougm 	 * Determine if the group already exists since it must in
8653034Sdougm 	 * order to be removed.
8663034Sdougm 	 *
8673034Sdougm 	 * We can delete when:
8683034Sdougm 	 *
8693034Sdougm 	 *	- group is empty
8703034Sdougm 	 *	- force flag is set
8713034Sdougm 	 *	- if protocol specified, only delete the protocol
8723034Sdougm 	 */
8733034Sdougm 
8743034Sdougm 	groupname = argv[optind];
8753910Sdougm 	group = sa_get_group(handle, groupname);
8763034Sdougm 	if (group == NULL) {
8773034Sdougm 		ret = SA_NO_SUCH_GROUP;
878*4653Sdougm 		goto done;
879*4653Sdougm 	}
880*4653Sdougm 	auth = check_authorizations(groupname, flags);
881*4653Sdougm 	if (protocol == NULL) {
8823034Sdougm 		share = sa_get_share(group, NULL);
8833034Sdougm 		if (share != NULL)
884*4653Sdougm 			ret = SA_BUSY;
8853034Sdougm 		if (share == NULL || (share != NULL && force == 1)) {
886*4653Sdougm 			ret = SA_OK;
887*4653Sdougm 			if (!dryrun) {
888*4653Sdougm 				while (share != NULL) {
889*4653Sdougm 					sa_share_t next_share;
890*4653Sdougm 					next_share = sa_get_next_share(share);
891*4653Sdougm 					/*
892*4653Sdougm 					 * need to do the disable of
893*4653Sdougm 					 * each share, but don't
894*4653Sdougm 					 * actually do anything on a
895*4653Sdougm 					 * dryrun.
896*4653Sdougm 					 */
897*4653Sdougm 					ret = sa_disable_share(share, NULL);
898*4653Sdougm 					ret = sa_remove_share(share);
899*4653Sdougm 					share = next_share;
900*4653Sdougm 				}
901*4653Sdougm 				ret = sa_remove_group(group);
9023034Sdougm 			}
9033034Sdougm 		}
904*4653Sdougm 		/* Commit to configuration if not a dryrun */
9053034Sdougm 		if (!dryrun && ret == SA_OK) {
906*4653Sdougm 			ret = sa_update_config(handle);
9073034Sdougm 		}
908*4653Sdougm 	} else {
9093034Sdougm 		/* a protocol delete */
9103034Sdougm 		sa_optionset_t optionset;
9113034Sdougm 		sa_security_t security;
912*4653Sdougm 			if (sectype != NULL) {
913*4653Sdougm 			/* only delete specified security */
914*4653Sdougm 			security = sa_get_security(group, sectype, protocol);
915*4653Sdougm 			if (security != NULL && !dryrun)
916*4653Sdougm 				ret = sa_destroy_security(security);
917*4653Sdougm 			else
918*4653Sdougm 				ret = SA_INVALID_PROTOCOL;
9193034Sdougm 		} else {
920*4653Sdougm 			optionset = sa_get_optionset(group, protocol);
921*4653Sdougm 			if (optionset != NULL && !dryrun) {
922*4653Sdougm 				/*
923*4653Sdougm 				 * have an optionset with
924*4653Sdougm 				 * protocol to delete
925*4653Sdougm 				 */
926*4653Sdougm 				ret = sa_destroy_optionset(optionset);
927*4653Sdougm 				/*
928*4653Sdougm 				 * Now find all security sets
929*4653Sdougm 				 * for the protocol and remove
930*4653Sdougm 				 * them. Don't remove other
931*4653Sdougm 				 * protocols.
932*4653Sdougm 				 */
933*4653Sdougm 				for (security =
934*4653Sdougm 				    sa_get_security(group, NULL, NULL);
935*4653Sdougm 				    ret == SA_OK && security != NULL;
936*4653Sdougm 				    security = sa_get_next_security(security)) {
937*4653Sdougm 					char *secprot;
938*4653Sdougm 					secprot = sa_get_security_attr(security,
939*4653Sdougm 					    "type");
940*4653Sdougm 					if (secprot != NULL &&
941*4653Sdougm 					    strcmp(secprot, protocol) == 0)
942*4653Sdougm 						ret = sa_destroy_security(
943*4653Sdougm 						    security);
944*4653Sdougm 					if (secprot != NULL)
945*4653Sdougm 						sa_free_attr_string(secprot);
946*4653Sdougm 				}
947*4653Sdougm 			} else {
948*4653Sdougm 				if (!dryrun)
949*4653Sdougm 					ret = SA_INVALID_PROTOCOL;
9503034Sdougm 			}
9513034Sdougm 		}
9523034Sdougm 	}
953*4653Sdougm 
954*4653Sdougm done:
9553034Sdougm 	if (ret != SA_OK) {
956*4653Sdougm 		(void) printf(gettext("Could not delete group: %s\n"),
957*4653Sdougm 		    sa_errorstr(ret));
9583034Sdougm 	} else if (dryrun && !auth && verbose) {
959*4653Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
960*4653Sdougm 		    sa_errorstr(SA_NO_PERMISSION));
9613034Sdougm 	}
9623034Sdougm 	return (ret);
9633034Sdougm }
9643034Sdougm 
9653034Sdougm /*
9663034Sdougm  * strndupr(*buff, str, buffsize)
9673034Sdougm  *
9683034Sdougm  * used with small strings to duplicate and possibly increase the
9693034Sdougm  * buffer size of a string.
9703034Sdougm  */
9713034Sdougm static char *
9723034Sdougm strndupr(char *buff, char *str, int *buffsize)
9733034Sdougm {
9743034Sdougm 	int limit;
9753034Sdougm 	char *orig_buff = buff;
9763034Sdougm 
9773034Sdougm 	if (buff == NULL) {
978*4653Sdougm 		buff = (char *)malloc(64);
979*4653Sdougm 		if (buff == NULL)
980*4653Sdougm 			return (NULL);
981*4653Sdougm 		*buffsize = 64;
982*4653Sdougm 		buff[0] = '\0';
9833034Sdougm 	}
9843034Sdougm 	limit = strlen(buff) + strlen(str) + 1;
9853034Sdougm 	if (limit > *buffsize) {
986*4653Sdougm 		limit = *buffsize = *buffsize + ((limit / 64) + 64);
987*4653Sdougm 		buff = realloc(buff, limit);
9883034Sdougm 	}
9893034Sdougm 	if (buff != NULL) {
990*4653Sdougm 		(void) strcat(buff, str);
9913034Sdougm 	} else {
992*4653Sdougm 		/* if it fails, fail it hard */
993*4653Sdougm 		if (orig_buff != NULL)
994*4653Sdougm 			free(orig_buff);
9953034Sdougm 	}
9963034Sdougm 	return (buff);
9973034Sdougm }
9983034Sdougm 
9993034Sdougm /*
10003034Sdougm  * group_proto(group)
10013034Sdougm  *
10023034Sdougm  * return a string of all the protocols (space separated) associated
10033034Sdougm  * with this group.
10043034Sdougm  */
10053034Sdougm 
10063034Sdougm static char *
10073034Sdougm group_proto(sa_group_t group)
10083034Sdougm {
10093034Sdougm 	sa_optionset_t optionset;
10103034Sdougm 	char *proto;
10113034Sdougm 	char *buff = NULL;
10123034Sdougm 	int buffsize = 0;
10133034Sdougm 	int addspace = 0;
10143034Sdougm 	/*
10153034Sdougm 	 * get the protocol list by finding the optionsets on this
10163034Sdougm 	 * group and extracting the type value. The initial call to
10173034Sdougm 	 * strndupr() initailizes buff.
10183034Sdougm 	 */
10193034Sdougm 	buff = strndupr(buff, "", &buffsize);
10203034Sdougm 	if (buff != NULL) {
1021*4653Sdougm 		for (optionset = sa_get_optionset(group, NULL);
1022*4653Sdougm 		    optionset != NULL && buff != NULL;
1023*4653Sdougm 		    optionset = sa_get_next_optionset(optionset)) {
1024*4653Sdougm 			/*
1025*4653Sdougm 			 * extract out the protocol type from this optionset
1026*4653Sdougm 			 * and append it to the buffer "buff". strndupr() will
1027*4653Sdougm 			 * reallocate space as necessay.
1028*4653Sdougm 			 */
1029*4653Sdougm 			proto = sa_get_optionset_attr(optionset, "type");
1030*4653Sdougm 			if (proto != NULL) {
1031*4653Sdougm 				if (addspace++)
1032*4653Sdougm 					buff = strndupr(buff, " ", &buffsize);
1033*4653Sdougm 				buff = strndupr(buff, proto, &buffsize);
1034*4653Sdougm 				sa_free_attr_string(proto);
1035*4653Sdougm 			}
10363034Sdougm 		}
10373034Sdougm 	}
10383034Sdougm 	return (buff);
10393034Sdougm }
10403034Sdougm 
10413034Sdougm /*
10423034Sdougm  * sa_list(flags, argc, argv)
10433034Sdougm  *
10443034Sdougm  * implements the "list" subcommand to list groups and optionally
10453034Sdougm  * their state and protocols.
10463034Sdougm  */
10473034Sdougm 
1048*4653Sdougm /*ARGSUSED*/
10493034Sdougm static int
10503910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
10513034Sdougm {
10523034Sdougm 	sa_group_t group;
10533034Sdougm 	int verbose = 0;
10543034Sdougm 	int c;
10553034Sdougm 	char *protocol = NULL;
10563034Sdougm 
10573034Sdougm 	while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
1058*4653Sdougm 		switch (c) {
1059*4653Sdougm 		case 'v':
1060*4653Sdougm 			verbose++;
1061*4653Sdougm 			break;
1062*4653Sdougm 		case 'P':
1063*4653Sdougm 			protocol = optarg;
1064*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
1065*4653Sdougm 				(void) printf(gettext(
1066*4653Sdougm 				    "Invalid protocol specified: %s\n"),
1067*4653Sdougm 				    protocol);
1068*4653Sdougm 				return (SA_INVALID_PROTOCOL);
1069*4653Sdougm 			}
1070*4653Sdougm 			break;
1071*4653Sdougm 		default:
1072*4653Sdougm 		case 'h':
1073*4653Sdougm 		case '?':
1074*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1075*4653Sdougm 			    sa_get_usage(USAGE_LIST));
1076*4653Sdougm 			return (0);
10773034Sdougm 		}
10783034Sdougm 	}
10793034Sdougm 
1080*4653Sdougm 	for (group = sa_get_group(handle, NULL);
1081*4653Sdougm 	    group != NULL;
10823034Sdougm 	    group = sa_get_next_group(group)) {
1083*4653Sdougm 		char *name;
1084*4653Sdougm 		char *proto;
1085*4653Sdougm 		if (protocol == NULL || has_protocol(group, protocol)) {
1086*4653Sdougm 			name = sa_get_group_attr(group, "name");
1087*4653Sdougm 			if (name != NULL && (verbose > 1 || name[0] != '#')) {
1088*4653Sdougm 				(void) printf("%s", (char *)name);
1089*4653Sdougm 				if (verbose) {
1090*4653Sdougm 					/*
1091*4653Sdougm 					 * Need the list of protocols
1092*4653Sdougm 					 * and current status once
1093*4653Sdougm 					 * available. We do want to
1094*4653Sdougm 					 * translate the
1095*4653Sdougm 					 * enabled/disabled text here.
1096*4653Sdougm 					 */
1097*4653Sdougm 					(void) printf("\t%s", isenabled(group) ?
1098*4653Sdougm 					    gettext("enabled") :
1099*4653Sdougm 					    gettext("disabled"));
1100*4653Sdougm 					proto = group_proto(group);
1101*4653Sdougm 					if (proto != NULL) {
1102*4653Sdougm 						(void) printf("\t%s",
1103*4653Sdougm 						    (char *)proto);
1104*4653Sdougm 						free(proto);
1105*4653Sdougm 					}
1106*4653Sdougm 				}
1107*4653Sdougm 				(void) printf("\n");
11083034Sdougm 			}
1109*4653Sdougm 			if (name != NULL)
1110*4653Sdougm 				sa_free_attr_string(name);
11113034Sdougm 		}
11123034Sdougm 	}
11133034Sdougm 	return (0);
11143034Sdougm }
11153034Sdougm 
11163034Sdougm /*
11173034Sdougm  * out_properties(optionset, proto, sec)
11183034Sdougm  *
11193034Sdougm  * Format the properties and encode the protocol and optional named
11203034Sdougm  * optionset into the string.
11213034Sdougm  *
11223034Sdougm  * format is protocol[:name]=(property-list)
11233034Sdougm  */
11243034Sdougm 
11253034Sdougm static void
11263034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec)
11273034Sdougm {
11283034Sdougm 	char *type;
11293034Sdougm 	char *value;
11303034Sdougm 	int spacer;
11313034Sdougm 	sa_property_t prop;
11323034Sdougm 
1133*4653Sdougm 	if (sec == NULL)
1134*4653Sdougm 		(void) printf(" %s=(", proto ? proto : gettext("all"));
1135*4653Sdougm 	else
1136*4653Sdougm 		(void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
11373034Sdougm 
11383034Sdougm 	for (spacer = 0, prop = sa_get_property(optionset, NULL);
1139*4653Sdougm 	    prop != NULL;
1140*4653Sdougm 	    prop = sa_get_next_property(prop)) {
11413034Sdougm 
11423034Sdougm 		/*
11433034Sdougm 		 * extract the property name/value and output with
11443034Sdougm 		 * appropriate spacing. I.e. no prefixed space the
11453034Sdougm 		 * first time through but a space on subsequent
11463034Sdougm 		 * properties.
11473034Sdougm 		 */
1148*4653Sdougm 		type = sa_get_property_attr(prop, "type");
1149*4653Sdougm 		value = sa_get_property_attr(prop, "value");
1150*4653Sdougm 		if (type != NULL) {
1151*4653Sdougm 			(void) printf("%s%s=", spacer ? " " : "",	type);
1152*4653Sdougm 			spacer = 1;
1153*4653Sdougm 			if (value != NULL)
1154*4653Sdougm 				(void) printf("\"%s\"", value);
1155*4653Sdougm 			else
1156*4653Sdougm 				(void) printf("\"\"");
1157*4653Sdougm 		}
1158*4653Sdougm 		if (type != NULL)
1159*4653Sdougm 			sa_free_attr_string(type);
11603034Sdougm 		if (value != NULL)
1161*4653Sdougm 			sa_free_attr_string(value);
11623034Sdougm 	}
11633034Sdougm 	(void) printf(")");
11643034Sdougm }
11653034Sdougm 
11663034Sdougm /*
11673034Sdougm  * show_properties(group, protocol, prefix)
11683034Sdougm  *
11693034Sdougm  * print the properties for a group. If protocol is NULL, do all
11703034Sdougm  * protocols otherwise only the specified protocol. All security
11713034Sdougm  * (named groups specific to the protocol) are included.
11723034Sdougm  *
11733034Sdougm  * The "prefix" is always applied. The caller knows whether it wants
11743034Sdougm  * some type of prefix string (white space) or not.  Once the prefix
11753034Sdougm  * has been output, it is reduced to the zero length string for the
11763034Sdougm  * remainder of the property output.
11773034Sdougm  */
11783034Sdougm 
11793034Sdougm static void
11803034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix)
11813034Sdougm {
11823034Sdougm 	sa_optionset_t optionset;
11833034Sdougm 	sa_security_t security;
11843034Sdougm 	char *value;
11853034Sdougm 	char *secvalue;
11863034Sdougm 
11873034Sdougm 	if (protocol != NULL) {
1188*4653Sdougm 		optionset = sa_get_optionset(group, protocol);
1189*4653Sdougm 		if (optionset != NULL) {
1190*4653Sdougm 			(void) printf("%s", prefix);
1191*4653Sdougm 			prefix = "";
1192*4653Sdougm 			out_properties(optionset, protocol, NULL);
1193*4653Sdougm 		}
1194*4653Sdougm 		security = sa_get_security(group, protocol, NULL);
1195*4653Sdougm 		if (security != NULL) {
1196*4653Sdougm 			(void) printf("%s", prefix);
1197*4653Sdougm 			prefix = "";
1198*4653Sdougm 			out_properties(security, protocol, NULL);
1199*4653Sdougm 		}
12003034Sdougm 	} else {
1201*4653Sdougm 		for (optionset = sa_get_optionset(group, protocol);
1202*4653Sdougm 		    optionset != NULL;
1203*4653Sdougm 		    optionset = sa_get_next_optionset(optionset)) {
1204*4653Sdougm 
1205*4653Sdougm 			value = sa_get_optionset_attr(optionset, "type");
1206*4653Sdougm 			(void) printf("%s", prefix);
1207*4653Sdougm 			prefix = "";
1208*4653Sdougm 			out_properties(optionset, value, 0);
1209*4653Sdougm 			if (value != NULL)
1210*4653Sdougm 				sa_free_attr_string(value);
1211*4653Sdougm 		}
1212*4653Sdougm 		for (security = sa_get_security(group, NULL, protocol);
1213*4653Sdougm 		    security != NULL;
1214*4653Sdougm 		    security = sa_get_next_security(security)) {
1215*4653Sdougm 
1216*4653Sdougm 			value = sa_get_security_attr(security, "type");
1217*4653Sdougm 			secvalue = sa_get_security_attr(security, "sectype");
1218*4653Sdougm 			(void) printf("%s", prefix);
1219*4653Sdougm 			prefix = "";
1220*4653Sdougm 			out_properties(security, value, secvalue);
1221*4653Sdougm 			if (value != NULL)
1222*4653Sdougm 				sa_free_attr_string(value);
1223*4653Sdougm 			if (secvalue != NULL)
1224*4653Sdougm 				sa_free_attr_string(secvalue);
1225*4653Sdougm 		}
12263034Sdougm 	}
12273034Sdougm }
12283034Sdougm 
12293034Sdougm /*
12303034Sdougm  * show_group(group, verbose, properties, proto, subgroup)
12313034Sdougm  *
12323034Sdougm  * helper function to show the contents of a group.
12333034Sdougm  */
12343034Sdougm 
12353034Sdougm static void
12363034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto,
12373034Sdougm 		char *subgroup)
12383034Sdougm {
12393034Sdougm 	sa_share_t share;
12403034Sdougm 	char *groupname;
12413034Sdougm 	char *sharepath;
12423034Sdougm 	char *resource;
12433034Sdougm 	char *description;
12443034Sdougm 	char *type;
12453034Sdougm 	char *zfs = NULL;
12463034Sdougm 	int iszfs = 0;
12473034Sdougm 
12483034Sdougm 	groupname = sa_get_group_attr(group, "name");
12493034Sdougm 	if (groupname != NULL) {
1250*4653Sdougm 		if (proto != NULL && !has_protocol(group, proto)) {
1251*4653Sdougm 			sa_free_attr_string(groupname);
1252*4653Sdougm 			return;
1253*4653Sdougm 		}
12543034Sdougm 		/*
12553034Sdougm 		 * check to see if the group is managed by ZFS. If
12563034Sdougm 		 * there is an attribute, then it is. A non-NULL zfs
12573034Sdougm 		 * variable will trigger the different way to display
12583034Sdougm 		 * and will remove the transient property indicator
12593034Sdougm 		 * from the output.
12603034Sdougm 		 */
1261*4653Sdougm 		zfs = sa_get_group_attr(group, "zfs");
1262*4653Sdougm 		if (zfs != NULL) {
1263*4653Sdougm 			iszfs = 1;
1264*4653Sdougm 			sa_free_attr_string(zfs);
12653034Sdougm 		}
1266*4653Sdougm 		share = sa_get_share(group, NULL);
1267*4653Sdougm 		if (subgroup == NULL)
1268*4653Sdougm 			(void) printf("%s", groupname);
1269*4653Sdougm 		else
1270*4653Sdougm 			(void) printf("    %s/%s", subgroup, groupname);
1271*4653Sdougm 		if (properties)
1272*4653Sdougm 			show_properties(group, proto, "");
1273*4653Sdougm 		(void) printf("\n");
1274*4653Sdougm 		if (strcmp(groupname, "zfs") == 0) {
1275*4653Sdougm 			sa_group_t zgroup;
1276*4653Sdougm 
1277*4653Sdougm 			for (zgroup = sa_get_sub_group(group);
1278*4653Sdougm 			    zgroup != NULL;
1279*4653Sdougm 			    zgroup = sa_get_next_group(zgroup)) {
1280*4653Sdougm 				show_group(zgroup, verbose, properties, proto,
1281*4653Sdougm 				    "zfs");
1282*4653Sdougm 			}
1283*4653Sdougm 			sa_free_attr_string(groupname);
1284*4653Sdougm 			return;
1285*4653Sdougm 		}
12863034Sdougm 		/*
1287*4653Sdougm 		 * Have a group, so list the contents. Resource and
12883034Sdougm 		 * description are only listed if verbose is set.
12893034Sdougm 		 */
1290*4653Sdougm 		for (share = sa_get_share(group, NULL);
1291*4653Sdougm 		    share != NULL;
1292*4653Sdougm 		    share = sa_get_next_share(share)) {
1293*4653Sdougm 			sharepath = sa_get_share_attr(share, "path");
1294*4653Sdougm 			if (sharepath != NULL) {
1295*4653Sdougm 				if (verbose) {
1296*4653Sdougm 					resource = sa_get_share_attr(share,
1297*4653Sdougm 					    "resource");
1298*4653Sdougm 					description =
1299*4653Sdougm 					    sa_get_share_description(share);
1300*4653Sdougm 					type = sa_get_share_attr(share,
1301*4653Sdougm 					    "type");
1302*4653Sdougm 					if (type != NULL && !iszfs &&
1303*4653Sdougm 					    strcmp(type, "transient") == 0)
1304*4653Sdougm 						(void) printf("\t* ");
1305*4653Sdougm 					else
1306*4653Sdougm 						(void) printf("\t  ");
1307*4653Sdougm 					if (resource != NULL &&
1308*4653Sdougm 					    strlen(resource) > 0) {
1309*4653Sdougm 						(void) printf("%s=%s",
1310*4653Sdougm 						    resource, sharepath);
1311*4653Sdougm 					} else {
1312*4653Sdougm 						(void) printf("%s", sharepath);
1313*4653Sdougm 					}
1314*4653Sdougm 					if (resource != NULL)
1315*4653Sdougm 						sa_free_attr_string(resource);
1316*4653Sdougm 					if (properties)
1317*4653Sdougm 						show_properties(share, NULL,
1318*4653Sdougm 						    "\t");
1319*4653Sdougm 					if (description != NULL) {
1320*4653Sdougm 						if (strlen(description) > 0) {
1321*4653Sdougm 							(void) printf(
1322*4653Sdougm 							    "\t\"%s\"",
1323*4653Sdougm 							    description);
1324*4653Sdougm 						}
1325*4653Sdougm 						sa_free_share_description(
1326*4653Sdougm 						    description);
1327*4653Sdougm 					}
1328*4653Sdougm 					if (type != NULL)
1329*4653Sdougm 						sa_free_attr_string(type);
1330*4653Sdougm 				} else {
1331*4653Sdougm 					(void) printf("\t%s", sharepath);
1332*4653Sdougm 					if (properties)
1333*4653Sdougm 						show_properties(share, NULL,
1334*4653Sdougm 						    "\t");
1335*4653Sdougm 				}
1336*4653Sdougm 				(void) printf("\n");
1337*4653Sdougm 				sa_free_attr_string(sharepath);
13383034Sdougm 			}
13393034Sdougm 		}
13403034Sdougm 	}
13413034Sdougm 	if (groupname != NULL) {
13423034Sdougm 		sa_free_attr_string(groupname);
13433034Sdougm 	}
13443034Sdougm }
13453034Sdougm 
13463034Sdougm /*
13473034Sdougm  * show_group_xml_init()
13483034Sdougm  *
13493034Sdougm  * Create an XML document that will be used to display config info via
13503034Sdougm  * XML format.
13513034Sdougm  */
13523034Sdougm 
13533034Sdougm xmlDocPtr
13543034Sdougm show_group_xml_init()
13553034Sdougm {
13563034Sdougm 	xmlDocPtr doc;
13573034Sdougm 	xmlNodePtr root;
13583034Sdougm 
13593034Sdougm 	doc = xmlNewDoc((xmlChar *)"1.0");
13603034Sdougm 	if (doc != NULL) {
1361*4653Sdougm 		root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
1362*4653Sdougm 		if (root != NULL)
1363*4653Sdougm 			xmlDocSetRootElement(doc, root);
13643034Sdougm 	}
13653034Sdougm 	return (doc);
13663034Sdougm }
13673034Sdougm 
13683034Sdougm /*
13693034Sdougm  * show_group_xml(doc, group)
13703034Sdougm  *
13713034Sdougm  * Copy the group info into the XML doc.
13723034Sdougm  */
13733034Sdougm 
13743034Sdougm static void
13753034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group)
13763034Sdougm {
13773034Sdougm 	xmlNodePtr node;
13783034Sdougm 	xmlNodePtr root;
13793034Sdougm 
13803034Sdougm 	root = xmlDocGetRootElement(doc);
13813034Sdougm 	node = xmlCopyNode((xmlNodePtr)group, 1);
13823034Sdougm 	if (node != NULL && root != NULL) {
1383*4653Sdougm 		xmlAddChild(root, node);
13843034Sdougm 		/*
13853034Sdougm 		 * In the future, we may have interally used tags that
13863034Sdougm 		 * should not appear in the XML output. Remove
13873034Sdougm 		 * anything we don't want to show here.
13883034Sdougm 		 */
13893034Sdougm 	}
13903034Sdougm }
13913034Sdougm 
13923034Sdougm /*
13933034Sdougm  * sa_show(flags, argc, argv)
13943034Sdougm  *
13953034Sdougm  * Implements the show subcommand.
13963034Sdougm  */
13973034Sdougm 
1398*4653Sdougm /*ARGSUSED*/
13993034Sdougm int
14003910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
14013034Sdougm {
14023034Sdougm 	sa_group_t group;
14033034Sdougm 	int verbose = 0;
14043034Sdougm 	int properties = 0;
14053034Sdougm 	int c;
14063034Sdougm 	int ret = SA_OK;
14073034Sdougm 	char *protocol = NULL;
14083034Sdougm 	int xml = 0;
14093034Sdougm 	xmlDocPtr doc;
14103034Sdougm 
14113034Sdougm 	while ((c = getopt(argc, argv, "?hvP:px")) !=	EOF) {
1412*4653Sdougm 		switch (c) {
1413*4653Sdougm 		case 'v':
1414*4653Sdougm 			verbose++;
1415*4653Sdougm 			break;
1416*4653Sdougm 		case 'p':
1417*4653Sdougm 			properties++;
1418*4653Sdougm 			break;
1419*4653Sdougm 		case 'P':
1420*4653Sdougm 			protocol = optarg;
1421*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
1422*4653Sdougm 				(void) printf(gettext(
1423*4653Sdougm 				    "Invalid protocol specified: %s\n"),
1424*4653Sdougm 				    protocol);
1425*4653Sdougm 				return (SA_INVALID_PROTOCOL);
1426*4653Sdougm 			}
1427*4653Sdougm 			break;
1428*4653Sdougm 		case 'x':
1429*4653Sdougm 			xml++;
1430*4653Sdougm 			break;
1431*4653Sdougm 		default:
1432*4653Sdougm 		case 'h':
1433*4653Sdougm 		case '?':
1434*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1435*4653Sdougm 			    sa_get_usage(USAGE_SHOW));
1436*4653Sdougm 			return (0);
14373034Sdougm 		}
14383034Sdougm 	}
14393034Sdougm 
14403034Sdougm 	if (xml) {
1441*4653Sdougm 		doc = show_group_xml_init();
1442*4653Sdougm 		if (doc == NULL)
1443*4653Sdougm 			ret = SA_NO_MEMORY;
14443034Sdougm 	}
14453034Sdougm 
14463034Sdougm 	if (optind == argc) {
1447*4653Sdougm 		/* No group specified so go through them all */
1448*4653Sdougm 		for (group = sa_get_group(handle, NULL);
1449*4653Sdougm 		    group != NULL;
1450*4653Sdougm 		    group = sa_get_next_group(group)) {
1451*4653Sdougm 			/*
1452*4653Sdougm 			 * Have a group so check if one we want and then list
1453*4653Sdougm 			 * contents with appropriate options.
1454*4653Sdougm 			 */
1455*4653Sdougm 			if (xml)
1456*4653Sdougm 				show_group_xml(doc, group);
1457*4653Sdougm 			else
1458*4653Sdougm 				show_group(group, verbose, properties, protocol,
1459*4653Sdougm 				    NULL);
1460*4653Sdougm 		}
14613034Sdougm 	} else {
1462*4653Sdougm 		/* Have a specified list of groups */
1463*4653Sdougm 		for (; optind < argc; optind++) {
1464*4653Sdougm 			group = sa_get_group(handle, argv[optind]);
1465*4653Sdougm 			if (group != NULL) {
1466*4653Sdougm 				if (xml)
1467*4653Sdougm 					show_group_xml(doc, group);
1468*4653Sdougm 				else
1469*4653Sdougm 					show_group(group, verbose, properties,
1470*4653Sdougm 					    protocol, NULL);
1471*4653Sdougm 			} else {
1472*4653Sdougm 				(void) printf(gettext("%s: not found\n"),
1473*4653Sdougm 				    argv[optind]);
1474*4653Sdougm 				ret = SA_NO_SUCH_GROUP;
1475*4653Sdougm 			}
14763034Sdougm 		}
14773034Sdougm 	}
14783034Sdougm 	if (xml && ret == SA_OK) {
1479*4653Sdougm 		xmlDocFormatDump(stdout, doc, 1);
1480*4653Sdougm 		xmlFreeDoc(doc);
14813034Sdougm 	}
14823034Sdougm 	return (ret);
14833034Sdougm 
14843034Sdougm }
14853034Sdougm 
14863034Sdougm /*
14873034Sdougm  * enable_share(group, share, update_legacy)
14883034Sdougm  *
14893034Sdougm  * helper function to enable a share if the group is enabled.
14903034Sdougm  */
14913034Sdougm 
14923034Sdougm static int
14933910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
14943910Sdougm 		int update_legacy)
14953034Sdougm {
14963034Sdougm 	char *value;
14973034Sdougm 	int enabled;
14983034Sdougm 	sa_optionset_t optionset;
14993034Sdougm 	int ret = SA_OK;
15003034Sdougm 	char *zfs = NULL;
15013034Sdougm 	int iszfs = 0;
15023034Sdougm 
15033034Sdougm 	/*
15043034Sdougm 	 * need to enable this share if the group is enabled but not
15053034Sdougm 	 * otherwise. The enable is also done on each protocol
15063034Sdougm 	 * represented in the group.
15073034Sdougm 	 */
15083034Sdougm 	value = sa_get_group_attr(group, "state");
15093034Sdougm 	enabled = value != NULL && strcmp(value, "enabled") == 0;
15103034Sdougm 	if (value != NULL)
1511*4653Sdougm 		sa_free_attr_string(value);
15123034Sdougm 	/* remove legacy config if necessary */
15133034Sdougm 	if (update_legacy)
1514*4653Sdougm 		ret = sa_delete_legacy(share);
15153034Sdougm 	zfs = sa_get_group_attr(group, "zfs");
15163034Sdougm 	if (zfs != NULL) {
1517*4653Sdougm 		iszfs++;
1518*4653Sdougm 		sa_free_attr_string(zfs);
15193034Sdougm 	}
15203034Sdougm 
15213034Sdougm 	/*
15223034Sdougm 	 * Step through each optionset at the group level and
15233034Sdougm 	 * enable the share based on the protocol type. This
15243034Sdougm 	 * works because protocols must be set on the group
15253034Sdougm 	 * for the protocol to be enabled.
15263034Sdougm 	 */
15273034Sdougm 	for (optionset = sa_get_optionset(group, NULL);
15283034Sdougm 	    optionset != NULL && ret == SA_OK;
15293034Sdougm 	    optionset = sa_get_next_optionset(optionset)) {
1530*4653Sdougm 		value = sa_get_optionset_attr(optionset, "type");
1531*4653Sdougm 		if (value != NULL) {
1532*4653Sdougm 			if (enabled)
1533*4653Sdougm 				ret = sa_enable_share(share, value);
1534*4653Sdougm 			if (update_legacy && !iszfs)
1535*4653Sdougm 				(void) sa_update_legacy(share, value);
1536*4653Sdougm 			sa_free_attr_string(value);
1537*4653Sdougm 		}
15383034Sdougm 	}
15393034Sdougm 	if (ret == SA_OK)
1540*4653Sdougm 		(void) sa_update_config(handle);
15413034Sdougm 	return (ret);
15423034Sdougm }
15433034Sdougm 
15443034Sdougm /*
15453034Sdougm  * sa_addshare(flags, argc, argv)
15463034Sdougm  *
15473034Sdougm  * implements add-share subcommand.
15483034Sdougm  */
15493034Sdougm 
15503034Sdougm int
15513910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
15523034Sdougm {
15533034Sdougm 	int verbose = 0;
15543034Sdougm 	int dryrun = 0;
15553034Sdougm 	int c;
15563034Sdougm 	int ret = SA_OK;
15573034Sdougm 	sa_group_t group;
15583034Sdougm 	sa_share_t share;
15593034Sdougm 	char *sharepath = NULL;
15603034Sdougm 	char *description = NULL;
15613034Sdougm 	char *resource = NULL;
15623034Sdougm 	int persist = SA_SHARE_PERMANENT; /* default to persist */
15633034Sdougm 	int auth;
15643034Sdougm 	char dir[MAXPATHLEN];
15653034Sdougm 
15663034Sdougm 	while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
1567*4653Sdougm 		switch (c) {
1568*4653Sdougm 		case 'n':
1569*4653Sdougm 			dryrun++;
1570*4653Sdougm 			break;
1571*4653Sdougm 		case 'v':
1572*4653Sdougm 			verbose++;
1573*4653Sdougm 			break;
1574*4653Sdougm 		case 'd':
1575*4653Sdougm 			description = optarg;
1576*4653Sdougm 			break;
1577*4653Sdougm 		case 'r':
1578*4653Sdougm 			resource = optarg;
1579*4653Sdougm 			break;
1580*4653Sdougm 		case 's':
1581*4653Sdougm 			/*
1582*4653Sdougm 			 * Save share path into group. Currently limit
1583*4653Sdougm 			 * to one share per command.
1584*4653Sdougm 			 */
1585*4653Sdougm 			if (sharepath != NULL) {
1586*4653Sdougm 				(void) printf(gettext(
1587*4653Sdougm 				    "Adding multiple shares not supported\n"));
1588*4653Sdougm 				return (1);
1589*4653Sdougm 			}
1590*4653Sdougm 			sharepath = optarg;
1591*4653Sdougm 			break;
1592*4653Sdougm 		case 't':
1593*4653Sdougm 			persist = SA_SHARE_TRANSIENT;
1594*4653Sdougm 			break;
1595*4653Sdougm 		default:
1596*4653Sdougm 		case 'h':
1597*4653Sdougm 		case '?':
1598*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1599*4653Sdougm 			    sa_get_usage(USAGE_ADD_SHARE));
1600*4653Sdougm 			return (0);
16013034Sdougm 		}
16023034Sdougm 	}
16033034Sdougm 
16043034Sdougm 	if (optind >= argc) {
1605*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
1606*4653Sdougm 		    sa_get_usage(USAGE_ADD_SHARE));
1607*4653Sdougm 		if (dryrun || sharepath != NULL || description != NULL ||
1608*4653Sdougm 		    resource != NULL || verbose || persist) {
1609*4653Sdougm 			(void) printf(gettext("\tgroup must be specified\n"));
1610*4653Sdougm 			ret = SA_NO_SUCH_GROUP;
1611*4653Sdougm 		} else {
1612*4653Sdougm 			ret = SA_OK;
1613*4653Sdougm 		}
16143034Sdougm 	} else {
1615*4653Sdougm 		if (sharepath == NULL) {
1616*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1617*4653Sdougm 			    sa_get_usage(USAGE_ADD_SHARE));
1618*4653Sdougm 			(void) printf(gettext(
1619*4653Sdougm 			    "\t-s sharepath must be specified\n"));
1620*4653Sdougm 			return (SA_BAD_PATH);
1621*4653Sdougm 		}
16223034Sdougm 		if (realpath(sharepath, dir) == NULL) {
1623*4653Sdougm 			(void) printf(gettext(
1624*4653Sdougm 			    "Path is not valid: %s\n"), sharepath);
1625*4653Sdougm 			return (SA_BAD_PATH);
16263034Sdougm 		} else {
1627*4653Sdougm 			sharepath = dir;
16283034Sdougm 		}
1629*4653Sdougm 
1630*4653Sdougm 		/* Check for valid syntax */
1631*4653Sdougm 		if (resource != NULL && strpbrk(resource, " \t/") != NULL) {
1632*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1633*4653Sdougm 			    sa_get_usage(USAGE_ADD_SHARE));
1634*4653Sdougm 			(void) printf(gettext(
1635*4653Sdougm 			    "\tresource must not contain white"
1636*4653Sdougm 			    "space or '/' characters\n"));
1637*4653Sdougm 			return (SA_BAD_PATH);
16383034Sdougm 		}
16393910Sdougm 		group = sa_get_group(handle, argv[optind]);
1640*4653Sdougm 		if (group == NULL) {
1641*4653Sdougm 			(void) printf(gettext("Group \"%s\" not found\n"),
1642*4653Sdougm 			    argv[optind]);
1643*4653Sdougm 			return (SA_NO_SUCH_GROUP);
1644*4653Sdougm 		}
1645*4653Sdougm 		auth = check_authorizations(argv[optind],  flags);
1646*4653Sdougm 		share = sa_find_share(handle, sharepath);
1647*4653Sdougm 		if (share != NULL) {
16483034Sdougm 			group = sa_get_parent_group(share);
16493034Sdougm 			if (group != NULL) {
1650*4653Sdougm 				char *groupname;
1651*4653Sdougm 				groupname = sa_get_group_attr(
1652*4653Sdougm 				    group, "name");
1653*4653Sdougm 				if (groupname != NULL) {
1654*4653Sdougm 					(void) printf(gettext(
1655*4653Sdougm 					    "Share path already "
1656*4653Sdougm 					    "shared in group "
1657*4653Sdougm 					    "\"%s\": %s\n"),
1658*4653Sdougm 					    groupname, sharepath);
1659*4653Sdougm 					sa_free_attr_string(groupname);
1660*4653Sdougm 				} else {
1661*4653Sdougm 					(void) printf(gettext(
1662*4653Sdougm 					    "Share path already"
1663*4653Sdougm 					    "shared: %s\n"),
1664*4653Sdougm 					    groupname, sharepath);
1665*4653Sdougm 				}
16663034Sdougm 			} else {
1667*4653Sdougm 				(void) printf(gettext(
1668*4653Sdougm 				    "Share path %s already shared\n"),
16693034Sdougm 				    sharepath);
16703034Sdougm 			}
1671*4653Sdougm 			return (SA_DUPLICATE_NAME);
1672*4653Sdougm 		} else {
16733034Sdougm 			/*
1674*4653Sdougm 			 * Need to check that resource name is
1675*4653Sdougm 			 * unique at some point. Path checking
1676*4653Sdougm 			 * should use the "normal" rules which
1677*4653Sdougm 			 * don't check the repository.
16783034Sdougm 			 */
16793034Sdougm 			if (dryrun)
1680*4653Sdougm 				ret = sa_check_path(group, sharepath,
1681*4653Sdougm 				    SA_CHECK_NORMAL);
16823034Sdougm 			else
1683*4653Sdougm 				share = sa_add_share(group, sharepath,
1684*4653Sdougm 				    persist, &ret);
16853034Sdougm 			if (!dryrun && share == NULL) {
1686*4653Sdougm 				(void) printf(gettext(
1687*4653Sdougm 				    "Could not add share: %s\n"),
1688*4653Sdougm 				    sa_errorstr(ret));
16893034Sdougm 			} else {
1690*4653Sdougm 				if (!dryrun && ret == SA_OK) {
1691*4653Sdougm 					if (resource != NULL &&
1692*4653Sdougm 					    strpbrk(resource, " \t/") == NULL) {
1693*4653Sdougm 						ret = sa_set_share_attr(share,
1694*4653Sdougm 						    "resource", resource);
1695*4653Sdougm 					}
1696*4653Sdougm 					if (ret == SA_OK &&
1697*4653Sdougm 					    description != NULL) {
1698*4653Sdougm 						ret = sa_set_share_description(
1699*4653Sdougm 						    share, description);
1700*4653Sdougm 					}
1701*4653Sdougm 					if (ret == SA_OK) {
1702*4653Sdougm 						/* Now enable the share(s) */
1703*4653Sdougm 						ret = enable_share(handle,
1704*4653Sdougm 						    group, share, 1);
1705*4653Sdougm 						ret = sa_update_config(handle);
1706*4653Sdougm 					}
1707*4653Sdougm 					switch (ret) {
1708*4653Sdougm 					case SA_DUPLICATE_NAME:
1709*4653Sdougm 						(void) printf(gettext(
1710*4653Sdougm 						    "Resource name in"
1711*4653Sdougm 						    "use: %s\n"), resource);
1712*4653Sdougm 						break;
1713*4653Sdougm 					default:
1714*4653Sdougm 						(void) printf(
1715*4653Sdougm 						    gettext("Could not set "
1716*4653Sdougm 						    "attribute: %s\n"),
1717*4653Sdougm 						    sa_errorstr(ret));
1718*4653Sdougm 						break;
1719*4653Sdougm 					case SA_OK:
1720*4653Sdougm 						break;
1721*4653Sdougm 					}
1722*4653Sdougm 				} else if (dryrun && ret == SA_OK && !auth &&
1723*4653Sdougm 				    verbose) {
1724*4653Sdougm 					(void) printf(gettext(
1725*4653Sdougm 					    "Command would fail: %s\n"),
1726*4653Sdougm 					    sa_errorstr(SA_NO_PERMISSION));
1727*4653Sdougm 					ret = SA_NO_PERMISSION;
17283034Sdougm 				}
17293034Sdougm 			}
17303034Sdougm 		}
17313034Sdougm 	}
17323034Sdougm 	return (ret);
17333034Sdougm }
17343034Sdougm 
17353034Sdougm /*
17363034Sdougm  * sa_moveshare(flags, argc, argv)
17373034Sdougm  *
17383034Sdougm  * implements move-share subcommand.
17393034Sdougm  */
17403034Sdougm 
17413034Sdougm int
17423910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
17433034Sdougm {
17443034Sdougm 	int verbose = 0;
17453034Sdougm 	int dryrun = 0;
17463034Sdougm 	int c;
17473034Sdougm 	int ret = SA_OK;
17483034Sdougm 	sa_group_t group;
17493034Sdougm 	sa_share_t share;
17503034Sdougm 	char *sharepath = NULL;
17513034Sdougm 	int authsrc = 0, authdst = 0;
17523034Sdougm 
17533034Sdougm 	while ((c = getopt(argc, argv, "?hvns:")) != EOF) {
1754*4653Sdougm 		switch (c) {
1755*4653Sdougm 		case 'n':
1756*4653Sdougm 			dryrun++;
1757*4653Sdougm 			break;
1758*4653Sdougm 		case 'v':
1759*4653Sdougm 			verbose++;
1760*4653Sdougm 			break;
1761*4653Sdougm 		case 's':
1762*4653Sdougm 			/*
1763*4653Sdougm 			 * Remove share path from group. Currently limit
1764*4653Sdougm 			 * to one share per command.
1765*4653Sdougm 			 */
1766*4653Sdougm 			if (sharepath != NULL) {
1767*4653Sdougm 				(void) printf(gettext("Moving multiple shares"
1768*4653Sdougm 				    "not supported\n"));
1769*4653Sdougm 				return (SA_BAD_PATH);
1770*4653Sdougm 			}
1771*4653Sdougm 			sharepath = optarg;
1772*4653Sdougm 			break;
1773*4653Sdougm 		default:
1774*4653Sdougm 		case 'h':
1775*4653Sdougm 		case '?':
1776*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1777*4653Sdougm 			    sa_get_usage(USAGE_MOVE_SHARE));
1778*4653Sdougm 			return (0);
17793034Sdougm 		}
17803034Sdougm 	}
17813034Sdougm 
17823034Sdougm 	if (optind >= argc || sharepath == NULL) {
17833034Sdougm 			(void) printf(gettext("usage: %s\n"),
1784*4653Sdougm 			    sa_get_usage(USAGE_MOVE_SHARE));
1785*4653Sdougm 			if (dryrun || verbose || sharepath != NULL) {
1786*4653Sdougm 				(void) printf(gettext(
1787*4653Sdougm 				    "\tgroup must be specified\n"));
1788*4653Sdougm 				ret = SA_NO_SUCH_GROUP;
1789*4653Sdougm 			} else {
1790*4653Sdougm 				if (sharepath == NULL) {
1791*4653Sdougm 					ret = SA_SYNTAX_ERR;
1792*4653Sdougm 					(void) printf(gettext(
1793*4653Sdougm 					    "\tsharepath must be specified\n"));
1794*4653Sdougm 				} else {
1795*4653Sdougm 					ret = SA_OK;
1796*4653Sdougm 				}
1797*4653Sdougm 			}
1798*4653Sdougm 	} else {
1799*4653Sdougm 		sa_group_t parent;
1800*4653Sdougm 		char *zfsold;
1801*4653Sdougm 		char *zfsnew;
1802*4653Sdougm 
18033034Sdougm 		if (sharepath == NULL) {
1804*4653Sdougm 			(void) printf(gettext(
1805*4653Sdougm 			    "sharepath must be specified with the -s "
1806*4653Sdougm 			    "option\n"));
1807*4653Sdougm 			return (SA_BAD_PATH);
1808*4653Sdougm 		}
18093910Sdougm 		group = sa_get_group(handle, argv[optind]);
1810*4653Sdougm 		if (group == NULL) {
1811*4653Sdougm 			(void) printf(gettext("Group \"%s\" not found\n"),
1812*4653Sdougm 			    argv[optind]);
1813*4653Sdougm 			return (SA_NO_SUCH_GROUP);
1814*4653Sdougm 		}
1815*4653Sdougm 		share = sa_find_share(handle, sharepath);
1816*4653Sdougm 		authdst = check_authorizations(argv[optind], flags);
1817*4653Sdougm 		if (share == NULL) {
18183034Sdougm 			(void) printf(gettext("Share not found: %s\n"),
1819*4653Sdougm 			    sharepath);
1820*4653Sdougm 			return (SA_NO_SUCH_PATH);
1821*4653Sdougm 		}
1822*4653Sdougm 
1823*4653Sdougm 		parent = sa_get_parent_group(share);
1824*4653Sdougm 		if (parent != NULL) {
1825*4653Sdougm 			char *pname;
1826*4653Sdougm 			pname = sa_get_group_attr(parent, "name");
1827*4653Sdougm 			if (pname != NULL) {
18283034Sdougm 				authsrc = check_authorizations(pname, flags);
18293034Sdougm 				sa_free_attr_string(pname);
1830*4653Sdougm 			}
1831*4653Sdougm 			zfsold = sa_get_group_attr(parent, "zfs");
1832*4653Sdougm 			zfsnew = sa_get_group_attr(group, "zfs");
1833*4653Sdougm 			if ((zfsold != NULL && zfsnew == NULL) ||
1834*4653Sdougm 			    (zfsold == NULL && zfsnew != NULL)) {
18353034Sdougm 				ret = SA_NOT_ALLOWED;
18363034Sdougm 			}
1837*4653Sdougm 			if (zfsold != NULL)
1838*4653Sdougm 				sa_free_attr_string(zfsold);
1839*4653Sdougm 			if (zfsnew != NULL)
1840*4653Sdougm 				sa_free_attr_string(zfsnew);
1841*4653Sdougm 		}
1842*4653Sdougm 		if (!dryrun && ret == SA_OK)
1843*4653Sdougm 			ret = sa_move_share(group, share);
1844*4653Sdougm 
1845*4653Sdougm 		if (ret == SA_OK && parent != group && !dryrun) {
1846*4653Sdougm 			char *oldstate;
1847*4653Sdougm 			ret = sa_update_config(handle);
1848*4653Sdougm 			/*
1849*4653Sdougm 			 * Note that the share may need to be
1850*4653Sdougm 			 * "unshared" if the new group is
1851*4653Sdougm 			 * disabled and the old was enabled or
1852*4653Sdougm 			 * it may need to be share to update
1853*4653Sdougm 			 * if the new group is enabled.
1854*4653Sdougm 			 */
1855*4653Sdougm 			oldstate = sa_get_group_attr(parent, "state");
1856*4653Sdougm 
1857*4653Sdougm 			/* enable_share determines what to do */
1858*4653Sdougm 			if (strcmp(oldstate, "enabled") == 0) {
18593034Sdougm 				(void) sa_disable_share(share, NULL);
1860*4653Sdougm 			}
1861*4653Sdougm 			(void) enable_share(handle, group, share, 1);
1862*4653Sdougm 			if (oldstate != NULL)
18633034Sdougm 				sa_free_attr_string(oldstate);
18643034Sdougm 		}
1865*4653Sdougm 
1866*4653Sdougm 		if (ret != SA_OK)
1867*4653Sdougm 			(void) printf(gettext("Could not move share: %s\n"),
1868*4653Sdougm 			    sa_errorstr(ret));
1869*4653Sdougm 
1870*4653Sdougm 		if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
1871*4653Sdougm 		    verbose) {
1872*4653Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
1873*4653Sdougm 			    sa_errorstr(SA_NO_PERMISSION));
1874*4653Sdougm 		}
18753034Sdougm 	}
18763034Sdougm 	return (ret);
18773034Sdougm }
18783034Sdougm 
18793034Sdougm /*
18803034Sdougm  * sa_removeshare(flags, argc, argv)
18813034Sdougm  *
18823034Sdougm  * implements remove-share subcommand.
18833034Sdougm  */
18843034Sdougm 
18853034Sdougm int
18863910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
18873034Sdougm {
18883034Sdougm 	int verbose = 0;
18893034Sdougm 	int dryrun = 0;
18903034Sdougm 	int force = 0;
18913034Sdougm 	int c;
18923034Sdougm 	int ret = SA_OK;
18933034Sdougm 	sa_group_t group;
18943034Sdougm 	sa_share_t share;
18953034Sdougm 	char *sharepath = NULL;
18963034Sdougm 	char dir[MAXPATHLEN];
18973034Sdougm 	int auth;
18983034Sdougm 
18993034Sdougm 	while ((c = getopt(argc, argv, "?hfns:v")) != EOF) {
1900*4653Sdougm 		switch (c) {
1901*4653Sdougm 		case 'n':
1902*4653Sdougm 			dryrun++;
1903*4653Sdougm 			break;
1904*4653Sdougm 		case 'v':
1905*4653Sdougm 			verbose++;
1906*4653Sdougm 			break;
1907*4653Sdougm 		case 'f':
1908*4653Sdougm 			force++;
1909*4653Sdougm 			break;
1910*4653Sdougm 		case 's':
1911*4653Sdougm 			/*
1912*4653Sdougm 			 * Remove share path from group. Currently limit
1913*4653Sdougm 			 * to one share per command.
1914*4653Sdougm 			 */
1915*4653Sdougm 			if (sharepath != NULL) {
1916*4653Sdougm 				(void) printf(gettext(
1917*4653Sdougm 				    "Removing multiple shares not "
19183034Sdougm 				    "supported\n"));
1919*4653Sdougm 				return (SA_SYNTAX_ERR);
1920*4653Sdougm 			}
1921*4653Sdougm 			sharepath = optarg;
1922*4653Sdougm 			break;
1923*4653Sdougm 		default:
1924*4653Sdougm 		case 'h':
1925*4653Sdougm 		case '?':
1926*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
1927*4653Sdougm 			    sa_get_usage(USAGE_REMOVE_SHARE));
1928*4653Sdougm 			return (0);
19293034Sdougm 		}
19303034Sdougm 	}
19313034Sdougm 
19323034Sdougm 	if (optind >= argc || sharepath == NULL) {
1933*4653Sdougm 		if (sharepath == NULL) {
19343034Sdougm 			(void) printf(gettext("usage: %s\n"),
1935*4653Sdougm 			    sa_get_usage(USAGE_REMOVE_SHARE));
1936*4653Sdougm 			(void) printf(gettext(
1937*4653Sdougm 			    "\t-s sharepath must be specified\n"));
1938*4653Sdougm 			ret = SA_BAD_PATH;
1939*4653Sdougm 		} else {
1940*4653Sdougm 			ret = SA_OK;
1941*4653Sdougm 		}
19423034Sdougm 	}
1943*4653Sdougm 	if (ret != SA_OK) {
1944*4653Sdougm 		return (ret);
1945*4653Sdougm 	}
1946*4653Sdougm 
1947*4653Sdougm 	if (optind < argc) {
19483034Sdougm 		if ((optind + 1) < argc) {
1949*4653Sdougm 			(void) printf(gettext("Extraneous group(s) at end of "
1950*4653Sdougm 			    "command\n"));
1951*4653Sdougm 			ret = SA_SYNTAX_ERR;
19523034Sdougm 		} else {
1953*4653Sdougm 			group = sa_get_group(handle, argv[optind]);
1954*4653Sdougm 			if (group == NULL) {
1955*4653Sdougm 				(void) printf(gettext(
1956*4653Sdougm 				    "Group \"%s\" not found\n"), argv[optind]);
1957*4653Sdougm 				ret = SA_NO_SUCH_GROUP;
1958*4653Sdougm 			}
19593034Sdougm 		}
1960*4653Sdougm 	} else {
19613034Sdougm 		group = NULL;
1962*4653Sdougm 	}
1963*4653Sdougm 
1964*4653Sdougm 	/*
1965*4653Sdougm 	 * Lookup the path in the internal configuration. Care
1966*4653Sdougm 	 * must be taken to handle the case where the
1967*4653Sdougm 	 * underlying path has been removed since we need to
1968*4653Sdougm 	 * be able to deal with that as well.
1969*4653Sdougm 	 */
1970*4653Sdougm 	if (ret == SA_OK) {
19713034Sdougm 		if (group != NULL)
1972*4653Sdougm 			share = sa_get_share(group, sharepath);
19733034Sdougm 		else
1974*4653Sdougm 			share = sa_find_share(handle, sharepath);
19753663Sdougm 		/*
19763663Sdougm 		 * If we didn't find the share with the provided path,
19773663Sdougm 		 * it may be a symlink so attempt to resolve it using
19783663Sdougm 		 * realpath and try again. Realpath will resolve any
19793663Sdougm 		 * symlinks and place them in "dir". Note that
19803663Sdougm 		 * sharepath is only used for the lookup the first
19813663Sdougm 		 * time and later for error messages. dir will be used
19823663Sdougm 		 * on the second attempt. Once a share is found, all
19833663Sdougm 		 * operations are based off of the share variable.
19843663Sdougm 		 */
19853663Sdougm 		if (share == NULL) {
1986*4653Sdougm 			if (realpath(sharepath, dir) == NULL) {
1987*4653Sdougm 				ret = SA_BAD_PATH;
1988*4653Sdougm 				(void) printf(gettext(
1989*4653Sdougm 				    "Path is not valid: %s\n"), sharepath);
1990*4653Sdougm 			} else {
1991*4653Sdougm 				if (group != NULL)
1992*4653Sdougm 					share = sa_get_share(group, dir);
1993*4653Sdougm 				else
1994*4653Sdougm 					share = sa_find_share(handle, dir);
1995*4653Sdougm 			}
19963663Sdougm 		}
1997*4653Sdougm 	}
1998*4653Sdougm 
1999*4653Sdougm 	/*
2000*4653Sdougm 	 * If there hasn't been an error, there was likely a
2001*4653Sdougm 	 * path found. If not, give the appropriate error
2002*4653Sdougm 	 * message and set the return error. If it was found,
2003*4653Sdougm 	 * then disable the share and then remove it from the
2004*4653Sdougm 	 * configuration.
2005*4653Sdougm 	 */
2006*4653Sdougm 	if (ret != SA_OK) {
2007*4653Sdougm 		return (ret);
2008*4653Sdougm 	}
2009*4653Sdougm 	if (share == NULL) {
2010*4653Sdougm 		if (group != NULL)
20113034Sdougm 			(void) printf(gettext("Share not found in group %s:"
2012*4653Sdougm 			    " %s\n"), argv[optind], sharepath);
2013*4653Sdougm 		else
20143034Sdougm 			(void) printf(gettext("Share not found: %s\n"),
2015*4653Sdougm 			    sharepath);
2016*4653Sdougm 			ret = SA_NO_SUCH_PATH;
2017*4653Sdougm 	} else {
2018*4653Sdougm 		if (group == NULL)
20193034Sdougm 			group = sa_get_parent_group(share);
2020*4653Sdougm 		if (!dryrun) {
20213034Sdougm 			if (ret == SA_OK) {
2022*4653Sdougm 				ret = sa_disable_share(share, NULL);
20233034Sdougm 				/*
2024*4653Sdougm 				 * We don't care if it fails since it
20253663Sdougm 				 * could be disabled already. Some
20263663Sdougm 				 * unexpected errors could occur that
20273663Sdougm 				 * prevent removal, so also check for
20283663Sdougm 				 * force being set.
20293034Sdougm 				 */
2030*4653Sdougm 				if (ret == SA_OK || ret == SA_NO_SUCH_PATH ||
2031*4653Sdougm 				    ret == SA_NOT_SUPPORTED ||
2032*4653Sdougm 				    ret == SA_SYSTEM_ERR || force) {
2033*4653Sdougm 					ret = sa_remove_share(share);
2034*4653Sdougm 				}
2035*4653Sdougm 				if (ret == SA_OK)
2036*4653Sdougm 					ret = sa_update_config(handle);
20373034Sdougm 			}
2038*4653Sdougm 			if (ret != SA_OK)
2039*4653Sdougm 				(void) printf(gettext(
2040*4653Sdougm 				    "Could not remove share: %s\n"),
2041*4653Sdougm 				    sa_errorstr(ret));
2042*4653Sdougm 
2043*4653Sdougm 		} else if (ret == SA_OK) {
20443034Sdougm 			char *pname;
20453034Sdougm 			pname = sa_get_group_attr(group, "name");
20463034Sdougm 			if (pname != NULL) {
2047*4653Sdougm 				auth = check_authorizations(pname, flags);
2048*4653Sdougm 				sa_free_attr_string(pname);
20493034Sdougm 			}
20503034Sdougm 			if (!auth && verbose) {
2051*4653Sdougm 				(void) printf(gettext(
2052*4653Sdougm 				    "Command would fail: %s\n"),
2053*4653Sdougm 				    sa_errorstr(SA_NO_PERMISSION));
20543034Sdougm 			}
20553034Sdougm 		}
20563034Sdougm 	}
20573034Sdougm 	return (ret);
20583034Sdougm }
20593034Sdougm 
20603034Sdougm /*
20613034Sdougm  * sa_set_share(flags, argc, argv)
20623034Sdougm  *
20633034Sdougm  * implements set-share subcommand.
20643034Sdougm  */
20653034Sdougm 
20663034Sdougm int
20673910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
20683034Sdougm {
20693034Sdougm 	int dryrun = 0;
20703034Sdougm 	int c;
20713034Sdougm 	int ret = SA_OK;
20723034Sdougm 	sa_group_t group, sharegroup;
20733034Sdougm 	sa_share_t share;
20743034Sdougm 	char *sharepath = NULL;
20753034Sdougm 	char *description = NULL;
20763034Sdougm 	char *resource = NULL;
20773034Sdougm 	int auth;
20783034Sdougm 	int verbose = 0;
2079*4653Sdougm 	char *groupname;
20803034Sdougm 
20813034Sdougm 	while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
2082*4653Sdougm 		switch (c) {
2083*4653Sdougm 		case 'n':
2084*4653Sdougm 			dryrun++;
2085*4653Sdougm 			break;
2086*4653Sdougm 		case 'd':
2087*4653Sdougm 			description = optarg;
2088*4653Sdougm 			break;
2089*4653Sdougm 		case 'r':
2090*4653Sdougm 			resource = optarg;
2091*4653Sdougm 			break;
2092*4653Sdougm 		case 'v':
2093*4653Sdougm 			verbose++;
2094*4653Sdougm 			break;
2095*4653Sdougm 		case 's':
2096*4653Sdougm 			/*
2097*4653Sdougm 			 * Save share path into group. Currently limit
2098*4653Sdougm 			 * to one share per command.
2099*4653Sdougm 			 */
2100*4653Sdougm 			if (sharepath != NULL) {
2101*4653Sdougm 				(void) printf(gettext(
2102*4653Sdougm 				    "Updating multiple shares not "
21033034Sdougm 				    "supported\n"));
2104*4653Sdougm 				return (SA_BAD_PATH);
2105*4653Sdougm 			}
2106*4653Sdougm 			sharepath = optarg;
2107*4653Sdougm 			break;
2108*4653Sdougm 		default:
2109*4653Sdougm 		case 'h':
2110*4653Sdougm 		case '?':
2111*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
2112*4653Sdougm 			    sa_get_usage(USAGE_SET_SHARE));
2113*4653Sdougm 			return (SA_OK);
21143034Sdougm 		}
21153034Sdougm 	}
2116*4653Sdougm 
21173034Sdougm 	if (optind >= argc || sharepath == NULL) {
2118*4653Sdougm 		if (sharepath == NULL) {
2119*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
2120*4653Sdougm 			    sa_get_usage(USAGE_SET_SHARE));
2121*4653Sdougm 			(void) printf(gettext("\tgroup must be specified\n"));
2122*4653Sdougm 			ret = SA_BAD_PATH;
2123*4653Sdougm 		} else {
2124*4653Sdougm 			ret = SA_OK;
2125*4653Sdougm 		}
21263034Sdougm 	}
21273034Sdougm 	if ((optind + 1) < argc) {
2128*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
2129*4653Sdougm 		    sa_get_usage(USAGE_SET_SHARE));
2130*4653Sdougm 		(void) printf(gettext("\tExtraneous group(s) at end\n"));
2131*4653Sdougm 		ret = SA_SYNTAX_ERR;
21323034Sdougm 	}
2133*4653Sdougm 
2134*4653Sdougm 	if (ret != SA_OK)
2135*4653Sdougm 		return (ret);
2136*4653Sdougm 
2137*4653Sdougm 	if (optind < argc) {
21383034Sdougm 		groupname = argv[optind];
21393910Sdougm 		group = sa_get_group(handle, groupname);
2140*4653Sdougm 	} else {
21413034Sdougm 		group = NULL;
21423034Sdougm 		groupname = NULL;
2143*4653Sdougm 	}
2144*4653Sdougm 	share = sa_find_share(handle, sharepath);
2145*4653Sdougm 	if (share == NULL) {
2146*4653Sdougm 		(void) printf(gettext("Share path \"%s\" not found\n"),
2147*4653Sdougm 		    sharepath);
2148*4653Sdougm 		return (SA_NO_SUCH_PATH);
2149*4653Sdougm 	}
2150*4653Sdougm 	sharegroup = sa_get_parent_group(share);
2151*4653Sdougm 	if (group != NULL && group != sharegroup) {
2152*4653Sdougm 		(void) printf(gettext("Group \"%s\" does not contain "
2153*4653Sdougm 		    "share %s\n"), argv[optind], sharepath);
2154*4653Sdougm 		ret = SA_BAD_PATH;
2155*4653Sdougm 	} else {
2156*4653Sdougm 		int delgroupname = 0;
2157*4653Sdougm 		if (groupname == NULL) {
21583034Sdougm 			groupname = sa_get_group_attr(sharegroup, "name");
21593034Sdougm 			delgroupname = 1;
2160*4653Sdougm 		}
2161*4653Sdougm 		if (groupname != NULL) {
21623034Sdougm 			auth = check_authorizations(groupname, flags);
21633034Sdougm 			if (delgroupname) {
2164*4653Sdougm 				sa_free_attr_string(groupname);
2165*4653Sdougm 				groupname = NULL;
21663034Sdougm 			}
2167*4653Sdougm 		} else {
21683034Sdougm 			ret = SA_NO_MEMORY;
2169*4653Sdougm 		}
2170*4653Sdougm 		if (resource != NULL) {
21713034Sdougm 			if (strpbrk(resource, " \t/") == NULL) {
2172*4653Sdougm 				if (!dryrun) {
2173*4653Sdougm 					ret = sa_set_share_attr(share,
2174*4653Sdougm 					    "resource", resource);
2175*4653Sdougm 				} else {
2176*4653Sdougm 					sa_share_t resshare;
2177*4653Sdougm 					resshare = sa_get_resource(sharegroup,
2178*4653Sdougm 					    resource);
2179*4653Sdougm 					if (resshare != NULL &&
2180*4653Sdougm 					    resshare != share)
2181*4653Sdougm 						ret = SA_DUPLICATE_NAME;
2182*4653Sdougm 				}
21833034Sdougm 			} else {
2184*4653Sdougm 				ret = SA_BAD_PATH;
2185*4653Sdougm 				(void) printf(gettext("Resource must not "
2186*4653Sdougm 				    "contain white space or '/'\n"));
21873034Sdougm 			}
2188*4653Sdougm 		}
2189*4653Sdougm 		if (ret == SA_OK && description != NULL)
21903034Sdougm 			ret = sa_set_share_description(share, description);
2191*4653Sdougm 	}
2192*4653Sdougm 	if (!dryrun && ret == SA_OK)
2193*4653Sdougm 		ret = sa_update_config(handle);
2194*4653Sdougm 
2195*4653Sdougm 	switch (ret) {
2196*4653Sdougm 	case SA_DUPLICATE_NAME:
2197*4653Sdougm 		(void) printf(gettext("Resource name in use: %s\n"), resource);
2198*4653Sdougm 		break;
2199*4653Sdougm 	default:
2200*4653Sdougm 		(void) printf(gettext("Could not set attribute: %s\n"),
2201*4653Sdougm 		    sa_errorstr(ret));
2202*4653Sdougm 		break;
2203*4653Sdougm 	case SA_OK:
2204*4653Sdougm 		if (dryrun && !auth && verbose)
22053034Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
2206*4653Sdougm 			    sa_errorstr(SA_NO_PERMISSION));
2207*4653Sdougm 		break;
22083034Sdougm 	}
2209*4653Sdougm 
22103034Sdougm 	return (ret);
22113034Sdougm }
22123034Sdougm 
22133034Sdougm /*
22143034Sdougm  * add_security(group, sectype, optlist, proto, *err)
22153034Sdougm  *
22163034Sdougm  * Helper function to add a security option (named optionset) to the
22173034Sdougm  * group.
22183034Sdougm  */
22193034Sdougm 
22203034Sdougm static int
22213034Sdougm add_security(sa_group_t group, char *sectype,
22223034Sdougm 		struct options *optlist, char *proto, int *err)
22233034Sdougm {
22243034Sdougm 	sa_security_t security;
22253034Sdougm 	int ret = SA_OK;
22263034Sdougm 	int result = 0;
22273034Sdougm 
22283034Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
22293034Sdougm 	security = sa_get_security(group, sectype, proto);
2230*4653Sdougm 	if (security == NULL)
2231*4653Sdougm 		security = sa_create_security(group, sectype, proto);
2232*4653Sdougm 
22333034Sdougm 	if (sectype != NULL)
2234*4653Sdougm 		sa_free_attr_string(sectype);
2235*4653Sdougm 
2236*4653Sdougm 	if (security == NULL)
2237*4653Sdougm 		return (ret);
2238*4653Sdougm 
2239*4653Sdougm 	while (optlist != NULL) {
22403034Sdougm 		sa_property_t prop;
22413034Sdougm 		prop = sa_get_property(security, optlist->optname);
22423034Sdougm 		if (prop == NULL) {
22433034Sdougm 			/*
2244*4653Sdougm 			 * Add the property, but only if it is
22453034Sdougm 			 * a non-NULL or non-zero length value
22463034Sdougm 			 */
2247*4653Sdougm 			if (optlist->optvalue != NULL) {
2248*4653Sdougm 				prop = sa_create_property(optlist->optname,
2249*4653Sdougm 				    optlist->optvalue);
2250*4653Sdougm 				if (prop != NULL) {
2251*4653Sdougm 					ret = sa_valid_property(security, proto,
2252*4653Sdougm 					    prop);
2253*4653Sdougm 					if (ret != SA_OK) {
2254*4653Sdougm 						(void) sa_remove_property(prop);
2255*4653Sdougm 						(void) printf(gettext(
2256*4653Sdougm 						    "Could not add "
2257*4653Sdougm 						    "property %s: %s\n"),
2258*4653Sdougm 						    optlist->optname,
2259*4653Sdougm 						    sa_errorstr(ret));
2260*4653Sdougm 					}
2261*4653Sdougm 					if (ret == SA_OK) {
2262*4653Sdougm 						ret = sa_add_property(security,
2263*4653Sdougm 						    prop);
2264*4653Sdougm 						if (ret != SA_OK) {
2265*4653Sdougm 							(void) printf(gettext(
2266*4653Sdougm 							    "Could not add "
2267*4653Sdougm 							    "property (%s=%s): "
2268*4653Sdougm 							    "%s\n"),
2269*4653Sdougm 							    optlist->optname,
2270*4653Sdougm 							    optlist->optvalue,
2271*4653Sdougm 							    sa_errorstr(ret));
2272*4653Sdougm 						} else {
2273*4653Sdougm 							result = 1;
2274*4653Sdougm 						}
2275*4653Sdougm 					}
22763034Sdougm 				}
22773034Sdougm 			}
22783034Sdougm 		} else {
2279*4653Sdougm 			ret = sa_update_property(prop, optlist->optvalue);
2280*4653Sdougm 			result = 1; /* should check if really changed */
22813034Sdougm 		}
22823034Sdougm 		optlist = optlist->next;
2283*4653Sdougm 	}
2284*4653Sdougm 	/*
2285*4653Sdougm 	 * When done, properties may have all been removed but
2286*4653Sdougm 	 * we need to keep the security type itself until
2287*4653Sdougm 	 * explicitly removed.
2288*4653Sdougm 	 */
2289*4653Sdougm 	if (result)
22903034Sdougm 		ret = sa_commit_properties(security, 0);
22913034Sdougm 	*err = ret;
22923034Sdougm 	return (result);
22933034Sdougm }
22943034Sdougm 
22953034Sdougm /*
22963034Sdougm  * basic_set(groupname, optlist, protocol, sharepath, dryrun)
22973034Sdougm  *
22983034Sdougm  * This function implements "set" when a name space (-S) is not
22993034Sdougm  * specified. It is a basic set. Options and other CLI parsing has
23003034Sdougm  * already been done.
23013034Sdougm  */
23023034Sdougm 
23033034Sdougm static int
23043910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
23053910Sdougm 		char *protocol,	char *sharepath, int dryrun)
23063034Sdougm {
23073034Sdougm 	sa_group_t group;
23083034Sdougm 	int ret = SA_OK;
23093034Sdougm 	int change = 0;
23103034Sdougm 	struct list *worklist = NULL;
23113034Sdougm 
23123910Sdougm 	group = sa_get_group(handle, groupname);
23133034Sdougm 	if (group != NULL) {
2314*4653Sdougm 		sa_share_t share = NULL;
2315*4653Sdougm 		if (sharepath != NULL) {
2316*4653Sdougm 			share = sa_get_share(group, sharepath);
2317*4653Sdougm 			if (share == NULL) {
2318*4653Sdougm 				(void) printf(gettext(
2319*4653Sdougm 				    "Share does not exist in group %s\n"),
2320*4653Sdougm 				    groupname, sharepath);
2321*4653Sdougm 				ret = SA_NO_SUCH_PATH;
2322*4653Sdougm 			}
23233034Sdougm 		}
2324*4653Sdougm 		if (ret == SA_OK) {
2325*4653Sdougm 			/* group must exist */
2326*4653Sdougm 			ret = valid_options(optlist, protocol,
2327*4653Sdougm 			    share == NULL ? group : share, NULL);
2328*4653Sdougm 			if (ret == SA_OK && !dryrun) {
2329*4653Sdougm 				if (share != NULL)
2330*4653Sdougm 					change |= add_optionset(share, optlist,
2331*4653Sdougm 					    protocol, &ret);
2332*4653Sdougm 				else
2333*4653Sdougm 					change |= add_optionset(group, optlist,
2334*4653Sdougm 					    protocol, &ret);
2335*4653Sdougm 				if (ret == SA_OK && change)
2336*4653Sdougm 					worklist = add_list(worklist, group,
2337*4653Sdougm 					    share);
2338*4653Sdougm 			}
23393034Sdougm 		}
2340*4653Sdougm 		free_opt(optlist);
23413034Sdougm 	} else {
23423034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
23433034Sdougm 		ret = SA_NO_SUCH_GROUP;
23443034Sdougm 	}
23453034Sdougm 	/*
23463034Sdougm 	 * we have a group and potentially legal additions
23473034Sdougm 	 */
23483034Sdougm 
2349*4653Sdougm 	/*
2350*4653Sdougm 	 * Commit to configuration if not a dryrunp and properties
2351*4653Sdougm 	 * have changed.
2352*4653Sdougm 	 */
2353*4653Sdougm 	if (!dryrun && ret == SA_OK && change && worklist != NULL)
23543034Sdougm 		/* properties changed, so update all shares */
23553910Sdougm 		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
2356*4653Sdougm 
23573034Sdougm 	if (worklist != NULL)
2358*4653Sdougm 		free_list(worklist);
23593034Sdougm 	return (ret);
23603034Sdougm }
23613034Sdougm 
23623034Sdougm /*
23633034Sdougm  * space_set(groupname, optlist, protocol, sharepath, dryrun)
23643034Sdougm  *
23653034Sdougm  * This function implements "set" when a name space (-S) is
23663034Sdougm  * specified. It is a namespace set. Options and other CLI parsing has
23673034Sdougm  * already been done.
23683034Sdougm  */
23693034Sdougm 
23703034Sdougm static int
23713910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist,
23723910Sdougm 		char *protocol,	char *sharepath, int dryrun, char *sectype)
23733034Sdougm {
23743034Sdougm 	sa_group_t group;
23753034Sdougm 	int ret = SA_OK;
23763034Sdougm 	int change = 0;
23773034Sdougm 	struct list *worklist = NULL;
23783034Sdougm 
23793034Sdougm 	/*
23803034Sdougm 	 * make sure protcol and sectype are valid
23813034Sdougm 	 */
23823034Sdougm 
23833034Sdougm 	if (sa_proto_valid_space(protocol, sectype) == 0) {
2384*4653Sdougm 		(void) printf(gettext("Option space \"%s\" not valid "
2385*4653Sdougm 		    "for protocol.\n"), sectype);
2386*4653Sdougm 		return (SA_INVALID_SECURITY);
23873034Sdougm 	}
23883034Sdougm 
23893910Sdougm 	group = sa_get_group(handle, groupname);
23903034Sdougm 	if (group != NULL) {
2391*4653Sdougm 		sa_share_t share = NULL;
2392*4653Sdougm 		if (sharepath != NULL) {
2393*4653Sdougm 			share = sa_get_share(group, sharepath);
2394*4653Sdougm 			if (share == NULL) {
2395*4653Sdougm 				(void) printf(gettext(
2396*4653Sdougm 				    "Share does not exist in group %s\n"),
2397*4653Sdougm 				    groupname, sharepath);
2398*4653Sdougm 				ret = SA_NO_SUCH_PATH;
2399*4653Sdougm 			}
24003034Sdougm 		}
2401*4653Sdougm 		if (ret == SA_OK) {
2402*4653Sdougm 			/* group must exist */
2403*4653Sdougm 			ret = valid_options(optlist, protocol,
2404*4653Sdougm 			    share == NULL ? group : share, sectype);
2405*4653Sdougm 			if (ret == SA_OK && !dryrun) {
2406*4653Sdougm 				if (share != NULL)
2407*4653Sdougm 					change = add_security(share, sectype,
2408*4653Sdougm 					    optlist, protocol, &ret);
2409*4653Sdougm 				else
2410*4653Sdougm 					change = add_security(group, sectype,
2411*4653Sdougm 					    optlist, protocol, &ret);
2412*4653Sdougm 				if (ret != SA_OK)
2413*4653Sdougm 					(void) printf(gettext(
2414*4653Sdougm 					    "Could not set property: %s\n"),
2415*4653Sdougm 					    sa_errorstr(ret));
2416*4653Sdougm 			}
2417*4653Sdougm 			if (ret == SA_OK && change)
2418*4653Sdougm 				worklist = add_list(worklist, group, share);
24193034Sdougm 		}
2420*4653Sdougm 		free_opt(optlist);
24213034Sdougm 	} else {
24223034Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
24233034Sdougm 		ret = SA_NO_SUCH_GROUP;
24243034Sdougm 	}
24253034Sdougm 	/*
24263034Sdougm 	 * we have a group and potentially legal additions
24273034Sdougm 	 */
24283034Sdougm 
2429*4653Sdougm 	/* Commit to configuration if not a dryrun */
24303034Sdougm 	if (!dryrun && ret == 0) {
2431*4653Sdougm 		if (change && worklist != NULL) {
2432*4653Sdougm 			/* properties changed, so update all shares */
2433*4653Sdougm 			(void) enable_all_groups(handle, worklist, 0, 0,
2434*4653Sdougm 			    protocol);
2435*4653Sdougm 		}
2436*4653Sdougm 		ret = sa_update_config(handle);
24373034Sdougm 	}
24383034Sdougm 	if (worklist != NULL)
2439*4653Sdougm 		free_list(worklist);
24403034Sdougm 	return (ret);
24413034Sdougm }
24423034Sdougm 
24433034Sdougm /*
24443034Sdougm  * sa_set(flags, argc, argv)
24453034Sdougm  *
24463034Sdougm  * Implements the set subcommand. It keys off of -S to determine which
24473034Sdougm  * set of operations to actually do.
24483034Sdougm  */
24493034Sdougm 
24503034Sdougm int
24513910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
24523034Sdougm {
24533034Sdougm 	char *groupname;
24543034Sdougm 	int verbose = 0;
24553034Sdougm 	int dryrun = 0;
24563034Sdougm 	int c;
24573034Sdougm 	char *protocol = NULL;
24583034Sdougm 	int ret = SA_OK;
24593034Sdougm 	struct options *optlist = NULL;
24603034Sdougm 	char *sharepath = NULL;
24613034Sdougm 	char *optset = NULL;
24623034Sdougm 	int auth;
24633034Sdougm 
24643034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
2465*4653Sdougm 		switch (c) {
2466*4653Sdougm 		case 'v':
2467*4653Sdougm 			verbose++;
2468*4653Sdougm 			break;
2469*4653Sdougm 		case 'n':
2470*4653Sdougm 			dryrun++;
2471*4653Sdougm 			break;
2472*4653Sdougm 		case 'P':
2473*4653Sdougm 			protocol = optarg;
2474*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
2475*4653Sdougm 				(void) printf(gettext(
2476*4653Sdougm 				    "Invalid protocol specified: %s\n"),
2477*4653Sdougm 				    protocol);
2478*4653Sdougm 				return (SA_INVALID_PROTOCOL);
2479*4653Sdougm 			}
2480*4653Sdougm 			break;
2481*4653Sdougm 		case 'p':
2482*4653Sdougm 			ret = add_opt(&optlist, optarg, 0);
2483*4653Sdougm 			switch (ret) {
2484*4653Sdougm 			case OPT_ADD_SYNTAX:
2485*4653Sdougm 				(void) printf(gettext("Property syntax error:"
2486*4653Sdougm 				    " %s\n"), optarg);
2487*4653Sdougm 				return (SA_SYNTAX_ERR);
2488*4653Sdougm 			case OPT_ADD_MEMORY:
2489*4653Sdougm 				(void) printf(gettext("No memory to set "
2490*4653Sdougm 				    "property: %s\n"), optarg);
2491*4653Sdougm 				return (SA_NO_MEMORY);
2492*4653Sdougm 			default:
2493*4653Sdougm 				break;
2494*4653Sdougm 			}
2495*4653Sdougm 			break;
2496*4653Sdougm 		case 's':
2497*4653Sdougm 			sharepath = optarg;
2498*4653Sdougm 			break;
2499*4653Sdougm 		case 'S':
2500*4653Sdougm 			optset = optarg;
2501*4653Sdougm 			break;
2502*4653Sdougm 		default:
2503*4653Sdougm 		case 'h':
2504*4653Sdougm 		case '?':
2505*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
2506*4653Sdougm 			    sa_get_usage(USAGE_SET));
2507*4653Sdougm 			return (SA_OK);
25083034Sdougm 		}
25093034Sdougm 	}
25103034Sdougm 
25113034Sdougm 	if (optlist != NULL)
2512*4653Sdougm 		ret = chk_opt(optlist, optset != NULL, protocol);
25133034Sdougm 
25143034Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
2515*4653Sdougm 	    protocol == NULL || ret != OPT_ADD_OK) {
2516*4653Sdougm 		char *sep = "\t";
2517*4653Sdougm 
2518*4653Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
2519*4653Sdougm 		if (optind >= argc) {
2520*4653Sdougm 			(void) printf(gettext("%sgroup must be specified"),
2521*4653Sdougm 			    sep);
2522*4653Sdougm 			sep = ", ";
2523*4653Sdougm 		}
2524*4653Sdougm 		if (optlist == NULL) {
2525*4653Sdougm 			(void) printf(gettext("%sat least one property must be"
2526*4653Sdougm 			    " specified"), sep);
2527*4653Sdougm 			sep = ", ";
2528*4653Sdougm 		}
2529*4653Sdougm 		if (protocol == NULL) {
2530*4653Sdougm 			(void) printf(gettext("%sprotocol must be specified"),
2531*4653Sdougm 			    sep);
2532*4653Sdougm 			sep = ", ";
2533*4653Sdougm 		}
2534*4653Sdougm 		(void) printf("\n");
2535*4653Sdougm 		ret = SA_SYNTAX_ERR;
25363034Sdougm 	} else {
25373034Sdougm 		/*
2538*4653Sdougm 		 * If a group already exists, we can only add a new
25393034Sdougm 		 * protocol to it and not create a new one or add the
25403034Sdougm 		 * same protocol again.
25413034Sdougm 		 */
25423034Sdougm 
2543*4653Sdougm 		groupname = argv[optind];
2544*4653Sdougm 		auth = check_authorizations(groupname, flags);
2545*4653Sdougm 		if (optset == NULL)
2546*4653Sdougm 			ret = basic_set(handle, groupname, optlist, protocol,
2547*4653Sdougm 			    sharepath, dryrun);
2548*4653Sdougm 		else
2549*4653Sdougm 			ret = space_set(handle, groupname, optlist, protocol,
2550*4653Sdougm 			    sharepath, dryrun, optset);
2551*4653Sdougm 		if (dryrun && ret == SA_OK && !auth && verbose) {
2552*4653Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
2553*4653Sdougm 			    sa_errorstr(SA_NO_PERMISSION));
2554*4653Sdougm 		}
25553034Sdougm 	}
25563034Sdougm 	return (ret);
25573034Sdougm }
25583034Sdougm 
25593034Sdougm /*
25603034Sdougm  * remove_options(group, optlist, proto, *err)
25613034Sdougm  *
2562*4653Sdougm  * Helper function to actually remove options from a group after all
25633034Sdougm  * preprocessing is done.
25643034Sdougm  */
25653034Sdougm 
25663034Sdougm static int
25673034Sdougm remove_options(sa_group_t group, struct options *optlist,
25683034Sdougm 		char *proto, int *err)
25693034Sdougm {
25703034Sdougm 	struct options *cur;
25713034Sdougm 	sa_optionset_t optionset;
25723034Sdougm 	sa_property_t prop;
25733034Sdougm 	int change = 0;
25743034Sdougm 	int ret = SA_OK;
25753034Sdougm 
25763034Sdougm 	optionset = sa_get_optionset(group, proto);
25773034Sdougm 	if (optionset != NULL) {
2578*4653Sdougm 		for (cur = optlist; cur != NULL; cur = cur->next) {
2579*4653Sdougm 			prop = sa_get_property(optionset, cur->optname);
2580*4653Sdougm 			if (prop != NULL) {
2581*4653Sdougm 				ret = sa_remove_property(prop);
2582*4653Sdougm 				if (ret != SA_OK)
2583*4653Sdougm 					break;
2584*4653Sdougm 				change = 1;
2585*4653Sdougm 			}
25863034Sdougm 		}
25873034Sdougm 	}
25883034Sdougm 	if (ret == SA_OK && change)
2589*4653Sdougm 		ret = sa_commit_properties(optionset, 0);
25903034Sdougm 
25913034Sdougm 	if (err != NULL)
2592*4653Sdougm 		*err = ret;
25933034Sdougm 	return (change);
25943034Sdougm }
25953034Sdougm 
25963034Sdougm /*
25973034Sdougm  * valid_unset(group, optlist, proto)
25983034Sdougm  *
25993034Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
26003034Sdougm  * error if a property doesn't exist.
26013034Sdougm  */
26023034Sdougm 
26033034Sdougm static int
26043034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto)
26053034Sdougm {
26063034Sdougm 	struct options *cur;
26073034Sdougm 	sa_optionset_t optionset;
26083034Sdougm 	sa_property_t prop;
26093034Sdougm 	int ret = SA_OK;
26103034Sdougm 
26113034Sdougm 	optionset = sa_get_optionset(group, proto);
26123034Sdougm 	if (optionset != NULL) {
2613*4653Sdougm 		for (cur = optlist; cur != NULL; cur = cur->next) {
2614*4653Sdougm 			prop = sa_get_property(optionset, cur->optname);
2615*4653Sdougm 			if (prop == NULL) {
2616*4653Sdougm 				(void) printf(gettext(
2617*4653Sdougm 				    "Could not unset property %s: not set\n"),
2618*4653Sdougm 				    cur->optname);
2619*4653Sdougm 				ret = SA_NO_SUCH_PROP;
2620*4653Sdougm 			}
26213034Sdougm 		}
26223034Sdougm 	}
26233034Sdougm 	return (ret);
26243034Sdougm }
26253034Sdougm 
26263034Sdougm /*
26273034Sdougm  * valid_unset_security(group, optlist, proto)
26283034Sdougm  *
26293034Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
26303034Sdougm  * error if a property doesn't exist.
26313034Sdougm  */
26323034Sdougm 
26333034Sdougm static int
26343034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
26353034Sdougm 	    char *sectype)
26363034Sdougm {
26373034Sdougm 	struct options *cur;
26383034Sdougm 	sa_security_t security;
26393034Sdougm 	sa_property_t prop;
26403034Sdougm 	int ret = SA_OK;
26413034Sdougm 	char *sec;
26423034Sdougm 
26433034Sdougm 	sec = sa_proto_space_alias(proto, sectype);
26443034Sdougm 	security = sa_get_security(group, sec, proto);
26453034Sdougm 	if (security != NULL) {
2646*4653Sdougm 		for (cur = optlist; cur != NULL; cur = cur->next) {
2647*4653Sdougm 			prop = sa_get_property(security, cur->optname);
2648*4653Sdougm 			if (prop == NULL) {
2649*4653Sdougm 				(void) printf(gettext(
2650*4653Sdougm 				    "Could not unset property %s: not set\n"),
2651*4653Sdougm 				    cur->optname);
2652*4653Sdougm 				ret = SA_NO_SUCH_PROP;
2653*4653Sdougm 			}
26543034Sdougm 		}
26553034Sdougm 	} else {
2656*4653Sdougm 		(void) printf(gettext(
2657*4653Sdougm 		    "Could not unset %s: space not defined\n"), sectype);
2658*4653Sdougm 		ret = SA_NO_SUCH_SECURITY;
26593034Sdougm 	}
26603034Sdougm 	if (sec != NULL)
2661*4653Sdougm 		sa_free_attr_string(sec);
26623034Sdougm 	return (ret);
26633034Sdougm }
26643034Sdougm 
26653034Sdougm /*
26663034Sdougm  * remove_security(group, optlist, proto)
26673034Sdougm  *
26683034Sdougm  * Remove the properties since they were checked as valid.
26693034Sdougm  */
26703034Sdougm 
26713034Sdougm static int
26723034Sdougm remove_security(sa_group_t group, char *sectype,
26733034Sdougm 		struct options *optlist, char *proto, int *err)
26743034Sdougm {
26753034Sdougm 	sa_security_t security;
26763034Sdougm 	int ret = SA_OK;
26773034Sdougm 	int change = 0;
26783034Sdougm 
26793034Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
26803034Sdougm 	security = sa_get_security(group, sectype, proto);
26813034Sdougm 	if (sectype != NULL)
2682*4653Sdougm 		sa_free_attr_string(sectype);
26833034Sdougm 
26843034Sdougm 	if (security != NULL) {
2685*4653Sdougm 		while (optlist != NULL) {
2686*4653Sdougm 			sa_property_t prop;
2687*4653Sdougm 			prop = sa_get_property(security, optlist->optname);
2688*4653Sdougm 			if (prop != NULL) {
2689*4653Sdougm 				ret = sa_remove_property(prop);
2690*4653Sdougm 				if (ret != SA_OK)
2691*4653Sdougm 					break;
2692*4653Sdougm 				change = 1;
2693*4653Sdougm 			}
2694*4653Sdougm 			optlist = optlist->next;
26953034Sdougm 		}
26963034Sdougm 		/*
26973034Sdougm 		 * when done, properties may have all been removed but
26983034Sdougm 		 * we need to keep the security type itself until
26993034Sdougm 		 * explicitly removed.
27003034Sdougm 		 */
2701*4653Sdougm 		if (ret == SA_OK && change)
2702*4653Sdougm 			ret = sa_commit_properties(security, 0);
27033034Sdougm 	} else {
2704*4653Sdougm 		ret = SA_NO_SUCH_PROP;
27053034Sdougm 	}
27063034Sdougm 	if (err != NULL)
2707*4653Sdougm 		*err = ret;
27083034Sdougm 	return (change);
27093034Sdougm }
27103034Sdougm 
27113034Sdougm /*
27123034Sdougm  * basic_unset(groupname, optlist, protocol, sharepath, dryrun)
27133034Sdougm  *
2714*4653Sdougm  * Unset non-named optionset properties.
27153034Sdougm  */
27163034Sdougm 
27173034Sdougm static int
27183910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
27193910Sdougm 		char *protocol,	char *sharepath, int dryrun)
27203034Sdougm {
27213034Sdougm 	sa_group_t group;
27223034Sdougm 	int ret = SA_OK;
27233034Sdougm 	int change = 0;
27243034Sdougm 	struct list *worklist = NULL;
2725*4653Sdougm 	sa_share_t share = NULL;
27263034Sdougm 
27273910Sdougm 	group = sa_get_group(handle, groupname);
2728*4653Sdougm 	if (group == NULL)
2729*4653Sdougm 		return (ret);
2730*4653Sdougm 
2731*4653Sdougm 	if (sharepath != NULL) {
27323034Sdougm 		share = sa_get_share(group, sharepath);
27333034Sdougm 		if (share == NULL) {
2734*4653Sdougm 			(void) printf(gettext(
2735*4653Sdougm 			    "Share does not exist in group %s\n"),
2736*4653Sdougm 			    groupname, sharepath);
2737*4653Sdougm 			ret = SA_NO_SUCH_PATH;
27383034Sdougm 		}
2739*4653Sdougm 	}
2740*4653Sdougm 	if (ret == SA_OK) {
27413034Sdougm 		/* group must exist */
27423034Sdougm 		ret = valid_unset(share != NULL ? share : group,
2743*4653Sdougm 		    optlist, protocol);
27443034Sdougm 		if (ret == SA_OK && !dryrun) {
2745*4653Sdougm 			if (share != NULL) {
2746*4653Sdougm 				sa_optionset_t optionset;
2747*4653Sdougm 				sa_property_t prop;
2748*4653Sdougm 				change |= remove_options(share, optlist,
2749*4653Sdougm 				    protocol, &ret);
2750*4653Sdougm 				/*
2751*4653Sdougm 				 * If a share optionset is
2752*4653Sdougm 				 * empty, remove it.
2753*4653Sdougm 				 */
2754*4653Sdougm 				optionset = sa_get_optionset((sa_share_t)share,
2755*4653Sdougm 				    protocol);
2756*4653Sdougm 				if (optionset != NULL) {
2757*4653Sdougm 					prop = sa_get_property(optionset, NULL);
2758*4653Sdougm 					if (prop == NULL)
2759*4653Sdougm 						(void) sa_destroy_optionset(
2760*4653Sdougm 						    optionset);
2761*4653Sdougm 				}
2762*4653Sdougm 			} else {
2763*4653Sdougm 				change |= remove_options(group,
2764*4653Sdougm 				    optlist, protocol, &ret);
27653034Sdougm 			}
2766*4653Sdougm 			if (ret == SA_OK && change)
2767*4653Sdougm 				worklist = add_list(worklist, group,
2768*4653Sdougm 				    share);
2769*4653Sdougm 			if (ret != SA_OK)
2770*4653Sdougm 				(void) printf(gettext(
2771*4653Sdougm 				    "Could not remove properties: "
2772*4653Sdougm 				    "%s\n"), sa_errorstr(ret));
27733034Sdougm 		}
2774*4653Sdougm 	} else {
2775*4653Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"),
2776*4653Sdougm 		    groupname);
27773034Sdougm 		ret = SA_NO_SUCH_GROUP;
27783034Sdougm 	}
2779*4653Sdougm 	free_opt(optlist);
27803034Sdougm 
27813034Sdougm 	/*
2782*4653Sdougm 	 * We have a group and potentially legal additions
2783*4653Sdougm 	 *
2784*4653Sdougm 	 * Commit to configuration if not a dryrun
27853034Sdougm 	 */
27863034Sdougm 	if (!dryrun && ret == SA_OK) {
2787*4653Sdougm 		if (change && worklist != NULL) {
2788*4653Sdougm 			/* properties changed, so update all shares */
2789*4653Sdougm 			(void) enable_all_groups(handle, worklist, 0, 0,
2790*4653Sdougm 			    protocol);
2791*4653Sdougm 		}
27923034Sdougm 	}
27933034Sdougm 	if (worklist != NULL)
2794*4653Sdougm 		free_list(worklist);
27953034Sdougm 	return (ret);
27963034Sdougm }
27973034Sdougm 
27983034Sdougm /*
27993034Sdougm  * space_unset(groupname, optlist, protocol, sharepath, dryrun)
28003034Sdougm  *
2801*4653Sdougm  * Unset named optionset properties.
28023034Sdougm  */
28033034Sdougm static int
28043910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
28053910Sdougm 		char *protocol, char *sharepath, int dryrun, char *sectype)
28063034Sdougm {
28073034Sdougm 	sa_group_t group;
28083034Sdougm 	int ret = SA_OK;
28093034Sdougm 	int change = 0;
28103034Sdougm 	struct list *worklist = NULL;
2811*4653Sdougm 	sa_share_t share = NULL;
28123034Sdougm 
28133910Sdougm 	group = sa_get_group(handle, groupname);
2814*4653Sdougm 	if (group == NULL) {
2815*4653Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
2816*4653Sdougm 		return (SA_NO_SUCH_GROUP);
2817*4653Sdougm 	}
2818*4653Sdougm 	if (sharepath != NULL) {
28193034Sdougm 		share = sa_get_share(group, sharepath);
28203034Sdougm 		if (share == NULL) {
2821*4653Sdougm 			(void) printf(gettext(
2822*4653Sdougm 			    "Share does not exist in group %s\n"),
2823*4653Sdougm 			    groupname, sharepath);
2824*4653Sdougm 			return (SA_NO_SUCH_PATH);
28253034Sdougm 		}
2826*4653Sdougm 	}
2827*4653Sdougm 	ret = valid_unset_security(share != NULL ? share : group, optlist,
2828*4653Sdougm 	    protocol, sectype);
2829*4653Sdougm 
2830*4653Sdougm 	if (ret == SA_OK && !dryrun) {
2831*4653Sdougm 		if (optlist != NULL) {
28323034Sdougm 			if (share != NULL) {
2833*4653Sdougm 				sa_security_t optionset;
2834*4653Sdougm 				sa_property_t prop;
2835*4653Sdougm 				change = remove_security(share,
2836*4653Sdougm 				    sectype, optlist, protocol, &ret);
2837*4653Sdougm 
2838*4653Sdougm 				/* If a share security is empty, remove it */
2839*4653Sdougm 				optionset = sa_get_security((sa_group_t)share,
2840*4653Sdougm 				    sectype, protocol);
2841*4653Sdougm 				if (optionset != NULL) {
2842*4653Sdougm 					prop = sa_get_property(optionset,
2843*4653Sdougm 					    NULL);
2844*4653Sdougm 					if (prop == NULL)
2845*4653Sdougm 						ret = sa_destroy_security(
2846*4653Sdougm 						    optionset);
2847*4653Sdougm 				}
28483034Sdougm 			} else {
2849*4653Sdougm 				change = remove_security(group, sectype,
2850*4653Sdougm 				    optlist, protocol, &ret);
28513034Sdougm 			}
2852*4653Sdougm 		} else {
28533034Sdougm 			sa_security_t security;
28543034Sdougm 			char *sec;
28553034Sdougm 			sec = sa_proto_space_alias(protocol, sectype);
28563034Sdougm 			security = sa_get_security(group, sec, protocol);
28573034Sdougm 			if (sec != NULL)
2858*4653Sdougm 				sa_free_attr_string(sec);
28593034Sdougm 			if (security != NULL) {
2860*4653Sdougm 				ret = sa_destroy_security(security);
2861*4653Sdougm 				if (ret == SA_OK)
2862*4653Sdougm 					change = 1;
28633034Sdougm 			} else {
2864*4653Sdougm 				ret = SA_NO_SUCH_PROP;
28653034Sdougm 			}
2866*4653Sdougm 		}
2867*4653Sdougm 		if (ret != SA_OK)
28683034Sdougm 			(void) printf(gettext("Could not unset property: %s\n"),
2869*4653Sdougm 			    sa_errorstr(ret));
28703034Sdougm 	}
2871*4653Sdougm 
2872*4653Sdougm 	if (ret == SA_OK && change)
2873*4653Sdougm 		worklist = add_list(worklist, group, 0);
2874*4653Sdougm 
28753034Sdougm 	free_opt(optlist);
28763034Sdougm 	/*
2877*4653Sdougm 	 * We have a group and potentially legal additions
28783034Sdougm 	 */
28793034Sdougm 
2880*4653Sdougm 	/* Commit to configuration if not a dryrun */
28813034Sdougm 	if (!dryrun && ret == 0) {
28823034Sdougm 		/* properties changed, so update all shares */
2883*4653Sdougm 		if (change && worklist != NULL)
2884*4653Sdougm 			(void) enable_all_groups(handle, worklist, 0, 0,
2885*4653Sdougm 			    protocol);
2886*4653Sdougm 		ret = sa_update_config(handle);
28873034Sdougm 	}
28883034Sdougm 	if (worklist != NULL)
2889*4653Sdougm 		free_list(worklist);
28903034Sdougm 	return (ret);
28913034Sdougm }
28923034Sdougm 
28933034Sdougm /*
28943034Sdougm  * sa_unset(flags, argc, argv)
28953034Sdougm  *
2896*4653Sdougm  * Implements the unset subcommand. Parsing done here and then basic
28973034Sdougm  * or space versions of the real code are called.
28983034Sdougm  */
28993034Sdougm 
29003034Sdougm int
29013910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
29023034Sdougm {
29033034Sdougm 	char *groupname;
29043034Sdougm 	int verbose = 0;
29053034Sdougm 	int dryrun = 0;
29063034Sdougm 	int c;
29073034Sdougm 	char *protocol = NULL;
29083034Sdougm 	int ret = SA_OK;
29093034Sdougm 	struct options *optlist = NULL;
29103034Sdougm 	char *sharepath = NULL;
29113034Sdougm 	char *optset = NULL;
29123034Sdougm 	int auth;
29133034Sdougm 
29143034Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
2915*4653Sdougm 		switch (c) {
2916*4653Sdougm 		case 'v':
2917*4653Sdougm 			verbose++;
2918*4653Sdougm 			break;
2919*4653Sdougm 		case 'n':
2920*4653Sdougm 			dryrun++;
2921*4653Sdougm 			break;
2922*4653Sdougm 		case 'P':
2923*4653Sdougm 			protocol = optarg;
2924*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
2925*4653Sdougm 				(void) printf(gettext(
2926*4653Sdougm 				    "Invalid protocol specified: %s\n"),
2927*4653Sdougm 				    protocol);
2928*4653Sdougm 				return (SA_INVALID_PROTOCOL);
2929*4653Sdougm 			}
2930*4653Sdougm 			break;
2931*4653Sdougm 		case 'p':
2932*4653Sdougm 			ret = add_opt(&optlist, optarg, 1);
2933*4653Sdougm 			switch (ret) {
2934*4653Sdougm 			case OPT_ADD_SYNTAX:
2935*4653Sdougm 				(void) printf(gettext("Property syntax error "
2936*4653Sdougm 				    "for property %s\n"), optarg);
2937*4653Sdougm 				return (SA_SYNTAX_ERR);
2938*4653Sdougm 
2939*4653Sdougm 			case OPT_ADD_PROPERTY:
2940*4653Sdougm 				(void) printf(gettext("Properties need to be "
2941*4653Sdougm 				    "set with set command: %s\n"), optarg);
2942*4653Sdougm 				return (SA_SYNTAX_ERR);
2943*4653Sdougm 
2944*4653Sdougm 			default:
2945*4653Sdougm 				break;
2946*4653Sdougm 			}
2947*4653Sdougm 			break;
2948*4653Sdougm 		case 's':
2949*4653Sdougm 			sharepath = optarg;
2950*4653Sdougm 			break;
2951*4653Sdougm 		case 'S':
2952*4653Sdougm 			optset = optarg;
2953*4653Sdougm 			break;
2954*4653Sdougm 		default:
2955*4653Sdougm 		case 'h':
2956*4653Sdougm 		case '?':
2957*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
2958*4653Sdougm 			    sa_get_usage(USAGE_UNSET));
2959*4653Sdougm 			return (SA_OK);
29603034Sdougm 		}
29613034Sdougm 	}
29623034Sdougm 
29633034Sdougm 	if (optlist != NULL)
2964*4653Sdougm 		ret = chk_opt(optlist, optset != NULL, protocol);
29653034Sdougm 
29663034Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
29673034Sdougm 	    protocol == NULL) {
2968*4653Sdougm 		char *sep = "\t";
2969*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
2970*4653Sdougm 		    sa_get_usage(USAGE_UNSET));
2971*4653Sdougm 		if (optind >= argc) {
2972*4653Sdougm 			(void) printf(gettext("%sgroup must be specified"),
2973*4653Sdougm 			    sep);
2974*4653Sdougm 			sep = ", ";
2975*4653Sdougm 		}
2976*4653Sdougm 		if (optlist == NULL) {
2977*4653Sdougm 			(void) printf(gettext("%sat least one property must "
2978*4653Sdougm 			    "be specified"), sep);
2979*4653Sdougm 			sep = ", ";
2980*4653Sdougm 		}
2981*4653Sdougm 		if (protocol == NULL) {
2982*4653Sdougm 			(void) printf(gettext("%sprotocol must be specified"),
2983*4653Sdougm 			    sep);
2984*4653Sdougm 			sep = ", ";
2985*4653Sdougm 		}
2986*4653Sdougm 		(void) printf("\n");
2987*4653Sdougm 		ret = SA_SYNTAX_ERR;
29883034Sdougm 	} else {
29893034Sdougm 
29903034Sdougm 		/*
2991*4653Sdougm 		 * If a group already exists, we can only add a new
29923034Sdougm 		 * protocol to it and not create a new one or add the
29933034Sdougm 		 * same protocol again.
29943034Sdougm 		 */
29953034Sdougm 
2996*4653Sdougm 		groupname = argv[optind];
2997*4653Sdougm 		auth = check_authorizations(groupname, flags);
2998*4653Sdougm 		if (optset == NULL)
2999*4653Sdougm 			ret = basic_unset(handle, groupname, optlist, protocol,
3000*4653Sdougm 			    sharepath, dryrun);
3001*4653Sdougm 		else
3002*4653Sdougm 			ret = space_unset(handle, groupname, optlist, protocol,
3003*4653Sdougm 			    sharepath, dryrun, optset);
3004*4653Sdougm 
3005*4653Sdougm 		if (dryrun && ret == SA_OK && !auth && verbose)
3006*4653Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
3007*4653Sdougm 			    sa_errorstr(SA_NO_PERMISSION));
30083034Sdougm 	}
30093034Sdougm 	return (ret);
30103034Sdougm }
30113034Sdougm 
30123034Sdougm /*
30133034Sdougm  * sa_enable_group(flags, argc, argv)
30143034Sdougm  *
30153034Sdougm  * Implements the enable subcommand
30163034Sdougm  */
30173034Sdougm 
30183034Sdougm int
30193910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
30203034Sdougm {
30213034Sdougm 	int verbose = 0;
30223034Sdougm 	int dryrun = 0;
30233034Sdougm 	int all = 0;
30243034Sdougm 	int c;
30253034Sdougm 	int ret = SA_OK;
30263034Sdougm 	char *protocol = NULL;
30273034Sdougm 	char *state;
30283034Sdougm 	struct list *worklist = NULL;
30293034Sdougm 	int auth = 1;
3030*4653Sdougm 	sa_group_t group;
30313034Sdougm 
30323034Sdougm 	while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
3033*4653Sdougm 		switch (c) {
3034*4653Sdougm 		case 'a':
3035*4653Sdougm 			all = 1;
3036*4653Sdougm 			break;
3037*4653Sdougm 		case 'n':
3038*4653Sdougm 			dryrun++;
3039*4653Sdougm 			break;
3040*4653Sdougm 		case 'P':
3041*4653Sdougm 			protocol = optarg;
3042*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
3043*4653Sdougm 				(void) printf(gettext(
3044*4653Sdougm 				    "Invalid protocol specified: %s\n"),
30453034Sdougm 				    protocol);
3046*4653Sdougm 				return (SA_INVALID_PROTOCOL);
3047*4653Sdougm 			}
3048*4653Sdougm 			break;
3049*4653Sdougm 		case 'v':
3050*4653Sdougm 			verbose++;
3051*4653Sdougm 			break;
3052*4653Sdougm 		default:
3053*4653Sdougm 		case 'h':
3054*4653Sdougm 		case '?':
3055*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
3056*4653Sdougm 			    sa_get_usage(USAGE_ENABLE));
3057*4653Sdougm 			return (0);
30583034Sdougm 		}
30593034Sdougm 	}
30603034Sdougm 
30613034Sdougm 	if (optind == argc && !all) {
3062*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
3063*4653Sdougm 		    sa_get_usage(USAGE_ENABLE));
3064*4653Sdougm 		(void) printf(gettext("\tmust specify group\n"));
3065*4653Sdougm 		return (SA_NO_SUCH_PATH);
3066*4653Sdougm 	}
3067*4653Sdougm 	if (!all) {
30683034Sdougm 		while (optind < argc) {
3069*4653Sdougm 			group = sa_get_group(handle, argv[optind]);
3070*4653Sdougm 			if (group != NULL) {
3071*4653Sdougm 				auth &= check_authorizations(argv[optind],
3072*4653Sdougm 				    flags);
3073*4653Sdougm 				state = sa_get_group_attr(group, "state");
3074*4653Sdougm 				if (state != NULL &&
3075*4653Sdougm 				    strcmp(state, "enabled") == 0) {
3076*4653Sdougm 					/* already enabled */
3077*4653Sdougm 					if (verbose)
3078*4653Sdougm 						(void) printf(gettext(
3079*4653Sdougm 						    "Group \"%s\" is already "
3080*4653Sdougm 						    "enabled\n"),
3081*4653Sdougm 						    argv[optind]);
3082*4653Sdougm 					ret = SA_BUSY; /* already enabled */
3083*4653Sdougm 				} else {
3084*4653Sdougm 					worklist = add_list(worklist, group,
3085*4653Sdougm 					    0);
3086*4653Sdougm 					if (verbose)
3087*4653Sdougm 						(void) printf(gettext(
3088*4653Sdougm 						    "Enabling group \"%s\"\n"),
3089*4653Sdougm 						    argv[optind]);
3090*4653Sdougm 				}
3091*4653Sdougm 				if (state != NULL)
3092*4653Sdougm 					sa_free_attr_string(state);
30933034Sdougm 			} else {
3094*4653Sdougm 				ret = SA_NO_SUCH_GROUP;
30953034Sdougm 			}
3096*4653Sdougm 			optind++;
30973034Sdougm 		}
3098*4653Sdougm 	} else {
3099*4653Sdougm 		for (group = sa_get_group(handle, NULL);
3100*4653Sdougm 		    group != NULL;
31013034Sdougm 		    group = sa_get_next_group(group)) {
3102*4653Sdougm 			worklist = add_list(worklist, group, 0);
31033034Sdougm 		}
3104*4653Sdougm 	}
3105*4653Sdougm 	if (!dryrun && ret == SA_OK)
31063910Sdougm 		ret = enable_all_groups(handle, worklist, 1, 0, NULL);
3107*4653Sdougm 
3108*4653Sdougm 	if (ret != SA_OK && ret != SA_BUSY)
31093034Sdougm 		(void) printf(gettext("Could not enable group: %s\n"),
3110*4653Sdougm 		    sa_errorstr(ret));
3111*4653Sdougm 	if (ret == SA_BUSY)
31123034Sdougm 		ret = SA_OK;
3113*4653Sdougm 
31143034Sdougm 	if (worklist != NULL)
3115*4653Sdougm 		free_list(worklist);
31163034Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
3117*4653Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
3118*4653Sdougm 		    sa_errorstr(SA_NO_PERMISSION));
31193034Sdougm 	}
31203034Sdougm 	return (ret);
31213034Sdougm }
31223034Sdougm 
31233034Sdougm /*
31243034Sdougm  * disable_group(group, setstate)
31253034Sdougm  *
3126*4653Sdougm  * Disable all the shares in the specified group honoring the setstate
31273034Sdougm  * argument. This is a helper for disable_all_groups in order to
31283034Sdougm  * simplify regular and subgroup (zfs) disabling. Group has already
31293034Sdougm  * been checked for non-NULL.
31303034Sdougm  */
31313034Sdougm 
31323034Sdougm static int
31333034Sdougm disable_group(sa_group_t group)
31343034Sdougm {
31353034Sdougm 	sa_share_t share;
31363034Sdougm 	int ret = SA_OK;
31373034Sdougm 
31383034Sdougm 	for (share = sa_get_share(group, NULL);
31393034Sdougm 	    share != NULL && ret == SA_OK;
31403034Sdougm 	    share = sa_get_next_share(share)) {
3141*4653Sdougm 		ret = sa_disable_share(share, NULL);
3142*4653Sdougm 		if (ret == SA_NO_SUCH_PATH) {
3143*4653Sdougm 			/*
3144*4653Sdougm 			 * this is OK since the path is gone. we can't
3145*4653Sdougm 			 * re-share it anyway so no error.
3146*4653Sdougm 			 */
3147*4653Sdougm 			ret = SA_OK;
3148*4653Sdougm 		}
31493034Sdougm 	}
31503034Sdougm 	return (ret);
31513034Sdougm }
31523034Sdougm 
31533034Sdougm 
31543034Sdougm /*
31553034Sdougm  * disable_all_groups(work, setstate)
31563034Sdougm  *
31573034Sdougm  * helper function that disables the shares in the list of groups
31583034Sdougm  * provided. It optionally marks the group as disabled. Used by both
31593034Sdougm  * enable and start subcommands.
31603034Sdougm  */
31613034Sdougm 
31623034Sdougm static int
31633910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
31643034Sdougm {
31653034Sdougm 	int ret = SA_OK;
31663034Sdougm 	sa_group_t subgroup, group;
31673034Sdougm 
31683034Sdougm 	while (work != NULL && ret == SA_OK) {
3169*4653Sdougm 		group = (sa_group_t)work->item;
3170*4653Sdougm 		if (setstate)
3171*4653Sdougm 			ret = sa_set_group_attr(group, "state", "disabled");
3172*4653Sdougm 		if (ret == SA_OK) {
3173*4653Sdougm 			char *name;
3174*4653Sdougm 			name = sa_get_group_attr(group, "name");
3175*4653Sdougm 			if (name != NULL && strcmp(name, "zfs") == 0) {
3176*4653Sdougm 				/* need to get the sub-groups for stopping */
3177*4653Sdougm 				for (subgroup = sa_get_sub_group(group);
3178*4653Sdougm 				    subgroup != NULL;
3179*4653Sdougm 				    subgroup = sa_get_next_group(subgroup)) {
3180*4653Sdougm 					ret = disable_group(subgroup);
3181*4653Sdougm 				}
3182*4653Sdougm 			} else {
3183*4653Sdougm 				ret = disable_group(group);
3184*4653Sdougm 			}
3185*4653Sdougm 			/*
3186*4653Sdougm 			 * We don't want to "disable" since it won't come
3187*4653Sdougm 			 * up after a reboot.  The SMF framework should do
3188*4653Sdougm 			 * the right thing. On enable we do want to do
3189*4653Sdougm 			 * something.
3190*4653Sdougm 			 */
31913034Sdougm 		}
3192*4653Sdougm 		work = work->next;
31933034Sdougm 	}
31943034Sdougm 	if (ret == SA_OK)
3195*4653Sdougm 		ret = sa_update_config(handle);
31963034Sdougm 	return (ret);
31973034Sdougm }
31983034Sdougm 
31993034Sdougm /*
32003034Sdougm  * sa_disable_group(flags, argc, argv)
32013034Sdougm  *
32023034Sdougm  * Implements the disable subcommand
32033034Sdougm  */
32043034Sdougm 
32053034Sdougm int
32063910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
32073034Sdougm {
32083034Sdougm 	int verbose = 0;
32093034Sdougm 	int dryrun = 0;
32103034Sdougm 	int all = 0;
32113034Sdougm 	int c;
32123034Sdougm 	int ret = SA_OK;
32133034Sdougm 	char *protocol;
32143034Sdougm 	char *state;
32153034Sdougm 	struct list *worklist = NULL;
3216*4653Sdougm 	sa_group_t group;
32173034Sdougm 	int auth = 1;
32183034Sdougm 
32193034Sdougm 	while ((c = getopt(argc, argv, "?havn")) != EOF) {
3220*4653Sdougm 		switch (c) {
3221*4653Sdougm 		case 'a':
3222*4653Sdougm 			all = 1;
3223*4653Sdougm 			break;
3224*4653Sdougm 		case 'n':
3225*4653Sdougm 			dryrun++;
3226*4653Sdougm 			break;
3227*4653Sdougm 		case 'P':
3228*4653Sdougm 			protocol = optarg;
3229*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
3230*4653Sdougm 				(void) printf(gettext(
3231*4653Sdougm 				    "Invalid protocol specified: %s\n"),
3232*4653Sdougm 				    protocol);
3233*4653Sdougm 				return (SA_INVALID_PROTOCOL);
3234*4653Sdougm 			}
3235*4653Sdougm 			break;
3236*4653Sdougm 		case 'v':
3237*4653Sdougm 			verbose++;
3238*4653Sdougm 			break;
3239*4653Sdougm 		default:
3240*4653Sdougm 		case 'h':
3241*4653Sdougm 		case '?':
3242*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
3243*4653Sdougm 			    sa_get_usage(USAGE_DISABLE));
3244*4653Sdougm 			return (0);
32453034Sdougm 		}
32463034Sdougm 	}
32473034Sdougm 
32483034Sdougm 	if (optind == argc && !all) {
32493034Sdougm 		(void) printf(gettext("usage: %s\n"),
3250*4653Sdougm 		    sa_get_usage(USAGE_DISABLE));
32513034Sdougm 		(void) printf(gettext("\tmust specify group\n"));
3252*4653Sdougm 		return (SA_NO_SUCH_PATH);
3253*4653Sdougm 	}
3254*4653Sdougm 	if (!all) {
3255*4653Sdougm 		while (optind < argc) {
32563910Sdougm 			group = sa_get_group(handle, argv[optind]);
32573034Sdougm 			if (group != NULL) {
3258*4653Sdougm 				auth &= check_authorizations(argv[optind],
3259*4653Sdougm 				    flags);
3260*4653Sdougm 				state = sa_get_group_attr(group, "state");
3261*4653Sdougm 				if (state == NULL ||
3262*4653Sdougm 				    strcmp(state, "disabled") == 0) {
3263*4653Sdougm 					/* already disabled */
3264*4653Sdougm 					if (verbose)
3265*4653Sdougm 						(void) printf(gettext(
3266*4653Sdougm 						    "Group \"%s\" is "
3267*4653Sdougm 						    "already disabled\n"),
3268*4653Sdougm 						    argv[optind]);
3269*4653Sdougm 					ret = SA_BUSY; /* already disable */
3270*4653Sdougm 				} else {
3271*4653Sdougm 					worklist = add_list(worklist, group, 0);
3272*4653Sdougm 					if (verbose)
3273*4653Sdougm 						(void) printf(gettext(
3274*4653Sdougm 						    "Disabling group "
3275*4653Sdougm 						    "\"%s\"\n"), argv[optind]);
3276*4653Sdougm 				}
3277*4653Sdougm 				if (state != NULL)
3278*4653Sdougm 					sa_free_attr_string(state);
32793034Sdougm 			} else {
3280*4653Sdougm 				ret = SA_NO_SUCH_GROUP;
32813034Sdougm 			}
32823034Sdougm 			optind++;
3283*4653Sdougm 		}
3284*4653Sdougm 	} else {
3285*4653Sdougm 		for (group = sa_get_group(handle, NULL);
3286*4653Sdougm 		    group != NULL;
3287*4653Sdougm 		    group = sa_get_next_group(group))
32883034Sdougm 			worklist = add_list(worklist, group, 0);
32893034Sdougm 	}
3290*4653Sdougm 
3291*4653Sdougm 	if (ret == SA_OK && !dryrun)
3292*4653Sdougm 		ret = disable_all_groups(handle, worklist, 1);
3293*4653Sdougm 	if (ret != SA_OK && ret != SA_BUSY)
3294*4653Sdougm 		(void) printf(gettext("Could not disable group: %s\n"),
3295*4653Sdougm 		    sa_errorstr(ret));
3296*4653Sdougm 	if (ret == SA_BUSY)
3297*4653Sdougm 		ret = SA_OK;
32983034Sdougm 	if (worklist != NULL)
3299*4653Sdougm 		free_list(worklist);
3300*4653Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose)
3301*4653Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
3302*4653Sdougm 		    sa_errorstr(SA_NO_PERMISSION));
33033034Sdougm 	return (ret);
33043034Sdougm }
33053034Sdougm 
33063034Sdougm /*
33073034Sdougm  * sa_start_group(flags, argc, argv)
33083034Sdougm  *
33093034Sdougm  * Implements the start command.
33103034Sdougm  * This is similar to enable except it doesn't change the state
33113034Sdougm  * of the group(s) and only enables shares if the group is already
33123034Sdougm  * enabled.
33133034Sdougm  */
3314*4653Sdougm /*ARGSUSED*/
33153034Sdougm int
33163910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
33173034Sdougm {
33183034Sdougm 	int verbose = 0;
33193034Sdougm 	int all = 0;
33203034Sdougm 	int c;
33213034Sdougm 	int ret = SMF_EXIT_OK;
33223034Sdougm 	char *protocol = NULL;
33233034Sdougm 	char *state;
33243034Sdougm 	struct list *worklist = NULL;
3325*4653Sdougm 	sa_group_t group;
33263034Sdougm 
33273034Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
3328*4653Sdougm 		switch (c) {
3329*4653Sdougm 		case 'a':
3330*4653Sdougm 			all = 1;
3331*4653Sdougm 			break;
3332*4653Sdougm 		case 'P':
3333*4653Sdougm 			protocol = optarg;
3334*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
3335*4653Sdougm 				(void) printf(gettext(
3336*4653Sdougm 				    "Invalid protocol specified: %s\n"),
33373034Sdougm 				    protocol);
3338*4653Sdougm 				return (SA_INVALID_PROTOCOL);
3339*4653Sdougm 			}
3340*4653Sdougm 			break;
3341*4653Sdougm 		case 'v':
3342*4653Sdougm 			verbose++;
3343*4653Sdougm 			break;
3344*4653Sdougm 		default:
3345*4653Sdougm 		case 'h':
3346*4653Sdougm 		case '?':
3347*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
3348*4653Sdougm 			    sa_get_usage(USAGE_START));
3349*4653Sdougm 			return (SA_OK);
33503034Sdougm 		}
33513034Sdougm 	}
33523034Sdougm 
33533034Sdougm 	if (optind == argc && !all) {
33543034Sdougm 		(void) printf(gettext("usage: %s\n"),
3355*4653Sdougm 		    sa_get_usage(USAGE_START));
3356*4653Sdougm 		return (SMF_EXIT_ERR_FATAL);
3357*4653Sdougm 	}
3358*4653Sdougm 
3359*4653Sdougm 	if (!all) {
3360*4653Sdougm 		while (optind < argc) {
33613910Sdougm 			group = sa_get_group(handle, argv[optind]);
33623034Sdougm 			if (group != NULL) {
3363*4653Sdougm 				state = sa_get_group_attr(group, "state");
3364*4653Sdougm 				if (state == NULL ||
3365*4653Sdougm 				    strcmp(state, "enabled") == 0) {
3366*4653Sdougm 					worklist = add_list(worklist, group, 0);
3367*4653Sdougm 					if (verbose)
3368*4653Sdougm 						(void) printf(gettext(
3369*4653Sdougm 						    "Starting group \"%s\"\n"),
3370*4653Sdougm 						    argv[optind]);
3371*4653Sdougm 				} else {
3372*4653Sdougm 					/*
3373*4653Sdougm 					 * Determine if there are any
3374*4653Sdougm 					 * protocols.  if there aren't any,
3375*4653Sdougm 					 * then there isn't anything to do in
3376*4653Sdougm 					 * any case so no error.
3377*4653Sdougm 					 */
3378*4653Sdougm 					if (sa_get_optionset(group,
3379*4653Sdougm 					    protocol) != NULL) {
3380*4653Sdougm 						ret = SMF_EXIT_OK;
3381*4653Sdougm 					}
33823034Sdougm 				}
3383*4653Sdougm 				if (state != NULL)
3384*4653Sdougm 					sa_free_attr_string(state);
33853034Sdougm 			}
33863034Sdougm 			optind++;
3387*4653Sdougm 		}
3388*4653Sdougm 	} else {
3389*4653Sdougm 		for (group = sa_get_group(handle, NULL); group != NULL;
3390*4653Sdougm 		    group = sa_get_next_group(group)) {
33913034Sdougm 			state = sa_get_group_attr(group, "state");
33923034Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
3393*4653Sdougm 				worklist = add_list(worklist, group, 0);
33943034Sdougm 			if (state != NULL)
3395*4653Sdougm 				sa_free_attr_string(state);
33963034Sdougm 		}
33973034Sdougm 	}
3398*4653Sdougm 
3399*4653Sdougm 	(void) enable_all_groups(handle, worklist, 0, 1, NULL);
3400*4653Sdougm 
34013034Sdougm 	if (worklist != NULL)
3402*4653Sdougm 		free_list(worklist);
34033034Sdougm 	return (ret);
34043034Sdougm }
34053034Sdougm 
34063034Sdougm /*
34073034Sdougm  * sa_stop_group(flags, argc, argv)
34083034Sdougm  *
34093034Sdougm  * Implements the stop command.
34103034Sdougm  * This is similar to disable except it doesn't change the state
34113034Sdougm  * of the group(s) and only disables shares if the group is already
34123034Sdougm  * enabled.
34133034Sdougm  */
3414*4653Sdougm /*ARGSUSED*/
34153034Sdougm int
34163910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
34173034Sdougm {
34183034Sdougm 	int verbose = 0;
34193034Sdougm 	int all = 0;
34203034Sdougm 	int c;
34213034Sdougm 	int ret = SMF_EXIT_OK;
34223034Sdougm 	char *protocol = NULL;
34233034Sdougm 	char *state;
34243034Sdougm 	struct list *worklist = NULL;
3425*4653Sdougm 	sa_group_t group;
34263034Sdougm 
34273034Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
3428*4653Sdougm 		switch (c) {
3429*4653Sdougm 		case 'a':
3430*4653Sdougm 			all = 1;
3431*4653Sdougm 			break;
3432*4653Sdougm 		case 'P':
3433*4653Sdougm 			protocol = optarg;
3434*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
3435*4653Sdougm 				(void) printf(gettext(
3436*4653Sdougm 				    "Invalid protocol specified: %s\n"),
3437*4653Sdougm 				    protocol);
3438*4653Sdougm 				return (SA_INVALID_PROTOCOL);
3439*4653Sdougm 			}
3440*4653Sdougm 			break;
3441*4653Sdougm 		case 'v':
3442*4653Sdougm 			verbose++;
3443*4653Sdougm 			break;
3444*4653Sdougm 		default:
3445*4653Sdougm 		case 'h':
3446*4653Sdougm 		case '?':
3447*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
3448*4653Sdougm 			    sa_get_usage(USAGE_STOP));
3449*4653Sdougm 			return (0);
34503034Sdougm 		}
34513034Sdougm 	}
34523034Sdougm 
34533034Sdougm 	if (optind == argc && !all) {
3454*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
3455*4653Sdougm 		    sa_get_usage(USAGE_STOP));
3456*4653Sdougm 		return (SMF_EXIT_ERR_FATAL);
3457*4653Sdougm 	} else if (!all) {
3458*4653Sdougm 		while (optind < argc) {
34593910Sdougm 			group = sa_get_group(handle, argv[optind]);
34603034Sdougm 			if (group != NULL) {
3461*4653Sdougm 				state = sa_get_group_attr(group, "state");
3462*4653Sdougm 				if (state == NULL ||
3463*4653Sdougm 				    strcmp(state, "enabled") == 0) {
3464*4653Sdougm 					worklist = add_list(worklist, group, 0);
3465*4653Sdougm 					if (verbose)
3466*4653Sdougm 						(void) printf(gettext(
3467*4653Sdougm 						    "Stopping group \"%s\"\n"),
3468*4653Sdougm 						    argv[optind]);
3469*4653Sdougm 				} else {
3470*4653Sdougm 					ret = SMF_EXIT_OK;
3471*4653Sdougm 				}
3472*4653Sdougm 				if (state != NULL)
3473*4653Sdougm 					sa_free_attr_string(state);
34743034Sdougm 			}
34753034Sdougm 			optind++;
3476*4653Sdougm 		}
3477*4653Sdougm 	} else {
3478*4653Sdougm 		for (group = sa_get_group(handle, NULL); group != NULL;
3479*4653Sdougm 		    group = sa_get_next_group(group)) {
34803034Sdougm 			state = sa_get_group_attr(group, "state");
34813034Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
3482*4653Sdougm 				worklist = add_list(worklist, group, 0);
34833034Sdougm 			if (state != NULL)
3484*4653Sdougm 				sa_free_attr_string(state);
34853034Sdougm 		}
34863034Sdougm 	}
3487*4653Sdougm 
3488*4653Sdougm 	(void) disable_all_groups(handle, worklist, 0);
3489*4653Sdougm 	ret = sa_update_config(handle);
3490*4653Sdougm 
34913034Sdougm 	if (worklist != NULL)
3492*4653Sdougm 		free_list(worklist);
34933034Sdougm 	return (ret);
34943034Sdougm }
34953034Sdougm 
34963034Sdougm /*
34973034Sdougm  * remove_all_options(share, proto)
34983034Sdougm  *
34993034Sdougm  * Removes all options on a share.
35003034Sdougm  */
35013034Sdougm 
35023034Sdougm static void
35033034Sdougm remove_all_options(sa_share_t share, char *proto)
35043034Sdougm {
35053034Sdougm 	sa_optionset_t optionset;
35063034Sdougm 	sa_security_t security;
35073034Sdougm 	sa_security_t prevsec = NULL;
35083034Sdougm 
35093034Sdougm 	optionset = sa_get_optionset(share, proto);
35103034Sdougm 	if (optionset != NULL)
3511*4653Sdougm 		(void) sa_destroy_optionset(optionset);
35123034Sdougm 	for (security = sa_get_security(share, NULL, NULL);
35133034Sdougm 	    security != NULL;
35143034Sdougm 	    security = sa_get_next_security(security)) {
3515*4653Sdougm 		char *type;
35163034Sdougm 		/*
3517*4653Sdougm 		 * We walk through the list.  prevsec keeps the
35183034Sdougm 		 * previous security so we can delete it without
35193034Sdougm 		 * destroying the list.
35203034Sdougm 		 */
3521*4653Sdougm 		if (prevsec != NULL) {
3522*4653Sdougm 			/* remove the previously seen security */
3523*4653Sdougm 			(void) sa_destroy_security(prevsec);
3524*4653Sdougm 			/* set to NULL so we don't try multiple times */
3525*4653Sdougm 			prevsec = NULL;
3526*4653Sdougm 		}
3527*4653Sdougm 		type = sa_get_security_attr(security, "type");
3528*4653Sdougm 		if (type != NULL) {
3529*4653Sdougm 			/*
3530*4653Sdougm 			 * if the security matches the specified protocol, we
3531*4653Sdougm 			 * want to remove it. prevsec holds it until either
3532*4653Sdougm 			 * the next pass or we fall out of the loop.
3533*4653Sdougm 			 */
3534*4653Sdougm 			if (strcmp(type, proto) == 0)
3535*4653Sdougm 				prevsec = security;
3536*4653Sdougm 			sa_free_attr_string(type);
3537*4653Sdougm 		}
35383034Sdougm 	}
35393034Sdougm 	/* in case there is one left */
35403034Sdougm 	if (prevsec != NULL)
3541*4653Sdougm 		(void) sa_destroy_security(prevsec);
35423034Sdougm }
35433034Sdougm 
35443034Sdougm 
35453034Sdougm /*
35463034Sdougm  * for legacy support, we need to handle the old syntax. This is what
35473034Sdougm  * we get if sharemgr is called with the name "share" rather than
35483034Sdougm  * sharemgr.
35493034Sdougm  */
35503034Sdougm 
35513034Sdougm static int
35523034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
35533034Sdougm {
35543034Sdougm 	int err;
35553034Sdougm 
35563034Sdougm 	err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
35573034Sdougm 	if (err > buffsize)
3558*4653Sdougm 		return (-1);
35593034Sdougm 	return (0);
35603034Sdougm }
35613034Sdougm 
35623034Sdougm 
35633034Sdougm /*
35643034Sdougm  * check_legacy_cmd(proto, cmd)
35653034Sdougm  *
35663034Sdougm  * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
35673034Sdougm  * executable.
35683034Sdougm  */
35693034Sdougm 
35703034Sdougm static int
35713034Sdougm check_legacy_cmd(char *path)
35723034Sdougm {
35733034Sdougm 	struct stat st;
35743034Sdougm 	int ret = 0;
35753034Sdougm 
35763034Sdougm 	if (stat(path, &st) == 0) {
3577*4653Sdougm 		if (S_ISREG(st.st_mode) &&
3578*4653Sdougm 		    st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
3579*4653Sdougm 			ret = 1;
35803034Sdougm 	}
35813034Sdougm 	return (ret);
35823034Sdougm }
35833034Sdougm 
35843034Sdougm /*
35853034Sdougm  * run_legacy_command(proto, cmd, argv)
35863034Sdougm  *
3587*4653Sdougm  * We know the command exists, so attempt to execute it with all the
35883034Sdougm  * arguments. This implements full legacy share support for those
35893034Sdougm  * protocols that don't have plugin providers.
35903034Sdougm  */
35913034Sdougm 
35923034Sdougm static int
35933034Sdougm run_legacy_command(char *path, char *argv[])
35943034Sdougm {
35953034Sdougm 	int ret;
35963034Sdougm 
35973034Sdougm 	ret = execv(path, argv);
35983034Sdougm 	if (ret < 0) {
3599*4653Sdougm 		switch (errno) {
3600*4653Sdougm 		case EACCES:
3601*4653Sdougm 			ret = SA_NO_PERMISSION;
3602*4653Sdougm 			break;
3603*4653Sdougm 		default:
3604*4653Sdougm 			ret = SA_SYSTEM_ERR;
3605*4653Sdougm 			break;
3606*4653Sdougm 		}
36073034Sdougm 	}
36083034Sdougm 	return (ret);
36093034Sdougm }
36103034Sdougm 
36113034Sdougm /*
36123348Sdougm  * out_share(out, group, proto)
36133034Sdougm  *
36143034Sdougm  * Display the share information in the format that the "share"
36153034Sdougm  * command has traditionally used.
36163034Sdougm  */
36173034Sdougm 
36183034Sdougm static void
36193348Sdougm out_share(FILE *out, sa_group_t group, char *proto)
36203034Sdougm {
36213034Sdougm 	sa_share_t share;
36223034Sdougm 	char resfmt[128];
36233034Sdougm 
3624*4653Sdougm 	for (share = sa_get_share(group, NULL);
3625*4653Sdougm 	    share != NULL;
3626*4653Sdougm 	    share = sa_get_next_share(share)) {
3627*4653Sdougm 		char *path;
3628*4653Sdougm 		char *type;
3629*4653Sdougm 		char *resource;
3630*4653Sdougm 		char *description;
3631*4653Sdougm 		char *groupname;
3632*4653Sdougm 		char *sharedstate;
3633*4653Sdougm 		int shared = 1;
3634*4653Sdougm 		char *soptions;
3635*4653Sdougm 
3636*4653Sdougm 		sharedstate = sa_get_share_attr(share, "shared");
3637*4653Sdougm 		path = sa_get_share_attr(share, "path");
3638*4653Sdougm 		type = sa_get_share_attr(share, "type");
3639*4653Sdougm 		resource = sa_get_share_attr(share, "resource");
3640*4653Sdougm 		groupname = sa_get_group_attr(group, "name");
3641*4653Sdougm 
3642*4653Sdougm 		if (groupname != NULL && strcmp(groupname, "default") == 0) {
3643*4653Sdougm 			sa_free_attr_string(groupname);
3644*4653Sdougm 			groupname = NULL;
3645*4653Sdougm 		}
3646*4653Sdougm 		description = sa_get_share_description(share);
3647*4653Sdougm 
3648*4653Sdougm 		/* Want the sharetab version if it exists */
3649*4653Sdougm 		soptions = sa_get_share_attr(share, "shareopts");
3650*4653Sdougm 
3651*4653Sdougm 		if (sharedstate == NULL)
3652*4653Sdougm 			shared = 0;
3653*4653Sdougm 
3654*4653Sdougm 		if (soptions == NULL)
3655*4653Sdougm 			soptions = sa_proto_legacy_format(proto, share, 1);
3656*4653Sdougm 
3657*4653Sdougm 		if (shared) {
3658*4653Sdougm 			/* only active shares go here */
3659*4653Sdougm 			(void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
3660*4653Sdougm 			    resource != NULL ? resource : "-",
3661*4653Sdougm 			    groupname != NULL ? "@" : "",
3662*4653Sdougm 			    groupname != NULL ? groupname : "");
3663*4653Sdougm 			(void) fprintf(out, "%-14.14s  %s   %s   \"%s\"  \n",
3664*4653Sdougm 			    resfmt, path,
3665*4653Sdougm 			    (soptions != NULL && strlen(soptions) > 0) ?
3666*4653Sdougm 			    soptions : "rw",
3667*4653Sdougm 			    (description != NULL) ? description : "");
3668*4653Sdougm 		}
3669*4653Sdougm 
3670*4653Sdougm 		if (path != NULL)
3671*4653Sdougm 			sa_free_attr_string(path);
3672*4653Sdougm 		if (type != NULL)
3673*4653Sdougm 			sa_free_attr_string(type);
3674*4653Sdougm 		if (resource != NULL)
3675*4653Sdougm 			sa_free_attr_string(resource);
3676*4653Sdougm 		if (groupname != NULL)
3677*4653Sdougm 			sa_free_attr_string(groupname);
3678*4653Sdougm 		if (description != NULL)
3679*4653Sdougm 			sa_free_share_description(description);
3680*4653Sdougm 		if (sharedstate != NULL)
3681*4653Sdougm 			sa_free_attr_string(sharedstate);
3682*4653Sdougm 		if (soptions != NULL)
3683*4653Sdougm 			sa_format_free(soptions);
36843034Sdougm 	}
36853034Sdougm }
36863034Sdougm 
36873034Sdougm /*
36883034Sdougm  * output_legacy_file(out, proto)
36893034Sdougm  *
36903034Sdougm  * Walk all of the groups for the specified protocol and call
36913034Sdougm  * out_share() to format and write in the format displayed by the
36923034Sdougm  * "share" command with no arguments.
36933034Sdougm  */
36943034Sdougm 
36953034Sdougm static void
36963910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
36973034Sdougm {
36983034Sdougm 	sa_group_t group;
36993034Sdougm 
37003910Sdougm 	for (group = sa_get_group(handle, NULL); group != NULL;
3701*4653Sdougm 	    group = sa_get_next_group(group)) {
3702*4653Sdougm 		char *options;
3703*4653Sdougm 		char *zfs;
37043034Sdougm 
37053034Sdougm 		/*
3706*4653Sdougm 		 * Get default options preformated, being careful to
37073034Sdougm 		 * handle legacy shares differently from new style
37083034Sdougm 		 * shares. Legacy share have options on the share.
37093034Sdougm 		 */
37103034Sdougm 
3711*4653Sdougm 		zfs = sa_get_group_attr(group, "zfs");
3712*4653Sdougm 		if (zfs != NULL) {
3713*4653Sdougm 			sa_group_t zgroup;
3714*4653Sdougm 			sa_free_attr_string(zfs);
3715*4653Sdougm 			options = sa_proto_legacy_format(proto, group, 1);
3716*4653Sdougm 			for (zgroup = sa_get_sub_group(group);
3717*4653Sdougm 			    zgroup != NULL;
3718*4653Sdougm 			    zgroup = sa_get_next_group(zgroup)) {
3719*4653Sdougm 
3720*4653Sdougm 				/* got a group, so display it */
3721*4653Sdougm 				out_share(out, zgroup, proto);
3722*4653Sdougm 			}
3723*4653Sdougm 		} else {
3724*4653Sdougm 			options = sa_proto_legacy_format(proto, group, 1);
3725*4653Sdougm 			out_share(out, group, proto);
37263034Sdougm 		}
3727*4653Sdougm 		if (options != NULL)
3728*4653Sdougm 			free(options);
37293034Sdougm 	}
37303034Sdougm }
37313034Sdougm 
3732*4653Sdougm /*ARGSUSED*/
37333034Sdougm int
37343910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
37353034Sdougm {
37363034Sdougm 	char *protocol = "nfs";
37373034Sdougm 	char *options = NULL;
37383034Sdougm 	char *description = NULL;
37393034Sdougm 	char *groupname = NULL;
37403034Sdougm 	char *sharepath = NULL;
37413034Sdougm 	char *resource = NULL;
37423034Sdougm 	char *groupstatus = NULL;
37433034Sdougm 	int persist = SA_SHARE_TRANSIENT;
37443034Sdougm 	int argsused = 0;
37453034Sdougm 	int c;
37463034Sdougm 	int ret = SA_OK;
37473034Sdougm 	int zfs = 0;
37483034Sdougm 	int true_legacy = 0;
37493034Sdougm 	int curtype = SA_SHARE_TRANSIENT;
37503034Sdougm 	char cmd[MAXPATHLEN];
3751*4653Sdougm 	sa_group_t group = NULL;
3752*4653Sdougm 	sa_share_t share;
3753*4653Sdougm 	char dir[MAXPATHLEN];
37543034Sdougm 
37553034Sdougm 	while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
3756*4653Sdougm 		switch (c) {
3757*4653Sdougm 		case 'd':
3758*4653Sdougm 			description = optarg;
3759*4653Sdougm 			argsused++;
3760*4653Sdougm 			break;
3761*4653Sdougm 		case 'F':
3762*4653Sdougm 			protocol = optarg;
3763*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
3764*4653Sdougm 				if (format_legacy_path(cmd, MAXPATHLEN,
3765*4653Sdougm 				    protocol, "share") == 0 &&
3766*4653Sdougm 				    check_legacy_cmd(cmd)) {
3767*4653Sdougm 					true_legacy++;
3768*4653Sdougm 				} else {
3769*4653Sdougm 					(void) fprintf(stderr, gettext(
3770*4653Sdougm 					    "Invalid protocol specified: "
3771*4653Sdougm 					    "%s\n"), protocol);
3772*4653Sdougm 					return (SA_INVALID_PROTOCOL);
3773*4653Sdougm 				}
3774*4653Sdougm 			}
3775*4653Sdougm 			break;
3776*4653Sdougm 		case 'o':
3777*4653Sdougm 			options = optarg;
3778*4653Sdougm 			argsused++;
3779*4653Sdougm 			break;
3780*4653Sdougm 		case 'p':
3781*4653Sdougm 			persist = SA_SHARE_PERMANENT;
3782*4653Sdougm 			argsused++;
3783*4653Sdougm 			break;
3784*4653Sdougm 		case 'h':
3785*4653Sdougm 		case '?':
3786*4653Sdougm 		default:
3787*4653Sdougm 			(void) fprintf(stderr, gettext("usage: %s\n"),
3788*4653Sdougm 			    sa_get_usage(USAGE_SHARE));
3789*4653Sdougm 			return (SA_OK);
37903034Sdougm 		}
3791*4653Sdougm 	}
3792*4653Sdougm 
3793*4653Sdougm 	/* Have the info so construct what is needed */
3794*4653Sdougm 	if (!argsused && optind == argc) {
3795*4653Sdougm 		/* display current info in share format */
3796*4653Sdougm 		(void) output_legacy_file(stdout, "nfs", handle);
3797*4653Sdougm 		return (ret);
37983034Sdougm 	}
37993034Sdougm 
3800*4653Sdougm 	/* We are modifying the configuration */
3801*4653Sdougm 	if (optind == argc) {
38023034Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
3803*4653Sdougm 		    sa_get_usage(USAGE_SHARE));
38043034Sdougm 		return (SA_LEGACY_ERR);
3805*4653Sdougm 	}
3806*4653Sdougm 	if (true_legacy) {
3807*4653Sdougm 		/* If still using legacy share/unshare, exec it */
38083034Sdougm 		ret = run_legacy_command(cmd, argv);
38093034Sdougm 		return (ret);
3810*4653Sdougm 	}
3811*4653Sdougm 
3812*4653Sdougm 	sharepath = argv[optind++];
3813*4653Sdougm 	if (optind < argc) {
38143034Sdougm 		resource = argv[optind];
38153034Sdougm 		groupname = strchr(resource, '@');
38163034Sdougm 		if (groupname != NULL)
3817*4653Sdougm 			*groupname++ = '\0';
3818*4653Sdougm 	}
3819*4653Sdougm 	if (realpath(sharepath, dir) == NULL)
38203034Sdougm 		ret = SA_BAD_PATH;
3821*4653Sdougm 	else
38223034Sdougm 		sharepath = dir;
3823*4653Sdougm 	if (ret == SA_OK)
38243910Sdougm 		share = sa_find_share(handle, sharepath);
3825*4653Sdougm 	else
38263034Sdougm 		share = NULL;
3827*4653Sdougm 
3828*4653Sdougm 	if (groupname != NULL) {
3829*4653Sdougm 		ret = SA_NOT_ALLOWED;
3830*4653Sdougm 	} else if (ret == SA_OK) {
38313034Sdougm 		char *legacygroup = "default";
38323034Sdougm 		/*
3833*4653Sdougm 		 * The legacy group is always present and zfs groups
38343034Sdougm 		 * come and go.  zfs shares may be in sub-groups and
38353034Sdougm 		 * the zfs share will already be in that group so it
38363034Sdougm 		 * isn't an error.
38373034Sdougm 		 */
38383034Sdougm 		/*
3839*4653Sdougm 		 * If the share exists (not NULL), then make sure it
3840*4653Sdougm 		 * is one we want to handle by getting the parent
3841*4653Sdougm 		 * group.
38423034Sdougm 		 */
3843*4653Sdougm 		if (share != NULL)
3844*4653Sdougm 			group = sa_get_parent_group(share);
3845*4653Sdougm 		else
3846*4653Sdougm 			group = sa_get_group(handle, legacygroup);
3847*4653Sdougm 
38483034Sdougm 		if (group != NULL) {
3849*4653Sdougm 			groupstatus = group_status(group);
3850*4653Sdougm 			if (share == NULL) {
3851*4653Sdougm 				share = sa_add_share(group, sharepath,
3852*4653Sdougm 				    persist, &ret);
3853*4653Sdougm 				if (share == NULL &&
3854*4653Sdougm 				    ret == SA_DUPLICATE_NAME) {
3855*4653Sdougm 					/*
3856*4653Sdougm 					 * Could be a ZFS path being started
3857*4653Sdougm 					 */
3858*4653Sdougm 					if (sa_zfs_is_shared(handle,
3859*4653Sdougm 					    sharepath)) {
3860*4653Sdougm 						ret = SA_OK;
3861*4653Sdougm 						group = sa_get_group(handle,
3862*4653Sdougm 						    "zfs");
3863*4653Sdougm 						if (group == NULL) {
3864*4653Sdougm 							/*
3865*4653Sdougm 							 * This shouldn't
3866*4653Sdougm 							 * happen.
3867*4653Sdougm 							 */
3868*4653Sdougm 							ret = SA_CONFIG_ERR;
3869*4653Sdougm 						} else {
3870*4653Sdougm 							share = sa_add_share(
3871*4653Sdougm 							    group, sharepath,
3872*4653Sdougm 							    persist, &ret);
3873*4653Sdougm 						}
3874*4653Sdougm 					}
38753034Sdougm 				}
3876*4653Sdougm 			} else {
3877*4653Sdougm 				char *type;
3878*4653Sdougm 				/*
3879*4653Sdougm 				 * May want to change persist state, but the
3880*4653Sdougm 				 * important thing is to change options. We
3881*4653Sdougm 				 * need to change them regardless of the
3882*4653Sdougm 				 * source.
3883*4653Sdougm 				 */
3884*4653Sdougm 				if (sa_zfs_is_shared(handle, sharepath)) {
3885*4653Sdougm 					zfs = 1;
38863034Sdougm 				}
3887*4653Sdougm 				remove_all_options(share, protocol);
3888*4653Sdougm 				type = sa_get_share_attr(share, "type");
3889*4653Sdougm 				if (type != NULL &&
3890*4653Sdougm 				    strcmp(type, "transient") != 0) {
3891*4653Sdougm 					curtype = SA_SHARE_PERMANENT;
3892*4653Sdougm 				}
3893*4653Sdougm 				if (type != NULL)
3894*4653Sdougm 					sa_free_attr_string(type);
3895*4653Sdougm 				if (curtype != persist) {
3896*4653Sdougm 					(void) sa_set_share_attr(share, "type",
3897*4653Sdougm 					    persist == SA_SHARE_PERMANENT ?
3898*4653Sdougm 					    "persist" : "transient");
3899*4653Sdougm 				}
39003108Sdougm 			}
3901*4653Sdougm 			/* Have a group to hold this share path */
3902*4653Sdougm 			if (ret == SA_OK && options != NULL &&
3903*4653Sdougm 			    strlen(options) > 0) {
3904*4653Sdougm 				ret = sa_parse_legacy_options(share,
3905*4653Sdougm 				    options,
3906*4653Sdougm 				    protocol);
39073034Sdougm 			}
3908*4653Sdougm 			if (!zfs) {
3909*4653Sdougm 				/*
3910*4653Sdougm 				 * ZFS shares never have resource or
3911*4653Sdougm 				 * description and we can't store the values
3912*4653Sdougm 				 * so don't try.
3913*4653Sdougm 				 */
3914*4653Sdougm 				if (ret == SA_OK && description != NULL)
3915*4653Sdougm 					ret = sa_set_share_description(share,
3916*4653Sdougm 					    description);
3917*4653Sdougm 				if (ret == SA_OK && resource != NULL)
3918*4653Sdougm 					ret = sa_set_share_attr(share,
3919*4653Sdougm 					    "resource", resource);
39203034Sdougm 			}
3921*4653Sdougm 			if (ret == SA_OK) {
3922*4653Sdougm 				if (strcmp(groupstatus, "enabled") == 0)
3923*4653Sdougm 					ret = sa_enable_share(share, protocol);
3924*4653Sdougm 				if (ret == SA_OK &&
3925*4653Sdougm 				    persist == SA_SHARE_PERMANENT) {
3926*4653Sdougm 					(void) sa_update_legacy(share,
3927*4653Sdougm 					    protocol);
3928*4653Sdougm 				}
3929*4653Sdougm 				if (ret == SA_OK)
3930*4653Sdougm 					ret = sa_update_config(handle);
3931*4653Sdougm 			}
39323034Sdougm 		} else {
3933*4653Sdougm 			ret = SA_SYSTEM_ERR;
39343034Sdougm 		}
39353034Sdougm 	}
39363034Sdougm 	if (ret != SA_OK) {
3937*4653Sdougm 		(void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
3938*4653Sdougm 		    sharepath, sa_errorstr(ret));
3939*4653Sdougm 		ret = SA_LEGACY_ERR;
39403034Sdougm 
39413034Sdougm 	}
39423034Sdougm 	return (ret);
39433034Sdougm }
39443034Sdougm 
39453034Sdougm /*
39463034Sdougm  * sa_legacy_unshare(flags, argc, argv)
39473034Sdougm  *
39483034Sdougm  * Implements the original unshare command.
39493034Sdougm  */
3950*4653Sdougm /*ARGSUSED*/
39513034Sdougm int
39523910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
39533034Sdougm {
39543034Sdougm 	char *protocol = "nfs"; /* for now */
39553034Sdougm 	char *options = NULL;
39563034Sdougm 	char *sharepath = NULL;
39573034Sdougm 	int persist = SA_SHARE_TRANSIENT;
39583034Sdougm 	int argsused = 0;
39593034Sdougm 	int c;
39603034Sdougm 	int ret = SA_OK;
39613034Sdougm 	int true_legacy = 0;
39623034Sdougm 	char cmd[MAXPATHLEN];
39633034Sdougm 
39643034Sdougm 	while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
3965*4653Sdougm 		switch (c) {
3966*4653Sdougm 		case 'h':
3967*4653Sdougm 		case '?':
3968*4653Sdougm 			break;
3969*4653Sdougm 		case 'F':
3970*4653Sdougm 			protocol = optarg;
3971*4653Sdougm 			if (!sa_valid_protocol(protocol)) {
3972*4653Sdougm 				if (format_legacy_path(cmd, MAXPATHLEN,
3973*4653Sdougm 				    protocol, "unshare") == 0 &&
3974*4653Sdougm 				    check_legacy_cmd(cmd)) {
3975*4653Sdougm 					true_legacy++;
3976*4653Sdougm 				} else {
3977*4653Sdougm 					(void) printf(gettext(
3978*4653Sdougm 					    "Invalid file system name\n"));
3979*4653Sdougm 					return (SA_INVALID_PROTOCOL);
3980*4653Sdougm 				}
3981*4653Sdougm 			}
3982*4653Sdougm 			break;
3983*4653Sdougm 		case 'o':
3984*4653Sdougm 			options = optarg;
3985*4653Sdougm 			argsused++;
3986*4653Sdougm 			break;
3987*4653Sdougm 		case 'p':
3988*4653Sdougm 			persist = SA_SHARE_PERMANENT;
3989*4653Sdougm 			argsused++;
3990*4653Sdougm 			break;
3991*4653Sdougm 		default:
3992*4653Sdougm 			(void) printf(gettext("usage: %s\n"),
3993*4653Sdougm 			    sa_get_usage(USAGE_UNSHARE));
3994*4653Sdougm 			return (SA_OK);
39953034Sdougm 		}
39963034Sdougm 	}
39973034Sdougm 
3998*4653Sdougm 	/* Have the info so construct what is needed */
3999*4653Sdougm 	if (optind == argc || (optind + 1) < argc || options != NULL) {
4000*4653Sdougm 		ret = SA_SYNTAX_ERR;
40013034Sdougm 	} else {
4002*4653Sdougm 		sa_share_t share;
4003*4653Sdougm 		char dir[MAXPATHLEN];
4004*4653Sdougm 		if (true_legacy) {
4005*4653Sdougm 			/* if still using legacy share/unshare, exec it */
4006*4653Sdougm 			ret = run_legacy_command(cmd, argv);
4007*4653Sdougm 			return (ret);
4008*4653Sdougm 		}
40093663Sdougm 		/*
40103663Sdougm 		 * Find the path in the internal configuration. If it
40113663Sdougm 		 * isn't found, attempt to resolve the path via
40123663Sdougm 		 * realpath() and try again.
40133663Sdougm 		 */
4014*4653Sdougm 		sharepath = argv[optind++];
4015*4653Sdougm 		share = sa_find_share(handle, sharepath);
4016*4653Sdougm 		if (share == NULL) {
4017*4653Sdougm 			if (realpath(sharepath, dir) == NULL) {
4018*4653Sdougm 				ret = SA_NO_SUCH_PATH;
4019*4653Sdougm 			} else {
4020*4653Sdougm 				share = sa_find_share(handle, dir);
4021*4653Sdougm 			}
40223663Sdougm 		}
4023*4653Sdougm 		if (share != NULL) {
4024*4653Sdougm 			ret = sa_disable_share(share, protocol);
4025*4653Sdougm 			/*
4026*4653Sdougm 			 * Errors are ok and removal should still occur. The
4027*4653Sdougm 			 * legacy unshare is more forgiving of errors than the
4028*4653Sdougm 			 * remove-share subcommand which may need the force
4029*4653Sdougm 			 * flag set for some error conditions. That is, the
4030*4653Sdougm 			 * "unshare" command will always unshare if it can
4031*4653Sdougm 			 * while "remove-share" might require the force option.
4032*4653Sdougm 			 */
4033*4653Sdougm 			if (persist == SA_SHARE_PERMANENT) {
4034*4653Sdougm 				ret = sa_remove_share(share);
4035*4653Sdougm 				if (ret == SA_OK)
4036*4653Sdougm 					ret = sa_update_config(handle);
4037*4653Sdougm 			}
4038*4653Sdougm 		} else {
4039*4653Sdougm 			ret = SA_NOT_SHARED;
40403663Sdougm 		}
40413034Sdougm 	}
40423034Sdougm 	switch (ret) {
40433034Sdougm 	default:
4044*4653Sdougm 		(void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
4045*4653Sdougm 		ret = SA_LEGACY_ERR;
4046*4653Sdougm 		break;
40473034Sdougm 	case SA_SYNTAX_ERR:
4048*4653Sdougm 		(void) printf(gettext("usage: %s\n"),
4049*4653Sdougm 		    sa_get_usage(USAGE_UNSHARE));
4050*4653Sdougm 		break;
40513034Sdougm 	case SA_OK:
4052*4653Sdougm 		break;
40533034Sdougm 	}
40543034Sdougm 	return (ret);
40553034Sdougm }
40563034Sdougm 
40573034Sdougm /*
4058*4653Sdougm  * Common commands that implement the sub-commands used by all
40593034Sdougm  * protcols. The entries are found via the lookup command
40603034Sdougm  */
40613034Sdougm 
40623034Sdougm static sa_command_t commands[] = {
40633034Sdougm 	{"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
40643034Sdougm 	{"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
40653034Sdougm 	{"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
40663034Sdougm 	{"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
40673034Sdougm 	{"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
40683034Sdougm 	{"list", 0, sa_list, USAGE_LIST},
40693034Sdougm 	{"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
40703034Sdougm 	{"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
40713034Sdougm 	{"set", 0, sa_set, USAGE_SET, SVC_SET},
40723034Sdougm 	{"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
40733034Sdougm 	{"show", 0, sa_show, USAGE_SHOW},
40743034Sdougm 	{"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
40753034Sdougm 	{"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
40763034Sdougm 		SVC_SET|SVC_ACTION},
40773034Sdougm 	{"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
40783034Sdougm 	{"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
40793034Sdougm 	{"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
40803034Sdougm 	{NULL, 0, NULL, NULL}
40813034Sdougm };
40823034Sdougm 
40833034Sdougm static char *
40843034Sdougm sa_get_usage(sa_usage_t index)
40853034Sdougm {
40863034Sdougm 	char *ret = NULL;
40873034Sdougm 	switch (index) {
40883034Sdougm 	case USAGE_ADD_SHARE:
4089*4653Sdougm 		ret = gettext("add-share [-nth] [-r resource-name] "
4090*4653Sdougm 		    "[-d \"description text\"] -s sharepath group");
4091*4653Sdougm 		break;
40923034Sdougm 	case USAGE_CREATE:
4093*4653Sdougm 		ret = gettext(
4094*4653Sdougm 		    "create [-nvh] [-P proto [-p property=value]] group");
4095*4653Sdougm 		break;
40963034Sdougm 	case USAGE_DELETE:
4097*4653Sdougm 		ret = gettext("delete [-nvh] [-P proto] [-f] group");
4098*4653Sdougm 		break;
40993034Sdougm 	case USAGE_DISABLE:
4100*4653Sdougm 		ret = gettext("disable [-nvh] {-a | group ...}");
4101*4653Sdougm 		break;
41023034Sdougm 	case USAGE_ENABLE:
4103*4653Sdougm 		ret = gettext("enable [-nvh] {-a | group ...}");
4104*4653Sdougm 		break;
41053034Sdougm 	case USAGE_LIST:
4106*4653Sdougm 		ret = gettext("list [-vh] [-P proto]");
4107*4653Sdougm 		break;
41083034Sdougm 	case USAGE_MOVE_SHARE:
4109*4653Sdougm 		ret = gettext(
4110*4653Sdougm 		    "move-share [-nvh] -s sharepath destination-group");
4111*4653Sdougm 		break;
41123034Sdougm 	case USAGE_REMOVE_SHARE:
4113*4653Sdougm 		ret = gettext("remove-share [-fnvh] -s sharepath group");
4114*4653Sdougm 		break;
41153034Sdougm 	case USAGE_SET:
4116*4653Sdougm 		ret = gettext("set [-nvh] -P proto [-S optspace] "
4117*4653Sdougm 		    "[-p property=value]* [-s sharepath] group");
4118*4653Sdougm 		break;
41193034Sdougm 	case USAGE_SET_SECURITY:
4120*4653Sdougm 		ret = gettext("set-security [-nvh] -P proto -S security-type "
4121*4653Sdougm 		    "[-p property=value]* group");
4122*4653Sdougm 		break;
41233034Sdougm 	case USAGE_SET_SHARE:
4124*4653Sdougm 		ret = gettext("set-share [-nh] [-r resource] "
4125*4653Sdougm 		    "[-d \"description text\"] -s sharepath group");
4126*4653Sdougm 		break;
41273034Sdougm 	case USAGE_SHOW:
4128*4653Sdougm 		ret = gettext("show [-pvxh] [-P proto] [group ...]");
4129*4653Sdougm 		break;
41303034Sdougm 	case USAGE_SHARE:
4131*4653Sdougm 		ret = gettext("share [-F fstype] [-p] [-o optionlist]"
4132*4653Sdougm 		    "[-d description] [pathname [resourcename]]");
4133*4653Sdougm 		break;
41343034Sdougm 	case USAGE_START:
4135*4653Sdougm 		ret = gettext("start [-vh] [-P proto] {-a | group ...}");
4136*4653Sdougm 		break;
41373034Sdougm 	case USAGE_STOP:
4138*4653Sdougm 		ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
4139*4653Sdougm 		break;
41403034Sdougm 	case USAGE_UNSET:
4141*4653Sdougm 		ret = gettext("unset [-nvh] -P proto [-S optspace] "
4142*4653Sdougm 		    "[-p property]* group");
4143*4653Sdougm 		break;
41443034Sdougm 	case USAGE_UNSET_SECURITY:
4145*4653Sdougm 		ret = gettext("unset-security [-nvh] -P proto -S security-type"
4146*4653Sdougm 		    " [-p property]* group");
4147*4653Sdougm 		break;
41483034Sdougm 	case USAGE_UNSHARE:
4149*4653Sdougm 		ret = gettext(
4150*4653Sdougm 		    "unshare [-F fstype] [-p] sharepath");
4151*4653Sdougm 		break;
41523034Sdougm 	}
41533034Sdougm 	return (ret);
41543034Sdougm }
41553034Sdougm 
41563034Sdougm /*
41573034Sdougm  * sa_lookup(cmd, proto)
41583034Sdougm  *
41593034Sdougm  * Lookup the sub-command. proto isn't currently used, but it may
41603034Sdougm  * eventually provide a way to provide protocol specific sub-commands.
41613034Sdougm  */
4162*4653Sdougm /*ARGSUSED*/
41633034Sdougm sa_command_t *
41643034Sdougm sa_lookup(char *cmd, char *proto)
41653034Sdougm {
41663034Sdougm 	int i;
41673034Sdougm 	size_t len;
41683034Sdougm 
41693034Sdougm 	len = strlen(cmd);
41703034Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
4171*4653Sdougm 		if (strncmp(cmd, commands[i].cmdname, len) == 0)
4172*4653Sdougm 			return (&commands[i]);
41733034Sdougm 	}
41743034Sdougm 	return (NULL);
41753034Sdougm }
41763034Sdougm 
4177*4653Sdougm /*ARGSUSED*/
41783034Sdougm void
41793034Sdougm sub_command_help(char *proto)
41803034Sdougm {
41813034Sdougm 	int i;
41823034Sdougm 
41833034Sdougm 	(void) printf(gettext("\tsub-commands:\n"));
41843034Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
4185*4653Sdougm 		if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
4186*4653Sdougm 			(void) printf("\t%s\n",
4187*4653Sdougm 			    sa_get_usage((sa_usage_t)commands[i].cmdidx));
41883034Sdougm 	}
41893034Sdougm }
4190