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