dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / dfs.cmds / sharemgr / commands.c
blobaee432fe08990f63a75df9c8704f56f4c4776894
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <unistd.h>
36 #include <getopt.h>
37 #include <utmpx.h>
38 #include <pwd.h>
39 #include <auth_attr.h>
40 #include <secdb.h>
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <errno.h>
45 #include <libshare.h>
46 #include "sharemgr.h"
47 #include <libscf.h>
48 #include <libxml/tree.h>
49 #include <libintl.h>
50 #include <assert.h>
51 #include <iconv.h>
52 #include <langinfo.h>
53 #include <dirent.h>
55 static char *sa_get_usage(sa_usage_t);
58 * Implementation of the common sub-commands supported by sharemgr.
59 * A number of helper functions are also included.
63 * has_protocol(group, proto)
64 * If the group has an optionset with the specified protocol,
65 * return true (1) otherwise false (0).
67 static int
68 has_protocol(sa_group_t group, char *protocol)
70 sa_optionset_t optionset;
71 int result = 0;
73 optionset = sa_get_optionset(group, protocol);
74 if (optionset != NULL) {
75 result++;
77 return (result);
81 * validresource(name)
83 * Check that name only has valid characters in it. The current valid
84 * set are the printable characters but not including:
85 * " / \ [ ] : | < > + ; , ? * = \t
86 * Note that space is included and there is a maximum length.
88 static int
89 validresource(const char *name)
91 const char *cp;
92 size_t len;
94 if (name == NULL)
95 return (B_FALSE);
97 len = strlen(name);
98 if (len == 0 || len > SA_MAX_RESOURCE_NAME)
99 return (B_FALSE);
101 if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
102 return (B_FALSE);
105 for (cp = name; *cp != '\0'; cp++)
106 if (iscntrl(*cp))
107 return (B_FALSE);
109 return (B_TRUE);
113 * conv_to_utf8(input)
115 * Convert the input string to utf8 from the current locale. If the
116 * conversion fails, use the current locale, it is likely close
117 * enough. For example, the "C" locale is a subset of utf-8. The
118 * return value may be a new string or the original input string.
121 static char *
122 conv_to_utf8(char *input)
124 iconv_t cd;
125 char *inval = input;
126 char *output = input;
127 char *outleft;
128 char *curlocale;
129 size_t bytesleft;
130 size_t size;
131 size_t osize;
132 static int warned = 0;
134 curlocale = nl_langinfo(CODESET);
135 if (curlocale == NULL)
136 curlocale = "C";
137 cd = iconv_open("UTF-8", curlocale);
138 if (cd != NULL && cd != (iconv_t)-1) {
139 size = strlen(input);
140 /* Assume worst case of characters expanding to 4 bytes. */
141 bytesleft = size * 4;
142 output = calloc(bytesleft, 1);
143 if (output != NULL) {
144 outleft = output;
145 /* inval can be modified on return */
146 osize = iconv(cd, (const char **)&inval, &size,
147 &outleft, &bytesleft);
148 if (osize == (size_t)-1 || size != 0) {
149 free(output);
150 output = input;
152 } else {
153 /* Need to return something. */
154 output = input;
156 (void) iconv_close(cd);
157 } else {
158 if (!warned)
159 (void) fprintf(stderr,
160 gettext("Cannot convert to UTF-8 from %s\n"),
161 curlocale ? curlocale : gettext("unknown"));
162 warned = 1;
164 return (output);
168 * conv_from(input)
170 * Convert the input string from utf8 to current locale. If the
171 * conversion isn't supported, just use as is. The return value may be
172 * a new string or the original input string.
175 static char *
176 conv_from_utf8(char *input)
178 iconv_t cd;
179 char *output = input;
180 char *inval = input;
181 char *outleft;
182 char *curlocale;
183 size_t bytesleft;
184 size_t size;
185 size_t osize;
186 static int warned = 0;
188 curlocale = nl_langinfo(CODESET);
189 if (curlocale == NULL)
190 curlocale = "C";
191 cd = iconv_open(curlocale, "UTF-8");
192 if (cd != NULL && cd != (iconv_t)-1) {
193 size = strlen(input);
194 /* Assume worst case of characters expanding to 4 bytes. */
195 bytesleft = size * 4;
196 output = calloc(bytesleft, 1);
197 if (output != NULL) {
198 outleft = output;
199 osize = iconv(cd, (const char **)&inval, &size,
200 &outleft, &bytesleft);
201 if (osize == (size_t)-1 || size != 0)
202 output = input;
203 } else {
204 /* Need to return something. */
205 output = input;
207 (void) iconv_close(cd);
208 } else {
209 if (!warned)
210 (void) fprintf(stderr,
211 gettext("Cannot convert to %s from UTF-8\n"),
212 curlocale ? curlocale : gettext("unknown"));
213 warned = 1;
215 return (output);
219 * print_rsrc_desc(resource, sharedesc)
221 * Print the resource description string after converting from UTF8 to
222 * the current locale. If sharedesc is not NULL and there is no
223 * description on the resource, use sharedesc. sharedesc will already
224 * be converted to UTF8.
227 static void
228 print_rsrc_desc(sa_resource_t resource, char *sharedesc)
230 char *description;
231 char *desc;
233 if (resource == NULL)
234 return;
236 description = sa_get_resource_description(resource);
237 if (description != NULL) {
238 desc = conv_from_utf8(description);
239 if (desc != description) {
240 sa_free_share_description(description);
241 description = desc;
243 } else if (sharedesc != NULL) {
244 description = strdup(sharedesc);
246 if (description != NULL) {
247 (void) printf("\t\"%s\"", description);
248 sa_free_share_description(description);
253 * set_resource_desc(share, description)
255 * Set the share description value after converting the description
256 * string to UTF8 from the current locale.
259 static int
260 set_resource_desc(sa_share_t share, char *description)
262 char *desc;
263 int ret;
265 desc = conv_to_utf8(description);
266 ret = sa_set_resource_description(share, desc);
267 if (description != desc)
268 sa_free_share_description(desc);
269 return (ret);
273 * set_share_desc(share, description)
275 * Set the resource description value after converting the description
276 * string to UTF8 from the current locale.
279 static int
280 set_share_desc(sa_share_t share, char *description)
282 char *desc;
283 int ret;
285 desc = conv_to_utf8(description);
286 ret = sa_set_share_description(share, desc);
287 if (description != desc)
288 sa_free_share_description(desc);
289 return (ret);
293 * add_list(list, item, data, proto)
294 * Adds a new list member that points holds item in the list.
295 * If list is NULL, it starts a new list. The function returns
296 * the first member of the list.
298 struct list *
299 add_list(struct list *listp, void *item, void *data, char *proto)
301 struct list *new, *tmp;
303 new = malloc(sizeof (struct list));
304 if (new != NULL) {
305 new->next = NULL;
306 new->item = item;
307 new->itemdata = data;
308 new->proto = proto;
309 } else {
310 return (listp);
313 if (listp == NULL)
314 return (new);
316 for (tmp = listp; tmp->next != NULL; tmp = tmp->next) {
317 /* get to end of list */
319 tmp->next = new;
320 return (listp);
324 * free_list(list)
325 * Given a list, free all the members of the list;
327 static void
328 free_list(struct list *listp)
330 struct list *tmp;
331 while (listp != NULL) {
332 tmp = listp;
333 listp = listp->next;
334 free(tmp);
339 * check_authorization(instname, which)
341 * Checks to see if the specific type of authorization in which is
342 * enabled for the user in this SMF service instance.
345 static int
346 check_authorization(char *instname, int which)
348 scf_handle_t *handle = NULL;
349 scf_simple_prop_t *prop = NULL;
350 char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
351 char *authstr = NULL;
352 ssize_t numauths;
353 int ret = B_TRUE;
354 uid_t uid;
355 struct passwd *pw = NULL;
357 uid = getuid();
358 pw = getpwuid(uid);
359 if (pw == NULL) {
360 ret = B_FALSE;
361 } else {
363 * Since names are restricted to SA_MAX_NAME_LEN won't
364 * overflow.
366 (void) snprintf(svcstring, sizeof (svcstring), "%s:%s",
367 SA_SVC_FMRI_BASE, instname);
368 handle = scf_handle_create(SCF_VERSION);
369 if (handle != NULL) {
370 if (scf_handle_bind(handle) == 0) {
371 switch (which) {
372 case SVC_SET:
373 prop = scf_simple_prop_get(handle,
374 svcstring, "general",
375 SVC_AUTH_VALUE);
376 break;
377 case SVC_ACTION:
378 prop = scf_simple_prop_get(handle,
379 svcstring, "general",
380 SVC_AUTH_ACTION);
381 break;
386 /* make sure we have an authorization string property */
387 if (prop != NULL) {
388 int i;
389 numauths = scf_simple_prop_numvalues(prop);
390 for (ret = 0, i = 0; i < numauths; i++) {
391 authstr = scf_simple_prop_next_astring(prop);
392 if (authstr != NULL) {
393 /* check if this user has one of the strings */
394 if (chkauthattr(authstr, pw->pw_name)) {
395 ret = 1;
396 break;
400 endauthattr();
401 scf_simple_prop_free(prop);
402 } else {
403 /* no authorization string defined */
404 ret = 0;
406 if (handle != NULL)
407 scf_handle_destroy(handle);
408 return (ret);
412 * check_authorizations(instname, flags)
414 * check all the needed authorizations for the user in this service
415 * instance. Return value of 1(true) or 0(false) indicates whether
416 * there are authorizations for the user or not.
419 static int
420 check_authorizations(char *instname, int flags)
422 int ret1 = 0;
423 int ret2 = 0;
424 int ret;
426 if (flags & SVC_SET)
427 ret1 = check_authorization(instname, SVC_SET);
428 if (flags & SVC_ACTION)
429 ret2 = check_authorization(instname, SVC_ACTION);
430 switch (flags) {
431 case SVC_ACTION:
432 ret = ret2;
433 break;
434 case SVC_SET:
435 ret = ret1;
436 break;
437 case SVC_ACTION|SVC_SET:
438 ret = ret1 & ret2;
439 break;
440 default:
441 /* if not flags set, we assume we don't need authorizations */
442 ret = 1;
444 return (ret);
448 * notify_or_enable_share(share, protocol)
450 * Since some protocols don't want an "enable" when properties change,
451 * this function will use the protocol specific notify function
452 * first. If that fails, it will then attempt to use the
453 * sa_enable_share(). "protocol" is the protocol that was specified
454 * on the command line.
456 static void
457 notify_or_enable_share(sa_share_t share, char *protocol)
459 sa_group_t group;
460 sa_optionset_t opt;
461 int ret = SA_OK;
462 char *path;
463 char *groupproto;
464 sa_share_t parent = share;
466 /* If really a resource, get parent share */
467 if (!sa_is_share(share)) {
468 parent = sa_get_resource_parent((sa_resource_t)share);
472 * Now that we've got a share in "parent", make sure it has a path.
474 path = sa_get_share_attr(parent, "path");
475 if (path == NULL)
476 return;
478 group = sa_get_parent_group(parent);
480 if (group == NULL) {
481 sa_free_attr_string(path);
482 return;
484 for (opt = sa_get_optionset(group, NULL);
485 opt != NULL;
486 opt = sa_get_next_optionset(opt)) {
487 groupproto = sa_get_optionset_attr(opt, "type");
488 if (groupproto == NULL ||
489 (protocol != NULL && strcmp(groupproto, protocol) != 0)) {
490 if (groupproto != NULL)
491 sa_free_attr_string(groupproto);
492 continue;
494 if (sa_is_share(share)) {
495 if ((ret = sa_proto_change_notify(share,
496 groupproto)) != SA_OK) {
497 ret = sa_enable_share(share, groupproto);
498 if (ret != SA_OK) {
499 (void) printf(
500 gettext("Could not reenable"
501 " share %s: %s\n"),
502 path, sa_errorstr(ret));
505 } else {
506 /* Must be a resource */
507 if ((ret = sa_proto_notify_resource(share,
508 groupproto)) != SA_OK) {
509 ret = sa_enable_resource(share, groupproto);
510 if (ret != SA_OK) {
511 (void) printf(
512 gettext("Could not "
513 "reenable resource %s: "
514 "%s\n"), path,
515 sa_errorstr(ret));
519 sa_free_attr_string(groupproto);
521 sa_free_attr_string(path);
525 * enable_group(group, updateproto, notify, proto)
527 * enable all the shares in the specified group. This is a helper for
528 * enable_all_groups in order to simplify regular and subgroup (zfs)
529 * enabling. Group has already been checked for non-NULL. If notify
530 * is non-zero, attempt to use the notify interface rather than
531 * enable.
533 static void
534 enable_group(sa_group_t group, char *updateproto, int notify, char *proto)
536 sa_share_t share;
538 /* If the protocol isn't enabled for this group skip it */
539 if (!has_protocol(group, proto))
540 return;
542 for (share = sa_get_share(group, NULL);
543 share != NULL;
544 share = sa_get_next_share(share)) {
545 if (updateproto != NULL)
546 (void) sa_update_legacy(share, updateproto);
547 if (notify)
548 notify_or_enable_share(share, proto);
549 else
550 (void) sa_enable_share(share, proto);
555 * isenabled(group)
557 * Returns B_TRUE if the group is enabled or B_FALSE if it isn't.
558 * Moved to separate function to reduce clutter in the code.
561 static int
562 isenabled(sa_group_t group)
564 char *state;
565 int ret = B_FALSE;
567 if (group != NULL) {
568 state = sa_get_group_attr(group, "state");
569 if (state != NULL) {
571 if (strcmp(state, "enabled") == 0)
572 ret = B_TRUE;
573 sa_free_attr_string(state);
576 return (ret);
580 * enable_all_groups(list, setstate, online, updateproto)
582 * Given a list of groups, enable each one found. If updateproto is
583 * not NULL, then update all the shares for the protocol that was
584 * passed in. If enable is non-zero, tell enable_group to try the
585 * notify interface since this is a property change.
587 static int
588 enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
589 int online, char *updateproto, int enable)
591 int ret;
592 char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
593 char *state;
594 char *name;
595 char *zfs = NULL;
596 sa_group_t group;
597 sa_group_t subgroup;
599 for (ret = SA_OK; work != NULL; work = work->next) {
600 group = (sa_group_t)work->item;
603 * If setstate == TRUE, then make sure to set
604 * enabled. This needs to be done here in order for
605 * the isenabled check to succeed on a newly enabled
606 * group.
608 if (setstate == B_TRUE) {
609 ret = sa_set_group_attr(group, "state", "enabled");
610 if (ret != SA_OK)
611 break;
615 * Check to see if group is enabled. If it isn't, skip
616 * the rest. We don't want shares starting if the
617 * group is disabled. The properties may have been
618 * updated, but there won't be a change until the
619 * group is enabled.
621 if (!isenabled(group))
622 continue;
624 /* if itemdata != NULL then a single share */
625 if (work->itemdata != NULL) {
626 if (enable) {
627 if (work->itemdata != NULL)
628 notify_or_enable_share(work->itemdata,
629 updateproto);
630 else
631 ret = SA_CONFIG_ERR;
632 } else {
633 if (sa_is_share(work->itemdata)) {
634 ret = sa_enable_share(
635 (sa_share_t)work->itemdata,
636 updateproto);
637 } else {
638 ret = sa_enable_resource(
639 (sa_resource_t)work->itemdata,
640 updateproto);
644 if (ret != SA_OK)
645 break;
647 /* if itemdata == NULL then the whole group */
648 if (work->itemdata == NULL) {
649 zfs = sa_get_group_attr(group, "zfs");
651 * If the share is managed by ZFS, don't
652 * update any of the protocols since ZFS is
653 * handling this. Updateproto will contain
654 * the name of the protocol that we want to
655 * update legacy files for.
657 enable_group(group, zfs == NULL ? updateproto : NULL,
658 enable, work->proto);
659 if (zfs != NULL)
660 sa_free_attr_string(zfs);
662 for (subgroup = sa_get_sub_group(group);
663 subgroup != NULL;
664 subgroup = sa_get_next_group(subgroup)) {
665 /* never update legacy for ZFS subgroups */
666 enable_group(subgroup, NULL, enable,
667 work->proto);
670 if (online) {
671 zfs = sa_get_group_attr(group, "zfs");
672 name = sa_get_group_attr(group, "name");
673 if (name != NULL) {
674 if (zfs == NULL) {
675 (void) snprintf(instance,
676 sizeof (instance), "%s:%s",
677 SA_SVC_FMRI_BASE, name);
678 state = smf_get_state(instance);
679 if (state == NULL ||
680 strcmp(state, "online") != 0) {
681 (void) smf_enable_instance(
682 instance, 0);
683 free(state);
685 } else {
686 sa_free_attr_string(zfs);
687 zfs = NULL;
689 if (name != NULL)
690 sa_free_attr_string(name);
694 if (ret == SA_OK) {
695 ret = sa_update_config(handle);
697 return (ret);
701 * chk_opt(optlistp, security, proto)
703 * Do a sanity check on the optlist provided for the protocol. This
704 * is a syntax check and verification that the property is either a
705 * general or specific to a names optionset.
708 static int
709 chk_opt(struct options *optlistp, int security, char *proto)
711 struct options *optlist;
712 char *sep = "";
713 int notfirst = 0;
714 int ret;
716 for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
717 char *optname;
719 optname = optlist->optname;
720 ret = OPT_ADD_OK;
721 /* extract property/value pair */
722 if (sa_is_security(optname, proto)) {
723 if (!security)
724 ret = OPT_ADD_SECURITY;
725 } else {
726 if (security)
727 ret = OPT_ADD_PROPERTY;
729 if (ret != OPT_ADD_OK) {
730 if (notfirst == 0)
731 (void) printf(
732 gettext("Property syntax error: "));
733 switch (ret) {
734 case OPT_ADD_SYNTAX:
735 (void) printf(gettext("%ssyntax error: %s"),
736 sep, optname);
737 sep = ", ";
738 break;
739 case OPT_ADD_SECURITY:
740 (void) printf(gettext("%s%s requires -S"),
741 optname, sep);
742 sep = ", ";
743 break;
744 case OPT_ADD_PROPERTY:
745 (void) printf(
746 gettext("%s%s not supported with -S"),
747 optname, sep);
748 sep = ", ";
749 break;
751 notfirst++;
754 if (notfirst) {
755 (void) printf("\n");
756 ret = SA_SYNTAX_ERR;
758 return (ret);
762 * free_opt(optlist)
763 * Free the specified option list.
765 static void
766 free_opt(struct options *optlist)
768 struct options *nextopt;
769 while (optlist != NULL) {
770 nextopt = optlist->next;
771 free(optlist);
772 optlist = nextopt;
777 * check property list for valid properties
778 * A null value is a remove which is always valid.
780 static int
781 valid_options(sa_handle_t handle, struct options *optlist, char *proto,
782 void *object, char *sec)
784 int ret = SA_OK;
785 struct options *cur;
786 sa_property_t prop;
787 sa_optionset_t parent = NULL;
789 if (object != NULL) {
790 if (sec == NULL)
791 parent = sa_get_optionset(object, proto);
792 else
793 parent = sa_get_security(object, sec, proto);
796 for (cur = optlist; cur != NULL; cur = cur->next) {
797 if (cur->optvalue == NULL)
798 continue;
799 prop = sa_create_property(cur->optname, cur->optvalue);
800 if (prop == NULL)
801 ret = SA_NO_MEMORY;
802 if (ret != SA_OK ||
803 (ret = sa_valid_property(handle, parent, proto, prop)) !=
804 SA_OK) {
805 (void) printf(
806 gettext("Could not add property %s: %s\n"),
807 cur->optname, sa_errorstr(ret));
809 (void) sa_remove_property(prop);
811 return (ret);
815 * add_optionset(group, optlist, protocol, *err)
816 * Add the options in optlist to an optionset and then add the optionset
817 * to the group.
819 * The return value indicates if there was a "change" while errors are
820 * returned via the *err parameters.
822 static int
823 add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
825 sa_optionset_t optionset;
826 int ret = SA_OK;
827 int result = B_FALSE;
828 sa_handle_t handle;
830 optionset = sa_get_optionset(group, proto);
831 if (optionset == NULL) {
832 optionset = sa_create_optionset(group, proto);
833 if (optionset == NULL)
834 ret = SA_NO_MEMORY;
835 result = B_TRUE; /* adding a protocol is a change */
837 if (optionset == NULL) {
838 ret = SA_NO_MEMORY;
839 goto out;
841 handle = sa_find_group_handle(group);
842 if (handle == NULL) {
843 ret = SA_CONFIG_ERR;
844 goto out;
846 while (optlist != NULL) {
847 sa_property_t prop;
848 prop = sa_get_property(optionset, optlist->optname);
849 if (prop == NULL) {
851 * add the property, but only if it is
852 * a non-NULL or non-zero length value
854 if (optlist->optvalue != NULL) {
855 prop = sa_create_property(optlist->optname,
856 optlist->optvalue);
857 if (prop != NULL) {
858 ret = sa_valid_property(handle,
859 optionset, proto, prop);
860 if (ret != SA_OK) {
861 (void) sa_remove_property(prop);
862 (void) printf(gettext("Could "
863 "not add property "
864 "%s: %s\n"),
865 optlist->optname,
866 sa_errorstr(ret));
869 if (ret == SA_OK) {
870 ret = sa_add_property(optionset, prop);
871 if (ret != SA_OK) {
872 (void) printf(gettext(
873 "Could not add property "
874 "%s: %s\n"),
875 optlist->optname,
876 sa_errorstr(ret));
877 } else {
878 /* there was a change */
879 result = B_TRUE;
883 } else {
884 ret = sa_update_property(prop, optlist->optvalue);
885 /* should check to see if value changed */
886 if (ret != SA_OK) {
887 (void) printf(gettext("Could not update "
888 "property %s: %s\n"), optlist->optname,
889 sa_errorstr(ret));
890 } else {
891 result = B_TRUE;
894 optlist = optlist->next;
896 ret = sa_commit_properties(optionset, 0);
898 out:
899 if (err != NULL)
900 *err = ret;
901 return (result);
905 * resource_compliant(group)
907 * Go through all the shares in the group. Assume compliant, but if
908 * any share doesn't have at least one resource name, it isn't
909 * compliant.
911 static int
912 resource_compliant(sa_group_t group)
914 sa_share_t share;
916 for (share = sa_get_share(group, NULL); share != NULL;
917 share = sa_get_next_share(share)) {
918 if (sa_get_share_resource(share, NULL) == NULL) {
919 return (B_FALSE);
922 return (B_TRUE);
926 * fix_path(path)
928 * change all illegal characters to something else. For now, all get
929 * converted to '_' and the leading '/' is stripped off. This is used
930 * to construct an resource name (SMB share name) that is valid.
931 * Caller must pass a valid path.
933 static void
934 fix_path(char *path)
936 char *cp;
937 size_t len;
939 assert(path != NULL);
941 /* make sure we are appropriate length */
942 cp = path + 1; /* skip leading slash */
943 while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
944 cp = strchr(cp, '/');
945 if (cp != NULL)
946 cp++;
948 /* two cases - cp == NULL and cp is substring of path */
949 if (cp == NULL) {
950 /* just take last SA_MAX_RESOURCE_NAME chars */
951 len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
952 (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
953 path[SA_MAX_RESOURCE_NAME] = '\0';
954 } else {
955 len = strlen(cp) + 1;
956 (void) memmove(path, cp, len);
960 * Don't want any of the characters that are not allowed
961 * in and SMB share name. Replace them with '_'.
963 while (*path) {
964 switch (*path) {
965 case '/':
966 case '"':
967 case '\\':
968 case '[':
969 case ']':
970 case ':':
971 case '|':
972 case '<':
973 case '>':
974 case '+':
975 case ';':
976 case ',':
977 case '?':
978 case '*':
979 case '=':
980 case '\t':
981 *path = '_';
982 break;
984 path++;
989 * name_adjust(path, count)
991 * Add a ~<count> in place of last few characters. The total number of
992 * characters is dependent on count.
994 #define MAX_MANGLE_NUMBER 10000
996 static int
997 name_adjust(char *path, int count)
999 size_t len;
1001 len = strlen(path) - 2;
1002 if (count > 10)
1003 len--;
1004 if (count > 100)
1005 len--;
1006 if (count > 1000)
1007 len--;
1008 if (len > 0)
1009 (void) sprintf(path + len, "~%d", count);
1010 else
1011 return (SA_BAD_VALUE);
1013 return (SA_OK);
1017 * make_resources(group)
1019 * Go through all the shares in the group and make them have resource
1020 * names.
1022 static void
1023 make_resources(sa_group_t group)
1025 sa_share_t share;
1026 int count;
1027 int err = SA_OK;
1029 for (share = sa_get_share(group, NULL); share != NULL;
1030 share = sa_get_next_share(share)) {
1031 /* Skip those with resources */
1032 if (sa_get_share_resource(share, NULL) == NULL) {
1033 char *path;
1034 path = sa_get_share_attr(share, "path");
1035 if (path == NULL)
1036 continue;
1037 fix_path(path);
1038 count = 0; /* reset for next resource */
1039 while (sa_add_resource(share, path,
1040 SA_SHARE_PERMANENT, &err) == NULL &&
1041 err == SA_DUPLICATE_NAME) {
1042 int ret;
1043 ret = name_adjust(path, count);
1044 count++;
1045 if (ret != SA_OK ||
1046 count >= MAX_MANGLE_NUMBER) {
1047 (void) printf(gettext(
1048 "Cannot create resource name for"
1049 " path: %s\n"), path);
1050 break;
1053 sa_free_attr_string(path);
1059 * check_valid_group(group, protocol)
1061 * Check to see that the group should have the protocol added (if
1062 * there is one specified).
1065 static int
1066 check_valid_group(sa_group_t group, char *groupname, char *protocol)
1069 if (protocol != NULL) {
1070 if (has_protocol(group, protocol)) {
1071 (void) printf(gettext(
1072 "Group \"%s\" already exists"
1073 " with protocol %s\n"), groupname,
1074 protocol);
1075 return (SA_DUPLICATE_NAME);
1076 } else if (strcmp(groupname, "default") == 0 &&
1077 strcmp(protocol, "nfs") != 0) {
1078 (void) printf(gettext(
1079 "Group \"%s\" only allows protocol "
1080 "\"%s\"\n"), groupname, "nfs");
1081 return (SA_INVALID_PROTOCOL);
1083 } else {
1084 /* must add new protocol */
1085 (void) printf(gettext(
1086 "Group already exists and no protocol "
1087 "specified.\n"));
1088 return (SA_DUPLICATE_NAME);
1090 return (SA_OK);
1094 * enforce_featureset(group, protocol, dryrun, force)
1096 * Check the protocol featureset against the group and enforce any
1097 * rules that might be imposed.
1100 static int
1101 enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun,
1102 boolean_t force)
1104 uint64_t features;
1106 if (protocol == NULL)
1107 return (SA_OK);
1110 * First check to see if specified protocol is one we want to
1111 * allow on a group. Only server protocols are allowed here.
1113 features = sa_proto_get_featureset(protocol);
1114 if (!(features & SA_FEATURE_SERVER)) {
1115 (void) printf(
1116 gettext("Protocol \"%s\" not supported.\n"), protocol);
1117 return (SA_INVALID_PROTOCOL);
1121 * Check to see if the new protocol is one that requires
1122 * resource names and make sure we are compliant before
1123 * proceeding.
1125 if ((features & SA_FEATURE_RESOURCE) &&
1126 !resource_compliant(group)) {
1127 if (force && !dryrun) {
1128 make_resources(group);
1129 } else {
1130 (void) printf(
1131 gettext("Protocol requires resource names to be "
1132 "set: %s\n"), protocol);
1133 return (SA_RESOURCE_REQUIRED);
1136 return (SA_OK);
1140 * set_all_protocols(group)
1142 * Get the list of all protocols and add all server protocols to the
1143 * group.
1146 static int
1147 set_all_protocols(sa_group_t group)
1149 char **protolist;
1150 int numprotos, i;
1151 uint64_t features;
1152 sa_optionset_t optionset;
1153 int ret = SA_OK;
1156 * Now make sure we really want to put this protocol on a
1157 * group. Only server protocols can go here.
1159 numprotos = sa_get_protocols(&protolist);
1160 for (i = 0; i < numprotos; i++) {
1161 features = sa_proto_get_featureset(protolist[i]);
1162 if (features & SA_FEATURE_SERVER) {
1163 optionset = sa_create_optionset(group, protolist[i]);
1164 if (optionset == NULL) {
1165 ret = SA_NO_MEMORY;
1166 break;
1171 free(protolist);
1173 return (ret);
1177 * sa_create(flags, argc, argv)
1178 * create a new group
1179 * this may or may not have a protocol associated with it.
1180 * No protocol means "all" protocols in this case.
1182 static int
1183 sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
1185 char *groupname;
1187 sa_group_t group;
1188 boolean_t force = B_FALSE;
1189 boolean_t verbose = B_FALSE;
1190 boolean_t dryrun = B_FALSE;
1191 int c;
1192 char *protocol = NULL;
1193 int ret = SA_OK;
1194 struct options *optlist = NULL;
1195 int err = SA_OK;
1196 int auth;
1197 boolean_t created = B_FALSE;
1199 while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) {
1200 switch (c) {
1201 case 'f':
1202 force = B_TRUE;
1203 break;
1204 case 'v':
1205 verbose = B_TRUE;
1206 break;
1207 case 'n':
1208 dryrun = B_TRUE;
1209 break;
1210 case 'P':
1211 if (protocol != NULL) {
1212 (void) printf(gettext("Specifying "
1213 "multiple protocols "
1214 "not supported: %s\n"), protocol);
1215 return (SA_SYNTAX_ERR);
1217 protocol = optarg;
1218 if (sa_valid_protocol(protocol))
1219 break;
1220 (void) printf(gettext(
1221 "Invalid protocol specified: %s\n"), protocol);
1222 return (SA_INVALID_PROTOCOL);
1223 case 'p':
1224 ret = add_opt(&optlist, optarg, 0);
1225 switch (ret) {
1226 case OPT_ADD_SYNTAX:
1227 (void) printf(gettext(
1228 "Property syntax error for property: %s\n"),
1229 optarg);
1230 return (SA_SYNTAX_ERR);
1231 case OPT_ADD_SECURITY:
1232 (void) printf(gettext(
1233 "Security properties need "
1234 "to be set with set-security: %s\n"),
1235 optarg);
1236 return (SA_SYNTAX_ERR);
1237 default:
1238 break;
1240 break;
1241 case 'h':
1242 /* optopt on valid arg isn't defined */
1243 optopt = c;
1244 /*FALLTHROUGH*/
1245 case '?':
1246 default:
1248 * Since a bad option gets to here, sort it
1249 * out and return a syntax error return value
1250 * if necessary.
1252 switch (optopt) {
1253 default:
1254 err = SA_SYNTAX_ERR;
1255 break;
1256 case 'h':
1257 case '?':
1258 break;
1260 (void) printf(gettext("usage: %s\n"),
1261 sa_get_usage(USAGE_CREATE));
1262 return (err);
1266 if (optind >= argc) {
1267 (void) printf(gettext("usage: %s\n"),
1268 sa_get_usage(USAGE_CREATE));
1269 (void) printf(gettext("\tgroup must be specified.\n"));
1270 return (SA_BAD_PATH);
1273 if ((optind + 1) < argc) {
1274 (void) printf(gettext("usage: %s\n"),
1275 sa_get_usage(USAGE_CREATE));
1276 (void) printf(gettext("\textraneous group(s) at end\n"));
1277 return (SA_SYNTAX_ERR);
1280 if (protocol == NULL && optlist != NULL) {
1281 /* lookup default protocol */
1282 (void) printf(gettext("usage: %s\n"),
1283 sa_get_usage(USAGE_CREATE));
1284 (void) printf(gettext("\tprotocol must be specified "
1285 "with properties\n"));
1286 return (SA_INVALID_PROTOCOL);
1289 if (optlist != NULL)
1290 ret = chk_opt(optlist, 0, protocol);
1291 if (ret == OPT_ADD_SECURITY) {
1292 (void) printf(gettext("Security properties not "
1293 "supported with create\n"));
1294 return (SA_SYNTAX_ERR);
1298 * If a group already exists, we can only add a new protocol
1299 * to it and not create a new one or add the same protocol
1300 * again.
1303 groupname = argv[optind];
1305 auth = check_authorizations(groupname, flags);
1307 group = sa_get_group(handle, groupname);
1308 if (group != NULL) {
1309 /* group exists so must be a protocol add */
1310 ret = check_valid_group(group, groupname, protocol);
1311 } else {
1313 * is it a valid name? Must comply with SMF instance
1314 * name restrictions.
1316 if (!sa_valid_group_name(groupname)) {
1317 ret = SA_INVALID_NAME;
1318 (void) printf(gettext("Invalid group name: %s\n"),
1319 groupname);
1322 if (ret == SA_OK) {
1323 /* check protocol vs optlist */
1324 if (optlist != NULL) {
1325 /* check options, if any, for validity */
1326 ret = valid_options(handle, optlist, protocol,
1327 group, NULL);
1330 if (ret == SA_OK && !dryrun) {
1331 if (group == NULL) {
1332 group = sa_create_group(handle, (char *)groupname,
1333 &err);
1334 created = B_TRUE;
1336 if (group != NULL) {
1337 sa_optionset_t optionset;
1340 * Check group and protocol against featureset
1341 * requirements.
1343 ret = enforce_featureset(group, protocol,
1344 dryrun, force);
1345 if (ret != SA_OK)
1346 goto err;
1349 * So far so good. Now add the required
1350 * optionset(s) to the group.
1352 if (optlist != NULL) {
1353 (void) add_optionset(group, optlist, protocol,
1354 &ret);
1355 } else if (protocol != NULL) {
1356 optionset = sa_create_optionset(group,
1357 protocol);
1358 if (optionset == NULL)
1359 ret = SA_NO_MEMORY;
1360 } else if (protocol == NULL) {
1361 /* default group create so add all protocols */
1362 ret = set_all_protocols(group);
1365 * We have a group and legal additions
1367 if (ret == SA_OK) {
1369 * Commit to configuration for protocols that
1370 * need to do block updates. For NFS, this
1371 * doesn't do anything but it will be run for
1372 * all protocols that implement the
1373 * appropriate plugin.
1375 ret = sa_update_config(handle);
1376 } else {
1377 if (group != NULL)
1378 (void) sa_remove_group(group);
1380 } else {
1381 ret = err;
1382 (void) printf(gettext("Could not create group: %s\n"),
1383 sa_errorstr(ret));
1386 if (dryrun && ret == SA_OK && !auth && verbose) {
1387 (void) printf(gettext("Command would fail: %s\n"),
1388 sa_errorstr(SA_NO_PERMISSION));
1389 ret = SA_NO_PERMISSION;
1391 err:
1392 if (ret != SA_OK && created)
1393 ret = sa_remove_group(group);
1395 free_opt(optlist);
1396 return (ret);
1400 * group_status(group)
1402 * return the current status (enabled/disabled) of the group.
1405 static char *
1406 group_status(sa_group_t group)
1408 char *state;
1409 int enabled = 0;
1411 state = sa_get_group_attr(group, "state");
1412 if (state != NULL) {
1413 if (strcmp(state, "enabled") == 0) {
1414 enabled = 1;
1416 sa_free_attr_string(state);
1418 return (enabled ? "enabled" : "disabled");
1422 * sa_delete(flags, argc, argv)
1424 * Delete a group.
1427 static int
1428 sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
1430 char *groupname;
1431 sa_group_t group;
1432 sa_share_t share;
1433 int verbose = 0;
1434 int dryrun = 0;
1435 int force = 0;
1436 int c;
1437 char *protocol = NULL;
1438 char *sectype = NULL;
1439 int ret = SA_OK;
1440 int auth;
1442 while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
1443 switch (c) {
1444 case 'v':
1445 verbose++;
1446 break;
1447 case 'n':
1448 dryrun++;
1449 break;
1450 case 'P':
1451 if (protocol != NULL) {
1452 (void) printf(gettext("Specifying "
1453 "multiple protocols "
1454 "not supported: %s\n"), protocol);
1455 return (SA_SYNTAX_ERR);
1457 protocol = optarg;
1458 if (!sa_valid_protocol(protocol)) {
1459 (void) printf(gettext("Invalid protocol "
1460 "specified: %s\n"), protocol);
1461 return (SA_INVALID_PROTOCOL);
1463 break;
1464 case 'S':
1465 if (sectype != NULL) {
1466 (void) printf(gettext("Specifying "
1467 "multiple property "
1468 "spaces not supported: %s\n"), sectype);
1469 return (SA_SYNTAX_ERR);
1471 sectype = optarg;
1472 break;
1473 case 'f':
1474 force++;
1475 break;
1476 case 'h':
1477 /* optopt on valid arg isn't defined */
1478 optopt = c;
1479 /*FALLTHROUGH*/
1480 case '?':
1481 default:
1483 * Since a bad option gets to here, sort it
1484 * out and return a syntax error return value
1485 * if necessary.
1487 switch (optopt) {
1488 default:
1489 ret = SA_SYNTAX_ERR;
1490 break;
1491 case 'h':
1492 case '?':
1493 break;
1495 (void) printf(gettext("usage: %s\n"),
1496 sa_get_usage(USAGE_DELETE));
1497 return (ret);
1501 if (optind >= argc) {
1502 (void) printf(gettext("usage: %s\n"),
1503 sa_get_usage(USAGE_DELETE));
1504 (void) printf(gettext("\tgroup must be specified.\n"));
1505 return (SA_SYNTAX_ERR);
1508 if ((optind + 1) < argc) {
1509 (void) printf(gettext("usage: %s\n"),
1510 sa_get_usage(USAGE_DELETE));
1511 (void) printf(gettext("\textraneous group(s) at end\n"));
1512 return (SA_SYNTAX_ERR);
1515 if (sectype != NULL && protocol == NULL) {
1516 (void) printf(gettext("usage: %s\n"),
1517 sa_get_usage(USAGE_DELETE));
1518 (void) printf(gettext("\tsecurity requires protocol to be "
1519 "specified.\n"));
1520 return (SA_SYNTAX_ERR);
1524 * Determine if the group already exists since it must in
1525 * order to be removed.
1527 * We can delete when:
1529 * - group is empty
1530 * - force flag is set
1531 * - if protocol specified, only delete the protocol
1534 groupname = argv[optind];
1535 group = sa_get_group(handle, groupname);
1536 if (group == NULL) {
1537 ret = SA_NO_SUCH_GROUP;
1538 goto done;
1540 auth = check_authorizations(groupname, flags);
1541 if (protocol == NULL) {
1542 share = sa_get_share(group, NULL);
1543 if (share != NULL)
1544 ret = SA_BUSY;
1545 if (share == NULL || (share != NULL && force == 1)) {
1546 ret = SA_OK;
1547 if (!dryrun) {
1548 while (share != NULL) {
1549 sa_share_t next_share;
1550 next_share = sa_get_next_share(share);
1552 * need to do the disable of
1553 * each share, but don't
1554 * actually do anything on a
1555 * dryrun.
1557 ret = sa_disable_share(share, NULL);
1558 ret = sa_remove_share(share);
1559 share = next_share;
1561 ret = sa_remove_group(group);
1564 /* Commit to configuration if not a dryrun */
1565 if (!dryrun && ret == SA_OK) {
1566 ret = sa_update_config(handle);
1568 } else {
1569 /* a protocol delete */
1570 sa_optionset_t optionset;
1571 sa_security_t security;
1572 if (sectype != NULL) {
1573 /* only delete specified security */
1574 security = sa_get_security(group, sectype, protocol);
1575 if (security != NULL && !dryrun)
1576 ret = sa_destroy_security(security);
1577 else
1578 ret = SA_INVALID_PROTOCOL;
1579 } else {
1580 optionset = sa_get_optionset(group, protocol);
1581 if (optionset != NULL && !dryrun) {
1583 * have an optionset with
1584 * protocol to delete
1586 ret = sa_destroy_optionset(optionset);
1588 * Now find all security sets
1589 * for the protocol and remove
1590 * them. Don't remove other
1591 * protocols.
1593 for (security =
1594 sa_get_security(group, NULL, NULL);
1595 ret == SA_OK && security != NULL;
1596 security = sa_get_next_security(security)) {
1597 char *secprot;
1598 secprot = sa_get_security_attr(security,
1599 "type");
1600 if (secprot != NULL &&
1601 strcmp(secprot, protocol) == 0)
1602 ret = sa_destroy_security(
1603 security);
1604 if (secprot != NULL)
1605 sa_free_attr_string(secprot);
1607 } else {
1608 if (!dryrun)
1609 ret = SA_INVALID_PROTOCOL;
1613 * With the protocol items removed, make sure that all
1614 * the shares are updated in the legacy files, if
1615 * necessary.
1617 for (share = sa_get_share(group, NULL);
1618 share != NULL;
1619 share = sa_get_next_share(share)) {
1620 (void) sa_delete_legacy(share, protocol);
1624 done:
1625 if (ret != SA_OK) {
1626 (void) printf(gettext("Could not delete group: %s\n"),
1627 sa_errorstr(ret));
1628 } else if (dryrun && !auth && verbose) {
1629 (void) printf(gettext("Command would fail: %s\n"),
1630 sa_errorstr(SA_NO_PERMISSION));
1632 return (ret);
1636 * strndupr(*buff, str, buffsize)
1638 * used with small strings to duplicate and possibly increase the
1639 * buffer size of a string.
1641 static char *
1642 strndupr(char *buff, char *str, int *buffsize)
1644 int limit;
1645 char *orig_buff = buff;
1647 if (buff == NULL) {
1648 buff = (char *)malloc(64);
1649 if (buff == NULL)
1650 return (NULL);
1651 *buffsize = 64;
1652 buff[0] = '\0';
1654 limit = strlen(buff) + strlen(str) + 1;
1655 if (limit > *buffsize) {
1656 limit = *buffsize = *buffsize + ((limit / 64) + 64);
1657 buff = realloc(buff, limit);
1659 if (buff != NULL) {
1660 (void) strcat(buff, str);
1661 } else {
1662 /* if it fails, fail it hard */
1663 free(orig_buff);
1665 return (buff);
1669 * group_proto(group)
1671 * return a string of all the protocols (space separated) associated
1672 * with this group.
1675 static char *
1676 group_proto(sa_group_t group)
1678 sa_optionset_t optionset;
1679 char *proto;
1680 char *buff = NULL;
1681 int buffsize = 0;
1682 int addspace = 0;
1684 * get the protocol list by finding the optionsets on this
1685 * group and extracting the type value. The initial call to
1686 * strndupr() initailizes buff.
1688 buff = strndupr(buff, "", &buffsize);
1689 if (buff != NULL) {
1690 for (optionset = sa_get_optionset(group, NULL);
1691 optionset != NULL && buff != NULL;
1692 optionset = sa_get_next_optionset(optionset)) {
1694 * extract out the protocol type from this optionset
1695 * and append it to the buffer "buff". strndupr() will
1696 * reallocate space as necessay.
1698 proto = sa_get_optionset_attr(optionset, "type");
1699 if (proto != NULL) {
1700 if (addspace++)
1701 buff = strndupr(buff, " ", &buffsize);
1702 buff = strndupr(buff, proto, &buffsize);
1703 sa_free_attr_string(proto);
1707 return (buff);
1711 * sa_list(flags, argc, argv)
1713 * implements the "list" subcommand to list groups and optionally
1714 * their state and protocols.
1717 static int
1718 sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
1720 sa_group_t group;
1721 int verbose = 0;
1722 int c;
1723 char *protocol = NULL;
1724 int ret = SA_OK;
1726 while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
1727 switch (c) {
1728 case 'v':
1729 verbose++;
1730 break;
1731 case 'P':
1732 if (protocol != NULL) {
1733 (void) printf(gettext(
1734 "Specifying multiple protocols "
1735 "not supported: %s\n"),
1736 protocol);
1737 return (SA_SYNTAX_ERR);
1739 protocol = optarg;
1740 if (!sa_valid_protocol(protocol)) {
1741 (void) printf(gettext(
1742 "Invalid protocol specified: %s\n"),
1743 protocol);
1744 return (SA_INVALID_PROTOCOL);
1746 break;
1747 case 'h':
1748 /* optopt on valid arg isn't defined */
1749 optopt = c;
1750 /*FALLTHROUGH*/
1751 case '?':
1752 default:
1754 * Since a bad option gets to here, sort it
1755 * out and return a syntax error return value
1756 * if necessary.
1758 switch (optopt) {
1759 default:
1760 ret = SA_SYNTAX_ERR;
1761 break;
1762 case 'h':
1763 case '?':
1764 break;
1766 (void) printf(gettext("usage: %s\n"),
1767 sa_get_usage(USAGE_LIST));
1768 return (ret);
1772 if (optind != argc) {
1773 (void) printf(gettext("usage: %s\n"),
1774 sa_get_usage(USAGE_LIST));
1775 return (SA_SYNTAX_ERR);
1778 for (group = sa_get_group(handle, NULL);
1779 group != NULL;
1780 group = sa_get_next_group(group)) {
1781 char *name;
1782 char *proto;
1783 if (protocol == NULL || has_protocol(group, protocol)) {
1784 name = sa_get_group_attr(group, "name");
1785 if (name != NULL && (verbose > 1 || name[0] != '#')) {
1786 (void) printf("%s", (char *)name);
1787 if (verbose) {
1789 * Need the list of protocols
1790 * and current status once
1791 * available. We do want to
1792 * translate the
1793 * enabled/disabled text here.
1795 (void) printf("\t%s", isenabled(group) ?
1796 gettext("enabled") :
1797 gettext("disabled"));
1798 proto = group_proto(group);
1799 if (proto != NULL) {
1800 (void) printf("\t%s",
1801 (char *)proto);
1802 free(proto);
1805 (void) printf("\n");
1807 if (name != NULL)
1808 sa_free_attr_string(name);
1811 return (0);
1815 * out_properties(optionset, proto, sec)
1817 * Format the properties and encode the protocol and optional named
1818 * optionset into the string.
1820 * format is protocol[:name]=(property-list)
1823 static void
1824 out_properties(sa_optionset_t optionset, char *proto, char *sec)
1826 char *type;
1827 char *value;
1828 int spacer;
1829 sa_property_t prop;
1831 if (sec == NULL)
1832 (void) printf(" %s=(", proto ? proto : gettext("all"));
1833 else
1834 (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
1836 for (spacer = 0, prop = sa_get_property(optionset, NULL);
1837 prop != NULL;
1838 prop = sa_get_next_property(prop)) {
1841 * extract the property name/value and output with
1842 * appropriate spacing. I.e. no prefixed space the
1843 * first time through but a space on subsequent
1844 * properties.
1846 type = sa_get_property_attr(prop, "type");
1847 value = sa_get_property_attr(prop, "value");
1848 if (type != NULL) {
1849 (void) printf("%s%s=", spacer ? " " : "", type);
1850 spacer = 1;
1851 if (value != NULL)
1852 (void) printf("\"%s\"", value);
1853 else
1854 (void) printf("\"\"");
1856 if (type != NULL)
1857 sa_free_attr_string(type);
1858 if (value != NULL)
1859 sa_free_attr_string(value);
1861 (void) printf(")");
1865 * show_properties(group, protocol, prefix)
1867 * print the properties for a group. If protocol is NULL, do all
1868 * protocols otherwise only the specified protocol. All security
1869 * (named groups specific to the protocol) are included.
1871 * The "prefix" is always applied. The caller knows whether it wants
1872 * some type of prefix string (white space) or not. Once the prefix
1873 * has been output, it is reduced to the zero length string for the
1874 * remainder of the property output.
1877 static void
1878 show_properties(sa_group_t group, char *protocol, char *prefix)
1880 sa_optionset_t optionset;
1881 sa_security_t security;
1882 char *value;
1883 char *secvalue;
1885 if (protocol != NULL) {
1886 optionset = sa_get_optionset(group, protocol);
1887 if (optionset != NULL) {
1888 (void) printf("%s", prefix);
1889 prefix = "";
1890 out_properties(optionset, protocol, NULL);
1892 security = sa_get_security(group, protocol, NULL);
1893 if (security != NULL) {
1894 (void) printf("%s", prefix);
1895 prefix = "";
1896 out_properties(security, protocol, NULL);
1898 } else {
1899 for (optionset = sa_get_optionset(group, protocol);
1900 optionset != NULL;
1901 optionset = sa_get_next_optionset(optionset)) {
1903 value = sa_get_optionset_attr(optionset, "type");
1904 (void) printf("%s", prefix);
1905 prefix = "";
1906 out_properties(optionset, value, 0);
1907 if (value != NULL)
1908 sa_free_attr_string(value);
1910 for (security = sa_get_security(group, NULL, protocol);
1911 security != NULL;
1912 security = sa_get_next_security(security)) {
1914 value = sa_get_security_attr(security, "type");
1915 secvalue = sa_get_security_attr(security, "sectype");
1916 (void) printf("%s", prefix);
1917 prefix = "";
1918 out_properties(security, value, secvalue);
1919 if (value != NULL)
1920 sa_free_attr_string(value);
1921 if (secvalue != NULL)
1922 sa_free_attr_string(secvalue);
1928 * get_resource(share)
1930 * Get the first resource name, if any, and fix string to be in
1931 * current locale and have quotes if it has embedded spaces. Return
1932 * an attr string that must be freed.
1935 static char *
1936 get_resource(sa_share_t share)
1938 sa_resource_t resource;
1939 char *resstring = NULL;
1940 char *retstring;
1942 if ((resource = sa_get_share_resource(share, NULL)) != NULL) {
1943 resstring = sa_get_resource_attr(resource, "name");
1944 if (resstring != NULL) {
1945 char *cp;
1946 int len;
1948 retstring = conv_from_utf8(resstring);
1949 if (retstring != resstring) {
1950 sa_free_attr_string(resstring);
1951 resstring = retstring;
1953 if (strpbrk(resstring, " ") != NULL) {
1954 /* account for quotes */
1955 len = strlen(resstring) + 3;
1956 cp = calloc(len, sizeof (char));
1957 if (cp != NULL) {
1958 (void) snprintf(cp, len,
1959 "\"%s\"", resstring);
1960 sa_free_attr_string(resstring);
1961 resstring = cp;
1962 } else {
1963 sa_free_attr_string(resstring);
1964 resstring = NULL;
1969 return (resstring);
1973 * has_resource_with_opt(share)
1975 * Check to see if the share has any resource names with optionsets
1976 * set. Also indicate if multiple resource names since the syntax
1977 * would be about the same.
1979 static int
1980 has_resource_with_opt(sa_share_t share)
1982 sa_resource_t resource;
1983 int ret = B_FALSE;
1985 for (resource = sa_get_share_resource(share, NULL);
1986 resource != NULL;
1987 resource = sa_get_next_resource(resource)) {
1989 if (sa_get_optionset(resource, NULL) != NULL) {
1990 ret = B_TRUE;
1991 break;
1994 return (ret);
1998 * has_multiple_resource(share)
2000 * Check to see if the share has multiple resource names since
2001 * the syntax would be about the same.
2003 static boolean_t
2004 has_multiple_resource(sa_share_t share)
2006 sa_resource_t resource;
2007 int num;
2009 for (num = 0, resource = sa_get_share_resource(share, NULL);
2010 resource != NULL;
2011 resource = sa_get_next_resource(resource)) {
2012 num++;
2013 if (num > 1)
2014 return (B_TRUE);
2016 return (B_FALSE);
2020 * show_share(share, verbose, properties, proto, iszfs, sharepath)
2022 * print out the share information. With the addition of resource as a
2023 * full object that can have multiple instances below the share, we
2024 * need to display that as well.
2027 static void
2028 show_share(sa_share_t share, int verbose, int properties, char *proto,
2029 int iszfs, char *sharepath)
2031 char *drive;
2032 char *exclude;
2033 sa_resource_t resource = NULL;
2034 char *description;
2035 char *rsrcname;
2036 int rsrcwithopt;
2037 boolean_t multiple;
2038 char *type;
2040 rsrcwithopt = has_resource_with_opt(share);
2042 if (verbose || (properties && rsrcwithopt)) {
2043 /* First, indicate if transient */
2044 type = sa_get_share_attr(share, "type");
2045 if (type != NULL && !iszfs && verbose &&
2046 strcmp(type, "transient") == 0)
2047 (void) printf("\t* ");
2048 else
2049 (void) printf("\t ");
2051 if (type != NULL)
2052 sa_free_attr_string(type);
2055 * If we came in with verbose, we want to handle the case of
2056 * multiple resources as though they had properties set.
2058 multiple = has_multiple_resource(share);
2061 * if there is a description on the share and there
2062 * are resources, treat as multiple resources in order
2063 * to get all descriptions displayed.
2065 description = sa_get_share_description(share);
2066 resource = sa_get_share_resource(share, NULL);
2068 if (description != NULL && resource != NULL)
2069 multiple = B_TRUE;
2071 /* Next, if not multiple follow old model */
2072 if (!multiple && !rsrcwithopt) {
2073 rsrcname = get_resource(share);
2074 if (rsrcname != NULL && strlen(rsrcname) > 0) {
2075 (void) printf("%s=%s", rsrcname, sharepath);
2076 } else {
2077 (void) printf("%s", sharepath);
2079 if (rsrcname != NULL)
2080 sa_free_attr_string(rsrcname);
2081 /* Print the description string if there is one. */
2082 print_rsrc_desc(resource, description);
2083 } else {
2084 /* Treat as simple and then resources come later */
2085 (void) printf("%s", sharepath);
2087 drive = sa_get_share_attr(share, "drive-letter");
2088 if (drive != NULL) {
2089 if (strlen(drive) > 0)
2090 (void) printf(gettext("\tdrive-letter=\"%s:\""),
2091 drive);
2092 sa_free_attr_string(drive);
2094 if (properties)
2095 show_properties(share, proto, "\t");
2096 exclude = sa_get_share_attr(share, "exclude");
2097 if (exclude != NULL) {
2098 (void) printf(gettext("\tnot-shared-with=[%s]"),
2099 exclude);
2100 sa_free_attr_string(exclude);
2103 if (description != NULL) {
2104 print_rsrc_desc((sa_resource_t)share, description);
2107 * If there are resource names with options, show them
2108 * here, with one line per resource. Resource specific
2109 * options are at the end of the line followed by
2110 * description, if any.
2112 if (rsrcwithopt || multiple) {
2113 for (resource = sa_get_share_resource(share, NULL);
2114 resource != NULL;
2115 resource = sa_get_next_resource(resource)) {
2116 int has_space;
2117 char *rsrc;
2119 (void) printf("\n\t\t ");
2120 rsrcname = sa_get_resource_attr(resource,
2121 "name");
2122 if (rsrcname == NULL)
2123 continue;
2125 rsrc = conv_from_utf8(rsrcname);
2126 has_space = strpbrk(rsrc, " ") != NULL;
2128 if (has_space)
2129 (void) printf("\"%s\"=%s", rsrc,
2130 sharepath);
2131 else
2132 (void) printf("%s=%s", rsrc,
2133 sharepath);
2134 if (rsrc != rsrcname)
2135 sa_free_attr_string(rsrc);
2136 sa_free_attr_string(rsrcname);
2137 if (properties || rsrcwithopt)
2138 show_properties(resource, proto, "\t");
2140 /* Get description string if any */
2141 print_rsrc_desc(resource, description);
2144 if (description != NULL)
2145 sa_free_share_description(description);
2146 } else {
2147 (void) printf("\t %s", sharepath);
2148 if (properties)
2149 show_properties(share, proto, "\t");
2151 (void) printf("\n");
2155 * show_group(group, verbose, properties, proto, subgroup)
2157 * helper function to show the contents of a group.
2160 static void
2161 show_group(sa_group_t group, int verbose, int properties, char *proto,
2162 char *subgroup)
2164 sa_share_t share;
2165 char *groupname;
2166 char *zfs = NULL;
2167 int iszfs = 0;
2168 char *sharepath;
2170 groupname = sa_get_group_attr(group, "name");
2171 if (groupname != NULL) {
2172 if (proto != NULL && !has_protocol(group, proto)) {
2173 sa_free_attr_string(groupname);
2174 return;
2177 * check to see if the group is managed by ZFS. If
2178 * there is an attribute, then it is. A non-NULL zfs
2179 * variable will trigger the different way to display
2180 * and will remove the transient property indicator
2181 * from the output.
2183 zfs = sa_get_group_attr(group, "zfs");
2184 if (zfs != NULL) {
2185 iszfs = 1;
2186 sa_free_attr_string(zfs);
2188 share = sa_get_share(group, NULL);
2189 if (subgroup == NULL)
2190 (void) printf("%s", groupname);
2191 else
2192 (void) printf(" %s/%s", subgroup, groupname);
2193 if (properties)
2194 show_properties(group, proto, "");
2195 (void) printf("\n");
2196 if (strcmp(groupname, "zfs") == 0) {
2197 sa_group_t zgroup;
2199 for (zgroup = sa_get_sub_group(group);
2200 zgroup != NULL;
2201 zgroup = sa_get_next_group(zgroup)) {
2202 show_group(zgroup, verbose, properties, proto,
2203 "zfs");
2205 sa_free_attr_string(groupname);
2206 return;
2209 * Have a group, so list the contents. Resource and
2210 * description are only listed if verbose is set.
2212 for (share = sa_get_share(group, NULL);
2213 share != NULL;
2214 share = sa_get_next_share(share)) {
2215 sharepath = sa_get_share_attr(share, "path");
2216 if (sharepath != NULL) {
2217 show_share(share, verbose, properties, proto,
2218 iszfs, sharepath);
2219 sa_free_attr_string(sharepath);
2223 if (groupname != NULL) {
2224 sa_free_attr_string(groupname);
2229 * show_group_xml_init()
2231 * Create an XML document that will be used to display config info via
2232 * XML format.
2235 xmlDocPtr
2236 show_group_xml_init()
2238 xmlDocPtr doc;
2239 xmlNodePtr root;
2241 doc = xmlNewDoc((xmlChar *)"1.0");
2242 if (doc != NULL) {
2243 root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
2244 if (root != NULL)
2245 (void) xmlDocSetRootElement(doc, root);
2247 return (doc);
2251 * show_group_xml(doc, group)
2253 * Copy the group info into the XML doc.
2256 static void
2257 show_group_xml(xmlDocPtr doc, sa_group_t group)
2259 xmlNodePtr node;
2260 xmlNodePtr root;
2262 root = xmlDocGetRootElement(doc);
2263 node = xmlCopyNode((xmlNodePtr)group, 1);
2264 if (node != NULL && root != NULL) {
2265 (void) xmlAddChild(root, node);
2267 * In the future, we may have interally used tags that
2268 * should not appear in the XML output. Remove
2269 * anything we don't want to show here.
2275 * sa_show(flags, argc, argv)
2277 * Implements the show subcommand.
2281 sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
2283 sa_group_t group;
2284 int verbose = 0;
2285 int properties = 0;
2286 int c;
2287 int ret = SA_OK;
2288 char *protocol = NULL;
2289 int xml = 0;
2290 xmlDocPtr doc;
2292 while ((c = getopt(argc, argv, "?hvP:px")) != EOF) {
2293 switch (c) {
2294 case 'v':
2295 verbose++;
2296 break;
2297 case 'p':
2298 properties++;
2299 break;
2300 case 'P':
2301 if (protocol != NULL) {
2302 (void) printf(gettext(
2303 "Specifying multiple protocols "
2304 "not supported: %s\n"),
2305 protocol);
2306 return (SA_SYNTAX_ERR);
2308 protocol = optarg;
2309 if (!sa_valid_protocol(protocol)) {
2310 (void) printf(gettext(
2311 "Invalid protocol specified: %s\n"),
2312 protocol);
2313 return (SA_INVALID_PROTOCOL);
2315 break;
2316 case 'x':
2317 xml++;
2318 break;
2319 case 'h':
2320 /* optopt on valid arg isn't defined */
2321 optopt = c;
2322 /*FALLTHROUGH*/
2323 case '?':
2324 default:
2326 * Since a bad option gets to here, sort it
2327 * out and return a syntax error return value
2328 * if necessary.
2330 switch (optopt) {
2331 default:
2332 ret = SA_SYNTAX_ERR;
2333 break;
2334 case 'h':
2335 case '?':
2336 break;
2338 (void) printf(gettext("usage: %s\n"),
2339 sa_get_usage(USAGE_SHOW));
2340 return (ret);
2344 if (xml) {
2345 doc = show_group_xml_init();
2346 if (doc == NULL)
2347 ret = SA_NO_MEMORY;
2350 if (optind == argc) {
2351 /* No group specified so go through them all */
2352 for (group = sa_get_group(handle, NULL);
2353 group != NULL;
2354 group = sa_get_next_group(group)) {
2356 * Have a group so check if one we want and then list
2357 * contents with appropriate options.
2359 if (xml)
2360 show_group_xml(doc, group);
2361 else
2362 show_group(group, verbose, properties, protocol,
2363 NULL);
2365 } else {
2366 /* Have a specified list of groups */
2367 for (; optind < argc; optind++) {
2368 group = sa_get_group(handle, argv[optind]);
2369 if (group != NULL) {
2370 if (xml)
2371 show_group_xml(doc, group);
2372 else
2373 show_group(group, verbose, properties,
2374 protocol, NULL);
2375 } else {
2376 (void) printf(gettext("%s: not found\n"),
2377 argv[optind]);
2378 ret = SA_NO_SUCH_GROUP;
2382 if (xml && ret == SA_OK) {
2383 (void) xmlDocFormatDump(stdout, doc, 1);
2384 xmlFreeDoc(doc);
2386 return (ret);
2391 * enable_share(group, share, update_legacy)
2393 * helper function to enable a share if the group is enabled.
2396 static int
2397 enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
2398 int update_legacy)
2400 char *value;
2401 int enabled;
2402 sa_optionset_t optionset;
2403 int err;
2404 int ret = SA_OK;
2405 char *zfs = NULL;
2406 int iszfs = 0;
2407 int isshare;
2410 * need to enable this share if the group is enabled but not
2411 * otherwise. The enable is also done on each protocol
2412 * represented in the group.
2414 value = sa_get_group_attr(group, "state");
2415 enabled = value != NULL && strcmp(value, "enabled") == 0;
2416 if (value != NULL)
2417 sa_free_attr_string(value);
2418 /* remove legacy config if necessary */
2419 if (update_legacy)
2420 ret = sa_delete_legacy(share, NULL);
2421 zfs = sa_get_group_attr(group, "zfs");
2422 if (zfs != NULL) {
2423 iszfs++;
2424 sa_free_attr_string(zfs);
2428 * Step through each optionset at the group level and
2429 * enable the share based on the protocol type. This
2430 * works because protocols must be set on the group
2431 * for the protocol to be enabled.
2433 isshare = sa_is_share(share);
2434 for (optionset = sa_get_optionset(group, NULL);
2435 optionset != NULL && ret == SA_OK;
2436 optionset = sa_get_next_optionset(optionset)) {
2437 value = sa_get_optionset_attr(optionset, "type");
2438 if (value != NULL) {
2439 if (enabled) {
2440 if (isshare) {
2441 err = sa_enable_share(share, value);
2442 } else {
2443 err = sa_enable_resource(share, value);
2444 if (err == SA_NOT_SUPPORTED) {
2445 sa_share_t parent;
2446 parent = sa_get_resource_parent(
2447 share);
2448 if (parent != NULL)
2449 err = sa_enable_share(
2450 parent, value);
2453 if (err != SA_OK) {
2454 ret = err;
2455 (void) printf(gettext(
2456 "Failed to enable share for "
2457 "\"%s\": %s\n"),
2458 value, sa_errorstr(ret));
2462 * If we want to update the legacy, use a copy of
2463 * share so we can avoid breaking the loop we are in
2464 * since we might also need to go up the tree to the
2465 * parent.
2467 if (update_legacy && !iszfs) {
2468 sa_share_t update = share;
2469 if (!sa_is_share(share)) {
2470 update = sa_get_resource_parent(share);
2472 (void) sa_update_legacy(update, value);
2474 sa_free_attr_string(value);
2477 if (ret == SA_OK)
2478 (void) sa_update_config(handle);
2479 return (ret);
2483 * sa_require_resource(group)
2485 * if any of the defined protocols on the group require resource
2486 * names, then all shares must have them.
2489 static int
2490 sa_require_resource(sa_group_t group)
2492 sa_optionset_t optionset;
2494 for (optionset = sa_get_optionset(group, NULL);
2495 optionset != NULL;
2496 optionset = sa_get_next_optionset(optionset)) {
2497 char *proto;
2499 proto = sa_get_optionset_attr(optionset, "type");
2500 if (proto != NULL) {
2501 uint64_t features;
2503 features = sa_proto_get_featureset(proto);
2504 if (features & SA_FEATURE_RESOURCE) {
2505 sa_free_attr_string(proto);
2506 return (B_TRUE);
2508 sa_free_attr_string(proto);
2511 return (B_FALSE);
2515 * sa_addshare(flags, argc, argv)
2517 * implements add-share subcommand.
2520 static int
2521 sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
2523 int verbose = 0;
2524 int dryrun = 0;
2525 int c;
2526 int ret = SA_OK;
2527 sa_group_t group;
2528 sa_share_t share;
2529 sa_resource_t resource = NULL;
2530 char *sharepath = NULL;
2531 char *description = NULL;
2532 char *rsrcname = NULL;
2533 char *rsrc = NULL;
2534 int persist = SA_SHARE_PERMANENT; /* default to persist */
2535 int auth;
2536 char dir[MAXPATHLEN];
2538 while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
2539 switch (c) {
2540 case 'n':
2541 dryrun++;
2542 break;
2543 case 'v':
2544 verbose++;
2545 break;
2546 case 'd':
2547 description = optarg;
2548 break;
2549 case 'r':
2550 if (rsrcname != NULL) {
2551 (void) printf(gettext("Adding multiple "
2552 "resource names not"
2553 " supported\n"));
2554 return (SA_SYNTAX_ERR);
2556 rsrcname = optarg;
2557 break;
2558 case 's':
2560 * Save share path into group. Currently limit
2561 * to one share per command.
2563 if (sharepath != NULL) {
2564 (void) printf(gettext(
2565 "Adding multiple shares not supported\n"));
2566 return (SA_SYNTAX_ERR);
2568 sharepath = optarg;
2569 break;
2570 case 't':
2571 persist = SA_SHARE_TRANSIENT;
2572 break;
2573 case 'h':
2574 /* optopt on valid arg isn't defined */
2575 optopt = c;
2576 /*FALLTHROUGH*/
2577 case '?':
2578 default:
2580 * Since a bad option gets to here, sort it
2581 * out and return a syntax error return value
2582 * if necessary.
2584 switch (optopt) {
2585 default:
2586 ret = SA_SYNTAX_ERR;
2587 break;
2588 case 'h':
2589 case '?':
2590 break;
2592 (void) printf(gettext("usage: %s\n"),
2593 sa_get_usage(USAGE_ADD_SHARE));
2594 return (ret);
2598 if (optind >= argc) {
2599 (void) printf(gettext("usage: %s\n"),
2600 sa_get_usage(USAGE_ADD_SHARE));
2601 if (dryrun || sharepath != NULL || description != NULL ||
2602 rsrcname != NULL || verbose || persist) {
2603 (void) printf(gettext("\tgroup must be specified\n"));
2604 ret = SA_NO_SUCH_GROUP;
2605 } else {
2606 ret = SA_OK;
2608 } else {
2609 if (sharepath == NULL) {
2610 (void) printf(gettext("usage: %s\n"),
2611 sa_get_usage(USAGE_ADD_SHARE));
2612 (void) printf(gettext(
2613 "\t-s sharepath must be specified\n"));
2614 ret = SA_BAD_PATH;
2616 if (ret == SA_OK) {
2617 if (realpath(sharepath, dir) == NULL) {
2618 ret = SA_BAD_PATH;
2619 (void) printf(gettext("Path "
2620 "is not valid: %s\n"),
2621 sharepath);
2622 } else {
2623 sharepath = dir;
2626 if (ret == SA_OK && rsrcname != NULL) {
2627 /* check for valid syntax */
2628 if (validresource(rsrcname)) {
2629 rsrc = conv_to_utf8(rsrcname);
2630 resource = sa_find_resource(handle, rsrc);
2631 if (resource != NULL) {
2633 * Resource names must be
2634 * unique in the system
2636 ret = SA_DUPLICATE_NAME;
2637 (void) printf(gettext("usage: %s\n"),
2638 sa_get_usage(USAGE_ADD_SHARE));
2639 (void) printf(gettext(
2640 "\tresource names must be unique "
2641 "in the system\n"));
2643 } else {
2644 (void) printf(gettext("usage: %s\n"),
2645 sa_get_usage(USAGE_ADD_SHARE));
2646 (void) printf(gettext(
2647 "\tresource names use restricted "
2648 "character set\n"));
2649 ret = SA_INVALID_NAME;
2653 if (ret != SA_OK) {
2654 if (rsrc != NULL && rsrcname != rsrc)
2655 sa_free_attr_string(rsrc);
2656 return (ret);
2659 share = sa_find_share(handle, sharepath);
2660 if (share != NULL) {
2661 if (rsrcname == NULL) {
2663 * Can only have a duplicate share if a new
2664 * resource name is being added.
2666 ret = SA_DUPLICATE_NAME;
2667 (void) printf(gettext("Share path already "
2668 "shared: %s\n"), sharepath);
2671 if (ret != SA_OK)
2672 return (ret);
2674 group = sa_get_group(handle, argv[optind]);
2675 if (group != NULL) {
2676 if (sa_require_resource(group) == B_TRUE &&
2677 rsrcname == NULL) {
2678 (void) printf(gettext(
2679 "Resource name is required "
2680 "by at least one enabled protocol "
2681 "in group\n"));
2682 return (SA_RESOURCE_REQUIRED);
2684 if (share == NULL && ret == SA_OK) {
2685 if (dryrun)
2686 ret = sa_check_path(group, sharepath,
2687 SA_CHECK_NORMAL);
2688 else
2689 share = sa_add_share(group, sharepath,
2690 persist, &ret);
2693 * Make sure this isn't an attempt to put a resourced
2694 * share into a different group than it already is in.
2696 if (share != NULL) {
2697 sa_group_t parent;
2698 parent = sa_get_parent_group(share);
2699 if (parent != group) {
2700 ret = SA_DUPLICATE_NAME;
2701 (void) printf(gettext(
2702 "Share path already "
2703 "shared: %s\n"), sharepath);
2706 if (!dryrun && share == NULL) {
2707 (void) printf(gettext(
2708 "Could not add share: %s\n"),
2709 sa_errorstr(ret));
2710 } else {
2711 auth = check_authorizations(argv[optind],
2712 flags);
2713 if (!dryrun && ret == SA_OK) {
2714 if (rsrcname != NULL) {
2715 resource = sa_add_resource(
2716 share,
2717 rsrc,
2718 SA_SHARE_PERMANENT,
2719 &ret);
2721 if (ret == SA_OK &&
2722 description != NULL) {
2723 if (resource != NULL)
2724 ret =
2725 set_resource_desc(
2726 resource,
2727 description);
2728 else
2729 ret =
2730 set_share_desc(
2731 share,
2732 description);
2734 if (ret == SA_OK) {
2735 /* now enable the share(s) */
2736 if (resource != NULL) {
2737 ret = enable_share(
2738 handle,
2739 group,
2740 resource,
2742 } else {
2743 ret = enable_share(
2744 handle,
2745 group,
2746 share,
2749 ret = sa_update_config(handle);
2751 switch (ret) {
2752 case SA_DUPLICATE_NAME:
2753 (void) printf(gettext(
2754 "Resource name in"
2755 "use: %s\n"),
2756 rsrcname);
2757 break;
2758 default:
2759 (void) printf(gettext(
2760 "Could not set "
2761 "attribute: %s\n"),
2762 sa_errorstr(ret));
2763 break;
2764 case SA_OK:
2765 break;
2767 } else if (dryrun && ret == SA_OK &&
2768 !auth && verbose) {
2769 (void) printf(gettext(
2770 "Command would fail: %s\n"),
2771 sa_errorstr(SA_NO_PERMISSION));
2772 ret = SA_NO_PERMISSION;
2775 } else {
2776 switch (ret) {
2777 default:
2778 (void) printf(gettext(
2779 "Group \"%s\" not found\n"), argv[optind]);
2780 ret = SA_NO_SUCH_GROUP;
2781 break;
2782 case SA_BAD_PATH:
2783 case SA_DUPLICATE_NAME:
2784 break;
2788 return (ret);
2792 * sa_moveshare(flags, argc, argv)
2794 * implements move-share subcommand.
2798 sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
2800 int verbose = 0;
2801 int dryrun = 0;
2802 int c;
2803 int ret = SA_OK;
2804 sa_group_t group;
2805 sa_share_t share;
2806 char *rsrcname = NULL;
2807 char *sharepath = NULL;
2808 int authsrc = 0, authdst = 0;
2809 char dir[MAXPATHLEN];
2811 while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) {
2812 switch (c) {
2813 case 'n':
2814 dryrun++;
2815 break;
2816 case 'v':
2817 verbose++;
2818 break;
2819 case 'r':
2820 if (rsrcname != NULL) {
2821 (void) printf(gettext(
2822 "Moving multiple resource names not"
2823 " supported\n"));
2824 return (SA_SYNTAX_ERR);
2826 rsrcname = optarg;
2827 break;
2828 case 's':
2830 * Remove share path from group. Currently limit
2831 * to one share per command.
2833 if (sharepath != NULL) {
2834 (void) printf(gettext("Moving multiple shares"
2835 " not supported\n"));
2836 return (SA_SYNTAX_ERR);
2838 sharepath = optarg;
2839 break;
2840 case 'h':
2841 /* optopt on valid arg isn't defined */
2842 optopt = c;
2843 /*FALLTHROUGH*/
2844 case '?':
2845 default:
2847 * Since a bad option gets to here, sort it
2848 * out and return a syntax error return value
2849 * if necessary.
2851 switch (optopt) {
2852 default:
2853 ret = SA_SYNTAX_ERR;
2854 break;
2855 case 'h':
2856 case '?':
2857 break;
2859 (void) printf(gettext("usage: %s\n"),
2860 sa_get_usage(USAGE_MOVE_SHARE));
2861 return (ret);
2865 if (optind >= argc || sharepath == NULL) {
2866 (void) printf(gettext("usage: %s\n"),
2867 sa_get_usage(USAGE_MOVE_SHARE));
2868 if (dryrun || verbose || sharepath != NULL) {
2869 (void) printf(gettext("\tgroup must be specified\n"));
2870 ret = SA_NO_SUCH_GROUP;
2871 } else {
2872 if (sharepath == NULL) {
2873 ret = SA_SYNTAX_ERR;
2874 (void) printf(gettext(
2875 "\tsharepath must be specified\n"));
2876 } else {
2877 ret = SA_OK;
2880 } else {
2881 sa_group_t parent;
2882 char *zfsold;
2883 char *zfsnew;
2885 if (sharepath == NULL) {
2886 (void) printf(gettext(
2887 "sharepath must be specified with the -s "
2888 "option\n"));
2889 return (SA_BAD_PATH);
2891 group = sa_get_group(handle, argv[optind]);
2892 if (group == NULL) {
2893 (void) printf(gettext("Group \"%s\" not found\n"),
2894 argv[optind]);
2895 return (SA_NO_SUCH_GROUP);
2897 share = sa_find_share(handle, sharepath);
2899 * If a share wasn't found, it may have been a symlink
2900 * or has a trailing '/'. Try again after resolving
2901 * with realpath().
2903 if (share == NULL) {
2904 if (realpath(sharepath, dir) == NULL) {
2905 (void) printf(gettext("Path "
2906 "is not valid: %s\n"),
2907 sharepath);
2908 return (SA_BAD_PATH);
2910 sharepath = dir;
2911 share = sa_find_share(handle, sharepath);
2913 if (share == NULL) {
2914 (void) printf(gettext("Share not found: %s\n"),
2915 sharepath);
2916 return (SA_NO_SUCH_PATH);
2918 authdst = check_authorizations(argv[optind], flags);
2920 parent = sa_get_parent_group(share);
2921 if (parent != NULL) {
2922 char *pname;
2923 pname = sa_get_group_attr(parent, "name");
2924 if (pname != NULL) {
2925 authsrc = check_authorizations(pname, flags);
2926 sa_free_attr_string(pname);
2928 zfsold = sa_get_group_attr(parent, "zfs");
2929 zfsnew = sa_get_group_attr(group, "zfs");
2930 if ((zfsold != NULL && zfsnew == NULL) ||
2931 (zfsold == NULL && zfsnew != NULL)) {
2932 ret = SA_NOT_ALLOWED;
2934 if (zfsold != NULL)
2935 sa_free_attr_string(zfsold);
2936 if (zfsnew != NULL)
2937 sa_free_attr_string(zfsnew);
2940 if (ret == SA_OK && parent != group && !dryrun) {
2941 char *oldstate;
2943 * Note that the share may need to be
2944 * "unshared" if the new group is disabled and
2945 * the old was enabled or it may need to be
2946 * share to update if the new group is
2947 * enabled. We disable before the move and
2948 * will have to enable after the move in order
2949 * to cleanup entries for protocols that
2950 * aren't in the new group.
2952 oldstate = sa_get_group_attr(parent, "state");
2953 if (oldstate != NULL) {
2954 /* enable_share determines what to do */
2955 if (strcmp(oldstate, "enabled") == 0)
2956 (void) sa_disable_share(share, NULL);
2957 sa_free_attr_string(oldstate);
2961 if (!dryrun && ret == SA_OK)
2962 ret = sa_move_share(group, share);
2965 * Reenable and update any config information.
2967 if (ret == SA_OK && parent != group && !dryrun) {
2968 ret = sa_update_config(handle);
2970 (void) enable_share(handle, group, share, 1);
2973 if (ret != SA_OK)
2974 (void) printf(gettext("Could not move share: %s\n"),
2975 sa_errorstr(ret));
2977 if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
2978 verbose) {
2979 (void) printf(gettext("Command would fail: %s\n"),
2980 sa_errorstr(SA_NO_PERMISSION));
2983 return (ret);
2987 * sa_removeshare(flags, argc, argv)
2989 * implements remove-share subcommand.
2993 sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
2995 int verbose = 0;
2996 int dryrun = 0;
2997 int force = 0;
2998 int c;
2999 int ret = SA_OK;
3000 sa_group_t group;
3001 sa_resource_t resource = NULL;
3002 sa_share_t share = NULL;
3003 char *rsrcname = NULL;
3004 char *sharepath = NULL;
3005 char dir[MAXPATHLEN];
3006 int auth;
3008 while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) {
3009 switch (c) {
3010 case 'n':
3011 dryrun++;
3012 break;
3013 case 'v':
3014 verbose++;
3015 break;
3016 case 'f':
3017 force++;
3018 break;
3019 case 's':
3021 * Remove share path from group. Currently limit
3022 * to one share per command.
3024 if (sharepath != NULL) {
3025 (void) printf(gettext(
3026 "Removing multiple shares not "
3027 "supported\n"));
3028 return (SA_SYNTAX_ERR);
3030 sharepath = optarg;
3031 break;
3032 case 'r':
3034 * Remove share from group if last resource or remove
3035 * resource from share if multiple resources.
3037 if (rsrcname != NULL) {
3038 (void) printf(gettext(
3039 "Removing multiple resource names not "
3040 "supported\n"));
3041 return (SA_SYNTAX_ERR);
3043 rsrcname = optarg;
3044 break;
3045 case 'h':
3046 /* optopt on valid arg isn't defined */
3047 optopt = c;
3048 /*FALLTHROUGH*/
3049 case '?':
3050 default:
3052 * Since a bad option gets to here, sort it
3053 * out and return a syntax error return value
3054 * if necessary.
3056 switch (optopt) {
3057 default:
3058 ret = SA_SYNTAX_ERR;
3059 break;
3060 case 'h':
3061 case '?':
3062 break;
3064 (void) printf(gettext("usage: %s\n"),
3065 sa_get_usage(USAGE_REMOVE_SHARE));
3066 return (ret);
3070 if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) {
3071 if (sharepath == NULL && rsrcname == NULL) {
3072 (void) printf(gettext("usage: %s\n"),
3073 sa_get_usage(USAGE_REMOVE_SHARE));
3074 (void) printf(gettext("\t-s sharepath or -r resource"
3075 " must be specified\n"));
3076 ret = SA_BAD_PATH;
3077 } else {
3078 ret = SA_OK;
3081 if (ret != SA_OK) {
3082 return (ret);
3085 if (optind < argc) {
3086 if ((optind + 1) < argc) {
3087 (void) printf(gettext("Extraneous group(s) at end of "
3088 "command\n"));
3089 ret = SA_SYNTAX_ERR;
3090 } else {
3091 group = sa_get_group(handle, argv[optind]);
3092 if (group == NULL) {
3093 (void) printf(gettext(
3094 "Group \"%s\" not found\n"), argv[optind]);
3095 ret = SA_NO_SUCH_GROUP;
3098 } else {
3099 group = NULL;
3102 if (rsrcname != NULL) {
3103 resource = sa_find_resource(handle, rsrcname);
3104 if (resource == NULL) {
3105 ret = SA_NO_SUCH_RESOURCE;
3106 (void) printf(gettext(
3107 "Resource name not found for share: %s\n"),
3108 rsrcname);
3113 * Lookup the path in the internal configuration. Care
3114 * must be taken to handle the case where the
3115 * underlying path has been removed since we need to
3116 * be able to deal with that as well.
3118 if (ret == SA_OK) {
3119 if (sharepath != NULL) {
3120 if (group != NULL)
3121 share = sa_get_share(group, sharepath);
3122 else
3123 share = sa_find_share(handle, sharepath);
3126 if (resource != NULL) {
3127 sa_share_t rsrcshare;
3128 rsrcshare = sa_get_resource_parent(resource);
3129 if (share == NULL)
3130 share = rsrcshare;
3131 else if (share != rsrcshare) {
3132 ret = SA_NO_SUCH_RESOURCE;
3133 (void) printf(gettext(
3134 "Bad resource name for share: %s\n"),
3135 rsrcname);
3136 share = NULL;
3141 * If we didn't find the share with the provided path,
3142 * it may be a symlink so attempt to resolve it using
3143 * realpath and try again. Realpath will resolve any
3144 * symlinks and place them in "dir". Note that
3145 * sharepath is only used for the lookup the first
3146 * time and later for error messages. dir will be used
3147 * on the second attempt. Once a share is found, all
3148 * operations are based off of the share variable.
3150 if (share == NULL) {
3151 if (realpath(sharepath, dir) == NULL) {
3152 ret = SA_BAD_PATH;
3153 (void) printf(gettext(
3154 "Path is not valid: %s\n"), sharepath);
3155 } else {
3156 if (group != NULL)
3157 share = sa_get_share(group, dir);
3158 else
3159 share = sa_find_share(handle, dir);
3165 * If there hasn't been an error, there was likely a
3166 * path found. If not, give the appropriate error
3167 * message and set the return error. If it was found,
3168 * then disable the share and then remove it from the
3169 * configuration.
3171 if (ret != SA_OK) {
3172 return (ret);
3174 if (share == NULL) {
3175 if (group != NULL)
3176 (void) printf(gettext("Share not found in group %s:"
3177 " %s\n"), argv[optind], sharepath);
3178 else
3179 (void) printf(gettext("Share not found: %s\n"),
3180 sharepath);
3181 ret = SA_NO_SUCH_PATH;
3182 } else {
3183 if (group == NULL)
3184 group = sa_get_parent_group(share);
3185 if (!dryrun) {
3186 if (ret == SA_OK) {
3187 if (resource != NULL)
3188 ret = sa_disable_resource(resource,
3189 NULL);
3190 else
3191 ret = sa_disable_share(share, NULL);
3193 * We don't care if it fails since it
3194 * could be disabled already. Some
3195 * unexpected errors could occur that
3196 * prevent removal, so also check for
3197 * force being set.
3199 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3200 ret == SA_NOT_SUPPORTED ||
3201 ret == SA_SYSTEM_ERR || force) &&
3202 resource == NULL)
3203 ret = sa_remove_share(share);
3205 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3206 ret == SA_NOT_SUPPORTED ||
3207 ret == SA_SYSTEM_ERR || force) &&
3208 resource != NULL) {
3209 ret = sa_remove_resource(resource);
3210 if (ret == SA_OK) {
3212 * If this was the
3213 * last one, remove
3214 * the share as well.
3216 resource =
3217 sa_get_share_resource(
3218 share, NULL);
3219 if (resource == NULL)
3220 ret = sa_remove_share(
3221 share);
3224 if (ret == SA_OK)
3225 ret = sa_update_config(handle);
3227 if (ret != SA_OK)
3228 (void) printf(gettext("Could not remove share:"
3229 " %s\n"), sa_errorstr(ret));
3230 } else if (ret == SA_OK) {
3231 char *pname;
3232 pname = sa_get_group_attr(group, "name");
3233 if (pname != NULL) {
3234 auth = check_authorizations(pname, flags);
3235 sa_free_attr_string(pname);
3237 if (!auth && verbose) {
3238 (void) printf(gettext(
3239 "Command would fail: %s\n"),
3240 sa_errorstr(SA_NO_PERMISSION));
3244 return (ret);
3248 * sa_set_share(flags, argc, argv)
3250 * implements set-share subcommand.
3254 sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
3256 int dryrun = 0;
3257 int c;
3258 int ret = SA_OK;
3259 sa_group_t group, sharegroup;
3260 sa_share_t share = NULL;
3261 sa_resource_t resource = NULL;
3262 char *sharepath = NULL;
3263 char *description = NULL;
3264 char *rsrcname = NULL;
3265 char *rsrc = NULL;
3266 char *newname = NULL;
3267 char *newrsrc;
3268 char *groupname = NULL;
3269 int auth;
3270 int verbose = 0;
3272 while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
3273 switch (c) {
3274 case 'n':
3275 dryrun++;
3276 break;
3277 case 'd':
3278 description = optarg;
3279 break;
3280 case 'v':
3281 verbose++;
3282 break;
3283 case 'r':
3285 * Update share by resource name
3287 if (rsrcname != NULL) {
3288 (void) printf(gettext(
3289 "Updating multiple resource names not "
3290 "supported\n"));
3291 return (SA_SYNTAX_ERR);
3293 rsrcname = optarg;
3294 break;
3295 case 's':
3297 * Save share path into group. Currently limit
3298 * to one share per command.
3300 if (sharepath != NULL) {
3301 (void) printf(gettext(
3302 "Updating multiple shares not "
3303 "supported\n"));
3304 return (SA_SYNTAX_ERR);
3306 sharepath = optarg;
3307 break;
3308 case 'h':
3309 /* optopt on valid arg isn't defined */
3310 optopt = c;
3311 /*FALLTHROUGH*/
3312 case '?':
3313 default:
3315 * Since a bad option gets to here, sort it
3316 * out and return a syntax error return value
3317 * if necessary.
3319 switch (optopt) {
3320 default:
3321 ret = SA_SYNTAX_ERR;
3322 break;
3323 case 'h':
3324 case '?':
3325 break;
3327 (void) printf(gettext("usage: %s\n"),
3328 sa_get_usage(USAGE_SET_SHARE));
3329 return (ret);
3333 if (optind >= argc && sharepath == NULL && rsrcname == NULL) {
3334 if (sharepath == NULL) {
3335 (void) printf(gettext("usage: %s\n"),
3336 sa_get_usage(USAGE_SET_SHARE));
3337 (void) printf(gettext("\tgroup must be specified\n"));
3338 ret = SA_BAD_PATH;
3339 } else {
3340 ret = SA_OK;
3343 if ((optind + 1) < argc) {
3344 (void) printf(gettext("usage: %s\n"),
3345 sa_get_usage(USAGE_SET_SHARE));
3346 (void) printf(gettext("\tExtraneous group(s) at end\n"));
3347 ret = SA_SYNTAX_ERR;
3351 * Must have at least one of sharepath and rsrcrname.
3352 * It is a syntax error to be missing both.
3354 if (sharepath == NULL && rsrcname == NULL) {
3355 (void) printf(gettext("usage: %s\n"),
3356 sa_get_usage(USAGE_SET_SHARE));
3357 ret = SA_SYNTAX_ERR;
3360 if (ret != SA_OK)
3361 return (ret);
3363 if (optind < argc) {
3364 groupname = argv[optind];
3365 group = sa_get_group(handle, groupname);
3366 } else {
3367 group = NULL;
3368 groupname = NULL;
3370 if (rsrcname != NULL) {
3372 * If rsrcname exists, split rename syntax and then
3373 * convert to utf 8 if no errors.
3375 newname = strchr(rsrcname, '=');
3376 if (newname != NULL) {
3377 *newname++ = '\0';
3379 if (!validresource(rsrcname)) {
3380 ret = SA_INVALID_NAME;
3381 (void) printf(gettext("Invalid resource name: "
3382 "\"%s\"\n"), rsrcname);
3383 } else {
3384 rsrc = conv_to_utf8(rsrcname);
3386 if (newname != NULL) {
3387 if (!validresource(newname)) {
3388 ret = SA_INVALID_NAME;
3389 (void) printf(gettext("Invalid resource name: "
3390 "%s\n"), newname);
3391 newname = NULL;
3392 } else {
3393 newrsrc = conv_to_utf8(newname);
3398 if (ret != SA_OK) {
3399 if (rsrcname != NULL && rsrcname != rsrc)
3400 sa_free_attr_string(rsrc);
3401 if (newname != NULL && newname != newrsrc)
3402 sa_free_attr_string(newrsrc);
3403 return (ret);
3406 if (sharepath != NULL) {
3407 share = sa_find_share(handle, sharepath);
3408 } else if (rsrcname != NULL) {
3409 resource = sa_find_resource(handle, rsrc);
3410 if (resource != NULL)
3411 share = sa_get_resource_parent(resource);
3412 else
3413 ret = SA_NO_SUCH_RESOURCE;
3415 if (share != NULL) {
3416 sharegroup = sa_get_parent_group(share);
3417 if (group != NULL && group != sharegroup) {
3418 (void) printf(gettext("Group \"%s\" does not contain "
3419 "share %s\n"),
3420 argv[optind], sharepath);
3421 ret = SA_BAD_PATH;
3422 } else {
3423 int delgroupname = 0;
3424 if (groupname == NULL) {
3425 groupname = sa_get_group_attr(sharegroup,
3426 "name");
3427 delgroupname = 1;
3429 if (groupname != NULL) {
3430 auth = check_authorizations(groupname, flags);
3431 if (delgroupname) {
3432 sa_free_attr_string(groupname);
3433 groupname = NULL;
3435 } else {
3436 ret = SA_NO_MEMORY;
3438 if (rsrcname != NULL) {
3439 resource = sa_find_resource(handle, rsrc);
3440 if (!dryrun) {
3441 if (newname != NULL &&
3442 resource != NULL)
3443 ret = sa_rename_resource(
3444 resource, newrsrc);
3445 else if (newname != NULL)
3446 ret = SA_NO_SUCH_RESOURCE;
3447 if (newname != NULL &&
3448 newname != newrsrc)
3449 sa_free_attr_string(newrsrc);
3451 if (rsrc != rsrcname)
3452 sa_free_attr_string(rsrc);
3456 * If the user has set a description, it will be
3457 * on the resource if -r was used otherwise it
3458 * must be on the share.
3460 if (!dryrun && ret == SA_OK && description != NULL) {
3461 char *desc;
3462 desc = conv_to_utf8(description);
3463 if (resource != NULL)
3464 ret = sa_set_resource_description(
3465 resource, desc);
3466 else
3467 ret = sa_set_share_description(share,
3468 desc);
3469 if (desc != description)
3470 sa_free_share_description(desc);
3473 if (!dryrun && ret == SA_OK) {
3474 if (resource != NULL)
3475 (void) sa_enable_resource(resource, NULL);
3476 ret = sa_update_config(handle);
3478 switch (ret) {
3479 case SA_DUPLICATE_NAME:
3480 (void) printf(gettext("Resource name in use: %s\n"),
3481 rsrcname);
3482 break;
3483 default:
3484 (void) printf(gettext("Could not set: %s\n"),
3485 sa_errorstr(ret));
3486 break;
3487 case SA_OK:
3488 if (dryrun && !auth && verbose) {
3489 (void) printf(gettext(
3490 "Command would fail: %s\n"),
3491 sa_errorstr(SA_NO_PERMISSION));
3493 break;
3495 } else {
3496 switch (ret) {
3497 case SA_NO_SUCH_RESOURCE:
3498 (void) printf(gettext("Resource \"%s\" not found\n"),
3499 rsrcname);
3500 break;
3501 default:
3502 if (sharepath != NULL) {
3503 (void) printf(
3504 gettext("Share path \"%s\" not found\n"),
3505 sharepath);
3506 ret = SA_NO_SUCH_PATH;
3507 } else {
3508 (void) printf(gettext("Set failed: %s\n"),
3509 sa_errorstr(ret));
3514 return (ret);
3518 * add_security(group, sectype, optlist, proto, *err)
3520 * Helper function to add a security option (named optionset) to the
3521 * group.
3524 static int
3525 add_security(sa_group_t group, char *sectype,
3526 struct options *optlist, char *proto, int *err)
3528 sa_security_t security;
3529 int ret = SA_OK;
3530 int result = 0;
3531 sa_handle_t handle;
3533 sectype = sa_proto_space_alias(proto, sectype);
3534 security = sa_get_security(group, sectype, proto);
3535 if (security == NULL)
3536 security = sa_create_security(group, sectype, proto);
3538 if (sectype != NULL)
3539 sa_free_attr_string(sectype);
3541 if (security == NULL)
3542 goto done;
3544 handle = sa_find_group_handle(group);
3545 if (handle == NULL) {
3546 ret = SA_CONFIG_ERR;
3547 goto done;
3549 while (optlist != NULL) {
3550 sa_property_t prop;
3551 prop = sa_get_property(security, optlist->optname);
3552 if (prop == NULL) {
3554 * Add the property, but only if it is
3555 * a non-NULL or non-zero length value
3557 if (optlist->optvalue != NULL) {
3558 prop = sa_create_property(optlist->optname,
3559 optlist->optvalue);
3560 if (prop != NULL) {
3561 ret = sa_valid_property(handle,
3562 security, proto, prop);
3563 if (ret != SA_OK) {
3564 (void) sa_remove_property(prop);
3565 (void) printf(gettext(
3566 "Could not add "
3567 "property %s: %s\n"),
3568 optlist->optname,
3569 sa_errorstr(ret));
3571 if (ret == SA_OK) {
3572 ret = sa_add_property(security,
3573 prop);
3574 if (ret != SA_OK) {
3575 (void) printf(gettext(
3576 "Could not add "
3577 "property (%s=%s):"
3578 " %s\n"),
3579 optlist->optname,
3580 optlist->optvalue,
3581 sa_errorstr(ret));
3582 } else {
3583 result = 1;
3588 } else {
3589 ret = sa_update_property(prop, optlist->optvalue);
3590 result = 1; /* should check if really changed */
3592 optlist = optlist->next;
3595 * When done, properties may have all been removed but
3596 * we need to keep the security type itself until
3597 * explicitly removed.
3599 if (result)
3600 ret = sa_commit_properties(security, 0);
3601 done:
3602 *err = ret;
3603 return (result);
3607 * zfscheck(group, share)
3609 * For the special case where a share was provided, make sure it is a
3610 * compatible path for a ZFS property change. The only path
3611 * acceptable is the path that defines the zfs sub-group (dataset with
3612 * the sharenfs property set) and not one of the paths that inherited
3613 * the NFS properties. Returns SA_OK if it is usable and
3614 * SA_NOT_ALLOWED if it isn't.
3616 * If group is not a ZFS group/subgroup, we assume OK since the check
3617 * on return will catch errors for those cases. What we are looking
3618 * for here is that the group is ZFS and the share is not the defining
3619 * share. All else is SA_OK.
3622 static int
3623 zfscheck(sa_group_t group, sa_share_t share)
3625 int ret = SA_OK;
3626 char *attr;
3628 if (sa_group_is_zfs(group)) {
3630 * The group is a ZFS group. Does the share represent
3631 * the dataset that defined the group? It is only OK
3632 * if the attribute "subgroup" exists on the share and
3633 * has a value of "true".
3636 ret = SA_NOT_ALLOWED;
3637 attr = sa_get_share_attr(share, "subgroup");
3638 if (attr != NULL) {
3639 if (strcmp(attr, "true") == 0)
3640 ret = SA_OK;
3641 sa_free_attr_string(attr);
3644 return (ret);
3648 * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
3650 * This function implements "set" when a name space (-S) is not
3651 * specified. It is a basic set. Options and other CLI parsing has
3652 * already been done.
3654 * "rsrcname" is a "resource name". If it is non-NULL, it must match
3655 * the sharepath if present or group if present, otherwise it is used
3656 * to set options.
3658 * Resource names may take options if the protocol supports it. If the
3659 * protocol doesn't support resource level options, rsrcname is just
3660 * an alias for the share.
3663 static int
3664 basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
3665 char *protocol, char *sharepath, char *rsrcname, int dryrun)
3667 sa_group_t group;
3668 int ret = SA_OK;
3669 int change = 0;
3670 struct list *worklist = NULL;
3672 group = sa_get_group(handle, groupname);
3673 if (group != NULL) {
3674 sa_share_t share = NULL;
3675 sa_resource_t resource = NULL;
3678 * If there is a sharepath, make sure it belongs to
3679 * the group.
3681 if (sharepath != NULL) {
3682 share = sa_get_share(group, sharepath);
3683 if (share == NULL) {
3684 (void) printf(gettext(
3685 "Share does not exist in group %s\n"),
3686 groupname, sharepath);
3687 ret = SA_NO_SUCH_PATH;
3688 } else {
3689 /* if ZFS and OK, then only group */
3690 ret = zfscheck(group, share);
3691 if (ret == SA_OK &&
3692 sa_group_is_zfs(group))
3693 share = NULL;
3694 if (ret == SA_NOT_ALLOWED)
3695 (void) printf(gettext(
3696 "Properties on ZFS group shares "
3697 "not supported: %s\n"), sharepath);
3702 * If a resource name exists, make sure it belongs to
3703 * the share if present else it belongs to the
3704 * group. Also check the protocol to see if it
3705 * supports resource level properties or not. If not,
3706 * use share only.
3708 if (rsrcname != NULL) {
3709 if (share != NULL) {
3710 resource = sa_get_share_resource(share,
3711 rsrcname);
3712 if (resource == NULL)
3713 ret = SA_NO_SUCH_RESOURCE;
3714 } else {
3715 resource = sa_get_resource(group, rsrcname);
3716 if (resource != NULL)
3717 share = sa_get_resource_parent(
3718 resource);
3719 else
3720 ret = SA_NO_SUCH_RESOURCE;
3722 if (ret == SA_OK && resource != NULL) {
3723 uint64_t features;
3725 * Check to see if the resource can take
3726 * properties. If so, stick the resource into
3727 * "share" so it will all just work.
3729 features = sa_proto_get_featureset(protocol);
3730 if (features & SA_FEATURE_RESOURCE)
3731 share = (sa_share_t)resource;
3735 if (ret == SA_OK) {
3736 /* group must exist */
3737 ret = valid_options(handle, optlist, protocol,
3738 share == NULL ? group : share, NULL);
3739 if (ret == SA_OK && !dryrun) {
3740 if (share != NULL)
3741 change |= add_optionset(share, optlist,
3742 protocol, &ret);
3743 else
3744 change |= add_optionset(group, optlist,
3745 protocol, &ret);
3746 if (ret == SA_OK && change)
3747 worklist = add_list(worklist, group,
3748 share, protocol);
3751 free_opt(optlist);
3752 } else {
3753 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3754 ret = SA_NO_SUCH_GROUP;
3757 * we have a group and potentially legal additions
3761 * Commit to configuration if not a dryrunp and properties
3762 * have changed.
3764 if (!dryrun && ret == SA_OK && change && worklist != NULL)
3765 /* properties changed, so update all shares */
3766 (void) enable_all_groups(handle, worklist, 0, 0, protocol,
3767 B_TRUE);
3769 if (worklist != NULL)
3770 free_list(worklist);
3771 return (ret);
3775 * space_set(groupname, optlist, protocol, sharepath, dryrun)
3777 * This function implements "set" when a name space (-S) is
3778 * specified. It is a namespace set. Options and other CLI parsing has
3779 * already been done.
3782 static int
3783 space_set(sa_handle_t handle, char *groupname, struct options *optlist,
3784 char *protocol, char *sharepath, int dryrun, char *sectype)
3786 sa_group_t group;
3787 int ret = SA_OK;
3788 int change = 0;
3789 struct list *worklist = NULL;
3792 * make sure protcol and sectype are valid
3795 if (sa_proto_valid_space(protocol, sectype) == 0) {
3796 (void) printf(gettext("Option space \"%s\" not valid "
3797 "for protocol.\n"), sectype);
3798 return (SA_INVALID_SECURITY);
3801 group = sa_get_group(handle, groupname);
3802 if (group != NULL) {
3803 sa_share_t share = NULL;
3804 if (sharepath != NULL) {
3805 share = sa_get_share(group, sharepath);
3806 if (share == NULL) {
3807 (void) printf(gettext(
3808 "Share does not exist in group %s\n"),
3809 groupname, sharepath);
3810 ret = SA_NO_SUCH_PATH;
3811 } else {
3812 /* if ZFS and OK, then only group */
3813 ret = zfscheck(group, share);
3814 if (ret == SA_OK &&
3815 sa_group_is_zfs(group))
3816 share = NULL;
3817 if (ret == SA_NOT_ALLOWED)
3818 (void) printf(gettext(
3819 "Properties on ZFS group shares "
3820 "not supported: %s\n"), sharepath);
3823 if (ret == SA_OK) {
3824 /* group must exist */
3825 ret = valid_options(handle, optlist, protocol,
3826 share == NULL ? group : share, sectype);
3827 if (ret == SA_OK && !dryrun) {
3828 if (share != NULL)
3829 change = add_security(share, sectype,
3830 optlist, protocol, &ret);
3831 else
3832 change = add_security(group, sectype,
3833 optlist, protocol, &ret);
3834 if (ret != SA_OK)
3835 (void) printf(gettext(
3836 "Could not set property: %s\n"),
3837 sa_errorstr(ret));
3839 if (ret == SA_OK && change)
3840 worklist = add_list(worklist, group, share,
3841 protocol);
3843 free_opt(optlist);
3844 } else {
3845 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3846 ret = SA_NO_SUCH_GROUP;
3850 * We have a group and potentially legal additions.
3853 /* Commit to configuration if not a dryrun */
3854 if (!dryrun && ret == 0) {
3855 if (change && worklist != NULL) {
3856 /* properties changed, so update all shares */
3857 (void) enable_all_groups(handle, worklist, 0, 0,
3858 protocol, B_TRUE);
3860 ret = sa_update_config(handle);
3862 if (worklist != NULL)
3863 free_list(worklist);
3864 return (ret);
3868 * sa_set(flags, argc, argv)
3870 * Implements the set subcommand. It keys off of -S to determine which
3871 * set of operations to actually do.
3875 sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
3877 char *groupname;
3878 int verbose = 0;
3879 int dryrun = 0;
3880 int c;
3881 char *protocol = NULL;
3882 int ret = SA_OK;
3883 struct options *optlist = NULL;
3884 char *rsrcname = NULL;
3885 char *sharepath = NULL;
3886 char *optset = NULL;
3887 int auth;
3889 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
3890 switch (c) {
3891 case 'v':
3892 verbose++;
3893 break;
3894 case 'n':
3895 dryrun++;
3896 break;
3897 case 'P':
3898 if (protocol != NULL) {
3899 (void) printf(gettext(
3900 "Specifying multiple protocols "
3901 "not supported: %s\n"), protocol);
3902 return (SA_SYNTAX_ERR);
3904 protocol = optarg;
3905 if (!sa_valid_protocol(protocol)) {
3906 (void) printf(gettext(
3907 "Invalid protocol specified: %s\n"),
3908 protocol);
3909 return (SA_INVALID_PROTOCOL);
3911 break;
3912 case 'p':
3913 ret = add_opt(&optlist, optarg, 0);
3914 switch (ret) {
3915 case OPT_ADD_SYNTAX:
3916 (void) printf(gettext("Property syntax error:"
3917 " %s\n"), optarg);
3918 return (SA_SYNTAX_ERR);
3919 case OPT_ADD_MEMORY:
3920 (void) printf(gettext("No memory to set "
3921 "property: %s\n"), optarg);
3922 return (SA_NO_MEMORY);
3923 default:
3924 break;
3926 break;
3927 case 'r':
3928 if (rsrcname != NULL) {
3929 (void) printf(gettext(
3930 "Setting multiple resource names not"
3931 " supported\n"));
3932 return (SA_SYNTAX_ERR);
3934 rsrcname = optarg;
3935 break;
3936 case 's':
3937 if (sharepath != NULL) {
3938 (void) printf(gettext(
3939 "Setting multiple shares not supported\n"));
3940 return (SA_SYNTAX_ERR);
3942 sharepath = optarg;
3943 break;
3944 case 'S':
3945 if (optset != NULL) {
3946 (void) printf(gettext(
3947 "Specifying multiple property "
3948 "spaces not supported: %s\n"), optset);
3949 return (SA_SYNTAX_ERR);
3951 optset = optarg;
3952 break;
3953 case 'h':
3954 /* optopt on valid arg isn't defined */
3955 optopt = c;
3956 /*FALLTHROUGH*/
3957 case '?':
3958 default:
3960 * Since a bad option gets to here, sort it
3961 * out and return a syntax error return value
3962 * if necessary.
3964 switch (optopt) {
3965 default:
3966 ret = SA_SYNTAX_ERR;
3967 break;
3968 case 'h':
3969 case '?':
3970 break;
3972 (void) printf(gettext("usage: %s\n"),
3973 sa_get_usage(USAGE_SET));
3974 return (ret);
3978 if (optlist != NULL)
3979 ret = chk_opt(optlist, optset != NULL, protocol);
3981 if (optind >= argc || (optlist == NULL && optset == NULL) ||
3982 protocol == NULL || ret != OPT_ADD_OK) {
3983 char *sep = "\t";
3985 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
3986 if (optind >= argc) {
3987 (void) printf(gettext("%sgroup must be specified"),
3988 sep);
3989 sep = ", ";
3991 if (optlist == NULL) {
3992 (void) printf(gettext("%sat least one property must be"
3993 " specified"), sep);
3994 sep = ", ";
3996 if (protocol == NULL) {
3997 (void) printf(gettext("%sprotocol must be specified"),
3998 sep);
3999 sep = ", ";
4001 (void) printf("\n");
4002 ret = SA_SYNTAX_ERR;
4003 } else {
4005 * Group already exists so we can proceed after a few
4006 * additional checks related to ZFS handling.
4009 groupname = argv[optind];
4010 if (strcmp(groupname, "zfs") == 0) {
4011 (void) printf(gettext("Changing properties for group "
4012 "\"zfs\" not allowed\n"));
4013 return (SA_NOT_ALLOWED);
4016 auth = check_authorizations(groupname, flags);
4017 if (optset == NULL)
4018 ret = basic_set(handle, groupname, optlist, protocol,
4019 sharepath, rsrcname, dryrun);
4020 else
4021 ret = space_set(handle, groupname, optlist, protocol,
4022 sharepath, dryrun, optset);
4023 if (dryrun && ret == SA_OK && !auth && verbose) {
4024 (void) printf(gettext("Command would fail: %s\n"),
4025 sa_errorstr(SA_NO_PERMISSION));
4028 return (ret);
4032 * remove_options(group, optlist, proto, *err)
4034 * Helper function to actually remove options from a group after all
4035 * preprocessing is done.
4038 static int
4039 remove_options(sa_group_t group, struct options *optlist,
4040 char *proto, int *err)
4042 struct options *cur;
4043 sa_optionset_t optionset;
4044 sa_property_t prop;
4045 int change = 0;
4046 int ret = SA_OK;
4048 optionset = sa_get_optionset(group, proto);
4049 if (optionset != NULL) {
4050 for (cur = optlist; cur != NULL; cur = cur->next) {
4051 prop = sa_get_property(optionset, cur->optname);
4052 if (prop != NULL) {
4053 ret = sa_remove_property(prop);
4054 if (ret != SA_OK)
4055 break;
4056 change = 1;
4060 if (ret == SA_OK && change)
4061 ret = sa_commit_properties(optionset, 0);
4063 if (err != NULL)
4064 *err = ret;
4065 return (change);
4069 * valid_unset(group, optlist, proto)
4071 * Sanity check the optlist to make sure they can be removed. Issue an
4072 * error if a property doesn't exist.
4075 static int
4076 valid_unset(sa_group_t group, struct options *optlist, char *proto)
4078 struct options *cur;
4079 sa_optionset_t optionset;
4080 sa_property_t prop;
4081 int ret = SA_OK;
4083 optionset = sa_get_optionset(group, proto);
4084 if (optionset != NULL) {
4085 for (cur = optlist; cur != NULL; cur = cur->next) {
4086 prop = sa_get_property(optionset, cur->optname);
4087 if (prop == NULL) {
4088 (void) printf(gettext(
4089 "Could not unset property %s: not set\n"),
4090 cur->optname);
4091 ret = SA_NO_SUCH_PROP;
4095 return (ret);
4099 * valid_unset_security(group, optlist, proto)
4101 * Sanity check the optlist to make sure they can be removed. Issue an
4102 * error if a property doesn't exist.
4105 static int
4106 valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
4107 char *sectype)
4109 struct options *cur;
4110 sa_security_t security;
4111 sa_property_t prop;
4112 int ret = SA_OK;
4113 char *sec;
4115 sec = sa_proto_space_alias(proto, sectype);
4116 security = sa_get_security(group, sec, proto);
4117 if (security != NULL) {
4118 for (cur = optlist; cur != NULL; cur = cur->next) {
4119 prop = sa_get_property(security, cur->optname);
4120 if (prop == NULL) {
4121 (void) printf(gettext(
4122 "Could not unset property %s: not set\n"),
4123 cur->optname);
4124 ret = SA_NO_SUCH_PROP;
4127 } else {
4128 (void) printf(gettext(
4129 "Could not unset %s: space not defined\n"), sectype);
4130 ret = SA_NO_SUCH_SECURITY;
4132 if (sec != NULL)
4133 sa_free_attr_string(sec);
4134 return (ret);
4138 * remove_security(group, optlist, proto)
4140 * Remove the properties since they were checked as valid.
4143 static int
4144 remove_security(sa_group_t group, char *sectype,
4145 struct options *optlist, char *proto, int *err)
4147 sa_security_t security;
4148 int ret = SA_OK;
4149 int change = 0;
4151 sectype = sa_proto_space_alias(proto, sectype);
4152 security = sa_get_security(group, sectype, proto);
4153 if (sectype != NULL)
4154 sa_free_attr_string(sectype);
4156 if (security != NULL) {
4157 while (optlist != NULL) {
4158 sa_property_t prop;
4159 prop = sa_get_property(security, optlist->optname);
4160 if (prop != NULL) {
4161 ret = sa_remove_property(prop);
4162 if (ret != SA_OK)
4163 break;
4164 change = 1;
4166 optlist = optlist->next;
4169 * when done, properties may have all been removed but
4170 * we need to keep the security type itself until
4171 * explicitly removed.
4173 if (ret == SA_OK && change)
4174 ret = sa_commit_properties(security, 0);
4175 } else {
4176 ret = SA_NO_SUCH_PROP;
4178 if (err != NULL)
4179 *err = ret;
4180 return (change);
4184 * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
4186 * Unset non-named optionset properties.
4189 static int
4190 basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4191 char *protocol, char *sharepath, char *rsrcname, int dryrun)
4193 sa_group_t group;
4194 int ret = SA_OK;
4195 int change = 0;
4196 struct list *worklist = NULL;
4197 sa_share_t share = NULL;
4198 sa_resource_t resource = NULL;
4200 group = sa_get_group(handle, groupname);
4201 if (group == NULL)
4202 return (ret);
4205 * If there is a sharepath, make sure it belongs to
4206 * the group.
4208 if (sharepath != NULL) {
4209 share = sa_get_share(group, sharepath);
4210 if (share == NULL) {
4211 (void) printf(gettext(
4212 "Share does not exist in group %s\n"),
4213 groupname, sharepath);
4214 ret = SA_NO_SUCH_PATH;
4218 * If a resource name exists, make sure it belongs to
4219 * the share if present else it belongs to the
4220 * group. Also check the protocol to see if it
4221 * supports resource level properties or not. If not,
4222 * use share only.
4224 if (rsrcname != NULL) {
4225 if (share != NULL) {
4226 resource = sa_get_share_resource(share, rsrcname);
4227 if (resource == NULL)
4228 ret = SA_NO_SUCH_RESOURCE;
4229 } else {
4230 resource = sa_get_resource(group, rsrcname);
4231 if (resource != NULL) {
4232 share = sa_get_resource_parent(resource);
4233 } else {
4234 ret = SA_NO_SUCH_RESOURCE;
4237 if (ret == SA_OK && resource != NULL) {
4238 uint64_t features;
4240 * Check to see if the resource can take
4241 * properties. If so, stick the resource into
4242 * "share" so it will all just work.
4244 features = sa_proto_get_featureset(protocol);
4245 if (features & SA_FEATURE_RESOURCE)
4246 share = (sa_share_t)resource;
4250 if (ret == SA_OK) {
4251 /* group must exist */
4252 ret = valid_unset(share != NULL ? share : group,
4253 optlist, protocol);
4254 if (ret == SA_OK && !dryrun) {
4255 if (share != NULL) {
4256 sa_optionset_t optionset;
4257 sa_property_t prop;
4258 change |= remove_options(share, optlist,
4259 protocol, &ret);
4261 * If a share optionset is
4262 * empty, remove it.
4264 optionset = sa_get_optionset((sa_share_t)share,
4265 protocol);
4266 if (optionset != NULL) {
4267 prop = sa_get_property(optionset, NULL);
4268 if (prop == NULL)
4269 (void) sa_destroy_optionset(
4270 optionset);
4272 } else {
4273 change |= remove_options(group,
4274 optlist, protocol, &ret);
4276 if (ret == SA_OK && change)
4277 worklist = add_list(worklist, group, share,
4278 protocol);
4279 if (ret != SA_OK)
4280 (void) printf(gettext(
4281 "Could not remove properties: "
4282 "%s\n"), sa_errorstr(ret));
4284 } else {
4285 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4286 ret = SA_NO_SUCH_GROUP;
4288 free_opt(optlist);
4291 * We have a group and potentially legal additions
4293 * Commit to configuration if not a dryrun
4295 if (!dryrun && ret == SA_OK) {
4296 if (change && worklist != NULL) {
4297 /* properties changed, so update all shares */
4298 (void) enable_all_groups(handle, worklist, 0, 0,
4299 protocol, B_TRUE);
4302 if (worklist != NULL)
4303 free_list(worklist);
4304 return (ret);
4308 * space_unset(groupname, optlist, protocol, sharepath, dryrun)
4310 * Unset named optionset properties.
4312 static int
4313 space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4314 char *protocol, char *sharepath, int dryrun, char *sectype)
4316 sa_group_t group;
4317 int ret = SA_OK;
4318 int change = 0;
4319 struct list *worklist = NULL;
4320 sa_share_t share = NULL;
4322 group = sa_get_group(handle, groupname);
4323 if (group == NULL) {
4324 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4325 return (SA_NO_SUCH_GROUP);
4327 if (sharepath != NULL) {
4328 share = sa_get_share(group, sharepath);
4329 if (share == NULL) {
4330 (void) printf(gettext(
4331 "Share does not exist in group %s\n"),
4332 groupname, sharepath);
4333 return (SA_NO_SUCH_PATH);
4336 ret = valid_unset_security(share != NULL ? share : group,
4337 optlist, protocol, sectype);
4339 if (ret == SA_OK && !dryrun) {
4340 if (optlist != NULL) {
4341 if (share != NULL) {
4342 sa_security_t optionset;
4343 sa_property_t prop;
4344 change = remove_security(share,
4345 sectype, optlist, protocol, &ret);
4347 /* If a share security is empty, remove it */
4348 optionset = sa_get_security((sa_group_t)share,
4349 sectype, protocol);
4350 if (optionset != NULL) {
4351 prop = sa_get_property(optionset,
4352 NULL);
4353 if (prop == NULL)
4354 ret = sa_destroy_security(
4355 optionset);
4357 } else {
4358 change = remove_security(group, sectype,
4359 optlist, protocol, &ret);
4361 } else {
4362 sa_security_t security;
4363 char *sec;
4364 sec = sa_proto_space_alias(protocol, sectype);
4365 security = sa_get_security(group, sec, protocol);
4366 if (sec != NULL)
4367 sa_free_attr_string(sec);
4368 if (security != NULL) {
4369 ret = sa_destroy_security(security);
4370 if (ret == SA_OK)
4371 change = 1;
4372 } else {
4373 ret = SA_NO_SUCH_PROP;
4376 if (ret != SA_OK)
4377 (void) printf(gettext("Could not unset property: %s\n"),
4378 sa_errorstr(ret));
4381 if (ret == SA_OK && change)
4382 worklist = add_list(worklist, group, 0, protocol);
4384 free_opt(optlist);
4386 * We have a group and potentially legal additions
4389 /* Commit to configuration if not a dryrun */
4390 if (!dryrun && ret == 0) {
4391 /* properties changed, so update all shares */
4392 if (change && worklist != NULL)
4393 (void) enable_all_groups(handle, worklist, 0, 0,
4394 protocol, B_TRUE);
4395 ret = sa_update_config(handle);
4397 if (worklist != NULL)
4398 free_list(worklist);
4399 return (ret);
4403 * sa_unset(flags, argc, argv)
4405 * Implements the unset subcommand. Parsing done here and then basic
4406 * or space versions of the real code are called.
4410 sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
4412 char *groupname;
4413 int verbose = 0;
4414 int dryrun = 0;
4415 int c;
4416 char *protocol = NULL;
4417 int ret = SA_OK;
4418 struct options *optlist = NULL;
4419 char *rsrcname = NULL;
4420 char *sharepath = NULL;
4421 char *optset = NULL;
4422 int auth;
4424 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
4425 switch (c) {
4426 case 'v':
4427 verbose++;
4428 break;
4429 case 'n':
4430 dryrun++;
4431 break;
4432 case 'P':
4433 if (protocol != NULL) {
4434 (void) printf(gettext(
4435 "Specifying multiple protocols "
4436 "not supported: %s\n"), protocol);
4437 return (SA_SYNTAX_ERR);
4439 protocol = optarg;
4440 if (!sa_valid_protocol(protocol)) {
4441 (void) printf(gettext(
4442 "Invalid protocol specified: %s\n"),
4443 protocol);
4444 return (SA_INVALID_PROTOCOL);
4446 break;
4447 case 'p':
4448 ret = add_opt(&optlist, optarg, 1);
4449 switch (ret) {
4450 case OPT_ADD_SYNTAX:
4451 (void) printf(gettext("Property syntax error "
4452 "for property %s\n"), optarg);
4453 return (SA_SYNTAX_ERR);
4455 case OPT_ADD_PROPERTY:
4456 (void) printf(gettext("Properties need to be "
4457 "set with set command: %s\n"), optarg);
4458 return (SA_SYNTAX_ERR);
4460 default:
4461 break;
4463 break;
4464 case 'r':
4466 * Unset properties on resource if applicable or on
4467 * share if resource for this protocol doesn't use
4468 * resources.
4470 if (rsrcname != NULL) {
4471 (void) printf(gettext(
4472 "Unsetting multiple resource "
4473 "names not supported\n"));
4474 return (SA_SYNTAX_ERR);
4476 rsrcname = optarg;
4477 break;
4478 case 's':
4479 if (sharepath != NULL) {
4480 (void) printf(gettext(
4481 "Adding multiple shares not supported\n"));
4482 return (SA_SYNTAX_ERR);
4484 sharepath = optarg;
4485 break;
4486 case 'S':
4487 if (optset != NULL) {
4488 (void) printf(gettext(
4489 "Specifying multiple property "
4490 "spaces not supported: %s\n"), optset);
4491 return (SA_SYNTAX_ERR);
4493 optset = optarg;
4494 break;
4495 case 'h':
4496 /* optopt on valid arg isn't defined */
4497 optopt = c;
4498 /*FALLTHROUGH*/
4499 case '?':
4500 default:
4502 * Since a bad option gets to here, sort it
4503 * out and return a syntax error return value
4504 * if necessary.
4506 switch (optopt) {
4507 default:
4508 ret = SA_SYNTAX_ERR;
4509 break;
4510 case 'h':
4511 case '?':
4512 break;
4514 (void) printf(gettext("usage: %s\n"),
4515 sa_get_usage(USAGE_UNSET));
4516 return (ret);
4520 if (optlist != NULL)
4521 ret = chk_opt(optlist, optset != NULL, protocol);
4523 if (optind >= argc || (optlist == NULL && optset == NULL) ||
4524 protocol == NULL) {
4525 char *sep = "\t";
4526 (void) printf(gettext("usage: %s\n"),
4527 sa_get_usage(USAGE_UNSET));
4528 if (optind >= argc) {
4529 (void) printf(gettext("%sgroup must be specified"),
4530 sep);
4531 sep = ", ";
4533 if (optlist == NULL) {
4534 (void) printf(gettext("%sat least one property must "
4535 "be specified"), sep);
4536 sep = ", ";
4538 if (protocol == NULL) {
4539 (void) printf(gettext("%sprotocol must be specified"),
4540 sep);
4541 sep = ", ";
4543 (void) printf("\n");
4544 ret = SA_SYNTAX_ERR;
4545 } else {
4548 * If a group already exists, we can only add a new
4549 * protocol to it and not create a new one or add the
4550 * same protocol again.
4553 groupname = argv[optind];
4554 auth = check_authorizations(groupname, flags);
4555 if (optset == NULL)
4556 ret = basic_unset(handle, groupname, optlist, protocol,
4557 sharepath, rsrcname, dryrun);
4558 else
4559 ret = space_unset(handle, groupname, optlist, protocol,
4560 sharepath, dryrun, optset);
4562 if (dryrun && ret == SA_OK && !auth && verbose)
4563 (void) printf(gettext("Command would fail: %s\n"),
4564 sa_errorstr(SA_NO_PERMISSION));
4566 return (ret);
4570 * sa_enable_group(flags, argc, argv)
4572 * Implements the enable subcommand
4576 sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4578 int verbose = 0;
4579 int dryrun = 0;
4580 int all = 0;
4581 int c;
4582 int ret = SA_OK;
4583 char *protocol = NULL;
4584 char *state;
4585 struct list *worklist = NULL;
4586 int auth = 1;
4587 sa_group_t group;
4589 while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
4590 switch (c) {
4591 case 'a':
4592 all = 1;
4593 break;
4594 case 'n':
4595 dryrun++;
4596 break;
4597 case 'P':
4598 if (protocol != NULL) {
4599 (void) printf(gettext(
4600 "Specifying multiple protocols "
4601 "not supported: %s\n"), protocol);
4602 return (SA_SYNTAX_ERR);
4604 protocol = optarg;
4605 if (!sa_valid_protocol(protocol)) {
4606 (void) printf(gettext(
4607 "Invalid protocol specified: %s\n"),
4608 protocol);
4609 return (SA_INVALID_PROTOCOL);
4611 break;
4612 case 'v':
4613 verbose++;
4614 break;
4615 case 'h':
4616 /* optopt on valid arg isn't defined */
4617 optopt = c;
4618 /*FALLTHROUGH*/
4619 case '?':
4620 default:
4622 * Since a bad option gets to here, sort it
4623 * out and return a syntax error return value
4624 * if necessary.
4626 switch (optopt) {
4627 default:
4628 ret = SA_SYNTAX_ERR;
4629 break;
4630 case 'h':
4631 case '?':
4632 (void) printf(gettext("usage: %s\n"),
4633 sa_get_usage(USAGE_ENABLE));
4634 return (ret);
4639 if (optind == argc && !all) {
4640 (void) printf(gettext("usage: %s\n"),
4641 sa_get_usage(USAGE_ENABLE));
4642 (void) printf(gettext("\tmust specify group\n"));
4643 return (SA_NO_SUCH_PATH);
4645 if (!all) {
4646 while (optind < argc) {
4647 group = sa_get_group(handle, argv[optind]);
4648 if (group != NULL) {
4649 auth &= check_authorizations(argv[optind],
4650 flags);
4651 state = sa_get_group_attr(group, "state");
4652 if (state != NULL &&
4653 strcmp(state, "enabled") == 0) {
4654 /* already enabled */
4655 if (verbose)
4656 (void) printf(gettext(
4657 "Group \"%s\" is already "
4658 "enabled\n"),
4659 argv[optind]);
4660 ret = SA_BUSY; /* already enabled */
4661 } else {
4662 worklist = add_list(worklist, group,
4663 0, protocol);
4664 if (verbose)
4665 (void) printf(gettext(
4666 "Enabling group \"%s\"\n"),
4667 argv[optind]);
4669 if (state != NULL)
4670 sa_free_attr_string(state);
4671 } else {
4672 ret = SA_NO_SUCH_GROUP;
4674 optind++;
4676 } else {
4677 for (group = sa_get_group(handle, NULL);
4678 group != NULL;
4679 group = sa_get_next_group(group)) {
4680 worklist = add_list(worklist, group, 0, protocol);
4683 if (!dryrun && ret == SA_OK)
4684 ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE);
4686 if (ret != SA_OK && ret != SA_BUSY)
4687 (void) printf(gettext("Could not enable group: %s\n"),
4688 sa_errorstr(ret));
4689 if (ret == SA_BUSY)
4690 ret = SA_OK;
4692 if (worklist != NULL)
4693 free_list(worklist);
4694 if (dryrun && ret == SA_OK && !auth && verbose) {
4695 (void) printf(gettext("Command would fail: %s\n"),
4696 sa_errorstr(SA_NO_PERMISSION));
4698 return (ret);
4702 * disable_group(group, proto)
4704 * Disable all the shares in the specified group.. This is a helper
4705 * for disable_all_groups in order to simplify regular and subgroup
4706 * (zfs) disabling. Group has already been checked for non-NULL.
4709 static int
4710 disable_group(sa_group_t group, char *proto)
4712 sa_share_t share;
4713 int ret = SA_OK;
4716 * If the protocol isn't enabled, skip it and treat as
4717 * successful.
4719 if (!has_protocol(group, proto))
4720 return (ret);
4722 for (share = sa_get_share(group, NULL);
4723 share != NULL && ret == SA_OK;
4724 share = sa_get_next_share(share)) {
4725 ret = sa_disable_share(share, proto);
4726 if (ret == SA_NO_SUCH_PATH) {
4728 * this is OK since the path is gone. we can't
4729 * re-share it anyway so no error.
4731 ret = SA_OK;
4734 return (ret);
4738 * disable_all_groups(work, setstate)
4740 * helper function that disables the shares in the list of groups
4741 * provided. It optionally marks the group as disabled. Used by both
4742 * enable and start subcommands.
4745 static int
4746 disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
4748 int ret = SA_OK;
4749 sa_group_t subgroup, group;
4751 while (work != NULL && ret == SA_OK) {
4752 group = (sa_group_t)work->item;
4753 if (setstate)
4754 ret = sa_set_group_attr(group, "state", "disabled");
4755 if (ret == SA_OK) {
4756 char *name;
4757 name = sa_get_group_attr(group, "name");
4758 if (name != NULL && strcmp(name, "zfs") == 0) {
4759 /* need to get the sub-groups for stopping */
4760 for (subgroup = sa_get_sub_group(group);
4761 subgroup != NULL;
4762 subgroup = sa_get_next_group(subgroup)) {
4763 ret = disable_group(subgroup,
4764 work->proto);
4766 } else {
4767 ret = disable_group(group, work->proto);
4769 if (name != NULL)
4770 sa_free_attr_string(name);
4772 * We don't want to "disable" since it won't come
4773 * up after a reboot. The SMF framework should do
4774 * the right thing. On enable we do want to do
4775 * something.
4778 work = work->next;
4780 if (ret == SA_OK)
4781 ret = sa_update_config(handle);
4782 return (ret);
4786 * sa_disable_group(flags, argc, argv)
4788 * Implements the disable subcommand
4792 sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4794 int verbose = 0;
4795 int dryrun = 0;
4796 int all = 0;
4797 int c;
4798 int ret = SA_OK;
4799 char *protocol = NULL;
4800 char *state;
4801 struct list *worklist = NULL;
4802 sa_group_t group;
4803 int auth = 1;
4805 while ((c = getopt(argc, argv, "?havn")) != EOF) {
4806 switch (c) {
4807 case 'a':
4808 all = 1;
4809 break;
4810 case 'n':
4811 dryrun++;
4812 break;
4813 case 'P':
4814 if (protocol != NULL) {
4815 (void) printf(gettext(
4816 "Specifying multiple protocols "
4817 "not supported: %s\n"), protocol);
4818 return (SA_SYNTAX_ERR);
4820 protocol = optarg;
4821 if (!sa_valid_protocol(protocol)) {
4822 (void) printf(gettext(
4823 "Invalid protocol specified: %s\n"),
4824 protocol);
4825 return (SA_INVALID_PROTOCOL);
4827 break;
4828 case 'v':
4829 verbose++;
4830 break;
4831 case 'h':
4832 /* optopt on valid arg isn't defined */
4833 optopt = c;
4834 /*FALLTHROUGH*/
4835 case '?':
4836 default:
4838 * Since a bad option gets to here, sort it
4839 * out and return a syntax error return value
4840 * if necessary.
4842 switch (optopt) {
4843 default:
4844 ret = SA_SYNTAX_ERR;
4845 break;
4846 case 'h':
4847 case '?':
4848 break;
4850 (void) printf(gettext("usage: %s\n"),
4851 sa_get_usage(USAGE_DISABLE));
4852 return (ret);
4856 if (optind == argc && !all) {
4857 (void) printf(gettext("usage: %s\n"),
4858 sa_get_usage(USAGE_DISABLE));
4859 (void) printf(gettext("\tmust specify group\n"));
4860 return (SA_NO_SUCH_PATH);
4862 if (!all) {
4863 while (optind < argc) {
4864 group = sa_get_group(handle, argv[optind]);
4865 if (group != NULL) {
4866 auth &= check_authorizations(argv[optind],
4867 flags);
4868 state = sa_get_group_attr(group, "state");
4869 if (state == NULL ||
4870 strcmp(state, "disabled") == 0) {
4871 /* already disabled */
4872 if (verbose)
4873 (void) printf(gettext(
4874 "Group \"%s\" is "
4875 "already disabled\n"),
4876 argv[optind]);
4877 ret = SA_BUSY; /* already disabled */
4878 } else {
4879 worklist = add_list(worklist, group, 0,
4880 protocol);
4881 if (verbose)
4882 (void) printf(gettext(
4883 "Disabling group "
4884 "\"%s\"\n"), argv[optind]);
4886 if (state != NULL)
4887 sa_free_attr_string(state);
4888 } else {
4889 ret = SA_NO_SUCH_GROUP;
4891 optind++;
4893 } else {
4894 for (group = sa_get_group(handle, NULL);
4895 group != NULL;
4896 group = sa_get_next_group(group))
4897 worklist = add_list(worklist, group, 0, protocol);
4900 if (ret == SA_OK && !dryrun)
4901 ret = disable_all_groups(handle, worklist, 1);
4902 if (ret != SA_OK && ret != SA_BUSY)
4903 (void) printf(gettext("Could not disable group: %s\n"),
4904 sa_errorstr(ret));
4905 if (ret == SA_BUSY)
4906 ret = SA_OK;
4907 if (worklist != NULL)
4908 free_list(worklist);
4909 if (dryrun && ret == SA_OK && !auth && verbose)
4910 (void) printf(gettext("Command would fail: %s\n"),
4911 sa_errorstr(SA_NO_PERMISSION));
4912 return (ret);
4916 * sa_start_group(flags, argc, argv)
4918 * Implements the start command.
4919 * This is similar to enable except it doesn't change the state
4920 * of the group(s) and only enables shares if the group is already
4921 * enabled.
4925 sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
4927 int verbose = 0;
4928 int all = 0;
4929 int c;
4930 int ret = SMF_EXIT_OK;
4931 char *protocol = NULL;
4932 char *state;
4933 struct list *worklist = NULL;
4934 sa_group_t group;
4936 while ((c = getopt(argc, argv, "?havP:")) != EOF) {
4937 switch (c) {
4938 case 'a':
4939 all = 1;
4940 break;
4941 case 'P':
4942 if (protocol != NULL) {
4943 (void) printf(gettext(
4944 "Specifying multiple protocols "
4945 "not supported: %s\n"), protocol);
4946 return (SA_SYNTAX_ERR);
4948 protocol = optarg;
4949 if (!sa_valid_protocol(protocol)) {
4950 (void) printf(gettext(
4951 "Invalid protocol specified: %s\n"),
4952 protocol);
4953 return (SA_INVALID_PROTOCOL);
4955 break;
4956 case 'v':
4957 verbose++;
4958 break;
4959 case 'h':
4960 /* optopt on valid arg isn't defined */
4961 optopt = c;
4962 /*FALLTHROUGH*/
4963 case '?':
4964 default:
4966 * Since a bad option gets to here, sort it
4967 * out and return a syntax error return value
4968 * if necessary.
4970 ret = SA_OK;
4971 switch (optopt) {
4972 default:
4973 ret = SA_SYNTAX_ERR;
4974 break;
4975 case 'h':
4976 case '?':
4977 break;
4979 (void) printf(gettext("usage: %s\n"),
4980 sa_get_usage(USAGE_START));
4981 return (ret);
4985 if (optind == argc && !all) {
4986 (void) printf(gettext("usage: %s\n"),
4987 sa_get_usage(USAGE_START));
4988 return (SMF_EXIT_ERR_FATAL);
4991 if (!all) {
4992 while (optind < argc) {
4993 group = sa_get_group(handle, argv[optind]);
4994 if (group != NULL) {
4995 state = sa_get_group_attr(group, "state");
4996 if (state == NULL ||
4997 strcmp(state, "enabled") == 0) {
4998 worklist = add_list(worklist, group, 0,
4999 protocol);
5000 if (verbose)
5001 (void) printf(gettext(
5002 "Starting group \"%s\"\n"),
5003 argv[optind]);
5004 } else {
5006 * Determine if there are any
5007 * protocols. If there aren't any,
5008 * then there isn't anything to do in
5009 * any case so no error.
5011 if (sa_get_optionset(group,
5012 protocol) != NULL) {
5013 ret = SMF_EXIT_OK;
5016 if (state != NULL)
5017 sa_free_attr_string(state);
5019 optind++;
5021 } else {
5022 for (group = sa_get_group(handle, NULL);
5023 group != NULL;
5024 group = sa_get_next_group(group)) {
5025 state = sa_get_group_attr(group, "state");
5026 if (state == NULL || strcmp(state, "enabled") == 0)
5027 worklist = add_list(worklist, group, 0,
5028 protocol);
5029 if (state != NULL)
5030 sa_free_attr_string(state);
5034 (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE);
5036 if (worklist != NULL)
5037 free_list(worklist);
5038 return (ret);
5042 * sa_stop_group(flags, argc, argv)
5044 * Implements the stop command.
5045 * This is similar to disable except it doesn't change the state
5046 * of the group(s) and only disables shares if the group is already
5047 * enabled.
5050 sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
5052 int verbose = 0;
5053 int all = 0;
5054 int c;
5055 int ret = SMF_EXIT_OK;
5056 char *protocol = NULL;
5057 char *state;
5058 struct list *worklist = NULL;
5059 sa_group_t group;
5061 while ((c = getopt(argc, argv, "?havP:")) != EOF) {
5062 switch (c) {
5063 case 'a':
5064 all = 1;
5065 break;
5066 case 'P':
5067 if (protocol != NULL) {
5068 (void) printf(gettext(
5069 "Specifying multiple protocols "
5070 "not supported: %s\n"), protocol);
5071 return (SA_SYNTAX_ERR);
5073 protocol = optarg;
5074 if (!sa_valid_protocol(protocol)) {
5075 (void) printf(gettext(
5076 "Invalid protocol specified: %s\n"),
5077 protocol);
5078 return (SA_INVALID_PROTOCOL);
5080 break;
5081 case 'v':
5082 verbose++;
5083 break;
5084 case 'h':
5085 /* optopt on valid arg isn't defined */
5086 optopt = c;
5087 /*FALLTHROUGH*/
5088 case '?':
5089 default:
5091 * Since a bad option gets to here, sort it
5092 * out and return a syntax error return value
5093 * if necessary.
5095 ret = SA_OK;
5096 switch (optopt) {
5097 default:
5098 ret = SA_SYNTAX_ERR;
5099 break;
5100 case 'h':
5101 case '?':
5102 break;
5104 (void) printf(gettext("usage: %s\n"),
5105 sa_get_usage(USAGE_STOP));
5106 return (ret);
5110 if (optind == argc && !all) {
5111 (void) printf(gettext("usage: %s\n"),
5112 sa_get_usage(USAGE_STOP));
5113 return (SMF_EXIT_ERR_FATAL);
5114 } else if (!all) {
5115 while (optind < argc) {
5116 group = sa_get_group(handle, argv[optind]);
5117 if (group != NULL) {
5118 state = sa_get_group_attr(group, "state");
5119 if (state == NULL ||
5120 strcmp(state, "enabled") == 0) {
5121 worklist = add_list(worklist, group, 0,
5122 protocol);
5123 if (verbose)
5124 (void) printf(gettext(
5125 "Stopping group \"%s\"\n"),
5126 argv[optind]);
5127 } else {
5128 ret = SMF_EXIT_OK;
5130 if (state != NULL)
5131 sa_free_attr_string(state);
5133 optind++;
5135 } else {
5136 for (group = sa_get_group(handle, NULL);
5137 group != NULL;
5138 group = sa_get_next_group(group)) {
5139 state = sa_get_group_attr(group, "state");
5140 if (state == NULL || strcmp(state, "enabled") == 0)
5141 worklist = add_list(worklist, group, 0,
5142 protocol);
5143 if (state != NULL)
5144 sa_free_attr_string(state);
5147 (void) disable_all_groups(handle, worklist, 0);
5148 ret = sa_update_config(handle);
5150 if (worklist != NULL)
5151 free_list(worklist);
5152 return (ret);
5156 * remove_all_options(share, proto)
5158 * Removes all options on a share.
5161 static void
5162 remove_all_options(sa_share_t share, char *proto)
5164 sa_optionset_t optionset;
5165 sa_security_t security;
5166 sa_security_t prevsec = NULL;
5168 optionset = sa_get_optionset(share, proto);
5169 if (optionset != NULL)
5170 (void) sa_destroy_optionset(optionset);
5171 for (security = sa_get_security(share, NULL, NULL);
5172 security != NULL;
5173 security = sa_get_next_security(security)) {
5174 char *type;
5176 * We walk through the list. prevsec keeps the
5177 * previous security so we can delete it without
5178 * destroying the list.
5180 if (prevsec != NULL) {
5181 /* remove the previously seen security */
5182 (void) sa_destroy_security(prevsec);
5183 /* set to NULL so we don't try multiple times */
5184 prevsec = NULL;
5186 type = sa_get_security_attr(security, "type");
5187 if (type != NULL) {
5189 * if the security matches the specified protocol, we
5190 * want to remove it. prevsec holds it until either
5191 * the next pass or we fall out of the loop.
5193 if (strcmp(type, proto) == 0)
5194 prevsec = security;
5195 sa_free_attr_string(type);
5198 /* in case there is one left */
5199 if (prevsec != NULL)
5200 (void) sa_destroy_security(prevsec);
5205 * for legacy support, we need to handle the old syntax. This is what
5206 * we get if sharemgr is called with the name "share" rather than
5207 * sharemgr.
5210 static int
5211 format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
5213 int err;
5215 err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
5216 if (err > buffsize)
5217 return (-1);
5218 return (0);
5223 * check_legacy_cmd(proto, cmd)
5225 * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
5226 * executable.
5229 static int
5230 check_legacy_cmd(char *path)
5232 struct stat st;
5233 int ret = 0;
5235 if (stat(path, &st) == 0) {
5236 if (S_ISREG(st.st_mode) &&
5237 st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
5238 ret = 1;
5240 return (ret);
5244 * run_legacy_command(proto, cmd, argv)
5246 * We know the command exists, so attempt to execute it with all the
5247 * arguments. This implements full legacy share support for those
5248 * protocols that don't have plugin providers.
5251 static int
5252 run_legacy_command(char *path, char *argv[])
5254 int ret;
5256 ret = execv(path, argv);
5257 if (ret < 0) {
5258 switch (errno) {
5259 case EACCES:
5260 ret = SA_NO_PERMISSION;
5261 break;
5262 default:
5263 ret = SA_SYSTEM_ERR;
5264 break;
5267 return (ret);
5271 * out_share(out, group, proto)
5273 * Display the share information in the format that the "share"
5274 * command has traditionally used.
5277 static void
5278 out_share(FILE *out, sa_group_t group, char *proto)
5280 sa_share_t share;
5281 char resfmt[128];
5282 char *defprop;
5285 * The original share command defaulted to displaying NFS
5286 * shares or allowed a protocol to be specified. We want to
5287 * skip those shares that are not the specified protocol.
5289 if (proto != NULL && sa_get_optionset(group, proto) == NULL)
5290 return;
5292 if (proto == NULL)
5293 proto = "nfs";
5296 * get the default property string. NFS uses "rw" but
5297 * everything else will use "".
5299 if (proto != NULL && strcmp(proto, "nfs") != 0)
5300 defprop = "\"\"";
5301 else
5302 defprop = "rw";
5304 for (share = sa_get_share(group, NULL);
5305 share != NULL;
5306 share = sa_get_next_share(share)) {
5307 char *path;
5308 char *type;
5309 char *resource;
5310 char *description;
5311 char *groupname;
5312 char *sharedstate;
5313 int shared = 1;
5314 char *soptions;
5315 char shareopts[MAXNAMLEN];
5317 sharedstate = sa_get_share_attr(share, "shared");
5318 path = sa_get_share_attr(share, "path");
5319 type = sa_get_share_attr(share, "type");
5320 resource = get_resource(share);
5321 groupname = sa_get_group_attr(group, "name");
5323 if (groupname != NULL && strcmp(groupname, "default") == 0) {
5324 sa_free_attr_string(groupname);
5325 groupname = NULL;
5327 description = sa_get_share_description(share);
5330 * Want the sharetab version if it exists, defaulting
5331 * to NFS if no protocol specified.
5333 (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto);
5334 soptions = sa_get_share_attr(share, shareopts);
5336 if (sharedstate == NULL)
5337 shared = 0;
5339 if (soptions == NULL)
5340 soptions = sa_proto_legacy_format(proto, share, 1);
5342 if (shared) {
5343 /* only active shares go here */
5344 (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
5345 resource != NULL ? resource : "-",
5346 groupname != NULL ? "@" : "",
5347 groupname != NULL ? groupname : "");
5348 (void) fprintf(out, "%-14.14s %s %s \"%s\" \n",
5349 resfmt, (path != NULL) ? path : "",
5350 (soptions != NULL && strlen(soptions) > 0) ?
5351 soptions : defprop,
5352 (description != NULL) ? description : "");
5355 if (path != NULL)
5356 sa_free_attr_string(path);
5357 if (type != NULL)
5358 sa_free_attr_string(type);
5359 if (resource != NULL)
5360 sa_free_attr_string(resource);
5361 if (groupname != NULL)
5362 sa_free_attr_string(groupname);
5363 if (description != NULL)
5364 sa_free_share_description(description);
5365 if (sharedstate != NULL)
5366 sa_free_attr_string(sharedstate);
5367 if (soptions != NULL)
5368 sa_format_free(soptions);
5373 * output_legacy_file(out, proto)
5375 * Walk all of the groups for the specified protocol and call
5376 * out_share() to format and write in the format displayed by the
5377 * "share" command with no arguments.
5380 static void
5381 output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
5383 sa_group_t group;
5385 for (group = sa_get_group(handle, NULL);
5386 group != NULL;
5387 group = sa_get_next_group(group)) {
5388 char *zfs;
5391 * Go through all the groups and ZFS
5392 * sub-groups. out_share() will format the shares in
5393 * the group appropriately.
5396 zfs = sa_get_group_attr(group, "zfs");
5397 if (zfs != NULL) {
5398 sa_group_t zgroup;
5399 sa_free_attr_string(zfs);
5400 for (zgroup = sa_get_sub_group(group);
5401 zgroup != NULL;
5402 zgroup = sa_get_next_group(zgroup)) {
5404 /* got a group, so display it */
5405 out_share(out, zgroup, proto);
5407 } else {
5408 out_share(out, group, proto);
5414 sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
5416 char *protocol = "nfs";
5417 char *options = NULL;
5418 char *description = NULL;
5419 char *groupname = NULL;
5420 char *sharepath = NULL;
5421 char *resource = NULL;
5422 char *groupstatus = NULL;
5423 int persist = SA_SHARE_TRANSIENT;
5424 int argsused = 0;
5425 int c;
5426 int ret = SA_OK;
5427 int zfs = 0;
5428 int true_legacy = 0;
5429 int curtype = SA_SHARE_TRANSIENT;
5430 char cmd[MAXPATHLEN];
5431 sa_group_t group = NULL;
5432 sa_resource_t rsrc = NULL;
5433 sa_share_t share;
5434 char dir[MAXPATHLEN];
5435 uint64_t features;
5437 while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
5438 switch (c) {
5439 case 'd':
5440 description = optarg;
5441 argsused++;
5442 break;
5443 case 'F':
5444 protocol = optarg;
5445 if (!sa_valid_protocol(protocol)) {
5446 if (format_legacy_path(cmd, MAXPATHLEN,
5447 protocol, "share") == 0 &&
5448 check_legacy_cmd(cmd)) {
5449 true_legacy++;
5450 } else {
5451 (void) fprintf(stderr, gettext(
5452 "Invalid protocol specified: "
5453 "%s\n"), protocol);
5454 return (SA_INVALID_PROTOCOL);
5457 break;
5458 case 'o':
5459 options = optarg;
5460 argsused++;
5461 break;
5462 case 'p':
5463 persist = SA_SHARE_PERMANENT;
5464 argsused++;
5465 break;
5466 case 'h':
5467 /* optopt on valid arg isn't defined */
5468 optopt = c;
5469 /*FALLTHROUGH*/
5470 case '?':
5471 default:
5473 * Since a bad option gets to here, sort it
5474 * out and return a syntax error return value
5475 * if necessary.
5477 switch (optopt) {
5478 default:
5479 ret = SA_LEGACY_ERR;
5480 break;
5481 case 'h':
5482 case '?':
5483 break;
5485 (void) fprintf(stderr, gettext("usage: %s\n"),
5486 sa_get_usage(USAGE_SHARE));
5487 return (ret);
5491 /* Have the info so construct what is needed */
5492 if (!argsused && optind == argc) {
5493 /* display current info in share format */
5494 (void) output_legacy_file(stdout, protocol, handle);
5495 return (ret);
5498 /* We are modifying the configuration */
5499 if (optind == argc) {
5500 (void) fprintf(stderr, gettext("usage: %s\n"),
5501 sa_get_usage(USAGE_SHARE));
5502 return (SA_LEGACY_ERR);
5504 if (true_legacy) {
5505 /* If still using legacy share/unshare, exec it */
5506 ret = run_legacy_command(cmd, argv);
5507 return (ret);
5510 sharepath = argv[optind++];
5511 if (optind < argc) {
5512 resource = argv[optind];
5513 groupname = strchr(resource, '@');
5514 if (groupname != NULL)
5515 *groupname++ = '\0';
5517 if (realpath(sharepath, dir) == NULL)
5518 ret = SA_BAD_PATH;
5519 else
5520 sharepath = dir;
5521 if (ret == SA_OK)
5522 share = sa_find_share(handle, sharepath);
5523 else
5524 share = NULL;
5526 features = sa_proto_get_featureset(protocol);
5528 if (groupname != NULL) {
5529 ret = SA_NOT_ALLOWED;
5530 } else if (ret == SA_OK) {
5531 char *legacygroup;
5533 * The legacy group is always present and zfs groups
5534 * come and go. zfs shares may be in sub-groups and
5535 * the zfs share will already be in that group so it
5536 * isn't an error. If the protocol is "smb", the group
5537 * "smb" is used when "default" would otherwise be
5538 * used. "default" is NFS only and "smb" is SMB only.
5540 if (strcmp(protocol, "smb") == 0)
5541 legacygroup = "smb";
5542 else
5543 legacygroup = "default";
5546 * If the share exists (not NULL), then make sure it
5547 * is one we want to handle by getting the parent
5548 * group.
5550 if (share != NULL) {
5551 group = sa_get_parent_group(share);
5552 } else {
5553 group = sa_get_group(handle, legacygroup);
5554 if (group == NULL && strcmp(legacygroup, "smb") == 0) {
5556 * This group may not exist, so create
5557 * as necessary. It only contains the
5558 * "smb" protocol.
5560 group = sa_create_group(handle, legacygroup,
5561 &ret);
5562 if (group != NULL)
5563 (void) sa_create_optionset(group,
5564 protocol);
5568 if (group == NULL) {
5569 ret = SA_SYSTEM_ERR;
5570 goto err;
5573 groupstatus = group_status(group);
5574 if (share == NULL) {
5575 share = sa_add_share(group, sharepath,
5576 persist, &ret);
5577 if (share == NULL &&
5578 ret == SA_DUPLICATE_NAME) {
5580 * Could be a ZFS path being started
5582 if (sa_zfs_is_shared(handle,
5583 sharepath)) {
5584 ret = SA_OK;
5585 group = sa_get_group(handle,
5586 "zfs");
5587 if (group == NULL) {
5589 * This shouldn't
5590 * happen.
5592 ret = SA_CONFIG_ERR;
5593 } else {
5594 share = sa_add_share(
5595 group, sharepath,
5596 persist, &ret);
5600 } else {
5601 char *type;
5603 * May want to change persist state, but the
5604 * important thing is to change options. We
5605 * need to change them regardless of the
5606 * source.
5609 if (sa_zfs_is_shared(handle, sharepath)) {
5610 zfs = 1;
5612 remove_all_options(share, protocol);
5613 type = sa_get_share_attr(share, "type");
5614 if (type != NULL &&
5615 strcmp(type, "transient") != 0) {
5616 curtype = SA_SHARE_PERMANENT;
5618 if (type != NULL)
5619 sa_free_attr_string(type);
5620 if (curtype != persist) {
5621 (void) sa_set_share_attr(share, "type",
5622 persist == SA_SHARE_PERMANENT ?
5623 "persist" : "transient");
5628 * If there is a resource name, we may
5629 * actually care about it if this is share for
5630 * a protocol that uses resource level sharing
5631 * (SMB). We need to find the resource and, if
5632 * it exists, make sure it belongs to the
5633 * current share. If it doesn't exist, attempt
5634 * to create it.
5637 if (ret == SA_OK && resource != NULL) {
5638 rsrc = sa_find_resource(handle, resource);
5639 if (rsrc != NULL) {
5640 if (share != sa_get_resource_parent(rsrc))
5641 ret = SA_DUPLICATE_NAME;
5642 } else {
5643 rsrc = sa_add_resource(share, resource,
5644 persist, &ret);
5646 if (features & SA_FEATURE_RESOURCE)
5647 share = rsrc;
5650 /* Have a group to hold this share path */
5651 if (ret == SA_OK && options != NULL &&
5652 strlen(options) > 0) {
5653 ret = sa_parse_legacy_options(share,
5654 options,
5655 protocol);
5657 if (!zfs) {
5659 * ZFS shares never have a description
5660 * and we can't store the values so
5661 * don't try.
5663 if (ret == SA_OK && description != NULL)
5664 ret = sa_set_share_description(share,
5665 description);
5667 if (ret == SA_OK &&
5668 strcmp(groupstatus, "enabled") == 0) {
5669 if (rsrc != share)
5670 ret = sa_enable_share(share, protocol);
5671 else
5672 ret = sa_enable_resource(rsrc,
5673 protocol);
5674 if (ret == SA_OK &&
5675 persist == SA_SHARE_PERMANENT) {
5676 (void) sa_update_legacy(share,
5677 protocol);
5679 if (ret == SA_OK)
5680 ret = sa_update_config(handle);
5683 err:
5684 if (ret != SA_OK) {
5685 (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
5686 sharepath, sa_errorstr(ret));
5687 ret = SA_LEGACY_ERR;
5689 return (ret);
5693 * sa_legacy_unshare(flags, argc, argv)
5695 * Implements the original unshare command.
5698 sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
5700 char *protocol = "nfs"; /* for now */
5701 char *options = NULL;
5702 char *sharepath = NULL;
5703 int persist = SA_SHARE_TRANSIENT;
5704 int argsused = 0;
5705 int c;
5706 int ret = SA_OK;
5707 int true_legacy = 0;
5708 uint64_t features = 0;
5709 sa_resource_t resource = NULL;
5710 char cmd[MAXPATHLEN];
5712 while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
5713 switch (c) {
5714 case 'F':
5715 protocol = optarg;
5716 if (!sa_valid_protocol(protocol)) {
5717 if (format_legacy_path(cmd, MAXPATHLEN,
5718 protocol, "unshare") == 0 &&
5719 check_legacy_cmd(cmd)) {
5720 true_legacy++;
5721 } else {
5722 (void) printf(gettext(
5723 "Invalid file system name\n"));
5724 return (SA_INVALID_PROTOCOL);
5727 break;
5728 case 'o':
5729 options = optarg;
5730 argsused++;
5731 break;
5732 case 'p':
5733 persist = SA_SHARE_PERMANENT;
5734 argsused++;
5735 break;
5736 case 'h':
5737 /* optopt on valid arg isn't defined */
5738 optopt = c;
5739 /*FALLTHROUGH*/
5740 case '?':
5741 default:
5743 * Since a bad option gets to here, sort it
5744 * out and return a syntax error return value
5745 * if necessary.
5747 switch (optopt) {
5748 default:
5749 ret = SA_LEGACY_ERR;
5750 break;
5751 case 'h':
5752 case '?':
5753 break;
5755 (void) printf(gettext("usage: %s\n"),
5756 sa_get_usage(USAGE_UNSHARE));
5757 return (ret);
5761 /* Have the info so construct what is needed */
5762 if (optind == argc || (optind + 1) < argc || options != NULL) {
5763 ret = SA_SYNTAX_ERR;
5764 } else {
5765 sa_share_t share;
5766 char dir[MAXPATHLEN];
5767 if (true_legacy) {
5768 /* if still using legacy share/unshare, exec it */
5769 ret = run_legacy_command(cmd, argv);
5770 return (ret);
5773 * Find the path in the internal configuration. If it
5774 * isn't found, attempt to resolve the path via
5775 * realpath() and try again.
5777 sharepath = argv[optind++];
5778 share = sa_find_share(handle, sharepath);
5779 if (share == NULL) {
5780 if (realpath(sharepath, dir) == NULL) {
5781 ret = SA_NO_SUCH_PATH;
5782 } else {
5783 share = sa_find_share(handle, dir);
5786 if (share == NULL) {
5787 /* Could be a resource name so check that next */
5788 features = sa_proto_get_featureset(protocol);
5789 resource = sa_find_resource(handle, sharepath);
5790 if (resource != NULL) {
5791 share = sa_get_resource_parent(resource);
5792 if (features & SA_FEATURE_RESOURCE)
5793 (void) sa_disable_resource(resource,
5794 protocol);
5795 if (persist == SA_SHARE_PERMANENT) {
5796 ret = sa_remove_resource(resource);
5797 if (ret == SA_OK)
5798 ret = sa_update_config(handle);
5801 * If we still have a resource on the
5802 * share, we don't disable the share
5803 * itself. IF there aren't anymore, we
5804 * need to remove the share. The
5805 * removal will be done in the next
5806 * section if appropriate.
5808 resource = sa_get_share_resource(share, NULL);
5809 if (resource != NULL)
5810 share = NULL;
5811 } else if (ret == SA_OK) {
5812 /* Didn't find path and no resource */
5813 ret = SA_BAD_PATH;
5816 if (share != NULL && resource == NULL) {
5817 ret = sa_disable_share(share, protocol);
5819 * Errors are ok and removal should still occur. The
5820 * legacy unshare is more forgiving of errors than the
5821 * remove-share subcommand which may need the force
5822 * flag set for some error conditions. That is, the
5823 * "unshare" command will always unshare if it can
5824 * while "remove-share" might require the force option.
5826 if (persist == SA_SHARE_PERMANENT) {
5827 ret = sa_remove_share(share);
5828 if (ret == SA_OK)
5829 ret = sa_update_config(handle);
5831 } else if (ret == SA_OK && share == NULL && resource == NULL) {
5833 * If both share and resource are NULL, then
5834 * share not found. If one or the other was
5835 * found or there was an earlier error, we
5836 * assume it was handled earlier.
5838 ret = SA_NOT_SHARED;
5841 switch (ret) {
5842 default:
5843 (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
5844 ret = SA_LEGACY_ERR;
5845 break;
5846 case SA_SYNTAX_ERR:
5847 (void) printf(gettext("usage: %s\n"),
5848 sa_get_usage(USAGE_UNSHARE));
5849 break;
5850 case SA_OK:
5851 break;
5853 return (ret);
5857 * Common commands that implement the sub-commands used by all
5858 * protocols. The entries are found via the lookup command
5861 static sa_command_t commands[] = {
5862 {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
5863 {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
5864 {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
5865 {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
5866 {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
5867 {"list", 0, sa_list, USAGE_LIST},
5868 {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
5869 {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
5870 {"set", 0, sa_set, USAGE_SET, SVC_SET},
5871 {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
5872 {"show", 0, sa_show, USAGE_SHOW},
5873 {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
5874 {"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
5875 SVC_SET|SVC_ACTION},
5876 {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
5877 {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
5878 {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
5879 {NULL, 0, 0, 0}
5882 static char *
5883 sa_get_usage(sa_usage_t index)
5885 char *ret = NULL;
5886 switch (index) {
5887 case USAGE_ADD_SHARE:
5888 ret = gettext("add-share [-nth] [-r resource-name] "
5889 "[-d \"description text\"] -s sharepath group");
5890 break;
5891 case USAGE_CREATE:
5892 ret = gettext(
5893 "create [-nvh] [-P proto [-p property=value]] group");
5894 break;
5895 case USAGE_DELETE:
5896 ret = gettext("delete [-nvh] [-P proto] [-f] group");
5897 break;
5898 case USAGE_DISABLE:
5899 ret = gettext("disable [-nvh] {-a | group ...}");
5900 break;
5901 case USAGE_ENABLE:
5902 ret = gettext("enable [-nvh] {-a | group ...}");
5903 break;
5904 case USAGE_LIST:
5905 ret = gettext("list [-vh] [-P proto]");
5906 break;
5907 case USAGE_MOVE_SHARE:
5908 ret = gettext(
5909 "move-share [-nvh] -s sharepath destination-group");
5910 break;
5911 case USAGE_REMOVE_SHARE:
5912 ret = gettext(
5913 "remove-share [-fnvh] {-s sharepath | -r resource} "
5914 "group");
5915 break;
5916 case USAGE_SET:
5917 ret = gettext("set [-nvh] -P proto [-S optspace] "
5918 "[-p property=value]* [-s sharepath] [-r resource]] "
5919 "group");
5920 break;
5921 case USAGE_SET_SECURITY:
5922 ret = gettext("set-security [-nvh] -P proto -S security-type "
5923 "[-p property=value]* group");
5924 break;
5925 case USAGE_SET_SHARE:
5926 ret = gettext("set-share [-nh] [-r resource] "
5927 "[-d \"description text\"] -s sharepath group");
5928 break;
5929 case USAGE_SHOW:
5930 ret = gettext("show [-pvxh] [-P proto] [group ...]");
5931 break;
5932 case USAGE_SHARE:
5933 ret = gettext("share [-F fstype] [-p] [-o optionlist]"
5934 "[-d description] [pathname [resourcename]]");
5935 break;
5936 case USAGE_START:
5937 ret = gettext("start [-vh] [-P proto] {-a | group ...}");
5938 break;
5939 case USAGE_STOP:
5940 ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
5941 break;
5942 case USAGE_UNSET:
5943 ret = gettext("unset [-nvh] -P proto [-S optspace] "
5944 "[-p property]* group");
5945 break;
5946 case USAGE_UNSET_SECURITY:
5947 ret = gettext("unset-security [-nvh] -P proto "
5948 "-S security-type [-p property]* group");
5949 break;
5950 case USAGE_UNSHARE:
5951 ret = gettext(
5952 "unshare [-F fstype] [-p] [-o optionlist] sharepath");
5953 break;
5955 return (ret);
5959 * sa_lookup(cmd, proto)
5961 * Lookup the sub-command. proto isn't currently used, but it may
5962 * eventually provide a way to provide protocol specific sub-commands.
5964 sa_command_t *
5965 sa_lookup(char *cmd, char *proto)
5967 int i;
5968 size_t len;
5970 len = strlen(cmd);
5971 for (i = 0; commands[i].cmdname != NULL; i++) {
5972 if (strncmp(cmd, commands[i].cmdname, len) == 0)
5973 return (&commands[i]);
5975 return (NULL);
5978 void
5979 sub_command_help(char *proto)
5981 int i;
5983 (void) printf(gettext("\tsub-commands:\n"));
5984 for (i = 0; commands[i].cmdname != NULL; i++) {
5985 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
5986 (void) printf("\t%s\n",
5987 sa_get_usage((sa_usage_t)commands[i].cmdidx));