1*6185db85Sdougm /*
2*6185db85Sdougm  * CDDL HEADER START
3*6185db85Sdougm  *
4*6185db85Sdougm  * The contents of this file are subject to the terms of the
5*6185db85Sdougm  * Common Development and Distribution License (the "License").
6*6185db85Sdougm  * You may not use this file except in compliance with the License.
7*6185db85Sdougm  *
8*6185db85Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6185db85Sdougm  * or http://www.opensolaris.org/os/licensing.
10*6185db85Sdougm  * See the License for the specific language governing permissions
11*6185db85Sdougm  * and limitations under the License.
12*6185db85Sdougm  *
13*6185db85Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
14*6185db85Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6185db85Sdougm  * If applicable, add the following below this CDDL HEADER, with the
16*6185db85Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
17*6185db85Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6185db85Sdougm  *
19*6185db85Sdougm  * CDDL HEADER END
20*6185db85Sdougm  */
21*6185db85Sdougm 
22*6185db85Sdougm /*
23*6185db85Sdougm  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*6185db85Sdougm  * Use is subject to license terms.
25*6185db85Sdougm  */
26*6185db85Sdougm 
27*6185db85Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*6185db85Sdougm 
29*6185db85Sdougm #include <sys/types.h>
30*6185db85Sdougm #include <sys/stat.h>
31*6185db85Sdougm #include <fcntl.h>
32*6185db85Sdougm #include <stdlib.h>
33*6185db85Sdougm #include <stdio.h>
34*6185db85Sdougm #include <string.h>
35*6185db85Sdougm #include <ctype.h>
36*6185db85Sdougm #include <unistd.h>
37*6185db85Sdougm #include <getopt.h>
38*6185db85Sdougm #include <utmpx.h>
39*6185db85Sdougm #include <pwd.h>
40*6185db85Sdougm #include <auth_attr.h>
41*6185db85Sdougm #include <secdb.h>
42*6185db85Sdougm #include <sys/param.h>
43*6185db85Sdougm #include <sys/stat.h>
44*6185db85Sdougm #include <errno.h>
45*6185db85Sdougm 
46*6185db85Sdougm #include <libshare.h>
47*6185db85Sdougm #include "sharemgr.h"
48*6185db85Sdougm #include <libscf.h>
49*6185db85Sdougm #include <libxml/tree.h>
50*6185db85Sdougm #include <libintl.h>
51*6185db85Sdougm 
52*6185db85Sdougm static char *sa_get_usage(sa_usage_t);
53*6185db85Sdougm 
54*6185db85Sdougm /*
55*6185db85Sdougm  * Implementation of the common sub-commands supported by sharemgr.
56*6185db85Sdougm  * A number of helper functions are also included.
57*6185db85Sdougm  */
58*6185db85Sdougm 
59*6185db85Sdougm /*
60*6185db85Sdougm  * has_protocol(group, proto)
61*6185db85Sdougm  *	If the group has an optionset with the specified protocol,
62*6185db85Sdougm  *	return true (1) otherwise false (0).
63*6185db85Sdougm  */
64*6185db85Sdougm static int
65*6185db85Sdougm has_protocol(sa_group_t group, char *protocol)
66*6185db85Sdougm {
67*6185db85Sdougm 	sa_optionset_t optionset;
68*6185db85Sdougm 	int result = 0;
69*6185db85Sdougm 
70*6185db85Sdougm 	optionset = sa_get_optionset(group, protocol);
71*6185db85Sdougm 	if (optionset != NULL) {
72*6185db85Sdougm 	    result++;
73*6185db85Sdougm 	}
74*6185db85Sdougm 	return (result);
75*6185db85Sdougm }
76*6185db85Sdougm 
77*6185db85Sdougm /*
78*6185db85Sdougm  * add_list(list, item)
79*6185db85Sdougm  *	Adds a new list member that points to item to the list.
80*6185db85Sdougm  *	If list is NULL, it starts a new list.  The function returns
81*6185db85Sdougm  *	the first member of the list.
82*6185db85Sdougm  */
83*6185db85Sdougm struct list *
84*6185db85Sdougm add_list(struct list *listp, void *item, void *data)
85*6185db85Sdougm {
86*6185db85Sdougm 	struct list *new, *tmp;
87*6185db85Sdougm 
88*6185db85Sdougm 	new = malloc(sizeof (struct list));
89*6185db85Sdougm 	if (new != NULL) {
90*6185db85Sdougm 	    new->next = NULL;
91*6185db85Sdougm 	    new->item = item;
92*6185db85Sdougm 	    new->itemdata = data;
93*6185db85Sdougm 	} else {
94*6185db85Sdougm 	    return (listp);
95*6185db85Sdougm 	}
96*6185db85Sdougm 
97*6185db85Sdougm 	if (listp == NULL)
98*6185db85Sdougm 	    return (new);
99*6185db85Sdougm 
100*6185db85Sdougm 	for (tmp = listp; tmp->next != NULL; tmp = tmp->next) {
101*6185db85Sdougm 		/* get to end of list */
102*6185db85Sdougm 	}
103*6185db85Sdougm 	tmp->next = new;
104*6185db85Sdougm 	return (listp);
105*6185db85Sdougm }
106*6185db85Sdougm 
107*6185db85Sdougm /*
108*6185db85Sdougm  * free_list(list)
109*6185db85Sdougm  *	Given a list, free all the members of the list;
110*6185db85Sdougm  */
111*6185db85Sdougm static void
112*6185db85Sdougm free_list(struct list *listp)
113*6185db85Sdougm {
114*6185db85Sdougm 	struct list *tmp;
115*6185db85Sdougm 	while (listp != NULL) {
116*6185db85Sdougm 	    tmp = listp;
117*6185db85Sdougm 	    listp = listp->next;
118*6185db85Sdougm 	    free(tmp);
119*6185db85Sdougm 	}
120*6185db85Sdougm }
121*6185db85Sdougm 
122*6185db85Sdougm /*
123*6185db85Sdougm  * check_authorization(instname, which)
124*6185db85Sdougm  *
125*6185db85Sdougm  * Checks to see if the specific type of authorization in which is
126*6185db85Sdougm  * enabled for the user in this SMF service instance.
127*6185db85Sdougm  */
128*6185db85Sdougm 
129*6185db85Sdougm static int
130*6185db85Sdougm check_authorization(char *instname, int which)
131*6185db85Sdougm {
132*6185db85Sdougm 	scf_handle_t *handle = NULL;
133*6185db85Sdougm 	scf_simple_prop_t *prop = NULL;
134*6185db85Sdougm 	char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
135*6185db85Sdougm 	char *authstr = NULL;
136*6185db85Sdougm 	ssize_t numauths;
137*6185db85Sdougm 	int ret = 1;
138*6185db85Sdougm 	uid_t uid;
139*6185db85Sdougm 	struct passwd *pw = NULL;
140*6185db85Sdougm 
141*6185db85Sdougm 	uid = getuid();
142*6185db85Sdougm 	pw = getpwuid(uid);
143*6185db85Sdougm 	if (pw == NULL)
144*6185db85Sdougm 	    ret = 0;
145*6185db85Sdougm 
146*6185db85Sdougm 	if (ret == 1) {
147*6185db85Sdougm 	    /* since names  are restricted to SA_MAX_NAME_LEN won't overflow */
148*6185db85Sdougm 	    (void) snprintf(svcstring, sizeof (svcstring),
149*6185db85Sdougm 				"%s:%s", SA_SVC_FMRI_BASE, instname);
150*6185db85Sdougm 	    handle = scf_handle_create(SCF_VERSION);
151*6185db85Sdougm 	    if (handle != NULL) {
152*6185db85Sdougm 		if (scf_handle_bind(handle) == 0) {
153*6185db85Sdougm 		    switch (which) {
154*6185db85Sdougm 		    case SVC_SET:
155*6185db85Sdougm 			prop = scf_simple_prop_get(handle, svcstring,
156*6185db85Sdougm 							"general",
157*6185db85Sdougm 							SVC_AUTH_VALUE);
158*6185db85Sdougm 			break;
159*6185db85Sdougm 		    case SVC_ACTION:
160*6185db85Sdougm 			prop = scf_simple_prop_get(handle, svcstring,
161*6185db85Sdougm 							"general",
162*6185db85Sdougm 							SVC_AUTH_ACTION);
163*6185db85Sdougm 			break;
164*6185db85Sdougm 		    }
165*6185db85Sdougm 		}
166*6185db85Sdougm 	    }
167*6185db85Sdougm 	}
168*6185db85Sdougm 	/* make sure we have an authorization string property */
169*6185db85Sdougm 	if (prop != NULL) {
170*6185db85Sdougm 	    int i;
171*6185db85Sdougm 	    numauths = scf_simple_prop_numvalues(prop);
172*6185db85Sdougm 	    for (ret = 0, i = 0; i < numauths; i++) {
173*6185db85Sdougm 		authstr = scf_simple_prop_next_astring(prop);
174*6185db85Sdougm 		if (authstr != NULL) {
175*6185db85Sdougm 		    /* check if this user has one of the strings */
176*6185db85Sdougm 		    if (chkauthattr(authstr, pw->pw_name)) {
177*6185db85Sdougm 			ret = 1;
178*6185db85Sdougm 			break;
179*6185db85Sdougm 		    }
180*6185db85Sdougm 		}
181*6185db85Sdougm 	    }
182*6185db85Sdougm 	    endauthattr();
183*6185db85Sdougm 	    scf_simple_prop_free(prop);
184*6185db85Sdougm 	} else {
185*6185db85Sdougm 	    /* no authorization string defined */
186*6185db85Sdougm 	    ret = 0;
187*6185db85Sdougm 	}
188*6185db85Sdougm 	if (handle != NULL)
189*6185db85Sdougm 	    scf_handle_destroy(handle);
190*6185db85Sdougm 	return (ret);
191*6185db85Sdougm }
192*6185db85Sdougm 
193*6185db85Sdougm /*
194*6185db85Sdougm  * check_authorizations(instname, flags)
195*6185db85Sdougm  *
196*6185db85Sdougm  * check all the needed authorizations for the user in this service
197*6185db85Sdougm  * instance. Return value of 1(true) or 0(false) indicates whether
198*6185db85Sdougm  * there are authorizations for the user or not.
199*6185db85Sdougm  */
200*6185db85Sdougm 
201*6185db85Sdougm static int
202*6185db85Sdougm check_authorizations(char *instname, int flags)
203*6185db85Sdougm {
204*6185db85Sdougm 	int ret1 = 0;
205*6185db85Sdougm 	int ret2 = 0;
206*6185db85Sdougm 	int ret;
207*6185db85Sdougm 
208*6185db85Sdougm 	if (flags & SVC_SET)
209*6185db85Sdougm 	    ret1 = check_authorization(instname, SVC_SET);
210*6185db85Sdougm 	if (flags & SVC_ACTION)
211*6185db85Sdougm 	    ret2 = check_authorization(instname, SVC_ACTION);
212*6185db85Sdougm 	switch (flags) {
213*6185db85Sdougm 	case SVC_ACTION:
214*6185db85Sdougm 	    ret = ret2;
215*6185db85Sdougm 	    break;
216*6185db85Sdougm 	case SVC_SET:
217*6185db85Sdougm 	    ret = ret1;
218*6185db85Sdougm 	    break;
219*6185db85Sdougm 	case SVC_ACTION|SVC_SET:
220*6185db85Sdougm 	    ret = ret1 & ret2;
221*6185db85Sdougm 	    break;
222*6185db85Sdougm 	default:
223*6185db85Sdougm 	    /* if not flags set, we assume we don't need authorizations */
224*6185db85Sdougm 	    ret = 1;
225*6185db85Sdougm 	}
226*6185db85Sdougm 	return (ret);
227*6185db85Sdougm }
228*6185db85Sdougm 
229*6185db85Sdougm /*
230*6185db85Sdougm  * enable_all_groups(list, setstate, online, update)
231*6185db85Sdougm  *	Given a list of groups, enable each one found.  If update is
232*6185db85Sdougm  *	not NULL, then update all the shares for the protocol that was
233*6185db85Sdougm  *	passed in.
234*6185db85Sdougm  */
235*6185db85Sdougm static int
236*6185db85Sdougm enable_all_groups(struct list *work, int setstate, int online, char *update)
237*6185db85Sdougm {
238*6185db85Sdougm 	sa_share_t share;
239*6185db85Sdougm 	int ret = SA_OK;
240*6185db85Sdougm 	char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
241*6185db85Sdougm 	char *state;
242*6185db85Sdougm 	char *name;
243*6185db85Sdougm 	char *zfs = NULL;
244*6185db85Sdougm 	int dozfs = 0;
245*6185db85Sdougm 	sa_group_t group;
246*6185db85Sdougm 
247*6185db85Sdougm 	while (work != NULL && ret == SA_OK) {
248*6185db85Sdougm 	    group = (sa_group_t)work->item;
249*6185db85Sdougm 	    /* if itemdata != NULL then a single share */
250*6185db85Sdougm 	    if (work->itemdata != NULL) {
251*6185db85Sdougm 		ret = sa_enable_share((sa_share_t)work->itemdata, NULL);
252*6185db85Sdougm 	    }
253*6185db85Sdougm 	    if (setstate)
254*6185db85Sdougm 		ret = sa_set_group_attr(group, "state",
255*6185db85Sdougm 					"enabled");
256*6185db85Sdougm 	    if (ret == SA_OK) {
257*6185db85Sdougm 		/* if itemdata == NULL then the whole group */
258*6185db85Sdougm 		if (work->itemdata == NULL) {
259*6185db85Sdougm 		    for (share = sa_get_share(group, NULL);
260*6185db85Sdougm 			share != NULL; share = sa_get_next_share(share)) {
261*6185db85Sdougm 			if (update != NULL)
262*6185db85Sdougm 			    (void) sa_update_legacy(share, update);
263*6185db85Sdougm 			ret = sa_enable_share(share, NULL);
264*6185db85Sdougm 		    }
265*6185db85Sdougm 		}
266*6185db85Sdougm 		if (online) {
267*6185db85Sdougm 		    name = sa_get_group_attr(group, "name");
268*6185db85Sdougm 		    zfs = sa_get_group_attr(group, "zfs");
269*6185db85Sdougm 		    if (name != NULL) {
270*6185db85Sdougm 			if (zfs == NULL) {
271*6185db85Sdougm 			    (void) snprintf(instance, sizeof (instance),
272*6185db85Sdougm 						"%s:%s",
273*6185db85Sdougm 						SA_SVC_FMRI_BASE, name);
274*6185db85Sdougm 			    state = smf_get_state(instance);
275*6185db85Sdougm 			    if (state == NULL ||
276*6185db85Sdougm 				strcmp(state, "online") != 0) {
277*6185db85Sdougm 				(void) smf_enable_instance(instance, 0);
278*6185db85Sdougm 				free(state);
279*6185db85Sdougm 			    }
280*6185db85Sdougm 			} else {
281*6185db85Sdougm 			    dozfs++;
282*6185db85Sdougm 			    sa_free_attr_string(zfs);
283*6185db85Sdougm 			    zfs = NULL;
284*6185db85Sdougm 			}
285*6185db85Sdougm 			if (name != NULL)
286*6185db85Sdougm 			    sa_free_attr_string(name);
287*6185db85Sdougm 		    }
288*6185db85Sdougm 		} else {
289*6185db85Sdougm 		    zfs = sa_get_group_attr(group, "zfs");
290*6185db85Sdougm 		    if (zfs != NULL) {
291*6185db85Sdougm 			dozfs++;
292*6185db85Sdougm 			sa_free_attr_string(zfs);
293*6185db85Sdougm 			zfs = NULL;
294*6185db85Sdougm 		    }
295*6185db85Sdougm 		}
296*6185db85Sdougm 		work = work->next;
297*6185db85Sdougm 	    }
298*6185db85Sdougm 	}
299*6185db85Sdougm 	if (ret == SA_OK) {
300*6185db85Sdougm 	    ret = sa_update_config();
301*6185db85Sdougm 	}
302*6185db85Sdougm 	/* do ZFS last to allow everything to get updated */
303*6185db85Sdougm 	if (ret == SA_OK && dozfs) {
304*6185db85Sdougm 	    FILE *sys;
305*6185db85Sdougm 	    int err;
306*6185db85Sdougm 	    sys = popen(ZFS_SHAREALL, "r");
307*6185db85Sdougm 	    if (sys != NULL) {
308*6185db85Sdougm 		err = pclose(sys);
309*6185db85Sdougm 		if (err != 0)
310*6185db85Sdougm 		    ret = SA_SYSTEM_ERR;
311*6185db85Sdougm 	    } else {
312*6185db85Sdougm 		ret = SA_SYSTEM_ERR;
313*6185db85Sdougm 	    }
314*6185db85Sdougm 	}
315*6185db85Sdougm 	return (ret);
316*6185db85Sdougm }
317*6185db85Sdougm 
318*6185db85Sdougm /*
319*6185db85Sdougm  * chk_opt(optlistp, security, proto)
320*6185db85Sdougm  *
321*6185db85Sdougm  * Do a sanity check on the optlist provided for the protocol.  This
322*6185db85Sdougm  * is a syntax check and verification that the property is either a
323*6185db85Sdougm  * general or specific to a names optionset.
324*6185db85Sdougm  */
325*6185db85Sdougm 
326*6185db85Sdougm static int
327*6185db85Sdougm chk_opt(struct options *optlistp, int security, char *proto)
328*6185db85Sdougm {
329*6185db85Sdougm 	struct options *optlist;
330*6185db85Sdougm 	char *sep = "";
331*6185db85Sdougm 	int notfirst = 0;
332*6185db85Sdougm 	int ret;
333*6185db85Sdougm 
334*6185db85Sdougm 	for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
335*6185db85Sdougm 	    char *optname;
336*6185db85Sdougm 
337*6185db85Sdougm 	    optname = optlist->optname;
338*6185db85Sdougm 	    ret = OPT_ADD_OK;
339*6185db85Sdougm 	    /* extract property/value pair */
340*6185db85Sdougm 	    if (sa_is_security(optname, proto)) {
341*6185db85Sdougm 		if (!security)
342*6185db85Sdougm 		    ret = OPT_ADD_SECURITY;
343*6185db85Sdougm 	    } else {
344*6185db85Sdougm 		if (security)
345*6185db85Sdougm 		    ret = OPT_ADD_PROPERTY;
346*6185db85Sdougm 	    }
347*6185db85Sdougm 	    if (ret != OPT_ADD_OK) {
348*6185db85Sdougm 		if (notfirst == 0)
349*6185db85Sdougm 		    (void) printf(gettext("Property syntax error: "));
350*6185db85Sdougm 		switch (ret) {
351*6185db85Sdougm 		case OPT_ADD_SYNTAX:
352*6185db85Sdougm 		    (void) printf(gettext("%ssyntax error: %s"),
353*6185db85Sdougm 				    sep, optname);
354*6185db85Sdougm 		    sep = ", ";
355*6185db85Sdougm 		    break;
356*6185db85Sdougm 		case OPT_ADD_SECURITY:
357*6185db85Sdougm 		    (void) printf(gettext("%s%s requires -S"),
358*6185db85Sdougm 				    optname, sep);
359*6185db85Sdougm 		    sep = ", ";
360*6185db85Sdougm 		    break;
361*6185db85Sdougm 		case OPT_ADD_PROPERTY:
362*6185db85Sdougm 		    (void) printf(gettext("%s%s not supported with -S"),
363*6185db85Sdougm 				    optname, sep);
364*6185db85Sdougm 		    sep = ", ";
365*6185db85Sdougm 		    break;
366*6185db85Sdougm 		}
367*6185db85Sdougm 		notfirst++;
368*6185db85Sdougm 	    }
369*6185db85Sdougm 	}
370*6185db85Sdougm 	if (notfirst) {
371*6185db85Sdougm 	    (void) printf("\n");
372*6185db85Sdougm 	    ret = SA_SYNTAX_ERR;
373*6185db85Sdougm 	}
374*6185db85Sdougm 	return (ret);
375*6185db85Sdougm }
376*6185db85Sdougm 
377*6185db85Sdougm /*
378*6185db85Sdougm  * free_opt(optlist)
379*6185db85Sdougm  *	Free the specified option list.
380*6185db85Sdougm  */
381*6185db85Sdougm static void
382*6185db85Sdougm free_opt(struct options *optlist)
383*6185db85Sdougm {
384*6185db85Sdougm 	struct options *nextopt;
385*6185db85Sdougm 	while (optlist != NULL) {
386*6185db85Sdougm 		nextopt = optlist->next;
387*6185db85Sdougm 		free(optlist);
388*6185db85Sdougm 		optlist = nextopt;
389*6185db85Sdougm 	}
390*6185db85Sdougm }
391*6185db85Sdougm 
392*6185db85Sdougm /*
393*6185db85Sdougm  * check property list for valid properties
394*6185db85Sdougm  * A null value is a remove which is always valid.
395*6185db85Sdougm  */
396*6185db85Sdougm static int
397*6185db85Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec)
398*6185db85Sdougm {
399*6185db85Sdougm 	int ret = SA_OK;
400*6185db85Sdougm 	struct options *cur;
401*6185db85Sdougm 	sa_property_t prop;
402*6185db85Sdougm 	sa_optionset_t parent = NULL;
403*6185db85Sdougm 
404*6185db85Sdougm 	if (object != NULL) {
405*6185db85Sdougm 	    if (sec == NULL)
406*6185db85Sdougm 		parent = sa_get_optionset(object, proto);
407*6185db85Sdougm 	    else
408*6185db85Sdougm 		parent = sa_get_security(object, sec, proto);
409*6185db85Sdougm 	}
410*6185db85Sdougm 
411*6185db85Sdougm 	for (cur = optlist; cur != NULL; cur = cur->next) {
412*6185db85Sdougm 	    if (cur->optvalue != NULL) {
413*6185db85Sdougm 		prop = sa_create_property(cur->optname, cur->optvalue);
414*6185db85Sdougm 		if (prop == NULL)
415*6185db85Sdougm 		    ret = SA_NO_MEMORY;
416*6185db85Sdougm 		if (ret != SA_OK ||
417*6185db85Sdougm 		    (ret = sa_valid_property(parent, proto, prop)) != SA_OK) {
418*6185db85Sdougm 		    (void) printf(gettext("Could not add property %s: %s\n"),
419*6185db85Sdougm 					cur->optname,
420*6185db85Sdougm 					sa_errorstr(ret));
421*6185db85Sdougm 		}
422*6185db85Sdougm 		(void) sa_remove_property(prop);
423*6185db85Sdougm 	    }
424*6185db85Sdougm 	}
425*6185db85Sdougm 	return (ret);
426*6185db85Sdougm }
427*6185db85Sdougm 
428*6185db85Sdougm /*
429*6185db85Sdougm  * add_optionset(group, optlist, protocol, *err)
430*6185db85Sdougm  *	Add the options in optlist to an optionset and then add the optionset
431*6185db85Sdougm  *	to the group.
432*6185db85Sdougm  *
433*6185db85Sdougm  *	The return value indicates if there was a "change" while errors are
434*6185db85Sdougm  *	returned via the *err parameters.
435*6185db85Sdougm  */
436*6185db85Sdougm static int
437*6185db85Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
438*6185db85Sdougm {
439*6185db85Sdougm 	sa_optionset_t optionset;
440*6185db85Sdougm 	int ret = SA_OK;
441*6185db85Sdougm 	int result = 0;
442*6185db85Sdougm 
443*6185db85Sdougm 	optionset = sa_get_optionset(group, proto);
444*6185db85Sdougm 	if (optionset == NULL) {
445*6185db85Sdougm 	    optionset = sa_create_optionset(group, proto);
446*6185db85Sdougm 	    result = 1; /* adding a protocol is a change */
447*6185db85Sdougm 	}
448*6185db85Sdougm 	if (optionset != NULL) {
449*6185db85Sdougm 	    while (optlist != NULL) {
450*6185db85Sdougm 		sa_property_t prop;
451*6185db85Sdougm 		prop = sa_get_property(optionset, optlist->optname);
452*6185db85Sdougm 		if (prop == NULL) {
453*6185db85Sdougm 			/*
454*6185db85Sdougm 			 * add the property, but only if it is
455*6185db85Sdougm 			 * a non-NULL or non-zero length value
456*6185db85Sdougm 			 */
457*6185db85Sdougm 		    if (optlist->optvalue != NULL) {
458*6185db85Sdougm 			prop = sa_create_property(optlist->optname,
459*6185db85Sdougm 						    optlist->optvalue);
460*6185db85Sdougm 			if (prop != NULL) {
461*6185db85Sdougm 			    ret = sa_valid_property(optionset, proto, prop);
462*6185db85Sdougm 			    if (ret != SA_OK) {
463*6185db85Sdougm 				(void) sa_remove_property(prop);
464*6185db85Sdougm 				(void) printf(gettext("Could not add property "
465*6185db85Sdougm 							"%s: %s\n"),
466*6185db85Sdougm 						optlist->optname,
467*6185db85Sdougm 						sa_errorstr(ret));
468*6185db85Sdougm 			    }
469*6185db85Sdougm 			}
470*6185db85Sdougm 			if (ret == SA_OK) {
471*6185db85Sdougm 			    ret = sa_add_property(optionset, prop);
472*6185db85Sdougm 			    if (ret != SA_OK) {
473*6185db85Sdougm 				(void) printf(gettext("Could not add property"
474*6185db85Sdougm 							" %s: %s\n"),
475*6185db85Sdougm 						optlist->optname,
476*6185db85Sdougm 						sa_errorstr(ret));
477*6185db85Sdougm 			    } else {
478*6185db85Sdougm 				/* there was a change */
479*6185db85Sdougm 				result = 1;
480*6185db85Sdougm 			    }
481*6185db85Sdougm 			}
482*6185db85Sdougm 		    }
483*6185db85Sdougm 		} else {
484*6185db85Sdougm 		    ret = sa_update_property(prop, optlist->optvalue);
485*6185db85Sdougm 		    /* should check to see if value changed */
486*6185db85Sdougm 		    if (ret != SA_OK) {
487*6185db85Sdougm 			(void) printf(gettext("Could not update "
488*6185db85Sdougm 						"property %s: %s\n"),
489*6185db85Sdougm 					optlist->optname,
490*6185db85Sdougm 					sa_errorstr(ret));
491*6185db85Sdougm 		    } else {
492*6185db85Sdougm 			result = 1;
493*6185db85Sdougm 		    }
494*6185db85Sdougm 		}
495*6185db85Sdougm 		optlist = optlist->next;
496*6185db85Sdougm 	    }
497*6185db85Sdougm 	    ret = sa_commit_properties(optionset, 0);
498*6185db85Sdougm 	}
499*6185db85Sdougm 	if (err != NULL)
500*6185db85Sdougm 	    *err = ret;
501*6185db85Sdougm 	return (result);
502*6185db85Sdougm }
503*6185db85Sdougm 
504*6185db85Sdougm /*
505*6185db85Sdougm  * sa_create(flags, argc, argv)
506*6185db85Sdougm  *	create a new group
507*6185db85Sdougm  *	this may or may not have a protocol associated with it.
508*6185db85Sdougm  *	No protocol means "all" protocols in this case.
509*6185db85Sdougm  */
510*6185db85Sdougm static int
511*6185db85Sdougm sa_create(int flags, int argc, char *argv[])
512*6185db85Sdougm {
513*6185db85Sdougm 	char *groupname;
514*6185db85Sdougm 
515*6185db85Sdougm 	sa_group_t group;
516*6185db85Sdougm 	int verbose = 0;
517*6185db85Sdougm 	int dryrun = 0;
518*6185db85Sdougm 	int c;
519*6185db85Sdougm 	char *protocol = NULL;
520*6185db85Sdougm 	int ret = SA_OK;
521*6185db85Sdougm 	struct options *optlist = NULL;
522*6185db85Sdougm 	int err = 0;
523*6185db85Sdougm 	int auth;
524*6185db85Sdougm 
525*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) {
526*6185db85Sdougm 	    switch (c) {
527*6185db85Sdougm 	    case 'v':
528*6185db85Sdougm 		verbose++;
529*6185db85Sdougm 		break;
530*6185db85Sdougm 	    case 'n':
531*6185db85Sdougm 		dryrun++;
532*6185db85Sdougm 		break;
533*6185db85Sdougm 	    case 'P':
534*6185db85Sdougm 		protocol = optarg;
535*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
536*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
537*6185db85Sdougm 					protocol);
538*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
539*6185db85Sdougm 		}
540*6185db85Sdougm 		break;
541*6185db85Sdougm 	    case 'p':
542*6185db85Sdougm 		ret = add_opt(&optlist, optarg, 0);
543*6185db85Sdougm 		switch (ret) {
544*6185db85Sdougm 		case OPT_ADD_SYNTAX:
545*6185db85Sdougm 		    (void) printf(gettext("Property syntax error for "
546*6185db85Sdougm 						"property: %s\n"),
547*6185db85Sdougm 				    optarg);
548*6185db85Sdougm 		    return (SA_SYNTAX_ERR);
549*6185db85Sdougm 		case OPT_ADD_SECURITY:
550*6185db85Sdougm 		    (void) printf(gettext("Security properties need "
551*6185db85Sdougm 					"to be set with set-security: %s\n"),
552*6185db85Sdougm 				    optarg);
553*6185db85Sdougm 		    return (SA_SYNTAX_ERR);
554*6185db85Sdougm 		default:
555*6185db85Sdougm 		    break;
556*6185db85Sdougm 		}
557*6185db85Sdougm 
558*6185db85Sdougm 		break;
559*6185db85Sdougm 	    default:
560*6185db85Sdougm 	    case 'h':
561*6185db85Sdougm 	    case '?':
562*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
563*6185db85Sdougm 				sa_get_usage(USAGE_CREATE));
564*6185db85Sdougm 		return (0);
565*6185db85Sdougm 	    }
566*6185db85Sdougm 	}
567*6185db85Sdougm 
568*6185db85Sdougm 	if (optind >= argc) {
569*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
570*6185db85Sdougm 	    (void) printf(gettext("\tgroup must be specified.\n"));
571*6185db85Sdougm 	    return (SA_BAD_PATH);
572*6185db85Sdougm 	}
573*6185db85Sdougm 
574*6185db85Sdougm 	if ((optind + 1) < argc) {
575*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
576*6185db85Sdougm 	    (void) printf(gettext("\textraneous group(s) at end\n"));
577*6185db85Sdougm 	    return (SA_SYNTAX_ERR);
578*6185db85Sdougm 	}
579*6185db85Sdougm 
580*6185db85Sdougm 	if (protocol == NULL && optlist != NULL) {
581*6185db85Sdougm 	    /* lookup default protocol */
582*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE));
583*6185db85Sdougm 	    (void) printf(gettext("\tprotocol must be specified "
584*6185db85Sdougm 				"with properties\n"));
585*6185db85Sdougm 	    return (SA_INVALID_PROTOCOL);
586*6185db85Sdougm 	}
587*6185db85Sdougm 
588*6185db85Sdougm 	if (optlist != NULL)
589*6185db85Sdougm 	    ret = chk_opt(optlist, 0, protocol);
590*6185db85Sdougm 	if (ret == OPT_ADD_SECURITY) {
591*6185db85Sdougm 	    (void) printf(gettext("Security properties not "
592*6185db85Sdougm 				"supported with create\n"));
593*6185db85Sdougm 	    return (SA_SYNTAX_ERR);
594*6185db85Sdougm 	}
595*6185db85Sdougm 
596*6185db85Sdougm 	/*
597*6185db85Sdougm 	 * if a group already exists, we can only add a new protocol
598*6185db85Sdougm 	 * to it and not create a new one or add the same protocol
599*6185db85Sdougm 	 * again.
600*6185db85Sdougm 	 */
601*6185db85Sdougm 
602*6185db85Sdougm 	groupname = argv[optind];
603*6185db85Sdougm 
604*6185db85Sdougm 	auth = check_authorizations(groupname, flags);
605*6185db85Sdougm 
606*6185db85Sdougm 	group = sa_get_group(groupname);
607*6185db85Sdougm 	if (group != NULL) {
608*6185db85Sdougm 	    /* group exists so must be a protocol add */
609*6185db85Sdougm 	    if (protocol != NULL) {
610*6185db85Sdougm 		if (has_protocol(group, protocol)) {
611*6185db85Sdougm 		    (void) printf(gettext("Group \"%s\" already exists"
612*6185db85Sdougm 						" with protocol %s\n"),
613*6185db85Sdougm 					groupname, protocol);
614*6185db85Sdougm 		    ret = SA_DUPLICATE_NAME;
615*6185db85Sdougm 		}
616*6185db85Sdougm 	    } else {
617*6185db85Sdougm 		/* must add new protocol */
618*6185db85Sdougm 		(void) printf(gettext("Group already exists and no protocol"
619*6185db85Sdougm 					" specified.\n"));
620*6185db85Sdougm 		ret = SA_DUPLICATE_NAME;
621*6185db85Sdougm 	    }
622*6185db85Sdougm 	} else {
623*6185db85Sdougm 		/*
624*6185db85Sdougm 		 * is it a valid name? Must comply with SMF instance
625*6185db85Sdougm 		 * name restrictions.
626*6185db85Sdougm 		 */
627*6185db85Sdougm 	    if (!sa_valid_group_name(groupname)) {
628*6185db85Sdougm 		ret = SA_INVALID_NAME;
629*6185db85Sdougm 		(void) printf(gettext("Invalid group name: %s\n"), groupname);
630*6185db85Sdougm 	    }
631*6185db85Sdougm 	}
632*6185db85Sdougm 	if (ret == SA_OK) {
633*6185db85Sdougm 	    /* check protocol vs optlist */
634*6185db85Sdougm 	    if (optlist != NULL) {
635*6185db85Sdougm 		/* check options, if any, for validity */
636*6185db85Sdougm 		ret = valid_options(optlist, protocol, group, NULL);
637*6185db85Sdougm 	    }
638*6185db85Sdougm 	}
639*6185db85Sdougm 	if (ret == SA_OK && !dryrun) {
640*6185db85Sdougm 	    if (group == NULL) {
641*6185db85Sdougm 		group = sa_create_group((char *)groupname, &err);
642*6185db85Sdougm 	    }
643*6185db85Sdougm 	    if (group != NULL) {
644*6185db85Sdougm 		sa_optionset_t optionset;
645*6185db85Sdougm 		if (optlist != NULL) {
646*6185db85Sdougm 		    (void) add_optionset(group, optlist, protocol, &ret);
647*6185db85Sdougm 		} else if (protocol != NULL) {
648*6185db85Sdougm 		    optionset = sa_create_optionset(group, protocol);
649*6185db85Sdougm 		    if (optionset == NULL)
650*6185db85Sdougm 			ret = SA_NO_MEMORY;
651*6185db85Sdougm 		} else if (protocol == NULL) {
652*6185db85Sdougm 		    char **protolist;
653*6185db85Sdougm 		    int numprotos, i;
654*6185db85Sdougm 		    numprotos = sa_get_protocols(&protolist);
655*6185db85Sdougm 		    for (i = 0; i < numprotos; i++) {
656*6185db85Sdougm 			optionset = sa_create_optionset(group, protolist[i]);
657*6185db85Sdougm 		    }
658*6185db85Sdougm 		    if (protolist != NULL)
659*6185db85Sdougm 			free(protolist);
660*6185db85Sdougm 		}
661*6185db85Sdougm 		/*
662*6185db85Sdougm 		 * we have a group and legal additions
663*6185db85Sdougm 		 */
664*6185db85Sdougm 		if (ret == SA_OK) {
665*6185db85Sdougm 			/*
666*6185db85Sdougm 			 * commit to configuration for protocols that
667*6185db85Sdougm 			 * need to do block updates. For NFS, this
668*6185db85Sdougm 			 * doesn't do anything but it will be run for
669*6185db85Sdougm 			 * all protocols that implement the
670*6185db85Sdougm 			 * appropriate plugin.
671*6185db85Sdougm 			 */
672*6185db85Sdougm 		    ret = sa_update_config();
673*6185db85Sdougm 		} else {
674*6185db85Sdougm 		    if (group != NULL)
675*6185db85Sdougm 			(void) sa_remove_group(group);
676*6185db85Sdougm 		}
677*6185db85Sdougm 	    } else {
678*6185db85Sdougm 		ret = err;
679*6185db85Sdougm 		(void) printf(gettext("Could not create group: %s\n"),
680*6185db85Sdougm 			sa_errorstr(ret));
681*6185db85Sdougm 	    }
682*6185db85Sdougm 	}
683*6185db85Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
684*6185db85Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
685*6185db85Sdougm 			sa_errorstr(SA_NO_PERMISSION));
686*6185db85Sdougm 	    ret = SA_NO_PERMISSION;
687*6185db85Sdougm 	}
688*6185db85Sdougm 	free_opt(optlist);
689*6185db85Sdougm 	return (ret);
690*6185db85Sdougm }
691*6185db85Sdougm 
692*6185db85Sdougm /*
693*6185db85Sdougm  * group_status(group)
694*6185db85Sdougm  *
695*6185db85Sdougm  * return the current status (enabled/disabled) of the group.
696*6185db85Sdougm  */
697*6185db85Sdougm 
698*6185db85Sdougm static char *
699*6185db85Sdougm group_status(sa_group_t group)
700*6185db85Sdougm {
701*6185db85Sdougm 	char *state;
702*6185db85Sdougm 	int enabled = 0;
703*6185db85Sdougm 
704*6185db85Sdougm 	state = sa_get_group_attr(group, "state");
705*6185db85Sdougm 	if (state != NULL) {
706*6185db85Sdougm 	    if (strcmp(state, "enabled") == 0) {
707*6185db85Sdougm 		enabled = 1;
708*6185db85Sdougm 	    }
709*6185db85Sdougm 	    sa_free_attr_string(state);
710*6185db85Sdougm 	}
711*6185db85Sdougm 	return (enabled ? gettext("enabled") : gettext("disabled"));
712*6185db85Sdougm }
713*6185db85Sdougm 
714*6185db85Sdougm /*
715*6185db85Sdougm  * sa_delete(flags, argc, argv)
716*6185db85Sdougm  *
717*6185db85Sdougm  *	Delete a group.
718*6185db85Sdougm  */
719*6185db85Sdougm 
720*6185db85Sdougm static int
721*6185db85Sdougm sa_delete(int flags, int argc, char *argv[])
722*6185db85Sdougm {
723*6185db85Sdougm 	char *groupname;
724*6185db85Sdougm 	sa_group_t group;
725*6185db85Sdougm 	sa_share_t share;
726*6185db85Sdougm 	int verbose = 0;
727*6185db85Sdougm 	int dryrun = 0;
728*6185db85Sdougm 	int force = 0;
729*6185db85Sdougm 	int c;
730*6185db85Sdougm 	char *protocol = NULL;
731*6185db85Sdougm 	char *sectype = NULL;
732*6185db85Sdougm 	int ret = SA_OK;
733*6185db85Sdougm 	int auth;
734*6185db85Sdougm 
735*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
736*6185db85Sdougm 	    switch (c) {
737*6185db85Sdougm 	    case 'v':
738*6185db85Sdougm 		verbose++;
739*6185db85Sdougm 		break;
740*6185db85Sdougm 	    case 'n':
741*6185db85Sdougm 		dryrun++;
742*6185db85Sdougm 		break;
743*6185db85Sdougm 	    case 'P':
744*6185db85Sdougm 		protocol = optarg;
745*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
746*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
747*6185db85Sdougm 				    protocol);
748*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
749*6185db85Sdougm 		}
750*6185db85Sdougm 		break;
751*6185db85Sdougm 	    case 'S':
752*6185db85Sdougm 		sectype = optarg;
753*6185db85Sdougm 		break;
754*6185db85Sdougm 	    case 'f':
755*6185db85Sdougm 		force++;
756*6185db85Sdougm 		break;
757*6185db85Sdougm 	    default:
758*6185db85Sdougm 	    case 'h':
759*6185db85Sdougm 	    case '?':
760*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
761*6185db85Sdougm 				sa_get_usage(USAGE_DELETE));
762*6185db85Sdougm 		return (0);
763*6185db85Sdougm 	    }
764*6185db85Sdougm 	}
765*6185db85Sdougm 
766*6185db85Sdougm 	if (optind >= argc) {
767*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
768*6185db85Sdougm 	    (void) printf(gettext("\tgroup must be specified.\n"));
769*6185db85Sdougm 	    return (SA_SYNTAX_ERR);
770*6185db85Sdougm 	}
771*6185db85Sdougm 
772*6185db85Sdougm 	if ((optind + 1) < argc) {
773*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
774*6185db85Sdougm 	    (void) printf(gettext("\textraneous group(s) at end\n"));
775*6185db85Sdougm 	    return (SA_SYNTAX_ERR);
776*6185db85Sdougm 	}
777*6185db85Sdougm 
778*6185db85Sdougm 	if (sectype != NULL && protocol == NULL) {
779*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE));
780*6185db85Sdougm 	    (void) printf(gettext("\tsecurity requires protocol to be "
781*6185db85Sdougm 					"specified.\n"));
782*6185db85Sdougm 	    return (SA_SYNTAX_ERR);
783*6185db85Sdougm 	}
784*6185db85Sdougm 
785*6185db85Sdougm 	/*
786*6185db85Sdougm 	 * Determine if the group already exists since it must in
787*6185db85Sdougm 	 * order to be removed.
788*6185db85Sdougm 	 *
789*6185db85Sdougm 	 * We can delete when:
790*6185db85Sdougm 	 *
791*6185db85Sdougm 	 *	- group is empty
792*6185db85Sdougm 	 *	- force flag is set
793*6185db85Sdougm 	 *	- if protocol specified, only delete the protocol
794*6185db85Sdougm 	 */
795*6185db85Sdougm 
796*6185db85Sdougm 	groupname = argv[optind];
797*6185db85Sdougm 	group = sa_get_group(groupname);
798*6185db85Sdougm 	if (group == NULL) {
799*6185db85Sdougm 		ret = SA_NO_SUCH_GROUP;
800*6185db85Sdougm 	} else {
801*6185db85Sdougm 	    auth = check_authorizations(groupname, flags);
802*6185db85Sdougm 	    if (protocol == NULL) {
803*6185db85Sdougm 		share = sa_get_share(group, NULL);
804*6185db85Sdougm 		if (share != NULL)
805*6185db85Sdougm 		    ret = SA_BUSY;
806*6185db85Sdougm 		if (share == NULL || (share != NULL && force == 1)) {
807*6185db85Sdougm 		    ret = SA_OK;
808*6185db85Sdougm 		    if (!dryrun) {
809*6185db85Sdougm 			while (share != NULL) {
810*6185db85Sdougm 			    sa_share_t next_share;
811*6185db85Sdougm 			    next_share = sa_get_next_share(share);
812*6185db85Sdougm 				/*
813*6185db85Sdougm 				 * need to do the disable of each
814*6185db85Sdougm 				 * share, but don't actually do
815*6185db85Sdougm 				 * anything on a dryrun.
816*6185db85Sdougm 				 */
817*6185db85Sdougm 			    ret = sa_disable_share(share, NULL);
818*6185db85Sdougm 			    ret = sa_remove_share(share);
819*6185db85Sdougm 			    share = next_share;
820*6185db85Sdougm 			}
821*6185db85Sdougm 			ret = sa_remove_group(group);
822*6185db85Sdougm 		    }
823*6185db85Sdougm 		}
824*6185db85Sdougm 		/* commit to configuration if not a dryrun */
825*6185db85Sdougm 		if (!dryrun && ret == SA_OK) {
826*6185db85Sdougm 		    ret = sa_update_config();
827*6185db85Sdougm 		}
828*6185db85Sdougm 	    } else {
829*6185db85Sdougm 		/* a protocol delete */
830*6185db85Sdougm 		sa_optionset_t optionset;
831*6185db85Sdougm 		sa_security_t security;
832*6185db85Sdougm 		if (sectype != NULL) {
833*6185db85Sdougm 		    /* only delete specified security */
834*6185db85Sdougm 		    security = sa_get_security(group, sectype, protocol);
835*6185db85Sdougm 		    if (security != NULL && !dryrun) {
836*6185db85Sdougm 			ret = sa_destroy_security(security);
837*6185db85Sdougm 		    } else {
838*6185db85Sdougm 			ret = SA_INVALID_PROTOCOL;
839*6185db85Sdougm 		    }
840*6185db85Sdougm 		} else {
841*6185db85Sdougm 		    optionset = sa_get_optionset(group, protocol);
842*6185db85Sdougm 		    if (optionset != NULL && !dryrun) {
843*6185db85Sdougm 			/* have an optionset with protocol to delete */
844*6185db85Sdougm 			ret = sa_destroy_optionset(optionset);
845*6185db85Sdougm 			/*
846*6185db85Sdougm 			 * now find all security sets for the protocol
847*6185db85Sdougm 			 * and remove them. Don't remove other
848*6185db85Sdougm 			 * protocols.
849*6185db85Sdougm 			 */
850*6185db85Sdougm 			for (security = sa_get_security(group, NULL, NULL);
851*6185db85Sdougm 			    ret == SA_OK && security != NULL;
852*6185db85Sdougm 			    security = sa_get_next_security(security)) {
853*6185db85Sdougm 			    char *secprot;
854*6185db85Sdougm 
855*6185db85Sdougm 			    secprot = sa_get_security_attr(security, "type");
856*6185db85Sdougm 			    if (secprot != NULL &&
857*6185db85Sdougm 				strcmp(secprot, protocol) == 0)
858*6185db85Sdougm 				ret = sa_destroy_security(security);
859*6185db85Sdougm 			    if (secprot != NULL)
860*6185db85Sdougm 				sa_free_attr_string(secprot);
861*6185db85Sdougm 			}
862*6185db85Sdougm 		    } else {
863*6185db85Sdougm 			if (!dryrun)
864*6185db85Sdougm 			    ret = SA_INVALID_PROTOCOL;
865*6185db85Sdougm 		    }
866*6185db85Sdougm 		}
867*6185db85Sdougm 	    }
868*6185db85Sdougm 	}
869*6185db85Sdougm 	if (ret != SA_OK) {
870*6185db85Sdougm 	    (void) printf(gettext("Could not delete group: %s\n"),
871*6185db85Sdougm 				sa_errorstr(ret));
872*6185db85Sdougm 	} else if (dryrun && !auth && verbose) {
873*6185db85Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
874*6185db85Sdougm 			sa_errorstr(SA_NO_PERMISSION));
875*6185db85Sdougm 	}
876*6185db85Sdougm 	return (ret);
877*6185db85Sdougm }
878*6185db85Sdougm 
879*6185db85Sdougm /*
880*6185db85Sdougm  * strndupr(*buff, str, buffsize)
881*6185db85Sdougm  *
882*6185db85Sdougm  * used with small strings to duplicate and possibly increase the
883*6185db85Sdougm  * buffer size of a string.
884*6185db85Sdougm  */
885*6185db85Sdougm static char *
886*6185db85Sdougm strndupr(char *buff, char *str, int *buffsize)
887*6185db85Sdougm {
888*6185db85Sdougm 	int limit;
889*6185db85Sdougm 	char *orig_buff = buff;
890*6185db85Sdougm 
891*6185db85Sdougm 	if (buff == NULL) {
892*6185db85Sdougm 	    buff = (char *)malloc(64);
893*6185db85Sdougm 	    if (buff == NULL)
894*6185db85Sdougm 		return (NULL);
895*6185db85Sdougm 	    *buffsize = 64;
896*6185db85Sdougm 	    buff[0] = '\0';
897*6185db85Sdougm 	}
898*6185db85Sdougm 	limit = strlen(buff) + strlen(str) + 1;
899*6185db85Sdougm 	if (limit > *buffsize) {
900*6185db85Sdougm 	    limit = *buffsize = *buffsize + ((limit / 64) + 64);
901*6185db85Sdougm 	    buff = realloc(buff, limit);
902*6185db85Sdougm 	}
903*6185db85Sdougm 	if (buff != NULL) {
904*6185db85Sdougm 	    (void) strcat(buff, str);
905*6185db85Sdougm 	} else {
906*6185db85Sdougm 	    /* if it fails, fail it hard */
907*6185db85Sdougm 	    if (orig_buff != NULL)
908*6185db85Sdougm 		free(orig_buff);
909*6185db85Sdougm 	}
910*6185db85Sdougm 	return (buff);
911*6185db85Sdougm }
912*6185db85Sdougm 
913*6185db85Sdougm /*
914*6185db85Sdougm  * group_proto(group)
915*6185db85Sdougm  *
916*6185db85Sdougm  * return a string of all the protocols (space separated) associated
917*6185db85Sdougm  * with this group.
918*6185db85Sdougm  */
919*6185db85Sdougm 
920*6185db85Sdougm static char *
921*6185db85Sdougm group_proto(sa_group_t group)
922*6185db85Sdougm {
923*6185db85Sdougm 	sa_optionset_t optionset;
924*6185db85Sdougm 	char *proto;
925*6185db85Sdougm 	char *buff = NULL;
926*6185db85Sdougm 	int buffsize = 0;
927*6185db85Sdougm 	int addspace = 0;
928*6185db85Sdougm 	/*
929*6185db85Sdougm 	 * get the protocol list by finding the optionsets on this
930*6185db85Sdougm 	 * group and extracting the type value. The initial call to
931*6185db85Sdougm 	 * strndupr() initailizes buff.
932*6185db85Sdougm 	 */
933*6185db85Sdougm 	buff = strndupr(buff, "", &buffsize);
934*6185db85Sdougm 	if (buff != NULL) {
935*6185db85Sdougm 	    for (optionset = sa_get_optionset(group, NULL);
936*6185db85Sdougm 		optionset != NULL && buff != NULL;
937*6185db85Sdougm 		optionset = sa_get_next_optionset(optionset)) {
938*6185db85Sdougm 		/*
939*6185db85Sdougm 		 * extract out the protocol type from this optionset
940*6185db85Sdougm 		 * and append it to the buffer "buff". strndupr() will
941*6185db85Sdougm 		 * reallocate space as necessay.
942*6185db85Sdougm 		 */
943*6185db85Sdougm 		proto = sa_get_optionset_attr(optionset, "type");
944*6185db85Sdougm 		if (proto != NULL) {
945*6185db85Sdougm 		    if (addspace++)
946*6185db85Sdougm 			buff = strndupr(buff, " ", &buffsize);
947*6185db85Sdougm 		    buff = strndupr(buff, proto, &buffsize);
948*6185db85Sdougm 		    sa_free_attr_string(proto);
949*6185db85Sdougm 		}
950*6185db85Sdougm 	    }
951*6185db85Sdougm 	}
952*6185db85Sdougm 	return (buff);
953*6185db85Sdougm }
954*6185db85Sdougm 
955*6185db85Sdougm /*
956*6185db85Sdougm  * sa_list(flags, argc, argv)
957*6185db85Sdougm  *
958*6185db85Sdougm  * implements the "list" subcommand to list groups and optionally
959*6185db85Sdougm  * their state and protocols.
960*6185db85Sdougm  */
961*6185db85Sdougm 
962*6185db85Sdougm static int
963*6185db85Sdougm sa_list(int flags, int argc, char *argv[])
964*6185db85Sdougm {
965*6185db85Sdougm 	sa_group_t group;
966*6185db85Sdougm 	int verbose = 0;
967*6185db85Sdougm 	int c;
968*6185db85Sdougm 	char *protocol = NULL;
969*6185db85Sdougm #ifdef lint
970*6185db85Sdougm 	flags = flags;
971*6185db85Sdougm #endif
972*6185db85Sdougm 
973*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
974*6185db85Sdougm 	    switch (c) {
975*6185db85Sdougm 	    case 'v':
976*6185db85Sdougm 		verbose++;
977*6185db85Sdougm 		break;
978*6185db85Sdougm 	    case 'P':
979*6185db85Sdougm 		protocol = optarg;
980*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
981*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified:"
982*6185db85Sdougm 					    "%s\n"),
983*6185db85Sdougm 					protocol);
984*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
985*6185db85Sdougm 		}
986*6185db85Sdougm 		break;
987*6185db85Sdougm 	    default:
988*6185db85Sdougm 	    case 'h':
989*6185db85Sdougm 	    case '?':
990*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_LIST));
991*6185db85Sdougm 		return (0);
992*6185db85Sdougm 	    }
993*6185db85Sdougm 	}
994*6185db85Sdougm 
995*6185db85Sdougm 	for (group = sa_get_group(NULL); group != NULL;
996*6185db85Sdougm 	    group = sa_get_next_group(group)) {
997*6185db85Sdougm 	    char *name;
998*6185db85Sdougm 	    char *proto;
999*6185db85Sdougm 	    if (protocol == NULL || has_protocol(group, protocol)) {
1000*6185db85Sdougm 		name = sa_get_group_attr(group, "name");
1001*6185db85Sdougm 		if (name != NULL && (verbose > 1 || name[0] != '#')) {
1002*6185db85Sdougm 		    (void) printf("%s", (char *)name);
1003*6185db85Sdougm 		    if (verbose) {
1004*6185db85Sdougm 			/*
1005*6185db85Sdougm 			 * need the list of protocols
1006*6185db85Sdougm 			 * and current status once
1007*6185db85Sdougm 			 * available.
1008*6185db85Sdougm 			 */
1009*6185db85Sdougm 			(void) printf("\t%s", group_status(group));
1010*6185db85Sdougm 			proto = group_proto(group);
1011*6185db85Sdougm 			if (proto != NULL) {
1012*6185db85Sdougm 			    (void) printf("\t%s", (char *)proto);
1013*6185db85Sdougm 			    free(proto);
1014*6185db85Sdougm 			}
1015*6185db85Sdougm 		    }
1016*6185db85Sdougm 		    (void) printf("\n");
1017*6185db85Sdougm 		}
1018*6185db85Sdougm 		if (name != NULL)
1019*6185db85Sdougm 		    sa_free_attr_string(name);
1020*6185db85Sdougm 	    }
1021*6185db85Sdougm 	}
1022*6185db85Sdougm 	return (0);
1023*6185db85Sdougm }
1024*6185db85Sdougm 
1025*6185db85Sdougm /*
1026*6185db85Sdougm  * out_properties(optionset, proto, sec)
1027*6185db85Sdougm  *
1028*6185db85Sdougm  * Format the properties and encode the protocol and optional named
1029*6185db85Sdougm  * optionset into the string.
1030*6185db85Sdougm  *
1031*6185db85Sdougm  * format is protocol[:name]=(property-list)
1032*6185db85Sdougm  */
1033*6185db85Sdougm 
1034*6185db85Sdougm static void
1035*6185db85Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec)
1036*6185db85Sdougm {
1037*6185db85Sdougm 	char *type;
1038*6185db85Sdougm 	char *value;
1039*6185db85Sdougm 	int spacer;
1040*6185db85Sdougm 	sa_property_t prop;
1041*6185db85Sdougm 
1042*6185db85Sdougm 	if (sec == NULL) {
1043*6185db85Sdougm 	    (void) printf(" %s=(", proto ? proto : gettext("all"));
1044*6185db85Sdougm 	} else {
1045*6185db85Sdougm 	    (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
1046*6185db85Sdougm 	}
1047*6185db85Sdougm 
1048*6185db85Sdougm 	for (spacer = 0, prop = sa_get_property(optionset, NULL);
1049*6185db85Sdougm 	    prop != NULL; prop = sa_get_next_property(prop)) {
1050*6185db85Sdougm 
1051*6185db85Sdougm 		/*
1052*6185db85Sdougm 		 * extract the property name/value and output with
1053*6185db85Sdougm 		 * appropriate spacing. I.e. no prefixed space the
1054*6185db85Sdougm 		 * first time through but a space on subsequent
1055*6185db85Sdougm 		 * properties.
1056*6185db85Sdougm 		 */
1057*6185db85Sdougm 	    type = sa_get_property_attr(prop, "type");
1058*6185db85Sdougm 	    value = sa_get_property_attr(prop, "value");
1059*6185db85Sdougm 	    if (type != NULL) {
1060*6185db85Sdougm 		(void) printf("%s%s=", spacer ? " " : "",	type);
1061*6185db85Sdougm 		spacer = 1;
1062*6185db85Sdougm 		if (value != NULL)
1063*6185db85Sdougm 		    (void) printf("\"%s\"", value);
1064*6185db85Sdougm 		else
1065*6185db85Sdougm 		    (void) printf("\"\"");
1066*6185db85Sdougm 	    }
1067*6185db85Sdougm 	    if (type != NULL)
1068*6185db85Sdougm 		sa_free_attr_string(type);
1069*6185db85Sdougm 	    if (value != NULL)
1070*6185db85Sdougm 		sa_free_attr_string(value);
1071*6185db85Sdougm 	}
1072*6185db85Sdougm 	(void) printf(")");
1073*6185db85Sdougm }
1074*6185db85Sdougm 
1075*6185db85Sdougm /*
1076*6185db85Sdougm  * show_properties(group, protocol, prefix)
1077*6185db85Sdougm  *
1078*6185db85Sdougm  * print the properties for a group. If protocol is NULL, do all
1079*6185db85Sdougm  * protocols otherwise only the specified protocol. All security
1080*6185db85Sdougm  * (named groups specific to the protocol) are included.
1081*6185db85Sdougm  *
1082*6185db85Sdougm  * The "prefix" is always applied. The caller knows whether it wants
1083*6185db85Sdougm  * some type of prefix string (white space) or not.  Once the prefix
1084*6185db85Sdougm  * has been output, it is reduced to the zero length string for the
1085*6185db85Sdougm  * remainder of the property output.
1086*6185db85Sdougm  */
1087*6185db85Sdougm 
1088*6185db85Sdougm static void
1089*6185db85Sdougm show_properties(sa_group_t group, char *protocol, char *prefix)
1090*6185db85Sdougm {
1091*6185db85Sdougm 	sa_optionset_t optionset;
1092*6185db85Sdougm 	sa_security_t security;
1093*6185db85Sdougm 	char *value;
1094*6185db85Sdougm 	char *secvalue;
1095*6185db85Sdougm 
1096*6185db85Sdougm 	if (protocol != NULL) {
1097*6185db85Sdougm 	    optionset = sa_get_optionset(group, protocol);
1098*6185db85Sdougm 	    if (optionset != NULL) {
1099*6185db85Sdougm 		(void) printf("%s", prefix);
1100*6185db85Sdougm 		prefix = "";
1101*6185db85Sdougm 		out_properties(optionset, protocol, NULL);
1102*6185db85Sdougm 	    }
1103*6185db85Sdougm 	    security = sa_get_security(group, protocol, NULL);
1104*6185db85Sdougm 	    if (security != NULL) {
1105*6185db85Sdougm 		(void) printf("%s", prefix);
1106*6185db85Sdougm 		prefix = "";
1107*6185db85Sdougm 		out_properties(security, protocol, NULL);
1108*6185db85Sdougm 	    }
1109*6185db85Sdougm 	} else {
1110*6185db85Sdougm 	    for (optionset = sa_get_optionset(group, protocol);
1111*6185db85Sdougm 		optionset != NULL;
1112*6185db85Sdougm 		optionset = sa_get_next_optionset(optionset)) {
1113*6185db85Sdougm 
1114*6185db85Sdougm 		value = sa_get_optionset_attr(optionset, "type");
1115*6185db85Sdougm 		(void) printf("%s", prefix);
1116*6185db85Sdougm 		prefix = "";
1117*6185db85Sdougm 		out_properties(optionset, value, 0);
1118*6185db85Sdougm 		if (value != NULL)
1119*6185db85Sdougm 		    sa_free_attr_string(value);
1120*6185db85Sdougm 	    }
1121*6185db85Sdougm 	    for (security = sa_get_security(group, NULL, protocol);
1122*6185db85Sdougm 		security != NULL;
1123*6185db85Sdougm 		security = sa_get_next_security(security)) {
1124*6185db85Sdougm 
1125*6185db85Sdougm 		value = sa_get_security_attr(security, "type");
1126*6185db85Sdougm 		secvalue = sa_get_security_attr(security, "sectype");
1127*6185db85Sdougm 		(void) printf("%s", prefix);
1128*6185db85Sdougm 		prefix = "";
1129*6185db85Sdougm 		out_properties(security, value, secvalue);
1130*6185db85Sdougm 		if (value != NULL)
1131*6185db85Sdougm 		    sa_free_attr_string(value);
1132*6185db85Sdougm 		if (secvalue != NULL)
1133*6185db85Sdougm 		    sa_free_attr_string(secvalue);
1134*6185db85Sdougm 	    }
1135*6185db85Sdougm 	}
1136*6185db85Sdougm }
1137*6185db85Sdougm 
1138*6185db85Sdougm /*
1139*6185db85Sdougm  * show_group(group, verbose, properties, proto, subgroup)
1140*6185db85Sdougm  *
1141*6185db85Sdougm  * helper function to show the contents of a group.
1142*6185db85Sdougm  */
1143*6185db85Sdougm 
1144*6185db85Sdougm static void
1145*6185db85Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto,
1146*6185db85Sdougm 		char *subgroup)
1147*6185db85Sdougm {
1148*6185db85Sdougm 	sa_share_t share;
1149*6185db85Sdougm 	char *groupname;
1150*6185db85Sdougm 	char *sharepath;
1151*6185db85Sdougm 	char *resource;
1152*6185db85Sdougm 	char *description;
1153*6185db85Sdougm 	char *type;
1154*6185db85Sdougm 	char *zfs = NULL;
1155*6185db85Sdougm 	int iszfs = 0;
1156*6185db85Sdougm 
1157*6185db85Sdougm 	groupname = sa_get_group_attr(group, "name");
1158*6185db85Sdougm 	if (groupname != NULL) {
1159*6185db85Sdougm 	    if (proto != NULL && !has_protocol(group, proto)) {
1160*6185db85Sdougm 		sa_free_attr_string(groupname);
1161*6185db85Sdougm 		return;
1162*6185db85Sdougm 	    }
1163*6185db85Sdougm 		/*
1164*6185db85Sdougm 		 * check to see if the group is managed by ZFS. If
1165*6185db85Sdougm 		 * there is an attribute, then it is. A non-NULL zfs
1166*6185db85Sdougm 		 * variable will trigger the different way to display
1167*6185db85Sdougm 		 * and will remove the transient property indicator
1168*6185db85Sdougm 		 * from the output.
1169*6185db85Sdougm 		 */
1170*6185db85Sdougm 	    zfs = sa_get_group_attr(group, "zfs");
1171*6185db85Sdougm 	    if (zfs != NULL) {
1172*6185db85Sdougm 		iszfs = 1;
1173*6185db85Sdougm 		sa_free_attr_string(zfs);
1174*6185db85Sdougm 	    }
1175*6185db85Sdougm 	    share = sa_get_share(group, NULL);
1176*6185db85Sdougm 	    if (subgroup == NULL)
1177*6185db85Sdougm 		(void) printf("%s", groupname);
1178*6185db85Sdougm 	    else
1179*6185db85Sdougm 		(void) printf("    %s/%s", subgroup, groupname);
1180*6185db85Sdougm 	    if (properties) {
1181*6185db85Sdougm 		show_properties(group, proto, "");
1182*6185db85Sdougm 	    }
1183*6185db85Sdougm 	    (void) printf("\n");
1184*6185db85Sdougm 	    if (strcmp(groupname, "zfs") == 0) {
1185*6185db85Sdougm 		sa_group_t zgroup;
1186*6185db85Sdougm 
1187*6185db85Sdougm 		for (zgroup = sa_get_sub_group(group); zgroup != NULL;
1188*6185db85Sdougm 		    zgroup = sa_get_next_group(zgroup)) {
1189*6185db85Sdougm 		    show_group(zgroup, verbose, properties, proto, "zfs");
1190*6185db85Sdougm 		}
1191*6185db85Sdougm 		sa_free_attr_string(groupname);
1192*6185db85Sdougm 		return;
1193*6185db85Sdougm 	    }
1194*6185db85Sdougm 		/*
1195*6185db85Sdougm 		 * have a group, so list the contents. Resource and
1196*6185db85Sdougm 		 * description are only listed if verbose is set.
1197*6185db85Sdougm 		 */
1198*6185db85Sdougm 	    for (share = sa_get_share(group, NULL); share != NULL;
1199*6185db85Sdougm 		share = sa_get_next_share(share)) {
1200*6185db85Sdougm 		sharepath = sa_get_share_attr(share, "path");
1201*6185db85Sdougm 		if (sharepath != NULL) {
1202*6185db85Sdougm 		    if (verbose) {
1203*6185db85Sdougm 			resource = sa_get_share_attr(share, "resource");
1204*6185db85Sdougm 			description = sa_get_share_description(share);
1205*6185db85Sdougm 			type = sa_get_share_attr(share, "type");
1206*6185db85Sdougm 			if (type != NULL && !iszfs &&
1207*6185db85Sdougm 				strcmp(type, "transient") == 0)
1208*6185db85Sdougm 			    (void) printf("\t* ");
1209*6185db85Sdougm 			else
1210*6185db85Sdougm 			    (void) printf("\t  ");
1211*6185db85Sdougm 			if (resource != NULL && strlen(resource) > 0) {
1212*6185db85Sdougm 			    (void) printf("%s=%s", resource, sharepath);
1213*6185db85Sdougm 			} else {
1214*6185db85Sdougm 			    (void) printf("%s", sharepath);
1215*6185db85Sdougm 			}
1216*6185db85Sdougm 			if (resource != NULL)
1217*6185db85Sdougm 			    sa_free_attr_string(resource);
1218*6185db85Sdougm 			if (properties)
1219*6185db85Sdougm 			    show_properties(share, NULL, "\t");
1220*6185db85Sdougm 			if (description != NULL) {
1221*6185db85Sdougm 			    if (strlen(description) > 0) {
1222*6185db85Sdougm 				(void) printf("\t\"%s\"", description);
1223*6185db85Sdougm 			    }
1224*6185db85Sdougm 			    sa_free_share_description(description);
1225*6185db85Sdougm 			}
1226*6185db85Sdougm 			if (type != NULL)
1227*6185db85Sdougm 			    sa_free_attr_string(type);
1228*6185db85Sdougm 		    } else {
1229*6185db85Sdougm 			(void) printf("\t%s", sharepath);
1230*6185db85Sdougm 			if (properties)
1231*6185db85Sdougm 			    show_properties(share, NULL, "\t");
1232*6185db85Sdougm 		    }
1233*6185db85Sdougm 		    (void) printf("\n");
1234*6185db85Sdougm 		    sa_free_attr_string(sharepath);
1235*6185db85Sdougm 		}
1236*6185db85Sdougm 	    }
1237*6185db85Sdougm 	}
1238*6185db85Sdougm 	if (groupname != NULL) {
1239*6185db85Sdougm 		sa_free_attr_string(groupname);
1240*6185db85Sdougm 	}
1241*6185db85Sdougm }
1242*6185db85Sdougm 
1243*6185db85Sdougm /*
1244*6185db85Sdougm  * show_group_xml_init()
1245*6185db85Sdougm  *
1246*6185db85Sdougm  * Create an XML document that will be used to display config info via
1247*6185db85Sdougm  * XML format.
1248*6185db85Sdougm  */
1249*6185db85Sdougm 
1250*6185db85Sdougm xmlDocPtr
1251*6185db85Sdougm show_group_xml_init()
1252*6185db85Sdougm {
1253*6185db85Sdougm 	xmlDocPtr doc;
1254*6185db85Sdougm 	xmlNodePtr root;
1255*6185db85Sdougm 
1256*6185db85Sdougm 	doc = xmlNewDoc((xmlChar *)"1.0");
1257*6185db85Sdougm 	if (doc != NULL) {
1258*6185db85Sdougm 	    root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
1259*6185db85Sdougm 	    if (root != NULL)
1260*6185db85Sdougm 		xmlDocSetRootElement(doc, root);
1261*6185db85Sdougm 	}
1262*6185db85Sdougm 	return (doc);
1263*6185db85Sdougm }
1264*6185db85Sdougm 
1265*6185db85Sdougm /*
1266*6185db85Sdougm  * show_group_xml(doc, group)
1267*6185db85Sdougm  *
1268*6185db85Sdougm  * Copy the group info into the XML doc.
1269*6185db85Sdougm  */
1270*6185db85Sdougm 
1271*6185db85Sdougm static void
1272*6185db85Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group)
1273*6185db85Sdougm {
1274*6185db85Sdougm 	xmlNodePtr node;
1275*6185db85Sdougm 	xmlNodePtr root;
1276*6185db85Sdougm 
1277*6185db85Sdougm 	root = xmlDocGetRootElement(doc);
1278*6185db85Sdougm 	node = xmlCopyNode((xmlNodePtr)group, 1);
1279*6185db85Sdougm 	if (node != NULL && root != NULL) {
1280*6185db85Sdougm 	    xmlAddChild(root, node);
1281*6185db85Sdougm 		/*
1282*6185db85Sdougm 		 * In the future, we may have interally used tags that
1283*6185db85Sdougm 		 * should not appear in the XML output. Remove
1284*6185db85Sdougm 		 * anything we don't want to show here.
1285*6185db85Sdougm 		 */
1286*6185db85Sdougm 	}
1287*6185db85Sdougm }
1288*6185db85Sdougm 
1289*6185db85Sdougm /*
1290*6185db85Sdougm  * sa_show(flags, argc, argv)
1291*6185db85Sdougm  *
1292*6185db85Sdougm  * Implements the show subcommand.
1293*6185db85Sdougm  */
1294*6185db85Sdougm 
1295*6185db85Sdougm int
1296*6185db85Sdougm sa_show(int flags, int argc, char *argv[])
1297*6185db85Sdougm {
1298*6185db85Sdougm 	sa_group_t group;
1299*6185db85Sdougm 	int verbose = 0;
1300*6185db85Sdougm 	int properties = 0;
1301*6185db85Sdougm 	int c;
1302*6185db85Sdougm 	int ret = SA_OK;
1303*6185db85Sdougm 	char *protocol = NULL;
1304*6185db85Sdougm 	int xml = 0;
1305*6185db85Sdougm 	xmlDocPtr doc;
1306*6185db85Sdougm #ifdef lint
1307*6185db85Sdougm 	flags = flags;
1308*6185db85Sdougm #endif
1309*6185db85Sdougm 
1310*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvP:px")) !=	EOF) {
1311*6185db85Sdougm 	    switch (c) {
1312*6185db85Sdougm 	    case 'v':
1313*6185db85Sdougm 		verbose++;
1314*6185db85Sdougm 		break;
1315*6185db85Sdougm 	    case 'p':
1316*6185db85Sdougm 		properties++;
1317*6185db85Sdougm 		break;
1318*6185db85Sdougm 	    case 'P':
1319*6185db85Sdougm 		protocol = optarg;
1320*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
1321*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
1322*6185db85Sdougm 					protocol);
1323*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
1324*6185db85Sdougm 		}
1325*6185db85Sdougm 		break;
1326*6185db85Sdougm 	    case 'x':
1327*6185db85Sdougm 		xml++;
1328*6185db85Sdougm 		break;
1329*6185db85Sdougm 	    default:
1330*6185db85Sdougm 	    case 'h':
1331*6185db85Sdougm 	    case '?':
1332*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SHOW));
1333*6185db85Sdougm 		return (0);
1334*6185db85Sdougm 	    }
1335*6185db85Sdougm 	}
1336*6185db85Sdougm 
1337*6185db85Sdougm 	if (xml) {
1338*6185db85Sdougm 	    doc = show_group_xml_init();
1339*6185db85Sdougm 	    if (doc == NULL)
1340*6185db85Sdougm 		ret = SA_NO_MEMORY;
1341*6185db85Sdougm 	}
1342*6185db85Sdougm 
1343*6185db85Sdougm 	if (optind == argc) {
1344*6185db85Sdougm 	    /* no group specified so go through them all */
1345*6185db85Sdougm 	    for (group = sa_get_group(NULL); group != NULL;
1346*6185db85Sdougm 		group = sa_get_next_group(group)) {
1347*6185db85Sdougm 		/*
1348*6185db85Sdougm 		 * have a group so check if one we want and then list
1349*6185db85Sdougm 		 * contents with appropriate options.
1350*6185db85Sdougm 		 */
1351*6185db85Sdougm 		if (xml)
1352*6185db85Sdougm 		    show_group_xml(doc, group);
1353*6185db85Sdougm 		else
1354*6185db85Sdougm 		    show_group(group, verbose, properties, protocol, NULL);
1355*6185db85Sdougm 	    }
1356*6185db85Sdougm 	} else {
1357*6185db85Sdougm 	    /* have a specified list of groups */
1358*6185db85Sdougm 	    for (; optind < argc; optind++) {
1359*6185db85Sdougm 		group = sa_get_group(argv[optind]);
1360*6185db85Sdougm 		if (group != NULL) {
1361*6185db85Sdougm 		    if (xml)
1362*6185db85Sdougm 			show_group_xml(doc, group);
1363*6185db85Sdougm 		    else
1364*6185db85Sdougm 			show_group(group, verbose, properties, protocol, NULL);
1365*6185db85Sdougm 		} else {
1366*6185db85Sdougm 		    (void) printf(gettext("%s: not found\n"), argv[optind]);
1367*6185db85Sdougm 		    ret = SA_NO_SUCH_GROUP;
1368*6185db85Sdougm 		}
1369*6185db85Sdougm 	    }
1370*6185db85Sdougm 	}
1371*6185db85Sdougm 	if (xml && ret == SA_OK) {
1372*6185db85Sdougm 	    xmlDocFormatDump(stdout, doc, 1);
1373*6185db85Sdougm 	    xmlFreeDoc(doc);
1374*6185db85Sdougm 	}
1375*6185db85Sdougm 	return (ret);
1376*6185db85Sdougm 
1377*6185db85Sdougm }
1378*6185db85Sdougm 
1379*6185db85Sdougm /*
1380*6185db85Sdougm  * enable_share(group, share, update_legacy)
1381*6185db85Sdougm  *
1382*6185db85Sdougm  * helper function to enable a share if the group is enabled.
1383*6185db85Sdougm  */
1384*6185db85Sdougm 
1385*6185db85Sdougm static int
1386*6185db85Sdougm enable_share(sa_group_t group, sa_share_t share, int update_legacy)
1387*6185db85Sdougm {
1388*6185db85Sdougm 	char *value;
1389*6185db85Sdougm 	int enabled;
1390*6185db85Sdougm 	sa_optionset_t optionset;
1391*6185db85Sdougm 	int ret = SA_OK;
1392*6185db85Sdougm 	char *zfs = NULL;
1393*6185db85Sdougm 	int iszfs = 0;
1394*6185db85Sdougm 
1395*6185db85Sdougm 	/*
1396*6185db85Sdougm 	 * need to enable this share if the group is enabled but not
1397*6185db85Sdougm 	 * otherwise. The enable is also done on each protocol
1398*6185db85Sdougm 	 * represented in the group.
1399*6185db85Sdougm 	 */
1400*6185db85Sdougm 	value = sa_get_group_attr(group, "state");
1401*6185db85Sdougm 	enabled = value != NULL && strcmp(value, "enabled") == 0;
1402*6185db85Sdougm 	if (value != NULL)
1403*6185db85Sdougm 	    sa_free_attr_string(value);
1404*6185db85Sdougm 	/* remove legacy config if necessary */
1405*6185db85Sdougm 	if (update_legacy)
1406*6185db85Sdougm 	    ret = sa_delete_legacy(share);
1407*6185db85Sdougm 	zfs = sa_get_group_attr(group, "zfs");
1408*6185db85Sdougm 	if (zfs != NULL) {
1409*6185db85Sdougm 	    iszfs++;
1410*6185db85Sdougm 	    sa_free_attr_string(zfs);
1411*6185db85Sdougm 	}
1412*6185db85Sdougm 
1413*6185db85Sdougm 	/*
1414*6185db85Sdougm 	 * Step through each optionset at the group level and
1415*6185db85Sdougm 	 * enable the share based on the protocol type. This
1416*6185db85Sdougm 	 * works because protocols must be set on the group
1417*6185db85Sdougm 	 * for the protocol to be enabled.
1418*6185db85Sdougm 	 */
1419*6185db85Sdougm 	for (optionset = sa_get_optionset(group, NULL);
1420*6185db85Sdougm 	    optionset != NULL && ret == SA_OK;
1421*6185db85Sdougm 	    optionset = sa_get_next_optionset(optionset)) {
1422*6185db85Sdougm 	    value = sa_get_optionset_attr(optionset, "type");
1423*6185db85Sdougm 	    if (value != NULL) {
1424*6185db85Sdougm 		if (enabled)
1425*6185db85Sdougm 		    ret = sa_enable_share(share, value);
1426*6185db85Sdougm 		if (update_legacy && !iszfs)
1427*6185db85Sdougm 		    (void) sa_update_legacy(share, value);
1428*6185db85Sdougm 		sa_free_attr_string(value);
1429*6185db85Sdougm 	    }
1430*6185db85Sdougm 	}
1431*6185db85Sdougm 	if (ret == SA_OK)
1432*6185db85Sdougm 	    (void) sa_update_config();
1433*6185db85Sdougm 	return (ret);
1434*6185db85Sdougm }
1435*6185db85Sdougm 
1436*6185db85Sdougm /*
1437*6185db85Sdougm  * sa_addshare(flags, argc, argv)
1438*6185db85Sdougm  *
1439*6185db85Sdougm  * implements add-share subcommand.
1440*6185db85Sdougm  */
1441*6185db85Sdougm 
1442*6185db85Sdougm int
1443*6185db85Sdougm sa_addshare(int flags, int argc, char *argv[])
1444*6185db85Sdougm {
1445*6185db85Sdougm 	int verbose = 0;
1446*6185db85Sdougm 	int dryrun = 0;
1447*6185db85Sdougm 	int c;
1448*6185db85Sdougm 	int ret = SA_OK;
1449*6185db85Sdougm 	sa_group_t group;
1450*6185db85Sdougm 	sa_share_t share;
1451*6185db85Sdougm 	char *sharepath = NULL;
1452*6185db85Sdougm 	char *description = NULL;
1453*6185db85Sdougm 	char *resource = NULL;
1454*6185db85Sdougm 	int persist = SA_SHARE_PERMANENT; /* default to persist */
1455*6185db85Sdougm 	int auth;
1456*6185db85Sdougm 	char dir[MAXPATHLEN];
1457*6185db85Sdougm 
1458*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
1459*6185db85Sdougm 	    switch (c) {
1460*6185db85Sdougm 	    case 'n':
1461*6185db85Sdougm 		dryrun++;
1462*6185db85Sdougm 		break;
1463*6185db85Sdougm 	    case 'v':
1464*6185db85Sdougm 		verbose++;
1465*6185db85Sdougm 		break;
1466*6185db85Sdougm 	    case 'd':
1467*6185db85Sdougm 		description = optarg;
1468*6185db85Sdougm 		break;
1469*6185db85Sdougm 	    case 'r':
1470*6185db85Sdougm 		resource = optarg;
1471*6185db85Sdougm 		break;
1472*6185db85Sdougm 	    case 's':
1473*6185db85Sdougm 		/*
1474*6185db85Sdougm 		 * save share path into group. Currently limit
1475*6185db85Sdougm 		 * to one share per command.
1476*6185db85Sdougm 		 */
1477*6185db85Sdougm 		if (sharepath != NULL) {
1478*6185db85Sdougm 		    (void) printf(gettext("Adding multiple shares not"
1479*6185db85Sdougm 				    "supported\n"));
1480*6185db85Sdougm 		    return (1);
1481*6185db85Sdougm 		}
1482*6185db85Sdougm 		sharepath = optarg;
1483*6185db85Sdougm 		break;
1484*6185db85Sdougm 	    case 't':
1485*6185db85Sdougm 		persist = SA_SHARE_TRANSIENT;
1486*6185db85Sdougm 		break;
1487*6185db85Sdougm 	    default:
1488*6185db85Sdougm 	    case 'h':
1489*6185db85Sdougm 	    case '?':
1490*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
1491*6185db85Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
1492*6185db85Sdougm 		return (0);
1493*6185db85Sdougm 	    }
1494*6185db85Sdougm 	}
1495*6185db85Sdougm 
1496*6185db85Sdougm 	if (optind >= argc) {
1497*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"),
1498*6185db85Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
1499*6185db85Sdougm 	    if (dryrun || sharepath != NULL || description != NULL ||
1500*6185db85Sdougm 		resource != NULL || verbose || persist) {
1501*6185db85Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
1502*6185db85Sdougm 		ret = SA_NO_SUCH_GROUP;
1503*6185db85Sdougm 	    } else {
1504*6185db85Sdougm 		ret = SA_OK;
1505*6185db85Sdougm 	    }
1506*6185db85Sdougm 	} else {
1507*6185db85Sdougm 	    if (sharepath == NULL) {
1508*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
1509*6185db85Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
1510*6185db85Sdougm 		(void) printf(gettext("\t-s sharepath must be specified\n"));
1511*6185db85Sdougm 		ret = SA_BAD_PATH;
1512*6185db85Sdougm 	    }
1513*6185db85Sdougm 	    if (ret == SA_OK) {
1514*6185db85Sdougm 		if (realpath(sharepath, dir) == NULL) {
1515*6185db85Sdougm 		    ret = SA_BAD_PATH;
1516*6185db85Sdougm 		    (void) printf(gettext("Path is not valid: %s\n"),
1517*6185db85Sdougm 					sharepath);
1518*6185db85Sdougm 		} else {
1519*6185db85Sdougm 		    sharepath = dir;
1520*6185db85Sdougm 		}
1521*6185db85Sdougm 	    }
1522*6185db85Sdougm 	    if (ret == SA_OK && resource != NULL) {
1523*6185db85Sdougm 		/* check for valid syntax */
1524*6185db85Sdougm 		if (strpbrk(resource, " \t/") != NULL) {
1525*6185db85Sdougm 		    (void) printf(gettext("usage: %s\n"),
1526*6185db85Sdougm 				sa_get_usage(USAGE_ADD_SHARE));
1527*6185db85Sdougm 		    (void) printf(gettext("\tresource must not contain white"
1528*6185db85Sdougm 				    "space or '/' characters\n"));
1529*6185db85Sdougm 		    ret = SA_BAD_PATH;
1530*6185db85Sdougm 		}
1531*6185db85Sdougm 	    }
1532*6185db85Sdougm 	    if (ret == SA_OK) {
1533*6185db85Sdougm 		group = sa_get_group(argv[optind]);
1534*6185db85Sdougm 		if (group != NULL) {
1535*6185db85Sdougm 		    auth = check_authorizations(argv[optind], flags);
1536*6185db85Sdougm 		    share = sa_find_share(sharepath);
1537*6185db85Sdougm 		    if (share != NULL) {
1538*6185db85Sdougm 			group = sa_get_parent_group(share);
1539*6185db85Sdougm 			if (group != NULL) {
1540*6185db85Sdougm 			    char *groupname;
1541*6185db85Sdougm 			    groupname = sa_get_group_attr(group, "name");
1542*6185db85Sdougm 			    if (groupname != NULL) {
1543*6185db85Sdougm 				(void) printf(gettext("Share path already "
1544*6185db85Sdougm 							"shared in group "
1545*6185db85Sdougm 							"\"%s\": %s\n"),
1546*6185db85Sdougm 						groupname, sharepath);
1547*6185db85Sdougm 				sa_free_attr_string(groupname);
1548*6185db85Sdougm 			    } else {
1549*6185db85Sdougm 				(void) printf(gettext("Share path already"
1550*6185db85Sdougm 							"shared: %s\n"),
1551*6185db85Sdougm 						groupname, sharepath);
1552*6185db85Sdougm 			    }
1553*6185db85Sdougm 			} else {
1554*6185db85Sdougm 			    (void) printf(gettext("Share path %s already "
1555*6185db85Sdougm 							"shared\n"),
1556*6185db85Sdougm 				    sharepath);
1557*6185db85Sdougm 			}
1558*6185db85Sdougm 			ret = SA_DUPLICATE_NAME;
1559*6185db85Sdougm 		    } else {
1560*6185db85Sdougm 			/*
1561*6185db85Sdougm 			 * need to check that resource name is unique
1562*6185db85Sdougm 			 * at some point.
1563*6185db85Sdougm 			 */
1564*6185db85Sdougm 			if (dryrun)
1565*6185db85Sdougm 			    ret = sa_check_path(group, sharepath);
1566*6185db85Sdougm 			else
1567*6185db85Sdougm 			    share = sa_add_share(group, sharepath,
1568*6185db85Sdougm 							persist, &ret);
1569*6185db85Sdougm 			if (!dryrun && share == NULL) {
1570*6185db85Sdougm 				(void) printf(gettext("Could not add share: "
1571*6185db85Sdougm 							"%s\n"),
1572*6185db85Sdougm 					sa_errorstr(ret));
1573*6185db85Sdougm 			} else {
1574*6185db85Sdougm 			    if (!dryrun && ret == SA_OK) {
1575*6185db85Sdougm 				if (resource != NULL) {
1576*6185db85Sdougm 				    if (strpbrk(resource, " \t/") == NULL) {
1577*6185db85Sdougm 					ret = sa_set_share_attr(share,
1578*6185db85Sdougm 								"resource",
1579*6185db85Sdougm 								resource);
1580*6185db85Sdougm 				    }
1581*6185db85Sdougm 				}
1582*6185db85Sdougm 				if (ret == SA_OK && description != NULL) {
1583*6185db85Sdougm 				    ret = sa_set_share_description(share,
1584*6185db85Sdougm 							    description);
1585*6185db85Sdougm 				}
1586*6185db85Sdougm 				if (ret == SA_OK) {
1587*6185db85Sdougm 				    /* now enable the share(s) */
1588*6185db85Sdougm 				    ret = enable_share(group, share, 1);
1589*6185db85Sdougm 				    ret = sa_update_config();
1590*6185db85Sdougm 				}
1591*6185db85Sdougm 				switch (ret) {
1592*6185db85Sdougm 				case SA_DUPLICATE_NAME:
1593*6185db85Sdougm 				    (void) printf(gettext("Resource name in"
1594*6185db85Sdougm 						    "use: %s\n"),
1595*6185db85Sdougm 					    resource);
1596*6185db85Sdougm 				    break;
1597*6185db85Sdougm 				default:
1598*6185db85Sdougm 				    (void) printf(gettext("Could not set "
1599*6185db85Sdougm 						    "attribute: %s\n"),
1600*6185db85Sdougm 					    sa_errorstr(ret));
1601*6185db85Sdougm 				    break;
1602*6185db85Sdougm 				case SA_OK:
1603*6185db85Sdougm 				    break;
1604*6185db85Sdougm 				}
1605*6185db85Sdougm 			    } else if (dryrun && ret == SA_OK &&
1606*6185db85Sdougm 					!auth && verbose) {
1607*6185db85Sdougm 				(void) printf(gettext("Command would fail: "
1608*6185db85Sdougm 							"%s\n"),
1609*6185db85Sdougm 					sa_errorstr(SA_NO_PERMISSION));
1610*6185db85Sdougm 				ret = SA_NO_PERMISSION;
1611*6185db85Sdougm 			    }
1612*6185db85Sdougm 			}
1613*6185db85Sdougm 		    }
1614*6185db85Sdougm 		} else {
1615*6185db85Sdougm 		    (void) printf(gettext("Group \"%s\" not found\n"),
1616*6185db85Sdougm 					argv[optind]);
1617*6185db85Sdougm 		    ret = SA_NO_SUCH_GROUP;
1618*6185db85Sdougm 		}
1619*6185db85Sdougm 	    }
1620*6185db85Sdougm 	}
1621*6185db85Sdougm 	return (ret);
1622*6185db85Sdougm }
1623*6185db85Sdougm 
1624*6185db85Sdougm /*
1625*6185db85Sdougm  * sa_moveshare(flags, argc, argv)
1626*6185db85Sdougm  *
1627*6185db85Sdougm  * implements move-share subcommand.
1628*6185db85Sdougm  */
1629*6185db85Sdougm 
1630*6185db85Sdougm int
1631*6185db85Sdougm sa_moveshare(int flags, int argc, char *argv[])
1632*6185db85Sdougm {
1633*6185db85Sdougm 	int verbose = 0;
1634*6185db85Sdougm 	int dryrun = 0;
1635*6185db85Sdougm 	int c;
1636*6185db85Sdougm 	int ret = SA_OK;
1637*6185db85Sdougm 	sa_group_t group;
1638*6185db85Sdougm 	sa_share_t share;
1639*6185db85Sdougm 	char *sharepath = NULL;
1640*6185db85Sdougm 	int authsrc = 0, authdst = 0;
1641*6185db85Sdougm 
1642*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvns:")) != EOF) {
1643*6185db85Sdougm 	    switch (c) {
1644*6185db85Sdougm 	    case 'n':
1645*6185db85Sdougm 		dryrun++;
1646*6185db85Sdougm 		break;
1647*6185db85Sdougm 	    case 'v':
1648*6185db85Sdougm 		verbose++;
1649*6185db85Sdougm 		break;
1650*6185db85Sdougm 	    case 's':
1651*6185db85Sdougm 		/*
1652*6185db85Sdougm 		 * remove share path from group. Currently limit
1653*6185db85Sdougm 		 * to one share per command.
1654*6185db85Sdougm 		 */
1655*6185db85Sdougm 		if (sharepath != NULL) {
1656*6185db85Sdougm 		    (void) printf(gettext("Moving multiple shares not"
1657*6185db85Sdougm 				    "supported\n"));
1658*6185db85Sdougm 		    return (SA_BAD_PATH);
1659*6185db85Sdougm 		}
1660*6185db85Sdougm 		sharepath = optarg;
1661*6185db85Sdougm 		break;
1662*6185db85Sdougm 	    default:
1663*6185db85Sdougm 	    case 'h':
1664*6185db85Sdougm 	    case '?':
1665*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
1666*6185db85Sdougm 				sa_get_usage(USAGE_MOVE_SHARE));
1667*6185db85Sdougm 		return (0);
1668*6185db85Sdougm 	    }
1669*6185db85Sdougm 	}
1670*6185db85Sdougm 
1671*6185db85Sdougm 	if (optind >= argc || sharepath == NULL) {
1672*6185db85Sdougm 			(void) printf(gettext("usage: %s\n"),
1673*6185db85Sdougm 				sa_get_usage(USAGE_MOVE_SHARE));
1674*6185db85Sdougm 	    if (dryrun || verbose || sharepath != NULL) {
1675*6185db85Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
1676*6185db85Sdougm 		ret = SA_NO_SUCH_GROUP;
1677*6185db85Sdougm 	    } else {
1678*6185db85Sdougm 		if (sharepath == NULL) {
1679*6185db85Sdougm 		    ret = SA_SYNTAX_ERR;
1680*6185db85Sdougm 		    (void) printf(gettext("\tsharepath must be specified\n"));
1681*6185db85Sdougm 		} else
1682*6185db85Sdougm 		    ret = SA_OK;
1683*6185db85Sdougm 	    }
1684*6185db85Sdougm 	} else {
1685*6185db85Sdougm 	    if (sharepath == NULL) {
1686*6185db85Sdougm 		(void) printf(gettext("sharepath must be specified with "
1687*6185db85Sdougm 				"the -s option\n"));
1688*6185db85Sdougm 		ret = SA_BAD_PATH;
1689*6185db85Sdougm 	    } else {
1690*6185db85Sdougm 		group = sa_get_group(argv[optind]);
1691*6185db85Sdougm 		if (group != NULL) {
1692*6185db85Sdougm 		    share = sa_find_share(sharepath);
1693*6185db85Sdougm 		    authdst = check_authorizations(argv[optind], flags);
1694*6185db85Sdougm 		    if (share == NULL) {
1695*6185db85Sdougm 			(void) printf(gettext("Share not found: %s\n"),
1696*6185db85Sdougm 					sharepath);
1697*6185db85Sdougm 			ret = SA_NO_SUCH_PATH;
1698*6185db85Sdougm 		    } else {
1699*6185db85Sdougm 			sa_group_t parent;
1700*6185db85Sdougm 			char *zfsold;
1701*6185db85Sdougm 			char *zfsnew;
1702*6185db85Sdougm 
1703*6185db85Sdougm 			parent = sa_get_parent_group(share);
1704*6185db85Sdougm 			if (parent != NULL) {
1705*6185db85Sdougm 			    char *pname;
1706*6185db85Sdougm 			    pname = sa_get_group_attr(parent, "name");
1707*6185db85Sdougm 			    if (pname != NULL) {
1708*6185db85Sdougm 				authsrc = check_authorizations(pname, flags);
1709*6185db85Sdougm 				sa_free_attr_string(pname);
1710*6185db85Sdougm 			    }
1711*6185db85Sdougm 			    zfsold = sa_get_group_attr(parent, "zfs");
1712*6185db85Sdougm 			    zfsnew = sa_get_group_attr(group, "zfs");
1713*6185db85Sdougm 			    if ((zfsold != NULL && zfsnew == NULL) ||
1714*6185db85Sdougm 				(zfsold == NULL && zfsnew != NULL)) {
1715*6185db85Sdougm 				ret = SA_NOT_ALLOWED;
1716*6185db85Sdougm 			    }
1717*6185db85Sdougm 			    if (zfsold != NULL)
1718*6185db85Sdougm 				sa_free_attr_string(zfsold);
1719*6185db85Sdougm 			    if (zfsnew != NULL)
1720*6185db85Sdougm 				sa_free_attr_string(zfsnew);
1721*6185db85Sdougm 			}
1722*6185db85Sdougm 			if (!dryrun && ret == SA_OK) {
1723*6185db85Sdougm 			    ret = sa_move_share(group, share);
1724*6185db85Sdougm 			}
1725*6185db85Sdougm 			if (ret == SA_OK && parent != group && !dryrun) {
1726*6185db85Sdougm 			    char *oldstate;
1727*6185db85Sdougm 			    ret = sa_update_config();
1728*6185db85Sdougm 				/*
1729*6185db85Sdougm 				 * note that the share may need to be
1730*6185db85Sdougm 				 * "unshared" if the new group is
1731*6185db85Sdougm 				 * disabled and the old was enabled or
1732*6185db85Sdougm 				 * it may need to be share to update
1733*6185db85Sdougm 				 * if the new group is enabled.
1734*6185db85Sdougm 				 */
1735*6185db85Sdougm 			    oldstate = sa_get_group_attr(parent, "state");
1736*6185db85Sdougm 			    /* enable_share determines what to do */
1737*6185db85Sdougm 			    if (strcmp(oldstate, "enabled") == 0) {
1738*6185db85Sdougm 				(void) sa_disable_share(share, NULL);
1739*6185db85Sdougm 			    }
1740*6185db85Sdougm 			    (void) enable_share(group, share, 1);
1741*6185db85Sdougm 			    if (oldstate != NULL)
1742*6185db85Sdougm 				sa_free_attr_string(oldstate);
1743*6185db85Sdougm 			}
1744*6185db85Sdougm 			if (ret != SA_OK) {
1745*6185db85Sdougm 			    (void) printf(gettext("Could not move share: %s\n"),
1746*6185db85Sdougm 				    sa_errorstr(ret));
1747*6185db85Sdougm 			}
1748*6185db85Sdougm 			if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
1749*6185db85Sdougm 			    verbose) {
1750*6185db85Sdougm 			    (void) printf(gettext("Command would fail: %s\n"),
1751*6185db85Sdougm 					sa_errorstr(SA_NO_PERMISSION));
1752*6185db85Sdougm 			}
1753*6185db85Sdougm 		    }
1754*6185db85Sdougm 		} else {
1755*6185db85Sdougm 		    (void) printf(gettext("Group \"%s\" not found\n"),
1756*6185db85Sdougm 					argv[optind]);
1757*6185db85Sdougm 		    ret = SA_NO_SUCH_GROUP;
1758*6185db85Sdougm 		}
1759*6185db85Sdougm 	    }
1760*6185db85Sdougm 	}
1761*6185db85Sdougm 	return (ret);
1762*6185db85Sdougm }
1763*6185db85Sdougm 
1764*6185db85Sdougm /*
1765*6185db85Sdougm  * sa_removeshare(flags, argc, argv)
1766*6185db85Sdougm  *
1767*6185db85Sdougm  * implements remove-share subcommand.
1768*6185db85Sdougm  */
1769*6185db85Sdougm 
1770*6185db85Sdougm int
1771*6185db85Sdougm sa_removeshare(int flags, int argc, char *argv[])
1772*6185db85Sdougm {
1773*6185db85Sdougm 	int verbose = 0;
1774*6185db85Sdougm 	int dryrun = 0;
1775*6185db85Sdougm 	int force = 0;
1776*6185db85Sdougm 	int c;
1777*6185db85Sdougm 	int ret = SA_OK;
1778*6185db85Sdougm 	sa_group_t group;
1779*6185db85Sdougm 	sa_share_t share;
1780*6185db85Sdougm 	char *sharepath = NULL;
1781*6185db85Sdougm 	char dir[MAXPATHLEN];
1782*6185db85Sdougm 	int auth;
1783*6185db85Sdougm 
1784*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hfns:v")) != EOF) {
1785*6185db85Sdougm 	    switch (c) {
1786*6185db85Sdougm 	    case 'n':
1787*6185db85Sdougm 		dryrun++;
1788*6185db85Sdougm 		break;
1789*6185db85Sdougm 	    case 'v':
1790*6185db85Sdougm 		verbose++;
1791*6185db85Sdougm 		break;
1792*6185db85Sdougm 	    case 'f':
1793*6185db85Sdougm 		force++;
1794*6185db85Sdougm 		break;
1795*6185db85Sdougm 	    case 's':
1796*6185db85Sdougm 		/*
1797*6185db85Sdougm 		 * remove share path from group. Currently limit
1798*6185db85Sdougm 		 * to one share per command.
1799*6185db85Sdougm 		 */
1800*6185db85Sdougm 		if (sharepath != NULL) {
1801*6185db85Sdougm 		    (void) printf(gettext("Removing multiple shares not"
1802*6185db85Sdougm 				    "supported\n"));
1803*6185db85Sdougm 		    return (SA_SYNTAX_ERR);
1804*6185db85Sdougm 		}
1805*6185db85Sdougm 		sharepath = optarg;
1806*6185db85Sdougm 		break;
1807*6185db85Sdougm 	    default:
1808*6185db85Sdougm 	    case 'h':
1809*6185db85Sdougm 	    case '?':
1810*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
1811*6185db85Sdougm 				sa_get_usage(USAGE_REMOVE_SHARE));
1812*6185db85Sdougm 		return (0);
1813*6185db85Sdougm 	    }
1814*6185db85Sdougm 	}
1815*6185db85Sdougm 
1816*6185db85Sdougm 	if (optind >= argc || sharepath == NULL) {
1817*6185db85Sdougm 	    if (sharepath == NULL) {
1818*6185db85Sdougm 			(void) printf(gettext("usage: %s\n"),
1819*6185db85Sdougm 				sa_get_usage(USAGE_REMOVE_SHARE));
1820*6185db85Sdougm 		(void) printf(gettext("\t-s sharepath must be specified\n"));
1821*6185db85Sdougm 		ret = SA_BAD_PATH;
1822*6185db85Sdougm 	    } else {
1823*6185db85Sdougm 		ret = SA_OK;
1824*6185db85Sdougm 	    }
1825*6185db85Sdougm 	}
1826*6185db85Sdougm 	if (ret == SA_OK) {
1827*6185db85Sdougm 	    if (optind < argc) {
1828*6185db85Sdougm 		if ((optind + 1) < argc) {
1829*6185db85Sdougm 		    (void) printf(gettext("Extraneous group(s) at end of "
1830*6185db85Sdougm 						"command\n"));
1831*6185db85Sdougm 		    ret = SA_SYNTAX_ERR;
1832*6185db85Sdougm 		} else {
1833*6185db85Sdougm 		    group = sa_get_group(argv[optind]);
1834*6185db85Sdougm 		    if (group == NULL) {
1835*6185db85Sdougm 			(void) printf(gettext("Group \"%s\" not found\n"),
1836*6185db85Sdougm 					argv[optind]);
1837*6185db85Sdougm 			ret = SA_NO_SUCH_GROUP;
1838*6185db85Sdougm 		    }
1839*6185db85Sdougm 		}
1840*6185db85Sdougm 	    } else {
1841*6185db85Sdougm 		group = NULL;
1842*6185db85Sdougm 	    }
1843*6185db85Sdougm 	    if (ret == SA_OK) {
1844*6185db85Sdougm 		if (realpath(sharepath, dir) == NULL) {
1845*6185db85Sdougm 		    ret = SA_BAD_PATH;
1846*6185db85Sdougm 		    (void) printf(gettext("Path is not valid: %s\n"),
1847*6185db85Sdougm 					sharepath);
1848*6185db85Sdougm 		} else {
1849*6185db85Sdougm 		    sharepath = dir;
1850*6185db85Sdougm 		}
1851*6185db85Sdougm 	    }
1852*6185db85Sdougm 	    if (ret == SA_OK) {
1853*6185db85Sdougm 		if (group != NULL)
1854*6185db85Sdougm 		    share = sa_get_share(group, sharepath);
1855*6185db85Sdougm 		else
1856*6185db85Sdougm 		    share = sa_find_share(sharepath);
1857*6185db85Sdougm 		if (share == NULL) {
1858*6185db85Sdougm 		    if (group != NULL)
1859*6185db85Sdougm 			(void) printf(gettext("Share not found in group %s:"
1860*6185db85Sdougm 						"%s\n"),
1861*6185db85Sdougm 					argv[optind], sharepath);
1862*6185db85Sdougm 		    else
1863*6185db85Sdougm 			(void) printf(gettext("Share not found: %s\n"),
1864*6185db85Sdougm 					sharepath);
1865*6185db85Sdougm 		    ret = SA_NO_SUCH_PATH;
1866*6185db85Sdougm 		} else {
1867*6185db85Sdougm 		    if (group == NULL)
1868*6185db85Sdougm 			group = sa_get_parent_group(share);
1869*6185db85Sdougm 		    if (!dryrun) {
1870*6185db85Sdougm 			if (ret == SA_OK) {
1871*6185db85Sdougm 			    ret = sa_disable_share(share, NULL);
1872*6185db85Sdougm 				/*
1873*6185db85Sdougm 				 * we don't care if it fails since it
1874*6185db85Sdougm 				 * could be disabled already.
1875*6185db85Sdougm 				 */
1876*6185db85Sdougm 			    if (ret == SA_OK || ret == SA_NO_SUCH_PATH ||
1877*6185db85Sdougm 				ret == SA_NOT_SUPPORTED) {
1878*6185db85Sdougm 				ret = sa_remove_share(share);
1879*6185db85Sdougm 			    }
1880*6185db85Sdougm 			    if (ret == SA_OK)
1881*6185db85Sdougm 				ret = sa_update_config();
1882*6185db85Sdougm 			}
1883*6185db85Sdougm 			if (ret != SA_OK) {
1884*6185db85Sdougm 			    (void) printf(gettext("Could not remove share:"
1885*6185db85Sdougm 							" %s\n"),
1886*6185db85Sdougm 					sa_errorstr(ret));
1887*6185db85Sdougm 			}
1888*6185db85Sdougm 		    } else if (ret == SA_OK) {
1889*6185db85Sdougm 			char *pname;
1890*6185db85Sdougm 			pname = sa_get_group_attr(group, "name");
1891*6185db85Sdougm 			if (pname != NULL) {
1892*6185db85Sdougm 			    auth = check_authorizations(pname, flags);
1893*6185db85Sdougm 			    sa_free_attr_string(pname);
1894*6185db85Sdougm 			}
1895*6185db85Sdougm 			if (!auth && verbose) {
1896*6185db85Sdougm 			    (void) printf(gettext("Command would fail: %s\n"),
1897*6185db85Sdougm 					sa_errorstr(SA_NO_PERMISSION));
1898*6185db85Sdougm 			}
1899*6185db85Sdougm 		    }
1900*6185db85Sdougm 		}
1901*6185db85Sdougm 	    }
1902*6185db85Sdougm 	}
1903*6185db85Sdougm 	return (ret);
1904*6185db85Sdougm }
1905*6185db85Sdougm 
1906*6185db85Sdougm /*
1907*6185db85Sdougm  * sa_set_share(flags, argc, argv)
1908*6185db85Sdougm  *
1909*6185db85Sdougm  * implements set-share subcommand.
1910*6185db85Sdougm  */
1911*6185db85Sdougm 
1912*6185db85Sdougm int
1913*6185db85Sdougm sa_set_share(int flags, int argc, char *argv[])
1914*6185db85Sdougm {
1915*6185db85Sdougm 	int dryrun = 0;
1916*6185db85Sdougm 	int c;
1917*6185db85Sdougm 	int ret = SA_OK;
1918*6185db85Sdougm 	sa_group_t group, sharegroup;
1919*6185db85Sdougm 	sa_share_t share;
1920*6185db85Sdougm 	char *sharepath = NULL;
1921*6185db85Sdougm 	char *description = NULL;
1922*6185db85Sdougm 	char *resource = NULL;
1923*6185db85Sdougm 	int auth;
1924*6185db85Sdougm 	int verbose = 0;
1925*6185db85Sdougm 
1926*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
1927*6185db85Sdougm 	    switch (c) {
1928*6185db85Sdougm 	    case 'n':
1929*6185db85Sdougm 		dryrun++;
1930*6185db85Sdougm 		break;
1931*6185db85Sdougm 	    case 'd':
1932*6185db85Sdougm 		description = optarg;
1933*6185db85Sdougm 		break;
1934*6185db85Sdougm 	    case 'r':
1935*6185db85Sdougm 		resource = optarg;
1936*6185db85Sdougm 		break;
1937*6185db85Sdougm 	    case 'v':
1938*6185db85Sdougm 		verbose++;
1939*6185db85Sdougm 		break;
1940*6185db85Sdougm 	    case 's':
1941*6185db85Sdougm 		/*
1942*6185db85Sdougm 		 * save share path into group. Currently limit
1943*6185db85Sdougm 		 * to one share per command.
1944*6185db85Sdougm 		 */
1945*6185db85Sdougm 		if (sharepath != NULL) {
1946*6185db85Sdougm 		    (void) printf(gettext("Updating multiple shares not"
1947*6185db85Sdougm 				    "supported\n"));
1948*6185db85Sdougm 		    return (SA_BAD_PATH);
1949*6185db85Sdougm 		}
1950*6185db85Sdougm 		sharepath = optarg;
1951*6185db85Sdougm 		break;
1952*6185db85Sdougm 	    default:
1953*6185db85Sdougm 	    case 'h':
1954*6185db85Sdougm 	    case '?':
1955*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
1956*6185db85Sdougm 				sa_get_usage(USAGE_SET_SHARE));
1957*6185db85Sdougm 		return (SA_OK);
1958*6185db85Sdougm 	    }
1959*6185db85Sdougm 	}
1960*6185db85Sdougm 	if (optind >= argc || sharepath == NULL) {
1961*6185db85Sdougm 	    if (sharepath == NULL) {
1962*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
1963*6185db85Sdougm 				sa_get_usage(USAGE_SET_SHARE));
1964*6185db85Sdougm 		(void) printf(gettext("\tgroup must be specified\n"));
1965*6185db85Sdougm 	    ret = SA_BAD_PATH;
1966*6185db85Sdougm 	    } else {
1967*6185db85Sdougm 		ret = SA_OK;
1968*6185db85Sdougm 	    }
1969*6185db85Sdougm 	}
1970*6185db85Sdougm 	if ((optind + 1) < argc) {
1971*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"),
1972*6185db85Sdougm 				sa_get_usage(USAGE_SET_SHARE));
1973*6185db85Sdougm 	    (void) printf(gettext("\tExtraneous group(s) at end\n"));
1974*6185db85Sdougm 	    ret = SA_SYNTAX_ERR;
1975*6185db85Sdougm 	}
1976*6185db85Sdougm 	if (ret == SA_OK) {
1977*6185db85Sdougm 	    char *groupname;
1978*6185db85Sdougm 	    if (optind < argc) {
1979*6185db85Sdougm 		groupname = argv[optind];
1980*6185db85Sdougm 		group = sa_get_group(groupname);
1981*6185db85Sdougm 	    } else {
1982*6185db85Sdougm 		group = NULL;
1983*6185db85Sdougm 		groupname = NULL;
1984*6185db85Sdougm 	    }
1985*6185db85Sdougm 	    share = sa_find_share(sharepath);
1986*6185db85Sdougm 	    if (share != NULL) {
1987*6185db85Sdougm 		sharegroup = sa_get_parent_group(share);
1988*6185db85Sdougm 		if (group != NULL && group != sharegroup) {
1989*6185db85Sdougm 		    (void) printf(gettext("Group \"%s\" does not contain "
1990*6185db85Sdougm 						"share %s\n"),
1991*6185db85Sdougm 			    argv[optind], sharepath);
1992*6185db85Sdougm 		    ret = SA_BAD_PATH;
1993*6185db85Sdougm 		} else {
1994*6185db85Sdougm 		    int delgroupname = 0;
1995*6185db85Sdougm 		    if (groupname == NULL) {
1996*6185db85Sdougm 			groupname = sa_get_group_attr(sharegroup, "name");
1997*6185db85Sdougm 			delgroupname = 1;
1998*6185db85Sdougm 		    }
1999*6185db85Sdougm 		    if (groupname != NULL) {
2000*6185db85Sdougm 			auth = check_authorizations(groupname, flags);
2001*6185db85Sdougm 			if (delgroupname) {
2002*6185db85Sdougm 			    sa_free_attr_string(groupname);
2003*6185db85Sdougm 			    groupname = NULL;
2004*6185db85Sdougm 			}
2005*6185db85Sdougm 		    } else {
2006*6185db85Sdougm 			ret = SA_NO_MEMORY;
2007*6185db85Sdougm 		    }
2008*6185db85Sdougm 		    if (resource != NULL) {
2009*6185db85Sdougm 			if (strpbrk(resource, " \t/") == NULL) {
2010*6185db85Sdougm 			    if (!dryrun) {
2011*6185db85Sdougm 				ret = sa_set_share_attr(share, "resource",
2012*6185db85Sdougm 						    resource);
2013*6185db85Sdougm 			    } else {
2014*6185db85Sdougm 				sa_share_t resshare;
2015*6185db85Sdougm 				resshare = sa_get_resource(sharegroup,
2016*6185db85Sdougm 							    resource);
2017*6185db85Sdougm 				if (resshare != NULL && resshare != share)
2018*6185db85Sdougm 				    ret = SA_DUPLICATE_NAME;
2019*6185db85Sdougm 			    }
2020*6185db85Sdougm 			} else {
2021*6185db85Sdougm 			    ret = SA_BAD_PATH;
2022*6185db85Sdougm 			    (void) printf(gettext("Resource must not contain "
2023*6185db85Sdougm 						"white space or '/'\n"));
2024*6185db85Sdougm 			}
2025*6185db85Sdougm 		    }
2026*6185db85Sdougm 		    if (ret == SA_OK && description != NULL) {
2027*6185db85Sdougm 			ret = sa_set_share_description(share, description);
2028*6185db85Sdougm 		    }
2029*6185db85Sdougm 		}
2030*6185db85Sdougm 		if (!dryrun && ret == SA_OK) {
2031*6185db85Sdougm 		    ret = sa_update_config();
2032*6185db85Sdougm 		}
2033*6185db85Sdougm 		switch (ret) {
2034*6185db85Sdougm 		case SA_DUPLICATE_NAME:
2035*6185db85Sdougm 		    (void) printf(gettext("Resource name in use: %s\n"),
2036*6185db85Sdougm 					resource);
2037*6185db85Sdougm 		    break;
2038*6185db85Sdougm 		default:
2039*6185db85Sdougm 		    (void) printf(gettext("Could not set attribute: %s\n"),
2040*6185db85Sdougm 			    sa_errorstr(ret));
2041*6185db85Sdougm 		    break;
2042*6185db85Sdougm 		case SA_OK:
2043*6185db85Sdougm 		    if (dryrun && !auth && verbose) {
2044*6185db85Sdougm 			(void) printf(gettext("Command would fail: %s\n"),
2045*6185db85Sdougm 				sa_errorstr(SA_NO_PERMISSION));
2046*6185db85Sdougm 		    }
2047*6185db85Sdougm 		    break;
2048*6185db85Sdougm 		}
2049*6185db85Sdougm 	    } else {
2050*6185db85Sdougm 		(void) printf(gettext("Share path \"%s\" not found\n"),
2051*6185db85Sdougm 				sharepath);
2052*6185db85Sdougm 		ret = SA_NO_SUCH_PATH;
2053*6185db85Sdougm 	    }
2054*6185db85Sdougm 	}
2055*6185db85Sdougm 	return (ret);
2056*6185db85Sdougm }
2057*6185db85Sdougm 
2058*6185db85Sdougm /*
2059*6185db85Sdougm  * add_security(group, sectype, optlist, proto, *err)
2060*6185db85Sdougm  *
2061*6185db85Sdougm  * Helper function to add a security option (named optionset) to the
2062*6185db85Sdougm  * group.
2063*6185db85Sdougm  */
2064*6185db85Sdougm 
2065*6185db85Sdougm static int
2066*6185db85Sdougm add_security(sa_group_t group, char *sectype,
2067*6185db85Sdougm 		struct options *optlist, char *proto, int *err)
2068*6185db85Sdougm {
2069*6185db85Sdougm 	sa_security_t security;
2070*6185db85Sdougm 	int ret = SA_OK;
2071*6185db85Sdougm 	int result = 0;
2072*6185db85Sdougm 
2073*6185db85Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
2074*6185db85Sdougm 	security = sa_get_security(group, sectype, proto);
2075*6185db85Sdougm 	if (security == NULL) {
2076*6185db85Sdougm 	    security = sa_create_security(group, sectype, proto);
2077*6185db85Sdougm 	}
2078*6185db85Sdougm 	if (sectype != NULL)
2079*6185db85Sdougm 	    sa_free_attr_string(sectype);
2080*6185db85Sdougm 	if (security != NULL) {
2081*6185db85Sdougm 	    while (optlist != NULL) {
2082*6185db85Sdougm 		sa_property_t prop;
2083*6185db85Sdougm 		prop = sa_get_property(security, optlist->optname);
2084*6185db85Sdougm 		if (prop == NULL) {
2085*6185db85Sdougm 			/*
2086*6185db85Sdougm 			 * add the property, but only if it is
2087*6185db85Sdougm 			 * a non-NULL or non-zero length value
2088*6185db85Sdougm 			 */
2089*6185db85Sdougm 		    if (optlist->optvalue != NULL) {
2090*6185db85Sdougm 			prop = sa_create_property(optlist->optname,
2091*6185db85Sdougm 							optlist->optvalue);
2092*6185db85Sdougm 			if (prop != NULL) {
2093*6185db85Sdougm 			    ret = sa_valid_property(security, proto, prop);
2094*6185db85Sdougm 			    if (ret != SA_OK) {
2095*6185db85Sdougm 				(void) sa_remove_property(prop);
2096*6185db85Sdougm 				(void) printf(gettext("Could not add "
2097*6185db85Sdougm 							"property %s: %s\n"),
2098*6185db85Sdougm 							optlist->optname,
2099*6185db85Sdougm 						sa_errorstr(ret));
2100*6185db85Sdougm 			    }
2101*6185db85Sdougm 			    if (ret == SA_OK) {
2102*6185db85Sdougm 				ret = sa_add_property(security, prop);
2103*6185db85Sdougm 				if (ret != SA_OK) {
2104*6185db85Sdougm 				    (void) printf(gettext("Could not add "
2105*6185db85Sdougm 						    "property (%s=%s): %s\n"),
2106*6185db85Sdougm 						optlist->optname,
2107*6185db85Sdougm 						optlist->optvalue,
2108*6185db85Sdougm 						sa_errorstr(ret));
2109*6185db85Sdougm 				} else {
2110*6185db85Sdougm 				    result = 1;
2111*6185db85Sdougm 				}
2112*6185db85Sdougm 			    }
2113*6185db85Sdougm 			}
2114*6185db85Sdougm 		    }
2115*6185db85Sdougm 		} else {
2116*6185db85Sdougm 		    ret = sa_update_property(prop, optlist->optvalue);
2117*6185db85Sdougm 		    result = 1; /* should check if really changed */
2118*6185db85Sdougm 		}
2119*6185db85Sdougm 		optlist = optlist->next;
2120*6185db85Sdougm 	    }
2121*6185db85Sdougm 		/*
2122*6185db85Sdougm 		 * when done, properties may have all been removed but
2123*6185db85Sdougm 		 * we need to keep the security type itself until
2124*6185db85Sdougm 		 * explicitly removed.
2125*6185db85Sdougm 		 */
2126*6185db85Sdougm 	    if (result)
2127*6185db85Sdougm 		ret = sa_commit_properties(security, 0);
2128*6185db85Sdougm 	}
2129*6185db85Sdougm 	*err = ret;
2130*6185db85Sdougm 	return (result);
2131*6185db85Sdougm }
2132*6185db85Sdougm 
2133*6185db85Sdougm /*
2134*6185db85Sdougm  * basic_set(groupname, optlist, protocol, sharepath, dryrun)
2135*6185db85Sdougm  *
2136*6185db85Sdougm  * This function implements "set" when a name space (-S) is not
2137*6185db85Sdougm  * specified. It is a basic set. Options and other CLI parsing has
2138*6185db85Sdougm  * already been done.
2139*6185db85Sdougm  */
2140*6185db85Sdougm 
2141*6185db85Sdougm static int
2142*6185db85Sdougm basic_set(char *groupname, struct options *optlist, char *protocol,
2143*6185db85Sdougm 		char *sharepath, int dryrun)
2144*6185db85Sdougm {
2145*6185db85Sdougm 	sa_group_t group;
2146*6185db85Sdougm 	int ret = SA_OK;
2147*6185db85Sdougm 	int change = 0;
2148*6185db85Sdougm 	struct list *worklist = NULL;
2149*6185db85Sdougm 
2150*6185db85Sdougm 	group = sa_get_group(groupname);
2151*6185db85Sdougm 	if (group != NULL) {
2152*6185db85Sdougm 	    sa_share_t share = NULL;
2153*6185db85Sdougm 	    if (sharepath != NULL) {
2154*6185db85Sdougm 		share = sa_get_share(group, sharepath);
2155*6185db85Sdougm 		if (share == NULL) {
2156*6185db85Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
2157*6185db85Sdougm 				groupname, sharepath);
2158*6185db85Sdougm 		    ret = SA_NO_SUCH_PATH;
2159*6185db85Sdougm 		}
2160*6185db85Sdougm 	    }
2161*6185db85Sdougm 	    if (ret == SA_OK) {
2162*6185db85Sdougm 		/* group must exist */
2163*6185db85Sdougm 		ret = valid_options(optlist, protocol,
2164*6185db85Sdougm 				    share == NULL ? group : share, NULL);
2165*6185db85Sdougm 		if (ret == SA_OK && !dryrun) {
2166*6185db85Sdougm 		    if (share != NULL)
2167*6185db85Sdougm 			change |= add_optionset(share, optlist, protocol,
2168*6185db85Sdougm 						&ret);
2169*6185db85Sdougm 		    else
2170*6185db85Sdougm 			change |= add_optionset(group, optlist, protocol,
2171*6185db85Sdougm 						&ret);
2172*6185db85Sdougm 		    if (ret == SA_OK && change) {
2173*6185db85Sdougm 			worklist = add_list(worklist, group, share);
2174*6185db85Sdougm 		    }
2175*6185db85Sdougm 		}
2176*6185db85Sdougm 	    }
2177*6185db85Sdougm 	    free_opt(optlist);
2178*6185db85Sdougm 	} else {
2179*6185db85Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
2180*6185db85Sdougm 		ret = SA_NO_SUCH_GROUP;
2181*6185db85Sdougm 	}
2182*6185db85Sdougm 	/*
2183*6185db85Sdougm 	 * we have a group and potentially legal additions
2184*6185db85Sdougm 	 */
2185*6185db85Sdougm 
2186*6185db85Sdougm 	/* commit to configuration if not a dryrun */
2187*6185db85Sdougm 	if (!dryrun && ret == SA_OK) {
2188*6185db85Sdougm 	    if (change && worklist != NULL) {
2189*6185db85Sdougm 		/* properties changed, so update all shares */
2190*6185db85Sdougm 		(void) enable_all_groups(worklist, 0, 0, protocol);
2191*6185db85Sdougm 	    }
2192*6185db85Sdougm 	}
2193*6185db85Sdougm 	if (worklist != NULL)
2194*6185db85Sdougm 	    free_list(worklist);
2195*6185db85Sdougm 	return (ret);
2196*6185db85Sdougm }
2197*6185db85Sdougm 
2198*6185db85Sdougm /*
2199*6185db85Sdougm  * space_set(groupname, optlist, protocol, sharepath, dryrun)
2200*6185db85Sdougm  *
2201*6185db85Sdougm  * This function implements "set" when a name space (-S) is
2202*6185db85Sdougm  * specified. It is a namespace set. Options and other CLI parsing has
2203*6185db85Sdougm  * already been done.
2204*6185db85Sdougm  */
2205*6185db85Sdougm 
2206*6185db85Sdougm static int
2207*6185db85Sdougm space_set(char *groupname, struct options *optlist, char *protocol,
2208*6185db85Sdougm 		char *sharepath, int dryrun, char *sectype)
2209*6185db85Sdougm {
2210*6185db85Sdougm 	sa_group_t group;
2211*6185db85Sdougm 	int ret = SA_OK;
2212*6185db85Sdougm 	int change = 0;
2213*6185db85Sdougm 	struct list *worklist = NULL;
2214*6185db85Sdougm 
2215*6185db85Sdougm 	/*
2216*6185db85Sdougm 	 * make sure protcol and sectype are valid
2217*6185db85Sdougm 	 */
2218*6185db85Sdougm 
2219*6185db85Sdougm 	if (sa_proto_valid_space(protocol, sectype) == 0) {
2220*6185db85Sdougm 	    (void) printf(gettext("Option space \"%s\" not valid "
2221*6185db85Sdougm 					"for protocol.\n"),
2222*6185db85Sdougm 				sectype);
2223*6185db85Sdougm 	    return (SA_INVALID_SECURITY);
2224*6185db85Sdougm 	}
2225*6185db85Sdougm 
2226*6185db85Sdougm 	group = sa_get_group(groupname);
2227*6185db85Sdougm 	if (group != NULL) {
2228*6185db85Sdougm 	    sa_share_t share = NULL;
2229*6185db85Sdougm 	    if (sharepath != NULL) {
2230*6185db85Sdougm 		share = sa_get_share(group, sharepath);
2231*6185db85Sdougm 		if (share == NULL) {
2232*6185db85Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
2233*6185db85Sdougm 				groupname, sharepath);
2234*6185db85Sdougm 		    ret = SA_NO_SUCH_PATH;
2235*6185db85Sdougm 		}
2236*6185db85Sdougm 	    }
2237*6185db85Sdougm 	    if (ret == SA_OK) {
2238*6185db85Sdougm 		/* group must exist */
2239*6185db85Sdougm 		ret = valid_options(optlist, protocol,
2240*6185db85Sdougm 				    share == NULL ? group : share, sectype);
2241*6185db85Sdougm 		if (ret == SA_OK && !dryrun) {
2242*6185db85Sdougm 		    if (share != NULL)
2243*6185db85Sdougm 			change = add_security(share, sectype, optlist,
2244*6185db85Sdougm 						protocol,
2245*6185db85Sdougm 						&ret);
2246*6185db85Sdougm 		    else
2247*6185db85Sdougm 			change = add_security(group, sectype, optlist,
2248*6185db85Sdougm 						protocol,
2249*6185db85Sdougm 						&ret);
2250*6185db85Sdougm 		    if (ret != SA_OK)
2251*6185db85Sdougm 			(void) printf(gettext("Could not set property: %s\n"),
2252*6185db85Sdougm 				sa_errorstr(ret));
2253*6185db85Sdougm 		}
2254*6185db85Sdougm 		if (ret == SA_OK && change)
2255*6185db85Sdougm 		    worklist = add_list(worklist, group, share);
2256*6185db85Sdougm 	    }
2257*6185db85Sdougm 	    free_opt(optlist);
2258*6185db85Sdougm 	} else {
2259*6185db85Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
2260*6185db85Sdougm 		ret = SA_NO_SUCH_GROUP;
2261*6185db85Sdougm 	}
2262*6185db85Sdougm 	/*
2263*6185db85Sdougm 	 * we have a group and potentially legal additions
2264*6185db85Sdougm 	 */
2265*6185db85Sdougm 
2266*6185db85Sdougm 	/* commit to configuration if not a dryrun */
2267*6185db85Sdougm 	if (!dryrun && ret == 0) {
2268*6185db85Sdougm 	    if (change && worklist != NULL) {
2269*6185db85Sdougm 		/* properties changed, so update all shares */
2270*6185db85Sdougm 		(void) enable_all_groups(worklist, 0, 0, protocol);
2271*6185db85Sdougm 	    }
2272*6185db85Sdougm 	    ret = sa_update_config();
2273*6185db85Sdougm 	}
2274*6185db85Sdougm 	if (worklist != NULL)
2275*6185db85Sdougm 	    free_list(worklist);
2276*6185db85Sdougm 	return (ret);
2277*6185db85Sdougm }
2278*6185db85Sdougm 
2279*6185db85Sdougm /*
2280*6185db85Sdougm  * sa_set(flags, argc, argv)
2281*6185db85Sdougm  *
2282*6185db85Sdougm  * Implements the set subcommand. It keys off of -S to determine which
2283*6185db85Sdougm  * set of operations to actually do.
2284*6185db85Sdougm  */
2285*6185db85Sdougm 
2286*6185db85Sdougm int
2287*6185db85Sdougm sa_set(int flags, int argc, char *argv[])
2288*6185db85Sdougm {
2289*6185db85Sdougm 	char *groupname;
2290*6185db85Sdougm 	int verbose = 0;
2291*6185db85Sdougm 	int dryrun = 0;
2292*6185db85Sdougm 	int c;
2293*6185db85Sdougm 	char *protocol = NULL;
2294*6185db85Sdougm 	int ret = SA_OK;
2295*6185db85Sdougm 	struct options *optlist = NULL;
2296*6185db85Sdougm 	char *sharepath = NULL;
2297*6185db85Sdougm 	char *optset = NULL;
2298*6185db85Sdougm 	int auth;
2299*6185db85Sdougm 
2300*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
2301*6185db85Sdougm 	    switch (c) {
2302*6185db85Sdougm 	    case 'v':
2303*6185db85Sdougm 		verbose++;
2304*6185db85Sdougm 		break;
2305*6185db85Sdougm 	    case 'n':
2306*6185db85Sdougm 		dryrun++;
2307*6185db85Sdougm 		break;
2308*6185db85Sdougm 	    case 'P':
2309*6185db85Sdougm 		protocol = optarg;
2310*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
2311*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified:"
2312*6185db85Sdougm 				    "%s\n"),
2313*6185db85Sdougm 					protocol);
2314*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
2315*6185db85Sdougm 		}
2316*6185db85Sdougm 		break;
2317*6185db85Sdougm 	    case 'p':
2318*6185db85Sdougm 		ret = add_opt(&optlist, optarg, 0);
2319*6185db85Sdougm 		switch (ret) {
2320*6185db85Sdougm 		case OPT_ADD_SYNTAX:
2321*6185db85Sdougm 		    (void) printf(gettext("Property syntax error: %s\n"),
2322*6185db85Sdougm 					optarg);
2323*6185db85Sdougm 		    return (SA_SYNTAX_ERR);
2324*6185db85Sdougm 		case OPT_ADD_MEMORY:
2325*6185db85Sdougm 		    (void) printf(gettext("No memory to set property: %s\n"),
2326*6185db85Sdougm 					optarg);
2327*6185db85Sdougm 		    return (SA_NO_MEMORY);
2328*6185db85Sdougm 		default:
2329*6185db85Sdougm 		    break;
2330*6185db85Sdougm 		}
2331*6185db85Sdougm 		break;
2332*6185db85Sdougm 	    case 's':
2333*6185db85Sdougm 		sharepath = optarg;
2334*6185db85Sdougm 		break;
2335*6185db85Sdougm 	    case 'S':
2336*6185db85Sdougm 		optset = optarg;
2337*6185db85Sdougm 		break;
2338*6185db85Sdougm 	    default:
2339*6185db85Sdougm 	    case 'h':
2340*6185db85Sdougm 	    case '?':
2341*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
2342*6185db85Sdougm 				sa_get_usage(USAGE_SET));
2343*6185db85Sdougm 		return (SA_OK);
2344*6185db85Sdougm 	    }
2345*6185db85Sdougm 	}
2346*6185db85Sdougm 
2347*6185db85Sdougm 	if (optlist != NULL)
2348*6185db85Sdougm 	    ret = chk_opt(optlist, optset != NULL, protocol);
2349*6185db85Sdougm 
2350*6185db85Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
2351*6185db85Sdougm 	    protocol == NULL ||
2352*6185db85Sdougm 	    ret != OPT_ADD_OK) {
2353*6185db85Sdougm 	    char *sep = "\t";
2354*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
2355*6185db85Sdougm 	    if (optind >= argc) {
2356*6185db85Sdougm 		(void) printf(gettext("%sgroup must be specified"), sep);
2357*6185db85Sdougm 		sep = ", ";
2358*6185db85Sdougm 	    }
2359*6185db85Sdougm 	    if (optlist == NULL) {
2360*6185db85Sdougm 		(void) printf(gettext("%sat least one property must be"
2361*6185db85Sdougm 				" specified"), sep);
2362*6185db85Sdougm 		sep = ", ";
2363*6185db85Sdougm 	    }
2364*6185db85Sdougm 	    if (protocol == NULL) {
2365*6185db85Sdougm 		(void) printf(gettext("%sprotocol must be specified"), sep);
2366*6185db85Sdougm 		sep = ", ";
2367*6185db85Sdougm 	    }
2368*6185db85Sdougm 	    (void) printf("\n");
2369*6185db85Sdougm 	    ret = SA_SYNTAX_ERR;
2370*6185db85Sdougm 	} else {
2371*6185db85Sdougm 		/*
2372*6185db85Sdougm 		 * if a group already exists, we can only add a new
2373*6185db85Sdougm 		 * protocol to it and not create a new one or add the
2374*6185db85Sdougm 		 * same protocol again.
2375*6185db85Sdougm 		 */
2376*6185db85Sdougm 
2377*6185db85Sdougm 	    groupname = argv[optind];
2378*6185db85Sdougm 	    auth = check_authorizations(groupname, flags);
2379*6185db85Sdougm 	    if (optset == NULL)
2380*6185db85Sdougm 		ret = basic_set(groupname, optlist, protocol,
2381*6185db85Sdougm 				sharepath, dryrun);
2382*6185db85Sdougm 	    else
2383*6185db85Sdougm 		ret = space_set(groupname, optlist, protocol,
2384*6185db85Sdougm 				sharepath, dryrun, optset);
2385*6185db85Sdougm 	    if (dryrun && ret == SA_OK && !auth && verbose) {
2386*6185db85Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
2387*6185db85Sdougm 			sa_errorstr(SA_NO_PERMISSION));
2388*6185db85Sdougm 	    }
2389*6185db85Sdougm 	}
2390*6185db85Sdougm 	return (ret);
2391*6185db85Sdougm }
2392*6185db85Sdougm 
2393*6185db85Sdougm /*
2394*6185db85Sdougm  * remove_options(group, optlist, proto, *err)
2395*6185db85Sdougm  *
2396*6185db85Sdougm  * helper function to actually remove options from a group after all
2397*6185db85Sdougm  * preprocessing is done.
2398*6185db85Sdougm  */
2399*6185db85Sdougm 
2400*6185db85Sdougm static int
2401*6185db85Sdougm remove_options(sa_group_t group, struct options *optlist,
2402*6185db85Sdougm 		char *proto, int *err)
2403*6185db85Sdougm {
2404*6185db85Sdougm 	struct options *cur;
2405*6185db85Sdougm 	sa_optionset_t optionset;
2406*6185db85Sdougm 	sa_property_t prop;
2407*6185db85Sdougm 	int change = 0;
2408*6185db85Sdougm 	int ret = SA_OK;
2409*6185db85Sdougm 
2410*6185db85Sdougm 	optionset = sa_get_optionset(group, proto);
2411*6185db85Sdougm 	if (optionset != NULL) {
2412*6185db85Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
2413*6185db85Sdougm 		prop = sa_get_property(optionset, cur->optname);
2414*6185db85Sdougm 		if (prop != NULL) {
2415*6185db85Sdougm 		    ret = sa_remove_property(prop);
2416*6185db85Sdougm 		    if (ret != SA_OK)
2417*6185db85Sdougm 			break;
2418*6185db85Sdougm 		    change = 1;
2419*6185db85Sdougm 		}
2420*6185db85Sdougm 	    }
2421*6185db85Sdougm 	}
2422*6185db85Sdougm 	if (ret == SA_OK && change)
2423*6185db85Sdougm 	    ret = sa_commit_properties(optionset, 0);
2424*6185db85Sdougm 
2425*6185db85Sdougm 	if (err != NULL)
2426*6185db85Sdougm 	    *err = ret;
2427*6185db85Sdougm 	return (change);
2428*6185db85Sdougm }
2429*6185db85Sdougm 
2430*6185db85Sdougm /*
2431*6185db85Sdougm  * valid_unset(group, optlist, proto)
2432*6185db85Sdougm  *
2433*6185db85Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
2434*6185db85Sdougm  * error if a property doesn't exist.
2435*6185db85Sdougm  */
2436*6185db85Sdougm 
2437*6185db85Sdougm static int
2438*6185db85Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto)
2439*6185db85Sdougm {
2440*6185db85Sdougm 	struct options *cur;
2441*6185db85Sdougm 	sa_optionset_t optionset;
2442*6185db85Sdougm 	sa_property_t prop;
2443*6185db85Sdougm 	int ret = SA_OK;
2444*6185db85Sdougm 
2445*6185db85Sdougm 	optionset = sa_get_optionset(group, proto);
2446*6185db85Sdougm 	if (optionset != NULL) {
2447*6185db85Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
2448*6185db85Sdougm 		prop = sa_get_property(optionset, cur->optname);
2449*6185db85Sdougm 		if (prop == NULL) {
2450*6185db85Sdougm 		    (void) printf(gettext("Could not unset property %s:"
2451*6185db85Sdougm 						" not set\n"),
2452*6185db85Sdougm 			    cur->optname);
2453*6185db85Sdougm 		    ret = SA_NO_SUCH_PROP;
2454*6185db85Sdougm 		}
2455*6185db85Sdougm 	    }
2456*6185db85Sdougm 	}
2457*6185db85Sdougm 	return (ret);
2458*6185db85Sdougm }
2459*6185db85Sdougm 
2460*6185db85Sdougm /*
2461*6185db85Sdougm  * valid_unset_security(group, optlist, proto)
2462*6185db85Sdougm  *
2463*6185db85Sdougm  * Sanity check the optlist to make sure they can be removed. Issue an
2464*6185db85Sdougm  * error if a property doesn't exist.
2465*6185db85Sdougm  */
2466*6185db85Sdougm 
2467*6185db85Sdougm static int
2468*6185db85Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
2469*6185db85Sdougm 	    char *sectype)
2470*6185db85Sdougm {
2471*6185db85Sdougm 	struct options *cur;
2472*6185db85Sdougm 	sa_security_t security;
2473*6185db85Sdougm 	sa_property_t prop;
2474*6185db85Sdougm 	int ret = SA_OK;
2475*6185db85Sdougm 	char *sec;
2476*6185db85Sdougm 
2477*6185db85Sdougm 	sec = sa_proto_space_alias(proto, sectype);
2478*6185db85Sdougm 	security = sa_get_security(group, sec, proto);
2479*6185db85Sdougm 	if (security != NULL) {
2480*6185db85Sdougm 	    for (cur = optlist; cur != NULL; cur = cur->next) {
2481*6185db85Sdougm 		prop = sa_get_property(security, cur->optname);
2482*6185db85Sdougm 		if (prop == NULL) {
2483*6185db85Sdougm 		    (void) printf(gettext("Could not unset property %s:"
2484*6185db85Sdougm 						" not set\n"),
2485*6185db85Sdougm 					cur->optname);
2486*6185db85Sdougm 		    ret = SA_NO_SUCH_PROP;
2487*6185db85Sdougm 		}
2488*6185db85Sdougm 	    }
2489*6185db85Sdougm 	} else {
2490*6185db85Sdougm 	    (void) printf(gettext("Could not unset %s: space not defined\n"),
2491*6185db85Sdougm 			    sectype);
2492*6185db85Sdougm 	    ret = SA_NO_SUCH_SECURITY;
2493*6185db85Sdougm 	}
2494*6185db85Sdougm 	if (sec != NULL)
2495*6185db85Sdougm 	    sa_free_attr_string(sec);
2496*6185db85Sdougm 	return (ret);
2497*6185db85Sdougm }
2498*6185db85Sdougm 
2499*6185db85Sdougm /*
2500*6185db85Sdougm  * remove_security(group, optlist, proto)
2501*6185db85Sdougm  *
2502*6185db85Sdougm  * Remove the properties since they were checked as valid.
2503*6185db85Sdougm  */
2504*6185db85Sdougm 
2505*6185db85Sdougm static int
2506*6185db85Sdougm remove_security(sa_group_t group, char *sectype,
2507*6185db85Sdougm 		struct options *optlist, char *proto, int *err)
2508*6185db85Sdougm {
2509*6185db85Sdougm 	sa_security_t security;
2510*6185db85Sdougm 	int ret = SA_OK;
2511*6185db85Sdougm 	int change = 0;
2512*6185db85Sdougm 
2513*6185db85Sdougm 	sectype = sa_proto_space_alias(proto, sectype);
2514*6185db85Sdougm 	security = sa_get_security(group, sectype, proto);
2515*6185db85Sdougm 	if (sectype != NULL)
2516*6185db85Sdougm 	    sa_free_attr_string(sectype);
2517*6185db85Sdougm 
2518*6185db85Sdougm 	if (security != NULL) {
2519*6185db85Sdougm 	    while (optlist != NULL) {
2520*6185db85Sdougm 		sa_property_t prop;
2521*6185db85Sdougm 		prop = sa_get_property(security, optlist->optname);
2522*6185db85Sdougm 		if (prop != NULL) {
2523*6185db85Sdougm 		    ret = sa_remove_property(prop);
2524*6185db85Sdougm 		    if (ret != SA_OK)
2525*6185db85Sdougm 			break;
2526*6185db85Sdougm 		    change = 1;
2527*6185db85Sdougm 		}
2528*6185db85Sdougm 		optlist = optlist->next;
2529*6185db85Sdougm 	    }
2530*6185db85Sdougm 		/*
2531*6185db85Sdougm 		 * when done, properties may have all been removed but
2532*6185db85Sdougm 		 * we need to keep the security type itself until
2533*6185db85Sdougm 		 * explicitly removed.
2534*6185db85Sdougm 		 */
2535*6185db85Sdougm 	    if (ret == SA_OK && change)
2536*6185db85Sdougm 		ret = sa_commit_properties(security, 0);
2537*6185db85Sdougm 	} else {
2538*6185db85Sdougm 	    ret = SA_NO_SUCH_PROP;
2539*6185db85Sdougm 	}
2540*6185db85Sdougm 	if (err != NULL)
2541*6185db85Sdougm 	    *err = ret;
2542*6185db85Sdougm 	return (change);
2543*6185db85Sdougm }
2544*6185db85Sdougm 
2545*6185db85Sdougm /*
2546*6185db85Sdougm  * basic_unset(groupname, optlist, protocol, sharepath, dryrun)
2547*6185db85Sdougm  *
2548*6185db85Sdougm  * unset non-named optionset properties.
2549*6185db85Sdougm  */
2550*6185db85Sdougm 
2551*6185db85Sdougm static int
2552*6185db85Sdougm basic_unset(char *groupname, struct options *optlist, char *protocol,
2553*6185db85Sdougm 		char *sharepath, int dryrun)
2554*6185db85Sdougm {
2555*6185db85Sdougm 	sa_group_t group;
2556*6185db85Sdougm 	int ret = SA_OK;
2557*6185db85Sdougm 	int change = 0;
2558*6185db85Sdougm 	struct list *worklist = NULL;
2559*6185db85Sdougm 
2560*6185db85Sdougm 	group = sa_get_group(groupname);
2561*6185db85Sdougm 	if (group != NULL) {
2562*6185db85Sdougm 	    sa_share_t share = NULL;
2563*6185db85Sdougm 	    if (sharepath != NULL) {
2564*6185db85Sdougm 		share = sa_get_share(group, sharepath);
2565*6185db85Sdougm 		if (share == NULL) {
2566*6185db85Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
2567*6185db85Sdougm 				groupname, sharepath);
2568*6185db85Sdougm 		    ret = SA_NO_SUCH_PATH;
2569*6185db85Sdougm 		}
2570*6185db85Sdougm 	    }
2571*6185db85Sdougm 	    if (ret == SA_OK) {
2572*6185db85Sdougm 		/* group must exist */
2573*6185db85Sdougm 		ret = valid_unset(share != NULL ? share : group,
2574*6185db85Sdougm 					optlist, protocol);
2575*6185db85Sdougm 		if (ret == SA_OK && !dryrun) {
2576*6185db85Sdougm 		    if (share != NULL) {
2577*6185db85Sdougm 			sa_optionset_t optionset;
2578*6185db85Sdougm 			sa_property_t prop;
2579*6185db85Sdougm 			change |= remove_options(share, optlist, protocol,
2580*6185db85Sdougm 							&ret);
2581*6185db85Sdougm 			/* if a share optionset is empty, remove it */
2582*6185db85Sdougm 			optionset = sa_get_optionset((sa_share_t)share,
2583*6185db85Sdougm 							protocol);
2584*6185db85Sdougm 			if (optionset != NULL) {
2585*6185db85Sdougm 			    prop = sa_get_property(optionset, NULL);
2586*6185db85Sdougm 			    if (prop == NULL)
2587*6185db85Sdougm 				(void) sa_destroy_optionset(optionset);
2588*6185db85Sdougm 			}
2589*6185db85Sdougm 		    } else {
2590*6185db85Sdougm 			change |= remove_options(group, optlist, protocol,
2591*6185db85Sdougm 							&ret);
2592*6185db85Sdougm 		    }
2593*6185db85Sdougm 		    if (ret == SA_OK && change)
2594*6185db85Sdougm 			worklist = add_list(worklist, group, share);
2595*6185db85Sdougm 		    if (ret != SA_OK)
2596*6185db85Sdougm 			(void) printf(gettext("Could not remove properties:"
2597*6185db85Sdougm 						"%s\n"),
2598*6185db85Sdougm 				sa_errorstr(ret));
2599*6185db85Sdougm 		}
2600*6185db85Sdougm 	    } else {
2601*6185db85Sdougm 		(void) printf(gettext("Group \"%s\" not found\n"), groupname);
2602*6185db85Sdougm 		ret = SA_NO_SUCH_GROUP;
2603*6185db85Sdougm 	    }
2604*6185db85Sdougm 	    free_opt(optlist);
2605*6185db85Sdougm 	}
2606*6185db85Sdougm 
2607*6185db85Sdougm 	/*
2608*6185db85Sdougm 	 * we have a group and potentially legal additions
2609*6185db85Sdougm 	 */
2610*6185db85Sdougm 	/* commit to configuration if not a dryrun */
2611*6185db85Sdougm 	if (!dryrun && ret == SA_OK) {
2612*6185db85Sdougm 	    if (change && worklist != NULL) {
2613*6185db85Sdougm 		/* properties changed, so update all shares */
2614*6185db85Sdougm 		(void) enable_all_groups(worklist, 0, 0, protocol);
2615*6185db85Sdougm 	    }
2616*6185db85Sdougm 	}
2617*6185db85Sdougm 	if (worklist != NULL)
2618*6185db85Sdougm 	    free_list(worklist);
2619*6185db85Sdougm 	return (ret);
2620*6185db85Sdougm }
2621*6185db85Sdougm 
2622*6185db85Sdougm /*
2623*6185db85Sdougm  * space_unset(groupname, optlist, protocol, sharepath, dryrun)
2624*6185db85Sdougm  *
2625*6185db85Sdougm  * unset named optionset properties.
2626*6185db85Sdougm  */
2627*6185db85Sdougm static int
2628*6185db85Sdougm space_unset(char *groupname, struct options *optlist, char *protocol,
2629*6185db85Sdougm 		char *sharepath, int dryrun, char *sectype)
2630*6185db85Sdougm {
2631*6185db85Sdougm 	sa_group_t group;
2632*6185db85Sdougm 	int ret = SA_OK;
2633*6185db85Sdougm 	int change = 0;
2634*6185db85Sdougm 	struct list *worklist = NULL;
2635*6185db85Sdougm 
2636*6185db85Sdougm 	group = sa_get_group(groupname);
2637*6185db85Sdougm 	if (group != NULL) {
2638*6185db85Sdougm 	    sa_share_t share = NULL;
2639*6185db85Sdougm 	    if (sharepath != NULL) {
2640*6185db85Sdougm 		share = sa_get_share(group, sharepath);
2641*6185db85Sdougm 		if (share == NULL) {
2642*6185db85Sdougm 		    (void) printf(gettext("Share does not exist in group %s\n"),
2643*6185db85Sdougm 				groupname, sharepath);
2644*6185db85Sdougm 		    ret = SA_NO_SUCH_PATH;
2645*6185db85Sdougm 		}
2646*6185db85Sdougm 	    }
2647*6185db85Sdougm 	    if (ret == SA_OK) {
2648*6185db85Sdougm 		ret = valid_unset_security(share != NULL ? share : group,
2649*6185db85Sdougm 						optlist, protocol, sectype);
2650*6185db85Sdougm 		if (ret == SA_OK && !dryrun) {
2651*6185db85Sdougm 		    if (optlist != NULL) {
2652*6185db85Sdougm 			if (share != NULL) {
2653*6185db85Sdougm 			    sa_security_t optionset;
2654*6185db85Sdougm 			    sa_property_t prop;
2655*6185db85Sdougm 			    change = remove_security(share, sectype,
2656*6185db85Sdougm 							optlist, protocol,
2657*6185db85Sdougm 							&ret);
2658*6185db85Sdougm 			    /* if a share security is empty, remove it */
2659*6185db85Sdougm 			    optionset = sa_get_security((sa_group_t)share,
2660*6185db85Sdougm 							sectype,
2661*6185db85Sdougm 							protocol);
2662*6185db85Sdougm 			    if (optionset != NULL) {
2663*6185db85Sdougm 				prop = sa_get_property(optionset, NULL);
2664*6185db85Sdougm 				if (prop == NULL)
2665*6185db85Sdougm 				    ret = sa_destroy_security(optionset);
2666*6185db85Sdougm 			    }
2667*6185db85Sdougm 			} else {
2668*6185db85Sdougm 			    change = remove_security(group, sectype,
2669*6185db85Sdougm 							optlist, protocol,
2670*6185db85Sdougm 							&ret);
2671*6185db85Sdougm 			}
2672*6185db85Sdougm 		    } else {
2673*6185db85Sdougm 			sa_security_t security;
2674*6185db85Sdougm 			char *sec;
2675*6185db85Sdougm 			sec = sa_proto_space_alias(protocol, sectype);
2676*6185db85Sdougm 			security = sa_get_security(group, sec, protocol);
2677*6185db85Sdougm 			if (sec != NULL)
2678*6185db85Sdougm 			    sa_free_attr_string(sec);
2679*6185db85Sdougm 			if (security != NULL) {
2680*6185db85Sdougm 			    ret = sa_destroy_security(security);
2681*6185db85Sdougm 			    if (ret == SA_OK)
2682*6185db85Sdougm 				change = 1;
2683*6185db85Sdougm 			} else {
2684*6185db85Sdougm 			    ret = SA_NO_SUCH_PROP;
2685*6185db85Sdougm 			}
2686*6185db85Sdougm 		    }
2687*6185db85Sdougm 		    if (ret != SA_OK)
2688*6185db85Sdougm 			(void) printf(gettext("Could not unset property: %s\n"),
2689*6185db85Sdougm 				sa_errorstr(ret));
2690*6185db85Sdougm 		}
2691*6185db85Sdougm 
2692*6185db85Sdougm 		if (ret == SA_OK && change)
2693*6185db85Sdougm 		    worklist = add_list(worklist, group, 0);
2694*6185db85Sdougm 	    }
2695*6185db85Sdougm 	} else {
2696*6185db85Sdougm 	    (void) printf(gettext("Group \"%s\" not found\n"), groupname);
2697*6185db85Sdougm 	    ret = SA_NO_SUCH_GROUP;
2698*6185db85Sdougm 	}
2699*6185db85Sdougm 	free_opt(optlist);
2700*6185db85Sdougm 	/*
2701*6185db85Sdougm 	 * we have a group and potentially legal additions
2702*6185db85Sdougm 	 */
2703*6185db85Sdougm 
2704*6185db85Sdougm 	/* commit to configuration if not a dryrun */
2705*6185db85Sdougm 	if (!dryrun && ret == 0) {
2706*6185db85Sdougm 	    if (change && worklist != NULL) {
2707*6185db85Sdougm 		/* properties changed, so update all shares */
2708*6185db85Sdougm 		(void) enable_all_groups(worklist, 0, 0, protocol);
2709*6185db85Sdougm 	    }
2710*6185db85Sdougm 	    ret = sa_update_config();
2711*6185db85Sdougm 	}
2712*6185db85Sdougm 	if (worklist != NULL)
2713*6185db85Sdougm 	    free_list(worklist);
2714*6185db85Sdougm 	return (ret);
2715*6185db85Sdougm }
2716*6185db85Sdougm 
2717*6185db85Sdougm /*
2718*6185db85Sdougm  * sa_unset(flags, argc, argv)
2719*6185db85Sdougm  *
2720*6185db85Sdougm  * implements the unset subcommand. Parsing done here and then basic
2721*6185db85Sdougm  * or space versions of the real code are called.
2722*6185db85Sdougm  */
2723*6185db85Sdougm 
2724*6185db85Sdougm int
2725*6185db85Sdougm sa_unset(int flags, int argc, char *argv[])
2726*6185db85Sdougm {
2727*6185db85Sdougm 	char *groupname;
2728*6185db85Sdougm 	int verbose = 0;
2729*6185db85Sdougm 	int dryrun = 0;
2730*6185db85Sdougm 	int c;
2731*6185db85Sdougm 	char *protocol = NULL;
2732*6185db85Sdougm 	int ret = SA_OK;
2733*6185db85Sdougm 	struct options *optlist = NULL;
2734*6185db85Sdougm 	char *sharepath = NULL;
2735*6185db85Sdougm 	char *optset = NULL;
2736*6185db85Sdougm 	int auth;
2737*6185db85Sdougm 
2738*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) {
2739*6185db85Sdougm 	    switch (c) {
2740*6185db85Sdougm 	    case 'v':
2741*6185db85Sdougm 		verbose++;
2742*6185db85Sdougm 		break;
2743*6185db85Sdougm 	    case 'n':
2744*6185db85Sdougm 		dryrun++;
2745*6185db85Sdougm 		break;
2746*6185db85Sdougm 	    case 'P':
2747*6185db85Sdougm 		protocol = optarg;
2748*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
2749*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
2750*6185db85Sdougm 					protocol);
2751*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
2752*6185db85Sdougm 		}
2753*6185db85Sdougm 		break;
2754*6185db85Sdougm 	    case 'p':
2755*6185db85Sdougm 		ret = add_opt(&optlist, optarg, 1);
2756*6185db85Sdougm 		switch (ret) {
2757*6185db85Sdougm 		case OPT_ADD_SYNTAX:
2758*6185db85Sdougm 		    (void) printf(gettext("Property syntax error for "
2759*6185db85Sdougm 						"property %s\n"),
2760*6185db85Sdougm 					optarg);
2761*6185db85Sdougm 		    return (SA_SYNTAX_ERR);
2762*6185db85Sdougm 		case OPT_ADD_PROPERTY:
2763*6185db85Sdougm 		    (void) printf(gettext("Properties need to be set"
2764*6185db85Sdougm 						" with set command: %s\n"),
2765*6185db85Sdougm 					optarg);
2766*6185db85Sdougm 		    return (SA_SYNTAX_ERR);
2767*6185db85Sdougm 		default:
2768*6185db85Sdougm 		    break;
2769*6185db85Sdougm 		}
2770*6185db85Sdougm 		break;
2771*6185db85Sdougm 	    case 's':
2772*6185db85Sdougm 		sharepath = optarg;
2773*6185db85Sdougm 		break;
2774*6185db85Sdougm 	    case 'S':
2775*6185db85Sdougm 		optset = optarg;
2776*6185db85Sdougm 		break;
2777*6185db85Sdougm 	    default:
2778*6185db85Sdougm 	    case 'h':
2779*6185db85Sdougm 	    case '?':
2780*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
2781*6185db85Sdougm 				sa_get_usage(USAGE_UNSET));
2782*6185db85Sdougm 		return (SA_OK);
2783*6185db85Sdougm 	    }
2784*6185db85Sdougm 	}
2785*6185db85Sdougm 
2786*6185db85Sdougm 	if (optlist != NULL)
2787*6185db85Sdougm 	    ret = chk_opt(optlist, optset != NULL, protocol);
2788*6185db85Sdougm 
2789*6185db85Sdougm 	if (optind >= argc || (optlist == NULL && optset == NULL) ||
2790*6185db85Sdougm 	    protocol == NULL) {
2791*6185db85Sdougm 	    char *sep = "\t";
2792*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET));
2793*6185db85Sdougm 	    if (optind >= argc) {
2794*6185db85Sdougm 		(void) printf(gettext("%sgroup must be specified"), sep);
2795*6185db85Sdougm 		sep = ", ";
2796*6185db85Sdougm 	    }
2797*6185db85Sdougm 	    if (optlist == NULL) {
2798*6185db85Sdougm 		(void) printf(gettext("%sat least one property must be "
2799*6185db85Sdougm 					"specified"),
2800*6185db85Sdougm 			sep);
2801*6185db85Sdougm 		sep = ", ";
2802*6185db85Sdougm 	    }
2803*6185db85Sdougm 	    if (protocol == NULL) {
2804*6185db85Sdougm 		(void) printf(gettext("%sprotocol must be specified"), sep);
2805*6185db85Sdougm 		sep = ", ";
2806*6185db85Sdougm 	    }
2807*6185db85Sdougm 	    (void) printf("\n");
2808*6185db85Sdougm 	    ret = SA_SYNTAX_ERR;
2809*6185db85Sdougm 	} else {
2810*6185db85Sdougm 
2811*6185db85Sdougm 		/*
2812*6185db85Sdougm 		 * if a group already exists, we can only add a new
2813*6185db85Sdougm 		 * protocol to it and not create a new one or add the
2814*6185db85Sdougm 		 * same protocol again.
2815*6185db85Sdougm 		 */
2816*6185db85Sdougm 
2817*6185db85Sdougm 	    groupname = argv[optind];
2818*6185db85Sdougm 	    auth = check_authorizations(groupname, flags);
2819*6185db85Sdougm 	    if (optset == NULL)
2820*6185db85Sdougm 		ret = basic_unset(groupname, optlist, protocol,
2821*6185db85Sdougm 					sharepath, dryrun);
2822*6185db85Sdougm 	    else
2823*6185db85Sdougm 		ret = space_unset(groupname, optlist, protocol,
2824*6185db85Sdougm 					sharepath, dryrun, optset);
2825*6185db85Sdougm 
2826*6185db85Sdougm 	    if (dryrun && ret == SA_OK && !auth && verbose) {
2827*6185db85Sdougm 		(void) printf(gettext("Command would fail: %s\n"),
2828*6185db85Sdougm 			sa_errorstr(SA_NO_PERMISSION));
2829*6185db85Sdougm 	    }
2830*6185db85Sdougm 	}
2831*6185db85Sdougm 	return (ret);
2832*6185db85Sdougm }
2833*6185db85Sdougm 
2834*6185db85Sdougm /*
2835*6185db85Sdougm  * sa_enable_group(flags, argc, argv)
2836*6185db85Sdougm  *
2837*6185db85Sdougm  * Implements the enable subcommand
2838*6185db85Sdougm  */
2839*6185db85Sdougm 
2840*6185db85Sdougm int
2841*6185db85Sdougm sa_enable_group(int flags, int argc, char *argv[])
2842*6185db85Sdougm {
2843*6185db85Sdougm 	int verbose = 0;
2844*6185db85Sdougm 	int dryrun = 0;
2845*6185db85Sdougm 	int all = 0;
2846*6185db85Sdougm 	int c;
2847*6185db85Sdougm 	int ret = SA_OK;
2848*6185db85Sdougm 	char *protocol = NULL;
2849*6185db85Sdougm 	char *state;
2850*6185db85Sdougm 	struct list *worklist = NULL;
2851*6185db85Sdougm 	int auth = 1;
2852*6185db85Sdougm 
2853*6185db85Sdougm 	while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
2854*6185db85Sdougm 	    switch (c) {
2855*6185db85Sdougm 	    case 'a':
2856*6185db85Sdougm 		all = 1;
2857*6185db85Sdougm 		break;
2858*6185db85Sdougm 	    case 'n':
2859*6185db85Sdougm 		dryrun++;
2860*6185db85Sdougm 		break;
2861*6185db85Sdougm 	    case 'P':
2862*6185db85Sdougm 		protocol = optarg;
2863*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
2864*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
2865*6185db85Sdougm 				    protocol);
2866*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
2867*6185db85Sdougm 		}
2868*6185db85Sdougm 		break;
2869*6185db85Sdougm 	    case 'v':
2870*6185db85Sdougm 		verbose++;
2871*6185db85Sdougm 		break;
2872*6185db85Sdougm 	    default:
2873*6185db85Sdougm 	    case 'h':
2874*6185db85Sdougm 	    case '?':
2875*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
2876*6185db85Sdougm 				sa_get_usage(USAGE_ENABLE));
2877*6185db85Sdougm 		return (0);
2878*6185db85Sdougm 	    }
2879*6185db85Sdougm 	}
2880*6185db85Sdougm 
2881*6185db85Sdougm 	if (optind == argc && !all) {
2882*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE));
2883*6185db85Sdougm 	    (void) printf(gettext("\tmust specify group\n"));
2884*6185db85Sdougm 	    ret = SA_NO_SUCH_PATH;
2885*6185db85Sdougm 	} else {
2886*6185db85Sdougm 	    sa_group_t group;
2887*6185db85Sdougm 	    if (!all) {
2888*6185db85Sdougm 		while (optind < argc) {
2889*6185db85Sdougm 		    group = sa_get_group(argv[optind]);
2890*6185db85Sdougm 		    if (group != NULL) {
2891*6185db85Sdougm 			auth &= check_authorizations(argv[optind], flags);
2892*6185db85Sdougm 			state = sa_get_group_attr(group, "state");
2893*6185db85Sdougm 			if (state != NULL &&
2894*6185db85Sdougm 			    strcmp(state, "enabled") == 0) {
2895*6185db85Sdougm 			    /* already enabled */
2896*6185db85Sdougm 			    if (verbose)
2897*6185db85Sdougm 				(void) printf(gettext("Group \"%s\" is already "
2898*6185db85Sdougm 						"enabled\n"),
2899*6185db85Sdougm 					argv[optind]);
2900*6185db85Sdougm 			    ret = SA_BUSY; /* already enabled */
2901*6185db85Sdougm 			} else {
2902*6185db85Sdougm 			    worklist = add_list(worklist, group, 0);
2903*6185db85Sdougm 			    if (verbose)
2904*6185db85Sdougm 				(void) printf(gettext("Enabling group "
2905*6185db85Sdougm 							"\"%s\"\n"),
2906*6185db85Sdougm 					argv[optind]);
2907*6185db85Sdougm 			}
2908*6185db85Sdougm 			if (state != NULL)
2909*6185db85Sdougm 			    sa_free_attr_string(state);
2910*6185db85Sdougm 		    } else {
2911*6185db85Sdougm 			ret = SA_NO_SUCH_GROUP;
2912*6185db85Sdougm 		    }
2913*6185db85Sdougm 		    optind++;
2914*6185db85Sdougm 		}
2915*6185db85Sdougm 	    } else {
2916*6185db85Sdougm 		for (group = sa_get_group(NULL); group != NULL;
2917*6185db85Sdougm 		    group = sa_get_next_group(group)) {
2918*6185db85Sdougm 		    worklist = add_list(worklist, group, 0);
2919*6185db85Sdougm 		}
2920*6185db85Sdougm 	    }
2921*6185db85Sdougm 	    if (!dryrun && ret == SA_OK) {
2922*6185db85Sdougm 		ret = enable_all_groups(worklist, 1, 0, NULL);
2923*6185db85Sdougm 	    }
2924*6185db85Sdougm 	    if (ret != SA_OK && ret != SA_BUSY)
2925*6185db85Sdougm 		(void) printf(gettext("Could not enable group: %s\n"),
2926*6185db85Sdougm 			sa_errorstr(ret));
2927*6185db85Sdougm 	    if (ret == SA_BUSY)
2928*6185db85Sdougm 		ret = SA_OK;
2929*6185db85Sdougm 	}
2930*6185db85Sdougm 	if (worklist != NULL)
2931*6185db85Sdougm 	    free_list(worklist);
2932*6185db85Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
2933*6185db85Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
2934*6185db85Sdougm 			sa_errorstr(SA_NO_PERMISSION));
2935*6185db85Sdougm 	}
2936*6185db85Sdougm 	return (ret);
2937*6185db85Sdougm }
2938*6185db85Sdougm 
2939*6185db85Sdougm /*
2940*6185db85Sdougm  * disable_group(group, setstate)
2941*6185db85Sdougm  *
2942*6185db85Sdougm  * disable all the shares in the specified group honoring the setstate
2943*6185db85Sdougm  * argument. This is a helper for disable_all_groups in order to
2944*6185db85Sdougm  * simplify regular and subgroup (zfs) disabling. Group has already
2945*6185db85Sdougm  * been checked for non-NULL.
2946*6185db85Sdougm  */
2947*6185db85Sdougm 
2948*6185db85Sdougm static int
2949*6185db85Sdougm disable_group(sa_group_t group)
2950*6185db85Sdougm {
2951*6185db85Sdougm 	sa_share_t share;
2952*6185db85Sdougm 	int ret = SA_OK;
2953*6185db85Sdougm 
2954*6185db85Sdougm 	for (share = sa_get_share(group, NULL);
2955*6185db85Sdougm 	    share != NULL && ret == SA_OK;
2956*6185db85Sdougm 	    share = sa_get_next_share(share)) {
2957*6185db85Sdougm 	    ret = sa_disable_share(share, NULL);
2958*6185db85Sdougm 	    if (ret == SA_NO_SUCH_PATH) {
2959*6185db85Sdougm 		/*
2960*6185db85Sdougm 		 * this is OK since the path is gone. we can't
2961*6185db85Sdougm 		 * re-share it anyway so no error.
2962*6185db85Sdougm 		 */
2963*6185db85Sdougm 		ret = SA_OK;
2964*6185db85Sdougm 	    }
2965*6185db85Sdougm 	}
2966*6185db85Sdougm 	return (ret);
2967*6185db85Sdougm }
2968*6185db85Sdougm 
2969*6185db85Sdougm 
2970*6185db85Sdougm /*
2971*6185db85Sdougm  * disable_all_groups(work, setstate)
2972*6185db85Sdougm  *
2973*6185db85Sdougm  * helper function that disables the shares in the list of groups
2974*6185db85Sdougm  * provided. It optionally marks the group as disabled. Used by both
2975*6185db85Sdougm  * enable and start subcommands.
2976*6185db85Sdougm  */
2977*6185db85Sdougm 
2978*6185db85Sdougm static int
2979*6185db85Sdougm disable_all_groups(struct list *work, int setstate)
2980*6185db85Sdougm {
2981*6185db85Sdougm 	int ret = SA_OK;
2982*6185db85Sdougm 	sa_group_t subgroup, group;
2983*6185db85Sdougm 
2984*6185db85Sdougm 	while (work != NULL && ret == SA_OK) {
2985*6185db85Sdougm 	    group = (sa_group_t)work->item;
2986*6185db85Sdougm 	    if (setstate)
2987*6185db85Sdougm 		ret = sa_set_group_attr(group, "state", "disabled");
2988*6185db85Sdougm 	    if (ret == SA_OK) {
2989*6185db85Sdougm 		char *name;
2990*6185db85Sdougm 		name = sa_get_group_attr(group, "name");
2991*6185db85Sdougm 		if (name != NULL && strcmp(name, "zfs") == 0) {
2992*6185db85Sdougm 		    /* need to get the sub-groups for stopping */
2993*6185db85Sdougm 		    for (subgroup = sa_get_sub_group(group); subgroup != NULL;
2994*6185db85Sdougm 			subgroup = sa_get_next_group(subgroup)) {
2995*6185db85Sdougm 			ret = disable_group(subgroup);
2996*6185db85Sdougm 		    }
2997*6185db85Sdougm 		} else {
2998*6185db85Sdougm 		    ret = disable_group(group);
2999*6185db85Sdougm 		}
3000*6185db85Sdougm 		/*
3001*6185db85Sdougm 		 * we don't want to "disable" since it won't come
3002*6185db85Sdougm 		 * up after a reboot.  The SMF framework should do
3003*6185db85Sdougm 		 * the right thing. On enable we do want to do
3004*6185db85Sdougm 		 * something.
3005*6185db85Sdougm 		 */
3006*6185db85Sdougm 	    }
3007*6185db85Sdougm 	    work = work->next;
3008*6185db85Sdougm 	}
3009*6185db85Sdougm 	if (ret == SA_OK)
3010*6185db85Sdougm 	    ret = sa_update_config();
3011*6185db85Sdougm 	return (ret);
3012*6185db85Sdougm }
3013*6185db85Sdougm 
3014*6185db85Sdougm /*
3015*6185db85Sdougm  * sa_disable_group(flags, argc, argv)
3016*6185db85Sdougm  *
3017*6185db85Sdougm  * Implements the disable subcommand
3018*6185db85Sdougm  */
3019*6185db85Sdougm 
3020*6185db85Sdougm int
3021*6185db85Sdougm sa_disable_group(int flags, int argc, char *argv[])
3022*6185db85Sdougm {
3023*6185db85Sdougm 	int verbose = 0;
3024*6185db85Sdougm 	int dryrun = 0;
3025*6185db85Sdougm 	int all = 0;
3026*6185db85Sdougm 	int c;
3027*6185db85Sdougm 	int ret = SA_OK;
3028*6185db85Sdougm 	char *protocol;
3029*6185db85Sdougm 	char *state;
3030*6185db85Sdougm 	struct list *worklist = NULL;
3031*6185db85Sdougm 	int auth = 1;
3032*6185db85Sdougm 
3033*6185db85Sdougm 	while ((c = getopt(argc, argv, "?havn")) != EOF) {
3034*6185db85Sdougm 	    switch (c) {
3035*6185db85Sdougm 	    case 'a':
3036*6185db85Sdougm 		all = 1;
3037*6185db85Sdougm 		break;
3038*6185db85Sdougm 	    case 'n':
3039*6185db85Sdougm 		dryrun++;
3040*6185db85Sdougm 		break;
3041*6185db85Sdougm 	    case 'P':
3042*6185db85Sdougm 		protocol = optarg;
3043*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
3044*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
3045*6185db85Sdougm 					protocol);
3046*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
3047*6185db85Sdougm 		}
3048*6185db85Sdougm 		break;
3049*6185db85Sdougm 	    case 'v':
3050*6185db85Sdougm 		verbose++;
3051*6185db85Sdougm 		break;
3052*6185db85Sdougm 	    default:
3053*6185db85Sdougm 	    case 'h':
3054*6185db85Sdougm 	    case '?':
3055*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
3056*6185db85Sdougm 				sa_get_usage(USAGE_DISABLE));
3057*6185db85Sdougm 		return (0);
3058*6185db85Sdougm 	    }
3059*6185db85Sdougm 	}
3060*6185db85Sdougm 
3061*6185db85Sdougm 	if (optind == argc && !all) {
3062*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
3063*6185db85Sdougm 				sa_get_usage(USAGE_DISABLE));
3064*6185db85Sdougm 		(void) printf(gettext("\tmust specify group\n"));
3065*6185db85Sdougm 		ret = SA_NO_SUCH_PATH;
3066*6185db85Sdougm 	} else {
3067*6185db85Sdougm 		sa_group_t group;
3068*6185db85Sdougm 		if (!all) {
3069*6185db85Sdougm 		    while (optind < argc) {
3070*6185db85Sdougm 			group = sa_get_group(argv[optind]);
3071*6185db85Sdougm 			if (group != NULL) {
3072*6185db85Sdougm 			    auth &= check_authorizations(argv[optind], flags);
3073*6185db85Sdougm 			    state = sa_get_group_attr(group, "state");
3074*6185db85Sdougm 			    if (state == NULL ||
3075*6185db85Sdougm 				strcmp(state, "disabled") == 0) {
3076*6185db85Sdougm 				/* already disabled */
3077*6185db85Sdougm 				if (verbose)
3078*6185db85Sdougm 				    (void) printf(gettext("Group \"%s\" is "
3079*6185db85Sdougm 							"already disabled\n"),
3080*6185db85Sdougm 					    argv[optind]);
3081*6185db85Sdougm 				ret = SA_BUSY; /* already disable */
3082*6185db85Sdougm 			    } else {
3083*6185db85Sdougm 				worklist = add_list(worklist, group, 0);
3084*6185db85Sdougm 				if (verbose)
3085*6185db85Sdougm 				    (void) printf(gettext("Disabling group "
3086*6185db85Sdougm 							    "\"%s\"\n"),
3087*6185db85Sdougm 					    argv[optind]);
3088*6185db85Sdougm 			    }
3089*6185db85Sdougm 			    if (state != NULL)
3090*6185db85Sdougm 				sa_free_attr_string(state);
3091*6185db85Sdougm 			} else {
3092*6185db85Sdougm 			    ret = SA_NO_SUCH_GROUP;
3093*6185db85Sdougm 			}
3094*6185db85Sdougm 			optind++;
3095*6185db85Sdougm 		    }
3096*6185db85Sdougm 		} else {
3097*6185db85Sdougm 		    for (group = sa_get_group(NULL); group != NULL;
3098*6185db85Sdougm 			    group = sa_get_next_group(group)) {
3099*6185db85Sdougm 			worklist = add_list(worklist, group, 0);
3100*6185db85Sdougm 		    }
3101*6185db85Sdougm 		}
3102*6185db85Sdougm 		if (ret == SA_OK && !dryrun) {
3103*6185db85Sdougm 			ret = disable_all_groups(worklist, 1);
3104*6185db85Sdougm 		}
3105*6185db85Sdougm 		if (ret != SA_OK && ret != SA_BUSY)
3106*6185db85Sdougm 		    (void) printf(gettext("Could not disable group: %s\n"),
3107*6185db85Sdougm 				sa_errorstr(ret));
3108*6185db85Sdougm 		if (ret == SA_BUSY)
3109*6185db85Sdougm 		    ret = SA_OK;
3110*6185db85Sdougm 	}
3111*6185db85Sdougm 	if (worklist != NULL)
3112*6185db85Sdougm 	    free_list(worklist);
3113*6185db85Sdougm 	if (dryrun && ret == SA_OK && !auth && verbose) {
3114*6185db85Sdougm 	    (void) printf(gettext("Command would fail: %s\n"),
3115*6185db85Sdougm 			sa_errorstr(SA_NO_PERMISSION));
3116*6185db85Sdougm 	}
3117*6185db85Sdougm 	return (ret);
3118*6185db85Sdougm }
3119*6185db85Sdougm 
3120*6185db85Sdougm /*
3121*6185db85Sdougm  * check_sharetab()
3122*6185db85Sdougm  *
3123*6185db85Sdougm  * Checks to see if the /etc/dfs/sharetab file is stale (exists from
3124*6185db85Sdougm  * before the current boot). If it is, truncate it since nothing is
3125*6185db85Sdougm  * really shared.
3126*6185db85Sdougm  */
3127*6185db85Sdougm 
3128*6185db85Sdougm static void
3129*6185db85Sdougm check_sharetab()
3130*6185db85Sdougm {
3131*6185db85Sdougm 	int fd;
3132*6185db85Sdougm 	struct utmpx *utmpxp;
3133*6185db85Sdougm 	struct stat st;
3134*6185db85Sdougm 
3135*6185db85Sdougm 	fd = open(SA_LEGACY_SHARETAB, O_RDWR);
3136*6185db85Sdougm 	if (fd >= 0) {
3137*6185db85Sdougm 		/*
3138*6185db85Sdougm 		 * Attempt to get a lock on the file. Whgen we get
3139*6185db85Sdougm 		 * one, then check to see if it is older than the boot
3140*6185db85Sdougm 		 * time. Truncate if older than boot.
3141*6185db85Sdougm 		 */
3142*6185db85Sdougm 	    (void) lockf(fd, F_LOCK, 0);
3143*6185db85Sdougm 	    if ((fstat(fd, &st) == 0) && /* does sharetab exist? */
3144*6185db85Sdougm 		(utmpxp = getutxent()) != NULL && /* does utmpx exist? */
3145*6185db85Sdougm 			(utmpxp->ut_xtime > st.st_mtime)) /* sharetab older? */
3146*6185db85Sdougm 		(void) ftruncate(fd, 0);
3147*6185db85Sdougm 
3148*6185db85Sdougm 	    (void) lockf(fd, F_ULOCK, 0);
3149*6185db85Sdougm 	    (void) close(fd);
3150*6185db85Sdougm 	    endutxent();
3151*6185db85Sdougm 	}
3152*6185db85Sdougm }
3153*6185db85Sdougm 
3154*6185db85Sdougm /*
3155*6185db85Sdougm  * sa_start_group(flags, argc, argv)
3156*6185db85Sdougm  *
3157*6185db85Sdougm  * Implements the start command.
3158*6185db85Sdougm  * This is similar to enable except it doesn't change the state
3159*6185db85Sdougm  * of the group(s) and only enables shares if the group is already
3160*6185db85Sdougm  * enabled.
3161*6185db85Sdougm  */
3162*6185db85Sdougm 
3163*6185db85Sdougm int
3164*6185db85Sdougm sa_start_group(int flags, int argc, char *argv[])
3165*6185db85Sdougm {
3166*6185db85Sdougm 	int verbose = 0;
3167*6185db85Sdougm 	int all = 0;
3168*6185db85Sdougm 	int c;
3169*6185db85Sdougm 	int ret = SMF_EXIT_OK;
3170*6185db85Sdougm 	char *protocol = NULL;
3171*6185db85Sdougm 	char *state;
3172*6185db85Sdougm 	struct list *worklist = NULL;
3173*6185db85Sdougm #ifdef lint
3174*6185db85Sdougm 	flags = flags;
3175*6185db85Sdougm #endif
3176*6185db85Sdougm 
3177*6185db85Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
3178*6185db85Sdougm 	    switch (c) {
3179*6185db85Sdougm 	    case 'a':
3180*6185db85Sdougm 		all = 1;
3181*6185db85Sdougm 		break;
3182*6185db85Sdougm 	    case 'P':
3183*6185db85Sdougm 		protocol = optarg;
3184*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
3185*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
3186*6185db85Sdougm 				    protocol);
3187*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
3188*6185db85Sdougm 		}
3189*6185db85Sdougm 		break;
3190*6185db85Sdougm 	    case 'v':
3191*6185db85Sdougm 		verbose++;
3192*6185db85Sdougm 		break;
3193*6185db85Sdougm 	    default:
3194*6185db85Sdougm 	    case 'h':
3195*6185db85Sdougm 	    case '?':
3196*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
3197*6185db85Sdougm 				sa_get_usage(USAGE_START));
3198*6185db85Sdougm 		return (SA_OK);
3199*6185db85Sdougm 	    }
3200*6185db85Sdougm 	}
3201*6185db85Sdougm 
3202*6185db85Sdougm 	if (optind == argc && !all) {
3203*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
3204*6185db85Sdougm 				sa_get_usage(USAGE_START));
3205*6185db85Sdougm 		ret = SMF_EXIT_ERR_FATAL;
3206*6185db85Sdougm 	} else {
3207*6185db85Sdougm 		sa_group_t group;
3208*6185db85Sdougm 
3209*6185db85Sdougm 		check_sharetab();
3210*6185db85Sdougm 
3211*6185db85Sdougm 		if (!all) {
3212*6185db85Sdougm 		    while (optind < argc) {
3213*6185db85Sdougm 			group = sa_get_group(argv[optind]);
3214*6185db85Sdougm 			if (group != NULL) {
3215*6185db85Sdougm 			    state = sa_get_group_attr(group, "state");
3216*6185db85Sdougm 			    if (state == NULL ||
3217*6185db85Sdougm 				strcmp(state, "enabled") == 0) {
3218*6185db85Sdougm 				worklist = add_list(worklist, group, 0);
3219*6185db85Sdougm 				if (verbose)
3220*6185db85Sdougm 				    (void) printf(gettext("Starting group "
3221*6185db85Sdougm 								"\"%s\"\n"),
3222*6185db85Sdougm 					    argv[optind]);
3223*6185db85Sdougm 			    } else {
3224*6185db85Sdougm 				/*
3225*6185db85Sdougm 				 * determine if there are any
3226*6185db85Sdougm 				 * protocols.  if there aren't any,
3227*6185db85Sdougm 				 * then there isn't anything to do in
3228*6185db85Sdougm 				 * any case so no error.
3229*6185db85Sdougm 				 */
3230*6185db85Sdougm 				if (sa_get_optionset(group, protocol) != NULL) {
3231*6185db85Sdougm 				    ret = SMF_EXIT_OK;
3232*6185db85Sdougm 				}
3233*6185db85Sdougm 			    }
3234*6185db85Sdougm 			    if (state != NULL)
3235*6185db85Sdougm 				sa_free_attr_string(state);
3236*6185db85Sdougm 			}
3237*6185db85Sdougm 			optind++;
3238*6185db85Sdougm 		    }
3239*6185db85Sdougm 		} else {
3240*6185db85Sdougm 		    for (group = sa_get_group(NULL); group != NULL;
3241*6185db85Sdougm 			    group = sa_get_next_group(group)) {
3242*6185db85Sdougm 			state = sa_get_group_attr(group, "state");
3243*6185db85Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
3244*6185db85Sdougm 			    worklist = add_list(worklist, group, 0);
3245*6185db85Sdougm 			if (state != NULL)
3246*6185db85Sdougm 			    sa_free_attr_string(state);
3247*6185db85Sdougm 		    }
3248*6185db85Sdougm 		}
3249*6185db85Sdougm 		(void) enable_all_groups(worklist, 0, 1, NULL);
3250*6185db85Sdougm 	}
3251*6185db85Sdougm 	if (worklist != NULL)
3252*6185db85Sdougm 	    free_list(worklist);
3253*6185db85Sdougm 	return (ret);
3254*6185db85Sdougm }
3255*6185db85Sdougm 
3256*6185db85Sdougm /*
3257*6185db85Sdougm  * sa_stop_group(flags, argc, argv)
3258*6185db85Sdougm  *
3259*6185db85Sdougm  * Implements the stop command.
3260*6185db85Sdougm  * This is similar to disable except it doesn't change the state
3261*6185db85Sdougm  * of the group(s) and only disables shares if the group is already
3262*6185db85Sdougm  * enabled.
3263*6185db85Sdougm  */
3264*6185db85Sdougm 
3265*6185db85Sdougm int
3266*6185db85Sdougm sa_stop_group(int flags, int argc, char *argv[])
3267*6185db85Sdougm {
3268*6185db85Sdougm 	int verbose = 0;
3269*6185db85Sdougm 	int all = 0;
3270*6185db85Sdougm 	int c;
3271*6185db85Sdougm 	int ret = SMF_EXIT_OK;
3272*6185db85Sdougm 	char *protocol = NULL;
3273*6185db85Sdougm 	char *state;
3274*6185db85Sdougm 	struct list *worklist = NULL;
3275*6185db85Sdougm #ifdef lint
3276*6185db85Sdougm 	flags = flags;
3277*6185db85Sdougm #endif
3278*6185db85Sdougm 
3279*6185db85Sdougm 	while ((c = getopt(argc, argv, "?havP:")) != EOF) {
3280*6185db85Sdougm 	    switch (c) {
3281*6185db85Sdougm 	    case 'a':
3282*6185db85Sdougm 		all = 1;
3283*6185db85Sdougm 		break;
3284*6185db85Sdougm 	    case 'P':
3285*6185db85Sdougm 		protocol = optarg;
3286*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
3287*6185db85Sdougm 		    (void) printf(gettext("Invalid protocol specified: %s\n"),
3288*6185db85Sdougm 					protocol);
3289*6185db85Sdougm 		    return (SA_INVALID_PROTOCOL);
3290*6185db85Sdougm 		}
3291*6185db85Sdougm 		break;
3292*6185db85Sdougm 	    case 'v':
3293*6185db85Sdougm 		verbose++;
3294*6185db85Sdougm 		break;
3295*6185db85Sdougm 	    default:
3296*6185db85Sdougm 	    case 'h':
3297*6185db85Sdougm 	    case '?':
3298*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
3299*6185db85Sdougm 				sa_get_usage(USAGE_STOP));
3300*6185db85Sdougm 		return (0);
3301*6185db85Sdougm 	    }
3302*6185db85Sdougm 	}
3303*6185db85Sdougm 
3304*6185db85Sdougm 	if (optind == argc && !all) {
3305*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP));
3306*6185db85Sdougm 		ret = SMF_EXIT_ERR_FATAL;
3307*6185db85Sdougm 	} else {
3308*6185db85Sdougm 		sa_group_t group;
3309*6185db85Sdougm 		if (!all) {
3310*6185db85Sdougm 		    while (optind < argc) {
3311*6185db85Sdougm 			group = sa_get_group(argv[optind]);
3312*6185db85Sdougm 			if (group != NULL) {
3313*6185db85Sdougm 			    state = sa_get_group_attr(group, "state");
3314*6185db85Sdougm 			    if (state == NULL ||
3315*6185db85Sdougm 				strcmp(state, "enabled") == 0) {
3316*6185db85Sdougm 				worklist = add_list(worklist, group, 0);
3317*6185db85Sdougm 				if (verbose)
3318*6185db85Sdougm 				    (void) printf(gettext("Stopping group "
3319*6185db85Sdougm 								"\"%s\"\n"),
3320*6185db85Sdougm 					    argv[optind]);
3321*6185db85Sdougm 			    } else {
3322*6185db85Sdougm 				ret = SMF_EXIT_OK;
3323*6185db85Sdougm 			    }
3324*6185db85Sdougm 			    if (state != NULL)
3325*6185db85Sdougm 				sa_free_attr_string(state);
3326*6185db85Sdougm 			}
3327*6185db85Sdougm 			optind++;
3328*6185db85Sdougm 		    }
3329*6185db85Sdougm 		} else {
3330*6185db85Sdougm 		    for (group = sa_get_group(NULL); group != NULL;
3331*6185db85Sdougm 			    group = sa_get_next_group(group)) {
3332*6185db85Sdougm 			state = sa_get_group_attr(group, "state");
3333*6185db85Sdougm 			if (state == NULL || strcmp(state, "enabled") == 0)
3334*6185db85Sdougm 			    worklist = add_list(worklist, group, 0);
3335*6185db85Sdougm 			if (state != NULL)
3336*6185db85Sdougm 			    sa_free_attr_string(state);
3337*6185db85Sdougm 		    }
3338*6185db85Sdougm 		}
3339*6185db85Sdougm 		(void) disable_all_groups(worklist, 0);
3340*6185db85Sdougm 		ret = sa_update_config();
3341*6185db85Sdougm 	}
3342*6185db85Sdougm 	if (worklist != NULL)
3343*6185db85Sdougm 	    free_list(worklist);
3344*6185db85Sdougm 	return (ret);
3345*6185db85Sdougm }
3346*6185db85Sdougm 
3347*6185db85Sdougm /*
3348*6185db85Sdougm  * remove_all_options(share, proto)
3349*6185db85Sdougm  *
3350*6185db85Sdougm  * Removes all options on a share.
3351*6185db85Sdougm  */
3352*6185db85Sdougm 
3353*6185db85Sdougm static void
3354*6185db85Sdougm remove_all_options(sa_share_t share, char *proto)
3355*6185db85Sdougm {
3356*6185db85Sdougm 	sa_optionset_t optionset;
3357*6185db85Sdougm 	sa_security_t security;
3358*6185db85Sdougm 	sa_security_t prevsec = NULL;
3359*6185db85Sdougm 
3360*6185db85Sdougm 	optionset = sa_get_optionset(share, proto);
3361*6185db85Sdougm 	if (optionset != NULL)
3362*6185db85Sdougm 	    (void) sa_destroy_optionset(optionset);
3363*6185db85Sdougm 	for (security = sa_get_security(share, NULL, NULL);
3364*6185db85Sdougm 	    security != NULL;
3365*6185db85Sdougm 	    security = sa_get_next_security(security)) {
3366*6185db85Sdougm 	    char *type;
3367*6185db85Sdougm 		/*
3368*6185db85Sdougm 		 * we walk through the list.  prevsec keeps the
3369*6185db85Sdougm 		 * previous security so we can delete it without
3370*6185db85Sdougm 		 * destroying the list.
3371*6185db85Sdougm 		 */
3372*6185db85Sdougm 	    if (prevsec != NULL) {
3373*6185db85Sdougm 		/* remove the previously seen security */
3374*6185db85Sdougm 		(void) sa_destroy_security(prevsec);
3375*6185db85Sdougm 		/* set to NULL so we don't try multiple times */
3376*6185db85Sdougm 		prevsec = NULL;
3377*6185db85Sdougm 	    }
3378*6185db85Sdougm 	    type = sa_get_security_attr(security, "type");
3379*6185db85Sdougm 	    if (type != NULL) {
3380*6185db85Sdougm 		/*
3381*6185db85Sdougm 		 * if the security matches the specified protocol, we
3382*6185db85Sdougm 		 * want to remove it. prevsec holds it until either
3383*6185db85Sdougm 		 * the next pass or we fall out of the loop.
3384*6185db85Sdougm 		 */
3385*6185db85Sdougm 		if (strcmp(type, proto) == 0)
3386*6185db85Sdougm 		    prevsec = security;
3387*6185db85Sdougm 		sa_free_attr_string(type);
3388*6185db85Sdougm 	    }
3389*6185db85Sdougm 	}
3390*6185db85Sdougm 	/* in case there is one left */
3391*6185db85Sdougm 	if (prevsec != NULL)
3392*6185db85Sdougm 	    (void) sa_destroy_security(prevsec);
3393*6185db85Sdougm }
3394*6185db85Sdougm 
3395*6185db85Sdougm 
3396*6185db85Sdougm /*
3397*6185db85Sdougm  * for legacy support, we need to handle the old syntax. This is what
3398*6185db85Sdougm  * we get if sharemgr is called with the name "share" rather than
3399*6185db85Sdougm  * sharemgr.
3400*6185db85Sdougm  */
3401*6185db85Sdougm 
3402*6185db85Sdougm static int
3403*6185db85Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
3404*6185db85Sdougm {
3405*6185db85Sdougm 	int err;
3406*6185db85Sdougm 
3407*6185db85Sdougm 	err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
3408*6185db85Sdougm 	if (err > buffsize)
3409*6185db85Sdougm 	    return (-1);
3410*6185db85Sdougm 	return (0);
3411*6185db85Sdougm }
3412*6185db85Sdougm 
3413*6185db85Sdougm 
3414*6185db85Sdougm /*
3415*6185db85Sdougm  * check_legacy_cmd(proto, cmd)
3416*6185db85Sdougm  *
3417*6185db85Sdougm  * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
3418*6185db85Sdougm  * executable.
3419*6185db85Sdougm  */
3420*6185db85Sdougm 
3421*6185db85Sdougm static int
3422*6185db85Sdougm check_legacy_cmd(char *path)
3423*6185db85Sdougm {
3424*6185db85Sdougm 	struct stat st;
3425*6185db85Sdougm 	int ret = 0;
3426*6185db85Sdougm 
3427*6185db85Sdougm 	if (stat(path, &st) == 0) {
3428*6185db85Sdougm 	    if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
3429*6185db85Sdougm 		ret = 1;
3430*6185db85Sdougm 	}
3431*6185db85Sdougm 	return (ret);
3432*6185db85Sdougm }
3433*6185db85Sdougm 
3434*6185db85Sdougm /*
3435*6185db85Sdougm  * run_legacy_command(proto, cmd, argv)
3436*6185db85Sdougm  *
3437*6185db85Sdougm  * we know the command exists, so attempt to execute it with all the
3438*6185db85Sdougm  * arguments. This implements full legacy share support for those
3439*6185db85Sdougm  * protocols that don't have plugin providers.
3440*6185db85Sdougm  */
3441*6185db85Sdougm 
3442*6185db85Sdougm static int
3443*6185db85Sdougm run_legacy_command(char *path, char *argv[])
3444*6185db85Sdougm {
3445*6185db85Sdougm 	int ret;
3446*6185db85Sdougm 
3447*6185db85Sdougm 	ret = execv(path, argv);
3448*6185db85Sdougm 	if (ret < 0) {
3449*6185db85Sdougm 	    switch (errno) {
3450*6185db85Sdougm 	    case EACCES:
3451*6185db85Sdougm 		ret = SA_NO_PERMISSION;
3452*6185db85Sdougm 		break;
3453*6185db85Sdougm 	    default:
3454*6185db85Sdougm 		ret = SA_SYSTEM_ERR;
3455*6185db85Sdougm 		break;
3456*6185db85Sdougm 	    }
3457*6185db85Sdougm 	}
3458*6185db85Sdougm 	return (ret);
3459*6185db85Sdougm }
3460*6185db85Sdougm 
3461*6185db85Sdougm /*
3462*6185db85Sdougm  * out_share(out, group, proto, options)
3463*6185db85Sdougm  *
3464*6185db85Sdougm  * Display the share information in the format that the "share"
3465*6185db85Sdougm  * command has traditionally used.
3466*6185db85Sdougm  */
3467*6185db85Sdougm 
3468*6185db85Sdougm static void
3469*6185db85Sdougm out_share(FILE *out, sa_group_t group, char *proto, char *options)
3470*6185db85Sdougm {
3471*6185db85Sdougm 	sa_share_t share;
3472*6185db85Sdougm 	char resfmt[128];
3473*6185db85Sdougm 
3474*6185db85Sdougm 	for (share = sa_get_share(group, NULL); share != NULL;
3475*6185db85Sdougm 		share = sa_get_next_share(share)) {
3476*6185db85Sdougm 	    char *path;
3477*6185db85Sdougm 	    char *type;
3478*6185db85Sdougm 	    char *resource;
3479*6185db85Sdougm 	    char *description;
3480*6185db85Sdougm 	    char *groupname;
3481*6185db85Sdougm 	    char *sharedstate;
3482*6185db85Sdougm 	    int shared = 1;
3483*6185db85Sdougm 	    char *soptions;
3484*6185db85Sdougm 
3485*6185db85Sdougm 	    sharedstate = sa_get_share_attr(share, "shared");
3486*6185db85Sdougm 	    path = sa_get_share_attr(share, "path");
3487*6185db85Sdougm 	    type = sa_get_share_attr(share, "type");
3488*6185db85Sdougm 	    resource = sa_get_share_attr(share, "resource");
3489*6185db85Sdougm 	    groupname = sa_get_group_attr(group, "name");
3490*6185db85Sdougm 
3491*6185db85Sdougm 	    if (groupname != NULL && strcmp(groupname, "default") == 0) {
3492*6185db85Sdougm 		sa_free_attr_string(groupname);
3493*6185db85Sdougm 		groupname = NULL;
3494*6185db85Sdougm 	    }
3495*6185db85Sdougm 	    description = sa_get_share_description(share);
3496*6185db85Sdougm 	    soptions = options;
3497*6185db85Sdougm 
3498*6185db85Sdougm 	    if (sharedstate == NULL)
3499*6185db85Sdougm 		shared = 0;
3500*6185db85Sdougm 
3501*6185db85Sdougm 	    soptions = sa_proto_legacy_format(proto, share, 1);
3502*6185db85Sdougm 
3503*6185db85Sdougm 	    if (shared) {
3504*6185db85Sdougm 		/* only persisting share go here */
3505*6185db85Sdougm 		(void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
3506*6185db85Sdougm 			resource != NULL ? resource : "-",
3507*6185db85Sdougm 			groupname != NULL ? "@" : "",
3508*6185db85Sdougm 			groupname != NULL ? groupname : "");
3509*6185db85Sdougm 		(void) fprintf(out, "%-14.14s  %s   %s   \"%s\"  \n",
3510*6185db85Sdougm 			resfmt,
3511*6185db85Sdougm 			path,
3512*6185db85Sdougm 			(soptions != NULL && strlen(soptions) > 0) ?
3513*6185db85Sdougm 					soptions : "rw",
3514*6185db85Sdougm 			(description != NULL) ? description : "");
3515*6185db85Sdougm 	    }
3516*6185db85Sdougm 
3517*6185db85Sdougm 	    if (path != NULL)
3518*6185db85Sdougm 		sa_free_attr_string(path);
3519*6185db85Sdougm 	    if (type != NULL)
3520*6185db85Sdougm 		sa_free_attr_string(type);
3521*6185db85Sdougm 	    if (resource != NULL)
3522*6185db85Sdougm 		sa_free_attr_string(resource);
3523*6185db85Sdougm 	    if (groupname != NULL)
3524*6185db85Sdougm 		sa_free_attr_string(groupname);
3525*6185db85Sdougm 	    if (description != NULL)
3526*6185db85Sdougm 		sa_free_share_description(description);
3527*6185db85Sdougm 	    if (sharedstate != NULL)
3528*6185db85Sdougm 		sa_free_attr_string(sharedstate);
3529*6185db85Sdougm 	    if (soptions != NULL && soptions != options)
3530*6185db85Sdougm 		sa_format_free(soptions);
3531*6185db85Sdougm 	}
3532*6185db85Sdougm }
3533*6185db85Sdougm 
3534*6185db85Sdougm /*
3535*6185db85Sdougm  * output_legacy_file(out, proto)
3536*6185db85Sdougm  *
3537*6185db85Sdougm  * Walk all of the groups for the specified protocol and call
3538*6185db85Sdougm  * out_share() to format and write in the format displayed by the
3539*6185db85Sdougm  * "share" command with no arguments.
3540*6185db85Sdougm  */
3541*6185db85Sdougm 
3542*6185db85Sdougm static void
3543*6185db85Sdougm output_legacy_file(FILE *out, char *proto)
3544*6185db85Sdougm {
3545*6185db85Sdougm 	sa_group_t group;
3546*6185db85Sdougm 
3547*6185db85Sdougm 	for (group = sa_get_group(NULL); group != NULL;
3548*6185db85Sdougm 		group = sa_get_next_group(group)) {
3549*6185db85Sdougm 	    char *options;
3550*6185db85Sdougm 	    char *zfs;
3551*6185db85Sdougm 
3552*6185db85Sdougm 		/*
3553*6185db85Sdougm 		 * get default options preformated, being careful to
3554*6185db85Sdougm 		 * handle legacy shares differently from new style
3555*6185db85Sdougm 		 * shares. Legacy share have options on the share.
3556*6185db85Sdougm 		 */
3557*6185db85Sdougm 
3558*6185db85Sdougm 	    zfs = sa_get_group_attr(group, "zfs");
3559*6185db85Sdougm 	    if (zfs != NULL) {
3560*6185db85Sdougm 		sa_group_t zgroup;
3561*6185db85Sdougm 		sa_free_attr_string(zfs);
3562*6185db85Sdougm 		options = sa_proto_legacy_format(proto, group, 1);
3563*6185db85Sdougm 		for (zgroup = sa_get_sub_group(group); zgroup != NULL;
3564*6185db85Sdougm 		    zgroup = sa_get_next_group(zgroup)) {
3565*6185db85Sdougm 
3566*6185db85Sdougm 		    /* got a group, so display it */
3567*6185db85Sdougm 		    out_share(out, zgroup, proto, options);
3568*6185db85Sdougm 		}
3569*6185db85Sdougm 	    } else {
3570*6185db85Sdougm 		options = sa_proto_legacy_format(proto, group, 1);
3571*6185db85Sdougm 		out_share(out, group, proto, options);
3572*6185db85Sdougm 	    }
3573*6185db85Sdougm 	    if (options != NULL)
3574*6185db85Sdougm 		free(options);
3575*6185db85Sdougm 	}
3576*6185db85Sdougm }
3577*6185db85Sdougm 
3578*6185db85Sdougm int
3579*6185db85Sdougm sa_legacy_share(int flags, int argc, char *argv[])
3580*6185db85Sdougm {
3581*6185db85Sdougm 	char *protocol = "nfs";
3582*6185db85Sdougm 	char *options = NULL;
3583*6185db85Sdougm 	char *description = NULL;
3584*6185db85Sdougm 	char *groupname = NULL;
3585*6185db85Sdougm 	char *sharepath = NULL;
3586*6185db85Sdougm 	char *resource = NULL;
3587*6185db85Sdougm 	char *groupstatus = NULL;
3588*6185db85Sdougm 	int persist = SA_SHARE_TRANSIENT;
3589*6185db85Sdougm 	int argsused = 0;
3590*6185db85Sdougm 	int c;
3591*6185db85Sdougm 	int ret = SA_OK;
3592*6185db85Sdougm 	int zfs = 0;
3593*6185db85Sdougm 	int true_legacy = 0;
3594*6185db85Sdougm 	int curtype = SA_SHARE_TRANSIENT;
3595*6185db85Sdougm 	char cmd[MAXPATHLEN];
3596*6185db85Sdougm #ifdef lint
3597*6185db85Sdougm 	flags = flags;
3598*6185db85Sdougm #endif
3599*6185db85Sdougm 
3600*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
3601*6185db85Sdougm 	    switch (c) {
3602*6185db85Sdougm 	    case 'd':
3603*6185db85Sdougm 		description = optarg;
3604*6185db85Sdougm 		argsused++;
3605*6185db85Sdougm 		break;
3606*6185db85Sdougm 	    case 'F':
3607*6185db85Sdougm 		protocol = optarg;
3608*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
3609*6185db85Sdougm 		    if (format_legacy_path(cmd, MAXPATHLEN,
3610*6185db85Sdougm 			    protocol, "share") == 0 && check_legacy_cmd(cmd)) {
3611*6185db85Sdougm 			true_legacy++;
3612*6185db85Sdougm 		    } else {
3613*6185db85Sdougm 			(void) fprintf(stderr,
3614*6185db85Sdougm 					gettext("Invalid protocol specified:"
3615*6185db85Sdougm 						"%s\n"),
3616*6185db85Sdougm 				protocol);
3617*6185db85Sdougm 			return (SA_INVALID_PROTOCOL);
3618*6185db85Sdougm 		    }
3619*6185db85Sdougm 		}
3620*6185db85Sdougm 		break;
3621*6185db85Sdougm 	    case 'o':
3622*6185db85Sdougm 		options = optarg;
3623*6185db85Sdougm 		argsused++;
3624*6185db85Sdougm 		break;
3625*6185db85Sdougm 	    case 'p':
3626*6185db85Sdougm 		persist = SA_SHARE_PERMANENT;
3627*6185db85Sdougm 		argsused++;
3628*6185db85Sdougm 		break;
3629*6185db85Sdougm 	    case 'h':
3630*6185db85Sdougm 	    case '?':
3631*6185db85Sdougm 	    default:
3632*6185db85Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
3633*6185db85Sdougm 						sa_get_usage(USAGE_SHARE));
3634*6185db85Sdougm 		return (SA_OK);
3635*6185db85Sdougm 	    }
3636*6185db85Sdougm 	}
3637*6185db85Sdougm 
3638*6185db85Sdougm 	/* have the info so construct what is needed */
3639*6185db85Sdougm 	if (!argsused && optind == argc) {
3640*6185db85Sdougm 	    /* display current info in share format */
3641*6185db85Sdougm 	    (void) output_legacy_file(stdout, "nfs");
3642*6185db85Sdougm 	} else {
3643*6185db85Sdougm 	    sa_group_t group = NULL;
3644*6185db85Sdougm 	    sa_share_t share;
3645*6185db85Sdougm 	    char dir[MAXPATHLEN];
3646*6185db85Sdougm 
3647*6185db85Sdougm 	    /* we are modifying the configuration */
3648*6185db85Sdougm 	    if (optind == argc) {
3649*6185db85Sdougm 		(void) fprintf(stderr, gettext("usage: %s\n"),
3650*6185db85Sdougm 				sa_get_usage(USAGE_SHARE));
3651*6185db85Sdougm 		return (SA_LEGACY_ERR);
3652*6185db85Sdougm 	    }
3653*6185db85Sdougm 
3654*6185db85Sdougm 	    if (true_legacy) {
3655*6185db85Sdougm 		/* if still using legacy share/unshare, exec it */
3656*6185db85Sdougm 		ret = run_legacy_command(cmd, argv);
3657*6185db85Sdougm 		return (ret);
3658*6185db85Sdougm 	    }
3659*6185db85Sdougm 
3660*6185db85Sdougm 	    sharepath = argv[optind++];
3661*6185db85Sdougm 	    if (optind < argc) {
3662*6185db85Sdougm 		resource = argv[optind];
3663*6185db85Sdougm 		groupname = strchr(resource, '@');
3664*6185db85Sdougm 		if (groupname != NULL)
3665*6185db85Sdougm 		    *groupname++ = '\0';
3666*6185db85Sdougm 	    }
3667*6185db85Sdougm 	    if (realpath(sharepath, dir) == NULL)
3668*6185db85Sdougm 		ret = SA_BAD_PATH;
3669*6185db85Sdougm 	    else
3670*6185db85Sdougm 		sharepath = dir;
3671*6185db85Sdougm 	    if (ret == SA_OK) {
3672*6185db85Sdougm 		share = sa_find_share(sharepath);
3673*6185db85Sdougm 	    } else {
3674*6185db85Sdougm 		share = NULL;
3675*6185db85Sdougm 	    }
3676*6185db85Sdougm 	    if (groupname != NULL) {
3677*6185db85Sdougm 		    ret = SA_NOT_ALLOWED;
3678*6185db85Sdougm 	    } else if (ret == SA_OK) {
3679*6185db85Sdougm 		char *legacygroup = "default";
3680*6185db85Sdougm 		/*
3681*6185db85Sdougm 		 * the legacy group is always present and zfs groups
3682*6185db85Sdougm 		 * come and go.  zfs shares may be in sub-groups and
3683*6185db85Sdougm 		 * the zfs share will already be in that group so it
3684*6185db85Sdougm 		 * isn't an error.
3685*6185db85Sdougm 		 */
3686*6185db85Sdougm 		if (share != NULL) {
3687*6185db85Sdougm 		/*
3688*6185db85Sdougm 		 * if the share exists, then make sure it is one we
3689*6185db85Sdougm 		 * want to handle.
3690*6185db85Sdougm 		 */
3691*6185db85Sdougm 		    group = sa_get_parent_group(share);
3692*6185db85Sdougm 		} else {
3693*6185db85Sdougm 		    group = sa_get_group(legacygroup);
3694*6185db85Sdougm 		}
3695*6185db85Sdougm 		if (group != NULL) {
3696*6185db85Sdougm 		    groupstatus = group_status(group);
3697*6185db85Sdougm 		    if (share == NULL) {
3698*6185db85Sdougm 			share = sa_add_share(group, sharepath, persist, &ret);
3699*6185db85Sdougm 			if (share == NULL && ret == SA_DUPLICATE_NAME) {
3700*6185db85Sdougm 			    /* could be a ZFS path being started */
3701*6185db85Sdougm 			    if (sa_zfs_is_shared(sharepath)) {
3702*6185db85Sdougm 				ret = SA_OK;
3703*6185db85Sdougm 				group = sa_get_group("zfs");
3704*6185db85Sdougm 				if (group == NULL) {
3705*6185db85Sdougm 				    /* this shouldn't happen */
3706*6185db85Sdougm 				    ret = SA_CONFIG_ERR;
3707*6185db85Sdougm 				}
3708*6185db85Sdougm 				if (group != NULL) {
3709*6185db85Sdougm 				    share = sa_add_share(group, sharepath,
3710*6185db85Sdougm 							    persist, &ret);
3711*6185db85Sdougm 				}
3712*6185db85Sdougm 			    }
3713*6185db85Sdougm 			}
3714*6185db85Sdougm 		    } else {
3715*6185db85Sdougm 			/*
3716*6185db85Sdougm 			 * may want to change persist state, but the
3717*6185db85Sdougm 			 * important thing is to change options unless
3718*6185db85Sdougm 			 * this is ZFS where we just want to do the
3719*6185db85Sdougm 			 * enable since everything is current.
3720*6185db85Sdougm 			 */
3721*6185db85Sdougm 			if (!sa_zfs_is_shared(sharepath)) {
3722*6185db85Sdougm 			    char *type;
3723*6185db85Sdougm 			    remove_all_options(share, protocol);
3724*6185db85Sdougm 			    type = sa_get_share_attr(share, "type");
3725*6185db85Sdougm 			    if (type != NULL &&
3726*6185db85Sdougm 				strcmp(type, "transient") != 0) {
3727*6185db85Sdougm 				curtype = SA_SHARE_PERMANENT;
3728*6185db85Sdougm 			    }
3729*6185db85Sdougm 			    if (type != NULL)
3730*6185db85Sdougm 				sa_free_attr_string(type);
3731*6185db85Sdougm 			    if (curtype != persist) {
3732*6185db85Sdougm 				(void) sa_set_share_attr(share, "type",
3733*6185db85Sdougm 					persist == SA_SHARE_PERMANENT ?
3734*6185db85Sdougm 						"persist" : "transient");
3735*6185db85Sdougm 			    }
3736*6185db85Sdougm 			} else {
3737*6185db85Sdougm 			    zfs++;
3738*6185db85Sdougm 			}
3739*6185db85Sdougm 		    }
3740*6185db85Sdougm 		    if (!zfs) {
3741*6185db85Sdougm 			/* have a group to hold this share path */
3742*6185db85Sdougm 			if (ret == SA_OK && options != NULL &&
3743*6185db85Sdougm 				strlen(options) > 0) {
3744*6185db85Sdougm 			    ret = sa_parse_legacy_options(share,
3745*6185db85Sdougm 							    options,
3746*6185db85Sdougm 							    protocol);
3747*6185db85Sdougm 			}
3748*6185db85Sdougm 			if (ret == SA_OK && description != NULL)
3749*6185db85Sdougm 			    ret = sa_set_share_description(share, description);
3750*6185db85Sdougm 			if (ret == SA_OK && resource != NULL)
3751*6185db85Sdougm 			    ret = sa_set_share_attr(share, "resource",
3752*6185db85Sdougm 						    resource);
3753*6185db85Sdougm 		    }
3754*6185db85Sdougm 		    if (ret == SA_OK) {
3755*6185db85Sdougm 			if (strcmp(groupstatus, "enabled") == 0)
3756*6185db85Sdougm 			    ret = sa_enable_share(share, protocol);
3757*6185db85Sdougm 			if (ret == SA_OK && persist == SA_SHARE_PERMANENT) {
3758*6185db85Sdougm 			    (void) sa_update_legacy(share, protocol);
3759*6185db85Sdougm 			}
3760*6185db85Sdougm 			if (ret == SA_OK)
3761*6185db85Sdougm 			    ret = sa_update_config();
3762*6185db85Sdougm 		    }
3763*6185db85Sdougm 		} else {
3764*6185db85Sdougm 		    ret = SA_SYSTEM_ERR;
3765*6185db85Sdougm 		}
3766*6185db85Sdougm 	    }
3767*6185db85Sdougm 	}
3768*6185db85Sdougm 	if (ret != SA_OK) {
3769*6185db85Sdougm 	    (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
3770*6185db85Sdougm 				sharepath, sa_errorstr(ret));
3771*6185db85Sdougm 	    ret = SA_LEGACY_ERR;
3772*6185db85Sdougm 
3773*6185db85Sdougm 	}
3774*6185db85Sdougm 	return (ret);
3775*6185db85Sdougm }
3776*6185db85Sdougm 
3777*6185db85Sdougm /*
3778*6185db85Sdougm  * sa_legacy_unshare(flags, argc, argv)
3779*6185db85Sdougm  *
3780*6185db85Sdougm  * Implements the original unshare command.
3781*6185db85Sdougm  */
3782*6185db85Sdougm 
3783*6185db85Sdougm int
3784*6185db85Sdougm sa_legacy_unshare(int flags, int argc, char *argv[])
3785*6185db85Sdougm {
3786*6185db85Sdougm 	char *protocol = "nfs"; /* for now */
3787*6185db85Sdougm 	char *options = NULL;
3788*6185db85Sdougm 	char *sharepath = NULL;
3789*6185db85Sdougm 	int persist = SA_SHARE_TRANSIENT;
3790*6185db85Sdougm 	int argsused = 0;
3791*6185db85Sdougm 	int c;
3792*6185db85Sdougm 	int ret = SA_OK;
3793*6185db85Sdougm 	int true_legacy = 0;
3794*6185db85Sdougm 	char cmd[MAXPATHLEN];
3795*6185db85Sdougm #ifdef lint
3796*6185db85Sdougm 	flags = flags;
3797*6185db85Sdougm 	options = options;
3798*6185db85Sdougm #endif
3799*6185db85Sdougm 
3800*6185db85Sdougm 	while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
3801*6185db85Sdougm 	    switch (c) {
3802*6185db85Sdougm 	    case 'h':
3803*6185db85Sdougm 	    case '?':
3804*6185db85Sdougm 		break;
3805*6185db85Sdougm 	    case 'F':
3806*6185db85Sdougm 		protocol = optarg;
3807*6185db85Sdougm 		if (!sa_valid_protocol(protocol)) {
3808*6185db85Sdougm 		    if (format_legacy_path(cmd, MAXPATHLEN,
3809*6185db85Sdougm 						protocol, "unshare") == 0 &&
3810*6185db85Sdougm 			check_legacy_cmd(cmd)) {
3811*6185db85Sdougm 			true_legacy++;
3812*6185db85Sdougm 		    } else {
3813*6185db85Sdougm 			(void) printf(gettext("Invalid file system name\n"));
3814*6185db85Sdougm 			return (SA_INVALID_PROTOCOL);
3815*6185db85Sdougm 		    }
3816*6185db85Sdougm 		}
3817*6185db85Sdougm 		break;
3818*6185db85Sdougm 	    case 'o':
3819*6185db85Sdougm 		options = optarg;
3820*6185db85Sdougm 		argsused++;
3821*6185db85Sdougm 		break;
3822*6185db85Sdougm 	    case 'p':
3823*6185db85Sdougm 		persist = SA_SHARE_PERMANENT;
3824*6185db85Sdougm 		argsused++;
3825*6185db85Sdougm 		break;
3826*6185db85Sdougm 	    default:
3827*6185db85Sdougm 		(void) printf(gettext("usage: %s\n"),
3828*6185db85Sdougm 				sa_get_usage(USAGE_UNSHARE));
3829*6185db85Sdougm 		return (SA_OK);
3830*6185db85Sdougm 	    }
3831*6185db85Sdougm 	}
3832*6185db85Sdougm 
3833*6185db85Sdougm 	/* have the info so construct what is needed */
3834*6185db85Sdougm 	if (optind == argc || (optind + 1) < argc) {
3835*6185db85Sdougm 	    ret = SA_SYNTAX_ERR;
3836*6185db85Sdougm 	} else {
3837*6185db85Sdougm 	    sa_share_t share;
3838*6185db85Sdougm 	    char dir[MAXPATHLEN];
3839*6185db85Sdougm 	    if (true_legacy) {
3840*6185db85Sdougm 		/* if still using legacy share/unshare, exec it */
3841*6185db85Sdougm 		ret = run_legacy_command(cmd, argv);
3842*6185db85Sdougm 		return (ret);
3843*6185db85Sdougm 	    }
3844*6185db85Sdougm 	    sharepath = argv[optind++];
3845*6185db85Sdougm 	    if (realpath(sharepath, dir) == NULL) {
3846*6185db85Sdougm 		ret = SA_NO_SUCH_PATH;
3847*6185db85Sdougm 	    } else {
3848*6185db85Sdougm 		sharepath = dir;
3849*6185db85Sdougm 		share = sa_find_share(sharepath);
3850*6185db85Sdougm 		if (share != NULL) {
3851*6185db85Sdougm 		    ret = sa_disable_share(share, protocol);
3852*6185db85Sdougm 		    if (ret == SA_OK) {
3853*6185db85Sdougm 			if (persist == SA_SHARE_PERMANENT)
3854*6185db85Sdougm 			    ret = sa_remove_share(share);
3855*6185db85Sdougm 			ret = sa_update_config();
3856*6185db85Sdougm 		    }
3857*6185db85Sdougm 		} else {
3858*6185db85Sdougm 		    ret = SA_NOT_SHARED;
3859*6185db85Sdougm 		}
3860*6185db85Sdougm 	    }
3861*6185db85Sdougm 	}
3862*6185db85Sdougm 	switch (ret) {
3863*6185db85Sdougm 	default:
3864*6185db85Sdougm 	    (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
3865*6185db85Sdougm 	    ret = SA_LEGACY_ERR;
3866*6185db85Sdougm 	    break;
3867*6185db85Sdougm 	case SA_SYNTAX_ERR:
3868*6185db85Sdougm 	    (void) printf(gettext("usage: %s\n"),
3869*6185db85Sdougm 				sa_get_usage(USAGE_UNSHARE));
3870*6185db85Sdougm 	    break;
3871*6185db85Sdougm 	case SA_OK:
3872*6185db85Sdougm 	    break;
3873*6185db85Sdougm 	}
3874*6185db85Sdougm 	return (ret);
3875*6185db85Sdougm }
3876*6185db85Sdougm 
3877*6185db85Sdougm /*
3878*6185db85Sdougm  * common commands that implement the sub-commands used by all
3879*6185db85Sdougm  * protcols. The entries are found via the lookup command
3880*6185db85Sdougm  */
3881*6185db85Sdougm 
3882*6185db85Sdougm static sa_command_t commands[] = {
3883*6185db85Sdougm 	{"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
3884*6185db85Sdougm 	{"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
3885*6185db85Sdougm 	{"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
3886*6185db85Sdougm 	{"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
3887*6185db85Sdougm 	{"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
3888*6185db85Sdougm 	{"list", 0, sa_list, USAGE_LIST},
3889*6185db85Sdougm 	{"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
3890*6185db85Sdougm 	{"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
3891*6185db85Sdougm 	{"set", 0, sa_set, USAGE_SET, SVC_SET},
3892*6185db85Sdougm 	{"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
3893*6185db85Sdougm 	{"show", 0, sa_show, USAGE_SHOW},
3894*6185db85Sdougm 	{"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
3895*6185db85Sdougm 	{"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
3896*6185db85Sdougm 		SVC_SET|SVC_ACTION},
3897*6185db85Sdougm 	{"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
3898*6185db85Sdougm 	{"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
3899*6185db85Sdougm 	{"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
3900*6185db85Sdougm 	{NULL, 0, NULL, NULL}
3901*6185db85Sdougm };
3902*6185db85Sdougm 
3903*6185db85Sdougm static char *
3904*6185db85Sdougm sa_get_usage(sa_usage_t index)
3905*6185db85Sdougm {
3906*6185db85Sdougm 	char *ret = NULL;
3907*6185db85Sdougm 	switch (index) {
3908*6185db85Sdougm 	case USAGE_ADD_SHARE:
3909*6185db85Sdougm 	    ret = gettext("add-share [-nth] [-r resource-name] "
3910*6185db85Sdougm 			    "[-d \"description text\"] -s sharepath group");
3911*6185db85Sdougm 	    break;
3912*6185db85Sdougm 	case USAGE_CREATE:
3913*6185db85Sdougm 	    ret = gettext("create [-nvh] [-P proto [-p property=value]] group");
3914*6185db85Sdougm 	    break;
3915*6185db85Sdougm 	case USAGE_DELETE:
3916*6185db85Sdougm 	    ret = gettext("delete [-nvh] [-P proto] [-f] group");
3917*6185db85Sdougm 	    break;
3918*6185db85Sdougm 	case USAGE_DISABLE:
3919*6185db85Sdougm 	    ret = gettext("disable [-nvh] {-a | group ...}");
3920*6185db85Sdougm 	    break;
3921*6185db85Sdougm 	case USAGE_ENABLE:
3922*6185db85Sdougm 	    ret = gettext("enable [-nvh] {-a | group ...}");
3923*6185db85Sdougm 	    break;
3924*6185db85Sdougm 	case USAGE_LIST:
3925*6185db85Sdougm 	    ret = gettext("list [-vh] [-P proto]");
3926*6185db85Sdougm 	    break;
3927*6185db85Sdougm 	case USAGE_MOVE_SHARE:
3928*6185db85Sdougm 	    ret = gettext("move-share [-nvh] -s sharepath destination-group");
3929*6185db85Sdougm 	    break;
3930*6185db85Sdougm 	case USAGE_REMOVE_SHARE:
3931*6185db85Sdougm 	    ret = gettext("remove-share [-fnvh] -s sharepath group");
3932*6185db85Sdougm 	    break;
3933*6185db85Sdougm 	case USAGE_SET:
3934*6185db85Sdougm 	    ret = gettext("set [-nvh] -P proto [-S optspace] "
3935*6185db85Sdougm 				"[-p property=value]* [-s sharepath] group");
3936*6185db85Sdougm 	    break;
3937*6185db85Sdougm 	case USAGE_SET_SECURITY:
3938*6185db85Sdougm 	    ret = gettext("set-security [-nvh] -P proto -S security-type "
3939*6185db85Sdougm 			    "[-p property=value]* group");
3940*6185db85Sdougm 	    break;
3941*6185db85Sdougm 	case USAGE_SET_SHARE:
3942*6185db85Sdougm 	    ret = gettext("set-share [-nh] [-r resource] "
3943*6185db85Sdougm 			    "[-d \"description text\"] -s sharepath group");
3944*6185db85Sdougm 	    break;
3945*6185db85Sdougm 	case USAGE_SHOW:
3946*6185db85Sdougm 	    ret = gettext("show [-pvxh] [-P proto] [group ...]");
3947*6185db85Sdougm 	    break;
3948*6185db85Sdougm 	case USAGE_SHARE:
3949*6185db85Sdougm 	    ret = gettext("share [-F fstype] [-p] [-o optionlist]"
3950*6185db85Sdougm 			    "[-d description] [pathname [resourcename]]");
3951*6185db85Sdougm 	    break;
3952*6185db85Sdougm 	case USAGE_START:
3953*6185db85Sdougm 	    ret = gettext("start [-vh] [-P proto] {-a | group ...}");
3954*6185db85Sdougm 	    break;
3955*6185db85Sdougm 	case USAGE_STOP:
3956*6185db85Sdougm 	    ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
3957*6185db85Sdougm 	    break;
3958*6185db85Sdougm 	case USAGE_UNSET:
3959*6185db85Sdougm 	    ret = gettext("unset [-nvh] -P proto [-S optspace] "
3960*6185db85Sdougm 			    "[-p property]* group");
3961*6185db85Sdougm 	    break;
3962*6185db85Sdougm 	case USAGE_UNSET_SECURITY:
3963*6185db85Sdougm 	    ret = gettext("unset-security [-nvh] -P proto -S security-type "
3964*6185db85Sdougm 				"[-p property]* group");
3965*6185db85Sdougm 	    break;
3966*6185db85Sdougm 	case USAGE_UNSHARE:
3967*6185db85Sdougm 	    ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath");
3968*6185db85Sdougm 	    break;
3969*6185db85Sdougm 	}
3970*6185db85Sdougm 	return (ret);
3971*6185db85Sdougm }
3972*6185db85Sdougm 
3973*6185db85Sdougm /*
3974*6185db85Sdougm  * sa_lookup(cmd, proto)
3975*6185db85Sdougm  *
3976*6185db85Sdougm  * Lookup the sub-command. proto isn't currently used, but it may
3977*6185db85Sdougm  * eventually provide a way to provide protocol specific sub-commands.
3978*6185db85Sdougm  */
3979*6185db85Sdougm 
3980*6185db85Sdougm sa_command_t *
3981*6185db85Sdougm sa_lookup(char *cmd, char *proto)
3982*6185db85Sdougm {
3983*6185db85Sdougm 	int i;
3984*6185db85Sdougm 	size_t len;
3985*6185db85Sdougm #ifdef lint
3986*6185db85Sdougm 	proto = proto;
3987*6185db85Sdougm #endif
3988*6185db85Sdougm 
3989*6185db85Sdougm 	len = strlen(cmd);
3990*6185db85Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
3991*6185db85Sdougm 	    if (strncmp(cmd, commands[i].cmdname, len) == 0)
3992*6185db85Sdougm 		return (&commands[i]);
3993*6185db85Sdougm 	}
3994*6185db85Sdougm 	return (NULL);
3995*6185db85Sdougm }
3996*6185db85Sdougm 
3997*6185db85Sdougm void
3998*6185db85Sdougm sub_command_help(char *proto)
3999*6185db85Sdougm {
4000*6185db85Sdougm 	int i;
4001*6185db85Sdougm #ifdef lint
4002*6185db85Sdougm 	proto = proto;
4003*6185db85Sdougm #endif
4004*6185db85Sdougm 
4005*6185db85Sdougm 	(void) printf(gettext("\tsub-commands:\n"));
4006*6185db85Sdougm 	for (i = 0; commands[i].cmdname != NULL; i++) {
4007*6185db85Sdougm 	    if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
4008*6185db85Sdougm 		(void) printf("\t%s\n",
4009*6185db85Sdougm 				sa_get_usage((sa_usage_t)commands[i].cmdidx));
4010*6185db85Sdougm 	}
4011*6185db85Sdougm }
4012