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