1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <getopt.h>
36 #include <utmpx.h>
37 #include <pwd.h>
38 #include <auth_attr.h>
39 #include <secdb.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42 #include <errno.h>
43
44 #include <libshare.h>
45 #include "sharemgr.h"
46 #include <libscf.h>
47 #include <libxml/tree.h>
48 #include <libintl.h>
49 #include <assert.h>
50 #include <iconv.h>
51 #include <langinfo.h>
52 #include <dirent.h>
53
54 static char *sa_get_usage(sa_usage_t);
55
56 /*
57 * Implementation of the common sub-commands supported by sharemgr.
58 * A number of helper functions are also included.
59 */
60
61 /*
62 * has_protocol(group, proto)
63 * If the group has an optionset with the specified protocol,
64 * return true (1) otherwise false (0).
65 */
66 static int
has_protocol(sa_group_t group,char * protocol)67 has_protocol(sa_group_t group, char *protocol)
68 {
69 sa_optionset_t optionset;
70 int result = 0;
71
72 optionset = sa_get_optionset(group, protocol);
73 if (optionset != NULL) {
74 result++;
75 }
76 return (result);
77 }
78
79 /*
80 * validresource(name)
81 *
82 * Check that name only has valid characters in it. The current valid
83 * set are the printable characters but not including:
84 * " / \ [ ] : | < > + ; , ? * = \t
85 * Note that space is included and there is a maximum length.
86 */
87 static int
validresource(const char * name)88 validresource(const char *name)
89 {
90 const char *cp;
91 size_t len;
92
93 if (name == NULL)
94 return (B_FALSE);
95
96 len = strlen(name);
97 if (len == 0 || len > SA_MAX_RESOURCE_NAME)
98 return (B_FALSE);
99
100 if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
101 return (B_FALSE);
102 }
103
104 for (cp = name; *cp != '\0'; cp++)
105 if (iscntrl(*cp))
106 return (B_FALSE);
107
108 return (B_TRUE);
109 }
110
111 /*
112 * conv_to_utf8(input)
113 *
114 * Convert the input string to utf8 from the current locale. If the
115 * conversion fails, use the current locale, it is likely close
116 * enough. For example, the "C" locale is a subset of utf-8. The
117 * return value may be a new string or the original input string.
118 */
119
120 static char *
conv_to_utf8(char * input)121 conv_to_utf8(char *input)
122 {
123 iconv_t cd;
124 char *inval = input;
125 char *output = input;
126 char *outleft;
127 char *curlocale;
128 size_t bytesleft;
129 size_t size;
130 size_t osize;
131 static int warned = 0;
132
133 curlocale = nl_langinfo(CODESET);
134 if (curlocale == NULL)
135 curlocale = "C";
136 cd = iconv_open("UTF-8", curlocale);
137 if (cd != NULL && cd != (iconv_t)-1) {
138 size = strlen(input);
139 /* Assume worst case of characters expanding to 4 bytes. */
140 bytesleft = size * 4;
141 output = calloc(bytesleft, 1);
142 if (output != NULL) {
143 outleft = output;
144 /* inval can be modified on return */
145 osize = iconv(cd, (const char **)&inval, &size,
146 &outleft, &bytesleft);
147 if (osize == (size_t)-1 || size != 0) {
148 free(output);
149 output = input;
150 }
151 } else {
152 /* Need to return something. */
153 output = input;
154 }
155 (void) iconv_close(cd);
156 } else {
157 if (!warned)
158 (void) fprintf(stderr,
159 gettext("Cannot convert to UTF-8 from %s\n"),
160 curlocale ? curlocale : gettext("unknown"));
161 warned = 1;
162 }
163 return (output);
164 }
165
166 /*
167 * conv_from(input)
168 *
169 * Convert the input string from utf8 to current locale. If the
170 * conversion isn't supported, just use as is. The return value may be
171 * a new string or the original input string.
172 */
173
174 static char *
conv_from_utf8(char * input)175 conv_from_utf8(char *input)
176 {
177 iconv_t cd;
178 char *output = input;
179 char *inval = input;
180 char *outleft;
181 char *curlocale;
182 size_t bytesleft;
183 size_t size;
184 size_t osize;
185 static int warned = 0;
186
187 curlocale = nl_langinfo(CODESET);
188 if (curlocale == NULL)
189 curlocale = "C";
190 cd = iconv_open(curlocale, "UTF-8");
191 if (cd != NULL && cd != (iconv_t)-1) {
192 size = strlen(input);
193 /* Assume worst case of characters expanding to 4 bytes. */
194 bytesleft = size * 4;
195 output = calloc(bytesleft, 1);
196 if (output != NULL) {
197 outleft = output;
198 osize = iconv(cd, (const char **)&inval, &size,
199 &outleft, &bytesleft);
200 if (osize == (size_t)-1 || size != 0)
201 output = input;
202 } else {
203 /* Need to return something. */
204 output = input;
205 }
206 (void) iconv_close(cd);
207 } else {
208 if (!warned)
209 (void) fprintf(stderr,
210 gettext("Cannot convert to %s from UTF-8\n"),
211 curlocale ? curlocale : gettext("unknown"));
212 warned = 1;
213 }
214 return (output);
215 }
216
217 /*
218 * print_rsrc_desc(resource, sharedesc)
219 *
220 * Print the resource description string after converting from UTF8 to
221 * the current locale. If sharedesc is not NULL and there is no
222 * description on the resource, use sharedesc. sharedesc will already
223 * be converted to UTF8.
224 */
225
226 static void
print_rsrc_desc(sa_resource_t resource,char * sharedesc)227 print_rsrc_desc(sa_resource_t resource, char *sharedesc)
228 {
229 char *description;
230 char *desc;
231
232 if (resource == NULL)
233 return;
234
235 description = sa_get_resource_description(resource);
236 if (description != NULL) {
237 desc = conv_from_utf8(description);
238 if (desc != description) {
239 sa_free_share_description(description);
240 description = desc;
241 }
242 } else if (sharedesc != NULL) {
243 description = strdup(sharedesc);
244 }
245 if (description != NULL) {
246 (void) printf("\t\"%s\"", description);
247 sa_free_share_description(description);
248 }
249 }
250
251 /*
252 * set_resource_desc(share, description)
253 *
254 * Set the share description value after converting the description
255 * string to UTF8 from the current locale.
256 */
257
258 static int
set_resource_desc(sa_share_t share,char * description)259 set_resource_desc(sa_share_t share, char *description)
260 {
261 char *desc;
262 int ret;
263
264 desc = conv_to_utf8(description);
265 ret = sa_set_resource_description(share, desc);
266 if (description != desc)
267 sa_free_share_description(desc);
268 return (ret);
269 }
270
271 /*
272 * set_share_desc(share, description)
273 *
274 * Set the resource description value after converting the description
275 * string to UTF8 from the current locale.
276 */
277
278 static int
set_share_desc(sa_share_t share,char * description)279 set_share_desc(sa_share_t share, char *description)
280 {
281 char *desc;
282 int ret;
283
284 desc = conv_to_utf8(description);
285 ret = sa_set_share_description(share, desc);
286 if (description != desc)
287 sa_free_share_description(desc);
288 return (ret);
289 }
290
291 /*
292 * add_list(list, item, data, proto)
293 * Adds a new list member that points holds item in the list.
294 * If list is NULL, it starts a new list. The function returns
295 * the first member of the list.
296 */
297 struct list *
add_list(struct list * listp,void * item,void * data,char * proto)298 add_list(struct list *listp, void *item, void *data, char *proto)
299 {
300 struct list *new, *tmp;
301
302 new = malloc(sizeof (struct list));
303 if (new != NULL) {
304 new->next = NULL;
305 new->item = item;
306 new->itemdata = data;
307 new->proto = proto;
308 } else {
309 return (listp);
310 }
311
312 if (listp == NULL)
313 return (new);
314
315 for (tmp = listp; tmp->next != NULL; tmp = tmp->next) {
316 /* get to end of list */
317 }
318 tmp->next = new;
319 return (listp);
320 }
321
322 /*
323 * free_list(list)
324 * Given a list, free all the members of the list;
325 */
326 static void
free_list(struct list * listp)327 free_list(struct list *listp)
328 {
329 struct list *tmp;
330 while (listp != NULL) {
331 tmp = listp;
332 listp = listp->next;
333 free(tmp);
334 }
335 }
336
337 /*
338 * check_authorization(instname, which)
339 *
340 * Checks to see if the specific type of authorization in which is
341 * enabled for the user in this SMF service instance.
342 */
343
344 static int
check_authorization(char * instname,int which)345 check_authorization(char *instname, int which)
346 {
347 scf_handle_t *handle = NULL;
348 scf_simple_prop_t *prop = NULL;
349 char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
350 char *authstr = NULL;
351 ssize_t numauths;
352 int ret = B_TRUE;
353 uid_t uid;
354 struct passwd *pw = NULL;
355
356 uid = getuid();
357 pw = getpwuid(uid);
358 if (pw == NULL) {
359 ret = B_FALSE;
360 } else {
361 /*
362 * Since names are restricted to SA_MAX_NAME_LEN won't
363 * overflow.
364 */
365 (void) snprintf(svcstring, sizeof (svcstring), "%s:%s",
366 SA_SVC_FMRI_BASE, instname);
367 handle = scf_handle_create(SCF_VERSION);
368 if (handle != NULL) {
369 if (scf_handle_bind(handle) == 0) {
370 switch (which) {
371 case SVC_SET:
372 prop = scf_simple_prop_get(handle,
373 svcstring, "general",
374 SVC_AUTH_VALUE);
375 break;
376 case SVC_ACTION:
377 prop = scf_simple_prop_get(handle,
378 svcstring, "general",
379 SVC_AUTH_ACTION);
380 break;
381 }
382 }
383 }
384 }
385 /* make sure we have an authorization string property */
386 if (prop != NULL) {
387 int i;
388 numauths = scf_simple_prop_numvalues(prop);
389 for (ret = 0, i = 0; i < numauths; i++) {
390 authstr = scf_simple_prop_next_astring(prop);
391 if (authstr != NULL) {
392 /* check if this user has one of the strings */
393 if (chkauthattr(authstr, pw->pw_name)) {
394 ret = 1;
395 break;
396 }
397 }
398 }
399 endauthattr();
400 scf_simple_prop_free(prop);
401 } else {
402 /* no authorization string defined */
403 ret = 0;
404 }
405 if (handle != NULL)
406 scf_handle_destroy(handle);
407 return (ret);
408 }
409
410 /*
411 * check_authorizations(instname, flags)
412 *
413 * check all the needed authorizations for the user in this service
414 * instance. Return value of 1(true) or 0(false) indicates whether
415 * there are authorizations for the user or not.
416 */
417
418 static int
check_authorizations(char * instname,int flags)419 check_authorizations(char *instname, int flags)
420 {
421 int ret1 = 0;
422 int ret2 = 0;
423 int ret;
424
425 if (flags & SVC_SET)
426 ret1 = check_authorization(instname, SVC_SET);
427 if (flags & SVC_ACTION)
428 ret2 = check_authorization(instname, SVC_ACTION);
429 switch (flags) {
430 case SVC_ACTION:
431 ret = ret2;
432 break;
433 case SVC_SET:
434 ret = ret1;
435 break;
436 case SVC_ACTION|SVC_SET:
437 ret = ret1 & ret2;
438 break;
439 default:
440 /* if not flags set, we assume we don't need authorizations */
441 ret = 1;
442 }
443 return (ret);
444 }
445
446 /*
447 * notify_or_enable_share(share, protocol)
448 *
449 * Since some protocols don't want an "enable" when properties change,
450 * this function will use the protocol specific notify function
451 * first. If that fails, it will then attempt to use the
452 * sa_enable_share(). "protocol" is the protocol that was specified
453 * on the command line.
454 */
455 static void
notify_or_enable_share(sa_share_t share,char * protocol)456 notify_or_enable_share(sa_share_t share, char *protocol)
457 {
458 sa_group_t group;
459 sa_optionset_t opt;
460 int ret = SA_OK;
461 char *path;
462 char *groupproto;
463 sa_share_t parent = share;
464
465 /* If really a resource, get parent share */
466 if (!sa_is_share(share)) {
467 parent = sa_get_resource_parent((sa_resource_t)share);
468 }
469
470 /*
471 * Now that we've got a share in "parent", make sure it has a path.
472 */
473 path = sa_get_share_attr(parent, "path");
474 if (path == NULL)
475 return;
476
477 group = sa_get_parent_group(parent);
478
479 if (group == NULL) {
480 sa_free_attr_string(path);
481 return;
482 }
483 for (opt = sa_get_optionset(group, NULL);
484 opt != NULL;
485 opt = sa_get_next_optionset(opt)) {
486 groupproto = sa_get_optionset_attr(opt, "type");
487 if (groupproto == NULL ||
488 (protocol != NULL && strcmp(groupproto, protocol) != 0)) {
489 if (groupproto != NULL)
490 sa_free_attr_string(groupproto);
491 continue;
492 }
493 if (sa_is_share(share)) {
494 if ((ret = sa_proto_change_notify(share,
495 groupproto)) != SA_OK) {
496 ret = sa_enable_share(share, groupproto);
497 if (ret != SA_OK) {
498 (void) printf(
499 gettext("Could not reenable"
500 " share %s: %s\n"),
501 path, sa_errorstr(ret));
502 }
503 }
504 } else {
505 /* Must be a resource */
506 if ((ret = sa_proto_notify_resource(share,
507 groupproto)) != SA_OK) {
508 ret = sa_enable_resource(share, groupproto);
509 if (ret != SA_OK) {
510 (void) printf(
511 gettext("Could not "
512 "reenable resource %s: "
513 "%s\n"), path,
514 sa_errorstr(ret));
515 }
516 }
517 }
518 sa_free_attr_string(groupproto);
519 }
520 sa_free_attr_string(path);
521 }
522
523 /*
524 * enable_group(group, updateproto, notify, proto)
525 *
526 * enable all the shares in the specified group. This is a helper for
527 * enable_all_groups in order to simplify regular and subgroup (zfs)
528 * enabling. Group has already been checked for non-NULL. If notify
529 * is non-zero, attempt to use the notify interface rather than
530 * enable.
531 */
532 static void
enable_group(sa_group_t group,char * updateproto,int notify,char * proto)533 enable_group(sa_group_t group, char *updateproto, int notify, char *proto)
534 {
535 sa_share_t share;
536
537 for (share = sa_get_share(group, NULL);
538 share != NULL;
539 share = sa_get_next_share(share)) {
540 if (updateproto != NULL)
541 (void) sa_update_legacy(share, updateproto);
542 if (notify)
543 notify_or_enable_share(share, proto);
544 else
545 (void) sa_enable_share(share, proto);
546 }
547 }
548
549 /*
550 * isenabled(group)
551 *
552 * Returns B_TRUE if the group is enabled or B_FALSE if it isn't.
553 * Moved to separate function to reduce clutter in the code.
554 */
555
556 static int
isenabled(sa_group_t group)557 isenabled(sa_group_t group)
558 {
559 char *state;
560 int ret = B_FALSE;
561
562 if (group != NULL) {
563 state = sa_get_group_attr(group, "state");
564 if (state != NULL) {
565
566 if (strcmp(state, "enabled") == 0)
567 ret = B_TRUE;
568 sa_free_attr_string(state);
569 }
570 }
571 return (ret);
572 }
573
574 /*
575 * enable_all_groups(list, setstate, online, updateproto)
576 *
577 * Given a list of groups, enable each one found. If updateproto is
578 * not NULL, then update all the shares for the protocol that was
579 * passed in. If enable is non-zero, tell enable_group to try the
580 * notify interface since this is a property change.
581 */
582 static int
enable_all_groups(sa_handle_t handle,struct list * work,int setstate,int online,char * updateproto,int enable)583 enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
584 int online, char *updateproto, int enable)
585 {
586 int ret;
587 char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
588 char *state;
589 char *name;
590 char *zfs = NULL;
591 sa_group_t group;
592 sa_group_t subgroup;
593
594 for (ret = SA_OK; work != NULL; work = work->next) {
595 group = (sa_group_t)work->item;
596
597 /*
598 * If setstate == TRUE, then make sure to set
599 * enabled. This needs to be done here in order for
600 * the isenabled check to succeed on a newly enabled
601 * group.
602 */
603 if (setstate == B_TRUE) {
604 ret = sa_set_group_attr(group, "state", "enabled");
605 if (ret != SA_OK)
606 break;
607 }
608
609 /*
610 * Check to see if group is enabled. If it isn't, skip
611 * the rest. We don't want shares starting if the
612 * group is disabled. The properties may have been
613 * updated, but there won't be a change until the
614 * group is enabled.
615 */
616 if (!isenabled(group))
617 continue;
618
619 /* if itemdata != NULL then a single share */
620 if (work->itemdata != NULL) {
621 if (enable) {
622 if (work->itemdata != NULL)
623 notify_or_enable_share(work->itemdata,
624 updateproto);
625 else
626 ret = SA_CONFIG_ERR;
627 } else {
628 if (sa_is_share(work->itemdata)) {
629 ret = sa_enable_share(
630 (sa_share_t)work->itemdata,
631 updateproto);
632 } else {
633 ret = sa_enable_resource(
634 (sa_resource_t)work->itemdata,
635 updateproto);
636 }
637 }
638 }
639 if (ret != SA_OK)
640 break;
641
642 /* if itemdata == NULL then the whole group */
643 if (work->itemdata == NULL) {
644 zfs = sa_get_group_attr(group, "zfs");
645 /*
646 * If the share is managed by ZFS, don't
647 * update any of the protocols since ZFS is
648 * handling this. Updateproto will contain
649 * the name of the protocol that we want to
650 * update legacy files for.
651 */
652 enable_group(group, zfs == NULL ? updateproto : NULL,
653 enable, work->proto);
654 if (zfs != NULL)
655 sa_free_attr_string(zfs);
656
657 for (subgroup = sa_get_sub_group(group);
658 subgroup != NULL;
659 subgroup = sa_get_next_group(subgroup)) {
660 /* never update legacy for ZFS subgroups */
661 enable_group(subgroup, NULL, enable,
662 work->proto);
663 }
664 }
665 if (online) {
666 zfs = sa_get_group_attr(group, "zfs");
667 name = sa_get_group_attr(group, "name");
668 if (name != NULL) {
669 if (zfs == NULL) {
670 (void) snprintf(instance,
671 sizeof (instance), "%s:%s",
672 SA_SVC_FMRI_BASE, name);
673 state = smf_get_state(instance);
674 if (state == NULL ||
675 strcmp(state, "online") != 0) {
676 (void) smf_enable_instance(
677 instance, 0);
678 free(state);
679 }
680 } else {
681 sa_free_attr_string(zfs);
682 zfs = NULL;
683 }
684 if (name != NULL)
685 sa_free_attr_string(name);
686 }
687 }
688 }
689 if (ret == SA_OK) {
690 ret = sa_update_config(handle);
691 }
692 return (ret);
693 }
694
695 /*
696 * chk_opt(optlistp, security, proto)
697 *
698 * Do a sanity check on the optlist provided for the protocol. This
699 * is a syntax check and verification that the property is either a
700 * general or specific to a names optionset.
701 */
702
703 static int
chk_opt(struct options * optlistp,int security,char * proto)704 chk_opt(struct options *optlistp, int security, char *proto)
705 {
706 struct options *optlist;
707 char *sep = "";
708 int notfirst = 0;
709 int ret;
710
711 for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
712 char *optname;
713
714 optname = optlist->optname;
715 ret = OPT_ADD_OK;
716 /* extract property/value pair */
717 if (sa_is_security(optname, proto)) {
718 if (!security)
719 ret = OPT_ADD_SECURITY;
720 } else {
721 if (security)
722 ret = OPT_ADD_PROPERTY;
723 }
724 if (ret != OPT_ADD_OK) {
725 if (notfirst == 0)
726 (void) printf(
727 gettext("Property syntax error: "));
728 switch (ret) {
729 case OPT_ADD_SYNTAX:
730 (void) printf(gettext("%ssyntax error: %s"),
731 sep, optname);
732 sep = ", ";
733 break;
734 case OPT_ADD_SECURITY:
735 (void) printf(gettext("%s%s requires -S"),
736 optname, sep);
737 sep = ", ";
738 break;
739 case OPT_ADD_PROPERTY:
740 (void) printf(
741 gettext("%s%s not supported with -S"),
742 optname, sep);
743 sep = ", ";
744 break;
745 }
746 notfirst++;
747 }
748 }
749 if (notfirst) {
750 (void) printf("\n");
751 ret = SA_SYNTAX_ERR;
752 }
753 return (ret);
754 }
755
756 /*
757 * free_opt(optlist)
758 * Free the specified option list.
759 */
760 static void
free_opt(struct options * optlist)761 free_opt(struct options *optlist)
762 {
763 struct options *nextopt;
764 while (optlist != NULL) {
765 nextopt = optlist->next;
766 free(optlist);
767 optlist = nextopt;
768 }
769 }
770
771 /*
772 * check property list for valid properties
773 * A null value is a remove which is always valid.
774 */
775 static int
valid_options(sa_handle_t handle,struct options * optlist,char * proto,void * object,char * sec)776 valid_options(sa_handle_t handle, struct options *optlist, char *proto,
777 void *object, char *sec)
778 {
779 int ret = SA_OK;
780 struct options *cur;
781 sa_property_t prop;
782 sa_optionset_t parent = NULL;
783
784 if (object != NULL) {
785 if (sec == NULL)
786 parent = sa_get_optionset(object, proto);
787 else
788 parent = sa_get_security(object, sec, proto);
789 }
790
791 for (cur = optlist; cur != NULL; cur = cur->next) {
792 if (cur->optvalue == NULL)
793 continue;
794 prop = sa_create_property(cur->optname, cur->optvalue);
795 if (prop == NULL)
796 ret = SA_NO_MEMORY;
797 if (ret != SA_OK ||
798 (ret = sa_valid_property(handle, parent, proto, prop)) !=
799 SA_OK) {
800 (void) printf(
801 gettext("Could not add property %s: %s\n"),
802 cur->optname, sa_errorstr(ret));
803 }
804 (void) sa_remove_property(prop);
805 }
806 return (ret);
807 }
808
809 /*
810 * add_optionset(group, optlist, protocol, *err)
811 * Add the options in optlist to an optionset and then add the optionset
812 * to the group.
813 *
814 * The return value indicates if there was a "change" while errors are
815 * returned via the *err parameters.
816 */
817 static int
add_optionset(sa_group_t group,struct options * optlist,char * proto,int * err)818 add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
819 {
820 sa_optionset_t optionset;
821 int ret = SA_OK;
822 int result = B_FALSE;
823 sa_handle_t handle;
824
825 optionset = sa_get_optionset(group, proto);
826 if (optionset == NULL) {
827 optionset = sa_create_optionset(group, proto);
828 if (optionset == NULL)
829 ret = SA_NO_MEMORY;
830 result = B_TRUE; /* adding a protocol is a change */
831 }
832 if (optionset == NULL) {
833 ret = SA_NO_MEMORY;
834 goto out;
835 }
836 handle = sa_find_group_handle(group);
837 if (handle == NULL) {
838 ret = SA_CONFIG_ERR;
839 goto out;
840 }
841 while (optlist != NULL) {
842 sa_property_t prop;
843 prop = sa_get_property(optionset, optlist->optname);
844 if (prop == NULL) {
845 /*
846 * add the property, but only if it is
847 * a non-NULL or non-zero length value
848 */
849 if (optlist->optvalue != NULL) {
850 prop = sa_create_property(optlist->optname,
851 optlist->optvalue);
852 if (prop != NULL) {
853 ret = sa_valid_property(handle,
854 optionset, proto, prop);
855 if (ret != SA_OK) {
856 (void) sa_remove_property(prop);
857 (void) printf(gettext("Could "
858 "not add property "
859 "%s: %s\n"),
860 optlist->optname,
861 sa_errorstr(ret));
862 }
863 }
864 if (ret == SA_OK) {
865 ret = sa_add_property(optionset, prop);
866 if (ret != SA_OK) {
867 (void) printf(gettext(
868 "Could not add property "
869 "%s: %s\n"),
870 optlist->optname,
871 sa_errorstr(ret));
872 } else {
873 /* there was a change */
874 result = B_TRUE;
875 }
876 }
877 }
878 } else {
879 ret = sa_update_property(prop, optlist->optvalue);
880 /* should check to see if value changed */
881 if (ret != SA_OK) {
882 (void) printf(gettext("Could not update "
883 "property %s: %s\n"), optlist->optname,
884 sa_errorstr(ret));
885 } else {
886 result = B_TRUE;
887 }
888 }
889 optlist = optlist->next;
890 }
891 ret = sa_commit_properties(optionset, 0);
892
893 out:
894 if (err != NULL)
895 *err = ret;
896 return (result);
897 }
898
899 /*
900 * resource_compliant(group)
901 *
902 * Go through all the shares in the group. Assume compliant, but if
903 * any share doesn't have at least one resource name, it isn't
904 * compliant.
905 */
906 static int
resource_compliant(sa_group_t group)907 resource_compliant(sa_group_t group)
908 {
909 sa_share_t share;
910
911 for (share = sa_get_share(group, NULL); share != NULL;
912 share = sa_get_next_share(share)) {
913 if (sa_get_share_resource(share, NULL) == NULL) {
914 return (B_FALSE);
915 }
916 }
917 return (B_TRUE);
918 }
919
920 /*
921 * fix_path(path)
922 *
923 * change all illegal characters to something else. For now, all get
924 * converted to '_' and the leading '/' is stripped off. This is used
925 * to construct an resource name (SMB share name) that is valid.
926 * Caller must pass a valid path.
927 */
928 static void
fix_path(char * path)929 fix_path(char *path)
930 {
931 char *cp;
932 size_t len;
933
934 assert(path != NULL);
935
936 /* make sure we are appropriate length */
937 cp = path + 1; /* skip leading slash */
938 while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
939 cp = strchr(cp, '/');
940 if (cp != NULL)
941 cp++;
942 }
943 /* two cases - cp == NULL and cp is substring of path */
944 if (cp == NULL) {
945 /* just take last SA_MAX_RESOURCE_NAME chars */
946 len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
947 (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
948 path[SA_MAX_RESOURCE_NAME] = '\0';
949 } else {
950 len = strlen(cp) + 1;
951 (void) memmove(path, cp, len);
952 }
953
954 /*
955 * Don't want any of the characters that are not allowed
956 * in and SMB share name. Replace them with '_'.
957 */
958 while (*path) {
959 switch (*path) {
960 case '/':
961 case '"':
962 case '\\':
963 case '[':
964 case ']':
965 case ':':
966 case '|':
967 case '<':
968 case '>':
969 case '+':
970 case ';':
971 case ',':
972 case '?':
973 case '*':
974 case '=':
975 case '\t':
976 *path = '_';
977 break;
978 }
979 path++;
980 }
981 }
982
983 /*
984 * name_adjust(path, count)
985 *
986 * Add a ~<count> in place of last few characters. The total number of
987 * characters is dependent on count.
988 */
989 #define MAX_MANGLE_NUMBER 10000
990
991 static int
name_adjust(char * path,int count)992 name_adjust(char *path, int count)
993 {
994 size_t len;
995
996 len = strlen(path) - 2;
997 if (count > 10)
998 len--;
999 if (count > 100)
1000 len--;
1001 if (count > 1000)
1002 len--;
1003 if (len > 0)
1004 (void) sprintf(path + len, "~%d", count);
1005 else
1006 return (SA_BAD_VALUE);
1007
1008 return (SA_OK);
1009 }
1010
1011 /*
1012 * make_resources(group)
1013 *
1014 * Go through all the shares in the group and make them have resource
1015 * names.
1016 */
1017 static void
make_resources(sa_group_t group)1018 make_resources(sa_group_t group)
1019 {
1020 sa_share_t share;
1021 int count;
1022 int err = SA_OK;
1023
1024 for (share = sa_get_share(group, NULL); share != NULL;
1025 share = sa_get_next_share(share)) {
1026 /* Skip those with resources */
1027 if (sa_get_share_resource(share, NULL) == NULL) {
1028 char *path;
1029 path = sa_get_share_attr(share, "path");
1030 if (path == NULL)
1031 continue;
1032 fix_path(path);
1033 count = 0; /* reset for next resource */
1034 while (sa_add_resource(share, path,
1035 SA_SHARE_PERMANENT, &err) == NULL &&
1036 err == SA_DUPLICATE_NAME) {
1037 int ret;
1038 ret = name_adjust(path, count);
1039 count++;
1040 if (ret != SA_OK ||
1041 count >= MAX_MANGLE_NUMBER) {
1042 (void) printf(gettext(
1043 "Cannot create resource name for"
1044 " path: %s\n"), path);
1045 break;
1046 }
1047 }
1048 sa_free_attr_string(path);
1049 }
1050 }
1051 }
1052
1053 /*
1054 * check_valid_group(group, protocol)
1055 *
1056 * Check to see that the group should have the protocol added (if
1057 * there is one specified).
1058 */
1059
1060 static int
check_valid_group(sa_group_t group,char * groupname,char * protocol)1061 check_valid_group(sa_group_t group, char *groupname, char *protocol)
1062 {
1063
1064 if (protocol != NULL) {
1065 if (has_protocol(group, protocol)) {
1066 (void) printf(gettext(
1067 "Group \"%s\" already exists"
1068 " with protocol %s\n"), groupname,
1069 protocol);
1070 return (SA_DUPLICATE_NAME);
1071 } else if (strcmp(groupname, "default") == 0 &&
1072 strcmp(protocol, "nfs") != 0) {
1073 (void) printf(gettext(
1074 "Group \"%s\" only allows protocol "
1075 "\"%s\"\n"), groupname, "nfs");
1076 return (SA_INVALID_PROTOCOL);
1077 }
1078 } else {
1079 /* must add new protocol */
1080 (void) printf(gettext(
1081 "Group already exists and no protocol "
1082 "specified.\n"));
1083 return (SA_DUPLICATE_NAME);
1084 }
1085 return (SA_OK);
1086 }
1087
1088 /*
1089 * enforce_featureset(group, protocol, dryrun, force)
1090 *
1091 * Check the protocol featureset against the group and enforce any
1092 * rules that might be imposed.
1093 */
1094
1095 static int
enforce_featureset(sa_group_t group,char * protocol,boolean_t dryrun,boolean_t force)1096 enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun,
1097 boolean_t force)
1098 {
1099 uint64_t features;
1100
1101 if (protocol == NULL)
1102 return (SA_OK);
1103
1104 /*
1105 * First check to see if specified protocol is one we want to
1106 * allow on a group. Only server protocols are allowed here.
1107 */
1108 features = sa_proto_get_featureset(protocol);
1109 if (!(features & SA_FEATURE_SERVER)) {
1110 (void) printf(
1111 gettext("Protocol \"%s\" not supported.\n"), protocol);
1112 return (SA_INVALID_PROTOCOL);
1113 }
1114
1115 /*
1116 * Check to see if the new protocol is one that requires
1117 * resource names and make sure we are compliant before
1118 * proceeding.
1119 */
1120 if ((features & SA_FEATURE_RESOURCE) &&
1121 !resource_compliant(group)) {
1122 if (force && !dryrun) {
1123 make_resources(group);
1124 } else {
1125 (void) printf(
1126 gettext("Protocol requires resource names to be "
1127 "set: %s\n"), protocol);
1128 return (SA_RESOURCE_REQUIRED);
1129 }
1130 }
1131 return (SA_OK);
1132 }
1133
1134 /*
1135 * set_all_protocols(group)
1136 *
1137 * Get the list of all protocols and add all server protocols to the
1138 * group.
1139 */
1140
1141 static int
set_all_protocols(sa_group_t group)1142 set_all_protocols(sa_group_t group)
1143 {
1144 char **protolist;
1145 int numprotos, i;
1146 uint64_t features;
1147 sa_optionset_t optionset;
1148 int ret = SA_OK;
1149
1150 /*
1151 * Now make sure we really want to put this protocol on a
1152 * group. Only server protocols can go here.
1153 */
1154 numprotos = sa_get_protocols(&protolist);
1155 for (i = 0; i < numprotos; i++) {
1156 features = sa_proto_get_featureset(protolist[i]);
1157 if (features & SA_FEATURE_SERVER) {
1158 optionset = sa_create_optionset(group, protolist[i]);
1159 if (optionset == NULL) {
1160 ret = SA_NO_MEMORY;
1161 break;
1162 }
1163 }
1164 }
1165
1166 if (protolist != NULL)
1167 free(protolist);
1168
1169 return (ret);
1170 }
1171
1172 /*
1173 * sa_create(flags, argc, argv)
1174 * create a new group
1175 * this may or may not have a protocol associated with it.
1176 * No protocol means "all" protocols in this case.
1177 */
1178 static int
sa_create(sa_handle_t handle,int flags,int argc,char * argv[])1179 sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
1180 {
1181 char *groupname;
1182
1183 sa_group_t group;
1184 boolean_t force = B_FALSE;
1185 boolean_t verbose = B_FALSE;
1186 boolean_t dryrun = B_FALSE;
1187 int c;
1188 char *protocol = NULL;
1189 int ret = SA_OK;
1190 struct options *optlist = NULL;
1191 int err = SA_OK;
1192 int auth;
1193 boolean_t created = B_FALSE;
1194
1195 while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) {
1196 switch (c) {
1197 case 'f':
1198 force = B_TRUE;
1199 break;
1200 case 'v':
1201 verbose = B_TRUE;
1202 break;
1203 case 'n':
1204 dryrun = B_TRUE;
1205 break;
1206 case 'P':
1207 if (protocol != NULL) {
1208 (void) printf(gettext("Specifying "
1209 "multiple protocols "
1210 "not supported: %s\n"), protocol);
1211 return (SA_SYNTAX_ERR);
1212 }
1213 protocol = optarg;
1214 if (sa_valid_protocol(protocol))
1215 break;
1216 (void) printf(gettext(
1217 "Invalid protocol specified: %s\n"), protocol);
1218 return (SA_INVALID_PROTOCOL);
1219 break;
1220 case 'p':
1221 ret = add_opt(&optlist, optarg, 0);
1222 switch (ret) {
1223 case OPT_ADD_SYNTAX:
1224 (void) printf(gettext(
1225 "Property syntax error for property: %s\n"),
1226 optarg);
1227 return (SA_SYNTAX_ERR);
1228 case OPT_ADD_SECURITY:
1229 (void) printf(gettext(
1230 "Security properties need "
1231 "to be set with set-security: %s\n"),
1232 optarg);
1233 return (SA_SYNTAX_ERR);
1234 default:
1235 break;
1236 }
1237 break;
1238 case 'h':
1239 /* optopt on valid arg isn't defined */
1240 optopt = c;
1241 /*FALLTHROUGH*/
1242 case '?':
1243 default:
1244 /*
1245 * Since a bad option gets to here, sort it
1246 * out and return a syntax error return value
1247 * if necessary.
1248 */
1249 switch (optopt) {
1250 default:
1251 err = SA_SYNTAX_ERR;
1252 break;
1253 case 'h':
1254 case '?':
1255 break;
1256 }
1257 (void) printf(gettext("usage: %s\n"),
1258 sa_get_usage(USAGE_CREATE));
1259 return (err);
1260 }
1261 }
1262
1263 if (optind >= argc) {
1264 (void) printf(gettext("usage: %s\n"),
1265 sa_get_usage(USAGE_CREATE));
1266 (void) printf(gettext("\tgroup must be specified.\n"));
1267 return (SA_BAD_PATH);
1268 }
1269
1270 if ((optind + 1) < argc) {
1271 (void) printf(gettext("usage: %s\n"),
1272 sa_get_usage(USAGE_CREATE));
1273 (void) printf(gettext("\textraneous group(s) at end\n"));
1274 return (SA_SYNTAX_ERR);
1275 }
1276
1277 if (protocol == NULL && optlist != NULL) {
1278 /* lookup default protocol */
1279 (void) printf(gettext("usage: %s\n"),
1280 sa_get_usage(USAGE_CREATE));
1281 (void) printf(gettext("\tprotocol must be specified "
1282 "with properties\n"));
1283 return (SA_INVALID_PROTOCOL);
1284 }
1285
1286 if (optlist != NULL)
1287 ret = chk_opt(optlist, 0, protocol);
1288 if (ret == OPT_ADD_SECURITY) {
1289 (void) printf(gettext("Security properties not "
1290 "supported with create\n"));
1291 return (SA_SYNTAX_ERR);
1292 }
1293
1294 /*
1295 * If a group already exists, we can only add a new protocol
1296 * to it and not create a new one or add the same protocol
1297 * again.
1298 */
1299
1300 groupname = argv[optind];
1301
1302 auth = check_authorizations(groupname, flags);
1303
1304 group = sa_get_group(handle, groupname);
1305 if (group != NULL) {
1306 /* group exists so must be a protocol add */
1307 ret = check_valid_group(group, groupname, protocol);
1308 } else {
1309 /*
1310 * is it a valid name? Must comply with SMF instance
1311 * name restrictions.
1312 */
1313 if (!sa_valid_group_name(groupname)) {
1314 ret = SA_INVALID_NAME;
1315 (void) printf(gettext("Invalid group name: %s\n"),
1316 groupname);
1317 }
1318 }
1319 if (ret == SA_OK) {
1320 /* check protocol vs optlist */
1321 if (optlist != NULL) {
1322 /* check options, if any, for validity */
1323 ret = valid_options(handle, optlist, protocol,
1324 group, NULL);
1325 }
1326 }
1327 if (ret == SA_OK && !dryrun) {
1328 if (group == NULL) {
1329 group = sa_create_group(handle, (char *)groupname,
1330 &err);
1331 created = B_TRUE;
1332 }
1333 if (group != NULL) {
1334 sa_optionset_t optionset;
1335
1336 /*
1337 * Check group and protocol against featureset
1338 * requirements.
1339 */
1340 ret = enforce_featureset(group, protocol,
1341 dryrun, force);
1342 if (ret != SA_OK)
1343 goto err;
1344
1345 /*
1346 * So far so good. Now add the required
1347 * optionset(s) to the group.
1348 */
1349 if (optlist != NULL) {
1350 (void) add_optionset(group, optlist, protocol,
1351 &ret);
1352 } else if (protocol != NULL) {
1353 optionset = sa_create_optionset(group,
1354 protocol);
1355 if (optionset == NULL)
1356 ret = SA_NO_MEMORY;
1357 } else if (protocol == NULL) {
1358 /* default group create so add all protocols */
1359 ret = set_all_protocols(group);
1360 }
1361 /*
1362 * We have a group and legal additions
1363 */
1364 if (ret == SA_OK) {
1365 /*
1366 * Commit to configuration for protocols that
1367 * need to do block updates. For NFS, this
1368 * doesn't do anything but it will be run for
1369 * all protocols that implement the
1370 * appropriate plugin.
1371 */
1372 ret = sa_update_config(handle);
1373 } else {
1374 if (group != NULL)
1375 (void) sa_remove_group(group);
1376 }
1377 } else {
1378 ret = err;
1379 (void) printf(gettext("Could not create group: %s\n"),
1380 sa_errorstr(ret));
1381 }
1382 }
1383 if (dryrun && ret == SA_OK && !auth && verbose) {
1384 (void) printf(gettext("Command would fail: %s\n"),
1385 sa_errorstr(SA_NO_PERMISSION));
1386 ret = SA_NO_PERMISSION;
1387 }
1388 err:
1389 if (ret != SA_OK && created)
1390 ret = sa_remove_group(group);
1391
1392 free_opt(optlist);
1393 return (ret);
1394 }
1395
1396 /*
1397 * group_status(group)
1398 *
1399 * return the current status (enabled/disabled) of the group.
1400 */
1401
1402 static char *
group_status(sa_group_t group)1403 group_status(sa_group_t group)
1404 {
1405 char *state;
1406 int enabled = 0;
1407
1408 state = sa_get_group_attr(group, "state");
1409 if (state != NULL) {
1410 if (strcmp(state, "enabled") == 0) {
1411 enabled = 1;
1412 }
1413 sa_free_attr_string(state);
1414 }
1415 return (enabled ? "enabled" : "disabled");
1416 }
1417
1418 /*
1419 * sa_delete(flags, argc, argv)
1420 *
1421 * Delete a group.
1422 */
1423
1424 static int
sa_delete(sa_handle_t handle,int flags,int argc,char * argv[])1425 sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
1426 {
1427 char *groupname;
1428 sa_group_t group;
1429 sa_share_t share;
1430 int verbose = 0;
1431 int dryrun = 0;
1432 int force = 0;
1433 int c;
1434 char *protocol = NULL;
1435 char *sectype = NULL;
1436 int ret = SA_OK;
1437 int auth;
1438
1439 while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
1440 switch (c) {
1441 case 'v':
1442 verbose++;
1443 break;
1444 case 'n':
1445 dryrun++;
1446 break;
1447 case 'P':
1448 if (protocol != NULL) {
1449 (void) printf(gettext("Specifying "
1450 "multiple protocols "
1451 "not supported: %s\n"), protocol);
1452 return (SA_SYNTAX_ERR);
1453 }
1454 protocol = optarg;
1455 if (!sa_valid_protocol(protocol)) {
1456 (void) printf(gettext("Invalid protocol "
1457 "specified: %s\n"), protocol);
1458 return (SA_INVALID_PROTOCOL);
1459 }
1460 break;
1461 case 'S':
1462 if (sectype != NULL) {
1463 (void) printf(gettext("Specifying "
1464 "multiple property "
1465 "spaces not supported: %s\n"), sectype);
1466 return (SA_SYNTAX_ERR);
1467 }
1468 sectype = optarg;
1469 break;
1470 case 'f':
1471 force++;
1472 break;
1473 case 'h':
1474 /* optopt on valid arg isn't defined */
1475 optopt = c;
1476 /*FALLTHROUGH*/
1477 case '?':
1478 default:
1479 /*
1480 * Since a bad option gets to here, sort it
1481 * out and return a syntax error return value
1482 * if necessary.
1483 */
1484 switch (optopt) {
1485 default:
1486 ret = SA_SYNTAX_ERR;
1487 break;
1488 case 'h':
1489 case '?':
1490 break;
1491 }
1492 (void) printf(gettext("usage: %s\n"),
1493 sa_get_usage(USAGE_DELETE));
1494 return (ret);
1495 }
1496 }
1497
1498 if (optind >= argc) {
1499 (void) printf(gettext("usage: %s\n"),
1500 sa_get_usage(USAGE_DELETE));
1501 (void) printf(gettext("\tgroup must be specified.\n"));
1502 return (SA_SYNTAX_ERR);
1503 }
1504
1505 if ((optind + 1) < argc) {
1506 (void) printf(gettext("usage: %s\n"),
1507 sa_get_usage(USAGE_DELETE));
1508 (void) printf(gettext("\textraneous group(s) at end\n"));
1509 return (SA_SYNTAX_ERR);
1510 }
1511
1512 if (sectype != NULL && protocol == NULL) {
1513 (void) printf(gettext("usage: %s\n"),
1514 sa_get_usage(USAGE_DELETE));
1515 (void) printf(gettext("\tsecurity requires protocol to be "
1516 "specified.\n"));
1517 return (SA_SYNTAX_ERR);
1518 }
1519
1520 /*
1521 * Determine if the group already exists since it must in
1522 * order to be removed.
1523 *
1524 * We can delete when:
1525 *
1526 * - group is empty
1527 * - force flag is set
1528 * - if protocol specified, only delete the protocol
1529 */
1530
1531 groupname = argv[optind];
1532 group = sa_get_group(handle, groupname);
1533 if (group == NULL) {
1534 ret = SA_NO_SUCH_GROUP;
1535 goto done;
1536 }
1537 auth = check_authorizations(groupname, flags);
1538 if (protocol == NULL) {
1539 share = sa_get_share(group, NULL);
1540 if (share != NULL)
1541 ret = SA_BUSY;
1542 if (share == NULL || (share != NULL && force == 1)) {
1543 ret = SA_OK;
1544 if (!dryrun) {
1545 while (share != NULL) {
1546 sa_share_t next_share;
1547 next_share = sa_get_next_share(share);
1548 /*
1549 * need to do the disable of
1550 * each share, but don't
1551 * actually do anything on a
1552 * dryrun.
1553 */
1554 ret = sa_disable_share(share, NULL);
1555 ret = sa_remove_share(share);
1556 share = next_share;
1557 }
1558 ret = sa_remove_group(group);
1559 }
1560 }
1561 /* Commit to configuration if not a dryrun */
1562 if (!dryrun && ret == SA_OK) {
1563 ret = sa_update_config(handle);
1564 }
1565 } else {
1566 /* a protocol delete */
1567 sa_optionset_t optionset;
1568 sa_security_t security;
1569 if (sectype != NULL) {
1570 /* only delete specified security */
1571 security = sa_get_security(group, sectype, protocol);
1572 if (security != NULL && !dryrun)
1573 ret = sa_destroy_security(security);
1574 else
1575 ret = SA_INVALID_PROTOCOL;
1576 } else {
1577 optionset = sa_get_optionset(group, protocol);
1578 if (optionset != NULL && !dryrun) {
1579 /*
1580 * have an optionset with
1581 * protocol to delete
1582 */
1583 ret = sa_destroy_optionset(optionset);
1584 /*
1585 * Now find all security sets
1586 * for the protocol and remove
1587 * them. Don't remove other
1588 * protocols.
1589 */
1590 for (security =
1591 sa_get_security(group, NULL, NULL);
1592 ret == SA_OK && security != NULL;
1593 security = sa_get_next_security(security)) {
1594 char *secprot;
1595 secprot = sa_get_security_attr(security,
1596 "type");
1597 if (secprot != NULL &&
1598 strcmp(secprot, protocol) == 0)
1599 ret = sa_destroy_security(
1600 security);
1601 if (secprot != NULL)
1602 sa_free_attr_string(secprot);
1603 }
1604 } else {
1605 if (!dryrun)
1606 ret = SA_INVALID_PROTOCOL;
1607 }
1608 }
1609 /*
1610 * With the protocol items removed, make sure that all
1611 * the shares are updated in the legacy files, if
1612 * necessary.
1613 */
1614 for (share = sa_get_share(group, NULL);
1615 share != NULL;
1616 share = sa_get_next_share(share)) {
1617 (void) sa_delete_legacy(share, protocol);
1618 }
1619 }
1620
1621 done:
1622 if (ret != SA_OK) {
1623 (void) printf(gettext("Could not delete group: %s\n"),
1624 sa_errorstr(ret));
1625 } else if (dryrun && !auth && verbose) {
1626 (void) printf(gettext("Command would fail: %s\n"),
1627 sa_errorstr(SA_NO_PERMISSION));
1628 }
1629 return (ret);
1630 }
1631
1632 /*
1633 * strndupr(*buff, str, buffsize)
1634 *
1635 * used with small strings to duplicate and possibly increase the
1636 * buffer size of a string.
1637 */
1638 static char *
strndupr(char * buff,char * str,int * buffsize)1639 strndupr(char *buff, char *str, int *buffsize)
1640 {
1641 int limit;
1642 char *orig_buff = buff;
1643
1644 if (buff == NULL) {
1645 buff = (char *)malloc(64);
1646 if (buff == NULL)
1647 return (NULL);
1648 *buffsize = 64;
1649 buff[0] = '\0';
1650 }
1651 limit = strlen(buff) + strlen(str) + 1;
1652 if (limit > *buffsize) {
1653 limit = *buffsize = *buffsize + ((limit / 64) + 64);
1654 buff = realloc(buff, limit);
1655 }
1656 if (buff != NULL) {
1657 (void) strcat(buff, str);
1658 } else {
1659 /* if it fails, fail it hard */
1660 if (orig_buff != NULL)
1661 free(orig_buff);
1662 }
1663 return (buff);
1664 }
1665
1666 /*
1667 * group_proto(group)
1668 *
1669 * return a string of all the protocols (space separated) associated
1670 * with this group.
1671 */
1672
1673 static char *
group_proto(sa_group_t group)1674 group_proto(sa_group_t group)
1675 {
1676 sa_optionset_t optionset;
1677 char *proto;
1678 char *buff = NULL;
1679 int buffsize = 0;
1680 int addspace = 0;
1681 /*
1682 * get the protocol list by finding the optionsets on this
1683 * group and extracting the type value. The initial call to
1684 * strndupr() initailizes buff.
1685 */
1686 buff = strndupr(buff, "", &buffsize);
1687 if (buff != NULL) {
1688 for (optionset = sa_get_optionset(group, NULL);
1689 optionset != NULL && buff != NULL;
1690 optionset = sa_get_next_optionset(optionset)) {
1691 /*
1692 * extract out the protocol type from this optionset
1693 * and append it to the buffer "buff". strndupr() will
1694 * reallocate space as necessay.
1695 */
1696 proto = sa_get_optionset_attr(optionset, "type");
1697 if (proto != NULL) {
1698 if (addspace++)
1699 buff = strndupr(buff, " ", &buffsize);
1700 buff = strndupr(buff, proto, &buffsize);
1701 sa_free_attr_string(proto);
1702 }
1703 }
1704 }
1705 return (buff);
1706 }
1707
1708 /*
1709 * sa_list(flags, argc, argv)
1710 *
1711 * implements the "list" subcommand to list groups and optionally
1712 * their state and protocols.
1713 */
1714
1715 static int
sa_list(sa_handle_t handle,int flags,int argc,char * argv[])1716 sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
1717 {
1718 sa_group_t group;
1719 int verbose = 0;
1720 int c;
1721 char *protocol = NULL;
1722 int ret = SA_OK;
1723 #ifdef lint
1724 flags = flags;
1725 #endif
1726
1727 while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
1728 switch (c) {
1729 case 'v':
1730 verbose++;
1731 break;
1732 case 'P':
1733 if (protocol != NULL) {
1734 (void) printf(gettext(
1735 "Specifying multiple protocols "
1736 "not supported: %s\n"),
1737 protocol);
1738 return (SA_SYNTAX_ERR);
1739 }
1740 protocol = optarg;
1741 if (!sa_valid_protocol(protocol)) {
1742 (void) printf(gettext(
1743 "Invalid protocol specified: %s\n"),
1744 protocol);
1745 return (SA_INVALID_PROTOCOL);
1746 }
1747 break;
1748 case 'h':
1749 /* optopt on valid arg isn't defined */
1750 optopt = c;
1751 /*FALLTHROUGH*/
1752 case '?':
1753 default:
1754 /*
1755 * Since a bad option gets to here, sort it
1756 * out and return a syntax error return value
1757 * if necessary.
1758 */
1759 switch (optopt) {
1760 default:
1761 ret = SA_SYNTAX_ERR;
1762 break;
1763 case 'h':
1764 case '?':
1765 break;
1766 }
1767 (void) printf(gettext("usage: %s\n"),
1768 sa_get_usage(USAGE_LIST));
1769 return (ret);
1770 }
1771 }
1772
1773 if (optind != argc) {
1774 (void) printf(gettext("usage: %s\n"),
1775 sa_get_usage(USAGE_LIST));
1776 return (SA_SYNTAX_ERR);
1777 }
1778
1779 for (group = sa_get_group(handle, NULL);
1780 group != NULL;
1781 group = sa_get_next_group(group)) {
1782 char *name;
1783 char *proto;
1784 if (protocol == NULL || has_protocol(group, protocol)) {
1785 name = sa_get_group_attr(group, "name");
1786 if (name != NULL && (verbose > 1 || name[0] != '#')) {
1787 (void) printf("%s", (char *)name);
1788 if (verbose) {
1789 /*
1790 * Need the list of protocols
1791 * and current status once
1792 * available. We do want to
1793 * translate the
1794 * enabled/disabled text here.
1795 */
1796 (void) printf("\t%s", isenabled(group) ?
1797 gettext("enabled") :
1798 gettext("disabled"));
1799 proto = group_proto(group);
1800 if (proto != NULL) {
1801 (void) printf("\t%s",
1802 (char *)proto);
1803 free(proto);
1804 }
1805 }
1806 (void) printf("\n");
1807 }
1808 if (name != NULL)
1809 sa_free_attr_string(name);
1810 }
1811 }
1812 return (0);
1813 }
1814
1815 /*
1816 * out_properties(optionset, proto, sec)
1817 *
1818 * Format the properties and encode the protocol and optional named
1819 * optionset into the string.
1820 *
1821 * format is protocol[:name]=(property-list)
1822 */
1823
1824 static void
out_properties(sa_optionset_t optionset,char * proto,char * sec)1825 out_properties(sa_optionset_t optionset, char *proto, char *sec)
1826 {
1827 char *type;
1828 char *value;
1829 int spacer;
1830 sa_property_t prop;
1831
1832 if (sec == NULL)
1833 (void) printf(" %s=(", proto ? proto : gettext("all"));
1834 else
1835 (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
1836
1837 for (spacer = 0, prop = sa_get_property(optionset, NULL);
1838 prop != NULL;
1839 prop = sa_get_next_property(prop)) {
1840
1841 /*
1842 * extract the property name/value and output with
1843 * appropriate spacing. I.e. no prefixed space the
1844 * first time through but a space on subsequent
1845 * properties.
1846 */
1847 type = sa_get_property_attr(prop, "type");
1848 value = sa_get_property_attr(prop, "value");
1849 if (type != NULL) {
1850 (void) printf("%s%s=", spacer ? " " : "", type);
1851 spacer = 1;
1852 if (value != NULL)
1853 (void) printf("\"%s\"", value);
1854 else
1855 (void) printf("\"\"");
1856 }
1857 if (type != NULL)
1858 sa_free_attr_string(type);
1859 if (value != NULL)
1860 sa_free_attr_string(value);
1861 }
1862 (void) printf(")");
1863 }
1864
1865 /*
1866 * show_properties(group, protocol, prefix)
1867 *
1868 * print the properties for a group. If protocol is NULL, do all
1869 * protocols otherwise only the specified protocol. All security
1870 * (named groups specific to the protocol) are included.
1871 *
1872 * The "prefix" is always applied. The caller knows whether it wants
1873 * some type of prefix string (white space) or not. Once the prefix
1874 * has been output, it is reduced to the zero length string for the
1875 * remainder of the property output.
1876 */
1877
1878 static void
show_properties(sa_group_t group,char * protocol,char * prefix)1879 show_properties(sa_group_t group, char *protocol, char *prefix)
1880 {
1881 sa_optionset_t optionset;
1882 sa_security_t security;
1883 char *value;
1884 char *secvalue;
1885
1886 if (protocol != NULL) {
1887 optionset = sa_get_optionset(group, protocol);
1888 if (optionset != NULL) {
1889 (void) printf("%s", prefix);
1890 prefix = "";
1891 out_properties(optionset, protocol, NULL);
1892 }
1893 security = sa_get_security(group, protocol, NULL);
1894 if (security != NULL) {
1895 (void) printf("%s", prefix);
1896 prefix = "";
1897 out_properties(security, protocol, NULL);
1898 }
1899 } else {
1900 for (optionset = sa_get_optionset(group, protocol);
1901 optionset != NULL;
1902 optionset = sa_get_next_optionset(optionset)) {
1903
1904 value = sa_get_optionset_attr(optionset, "type");
1905 (void) printf("%s", prefix);
1906 prefix = "";
1907 out_properties(optionset, value, 0);
1908 if (value != NULL)
1909 sa_free_attr_string(value);
1910 }
1911 for (security = sa_get_security(group, NULL, protocol);
1912 security != NULL;
1913 security = sa_get_next_security(security)) {
1914
1915 value = sa_get_security_attr(security, "type");
1916 secvalue = sa_get_security_attr(security, "sectype");
1917 (void) printf("%s", prefix);
1918 prefix = "";
1919 out_properties(security, value, secvalue);
1920 if (value != NULL)
1921 sa_free_attr_string(value);
1922 if (secvalue != NULL)
1923 sa_free_attr_string(secvalue);
1924 }
1925 }
1926 }
1927
1928 /*
1929 * get_resource(share)
1930 *
1931 * Get the first resource name, if any, and fix string to be in
1932 * current locale and have quotes if it has embedded spaces. Return
1933 * an attr string that must be freed.
1934 */
1935
1936 static char *
get_resource(sa_share_t share)1937 get_resource(sa_share_t share)
1938 {
1939 sa_resource_t resource;
1940 char *resstring = NULL;
1941 char *retstring;
1942
1943 if ((resource = sa_get_share_resource(share, NULL)) != NULL) {
1944 resstring = sa_get_resource_attr(resource, "name");
1945 if (resstring != NULL) {
1946 char *cp;
1947 int len;
1948
1949 retstring = conv_from_utf8(resstring);
1950 if (retstring != resstring) {
1951 sa_free_attr_string(resstring);
1952 resstring = retstring;
1953 }
1954 if (strpbrk(resstring, " ") != NULL) {
1955 /* account for quotes */
1956 len = strlen(resstring) + 3;
1957 cp = calloc(len, sizeof (char));
1958 if (cp != NULL) {
1959 (void) snprintf(cp, len,
1960 "\"%s\"", resstring);
1961 sa_free_attr_string(resstring);
1962 resstring = cp;
1963 } else {
1964 sa_free_attr_string(resstring);
1965 resstring = NULL;
1966 }
1967 }
1968 }
1969 }
1970 return (resstring);
1971 }
1972
1973 /*
1974 * has_resource_with_opt(share)
1975 *
1976 * Check to see if the share has any resource names with optionsets
1977 * set. Also indicate if multiple resource names since the syntax
1978 * would be about the same.
1979 */
1980 static int
has_resource_with_opt(sa_share_t share)1981 has_resource_with_opt(sa_share_t share)
1982 {
1983 sa_resource_t resource;
1984 int ret = B_FALSE;
1985
1986 for (resource = sa_get_share_resource(share, NULL);
1987 resource != NULL;
1988 resource = sa_get_next_resource(resource)) {
1989
1990 if (sa_get_optionset(resource, NULL) != NULL) {
1991 ret = B_TRUE;
1992 break;
1993 }
1994 }
1995 return (ret);
1996 }
1997
1998 /*
1999 * has_multiple_resource(share)
2000 *
2001 * Check to see if the share has multiple resource names since
2002 * the syntax would be about the same.
2003 */
2004 static boolean_t
has_multiple_resource(sa_share_t share)2005 has_multiple_resource(sa_share_t share)
2006 {
2007 sa_resource_t resource;
2008 int num;
2009
2010 for (num = 0, resource = sa_get_share_resource(share, NULL);
2011 resource != NULL;
2012 resource = sa_get_next_resource(resource)) {
2013 num++;
2014 if (num > 1)
2015 return (B_TRUE);
2016 }
2017 return (B_FALSE);
2018 }
2019
2020 /*
2021 * show_share(share, verbose, properties, proto, iszfs, sharepath)
2022 *
2023 * print out the share information. With the addition of resource as a
2024 * full object that can have multiple instances below the share, we
2025 * need to display that as well.
2026 */
2027
2028 static void
show_share(sa_share_t share,int verbose,int properties,char * proto,int iszfs,char * sharepath)2029 show_share(sa_share_t share, int verbose, int properties, char *proto,
2030 int iszfs, char *sharepath)
2031 {
2032 char *drive;
2033 char *exclude;
2034 sa_resource_t resource = NULL;
2035 char *description;
2036 char *rsrcname;
2037 int rsrcwithopt;
2038 boolean_t multiple;
2039 char *type;
2040
2041 rsrcwithopt = has_resource_with_opt(share);
2042
2043 if (verbose || (properties && rsrcwithopt)) {
2044 /* First, indicate if transient */
2045 type = sa_get_share_attr(share, "type");
2046 if (type != NULL && !iszfs && verbose &&
2047 strcmp(type, "transient") == 0)
2048 (void) printf("\t* ");
2049 else
2050 (void) printf("\t ");
2051
2052 if (type != NULL)
2053 sa_free_attr_string(type);
2054
2055 /*
2056 * If we came in with verbose, we want to handle the case of
2057 * multiple resources as though they had properties set.
2058 */
2059 multiple = has_multiple_resource(share);
2060
2061 /*
2062 * if there is a description on the share and there
2063 * are resources, treat as multiple resources in order
2064 * to get all descriptions displayed.
2065 */
2066 description = sa_get_share_description(share);
2067 resource = sa_get_share_resource(share, NULL);
2068
2069 if (description != NULL && resource != NULL)
2070 multiple = B_TRUE;
2071
2072 /* Next, if not multiple follow old model */
2073 if (!multiple && !rsrcwithopt) {
2074 rsrcname = get_resource(share);
2075 if (rsrcname != NULL && strlen(rsrcname) > 0) {
2076 (void) printf("%s=%s", rsrcname, sharepath);
2077 } else {
2078 (void) printf("%s", sharepath);
2079 }
2080 if (rsrcname != NULL)
2081 sa_free_attr_string(rsrcname);
2082 /* Print the description string if there is one. */
2083 print_rsrc_desc(resource, description);
2084 } else {
2085 /* Treat as simple and then resources come later */
2086 (void) printf("%s", sharepath);
2087 }
2088 drive = sa_get_share_attr(share, "drive-letter");
2089 if (drive != NULL) {
2090 if (strlen(drive) > 0)
2091 (void) printf(gettext("\tdrive-letter=\"%s:\""),
2092 drive);
2093 sa_free_attr_string(drive);
2094 }
2095 if (properties)
2096 show_properties(share, proto, "\t");
2097 exclude = sa_get_share_attr(share, "exclude");
2098 if (exclude != NULL) {
2099 (void) printf(gettext("\tnot-shared-with=[%s]"),
2100 exclude);
2101 sa_free_attr_string(exclude);
2102 }
2103
2104 if (description != NULL) {
2105 print_rsrc_desc((sa_resource_t)share, description);
2106 }
2107 /*
2108 * If there are resource names with options, show them
2109 * here, with one line per resource. Resource specific
2110 * options are at the end of the line followed by
2111 * description, if any.
2112 */
2113 if (rsrcwithopt || multiple) {
2114 for (resource = sa_get_share_resource(share, NULL);
2115 resource != NULL;
2116 resource = sa_get_next_resource(resource)) {
2117 int has_space;
2118 char *rsrc;
2119
2120 (void) printf("\n\t\t ");
2121 rsrcname = sa_get_resource_attr(resource,
2122 "name");
2123 if (rsrcname == NULL)
2124 continue;
2125
2126 rsrc = conv_from_utf8(rsrcname);
2127 has_space = strpbrk(rsrc, " ") != NULL;
2128
2129 if (has_space)
2130 (void) printf("\"%s\"=%s", rsrc,
2131 sharepath);
2132 else
2133 (void) printf("%s=%s", rsrc,
2134 sharepath);
2135 if (rsrc != rsrcname)
2136 sa_free_attr_string(rsrc);
2137 sa_free_attr_string(rsrcname);
2138 if (properties || rsrcwithopt)
2139 show_properties(resource, proto, "\t");
2140
2141 /* Get description string if any */
2142 print_rsrc_desc(resource, description);
2143 }
2144 }
2145 if (description != NULL)
2146 sa_free_share_description(description);
2147 } else {
2148 (void) printf("\t %s", sharepath);
2149 if (properties)
2150 show_properties(share, proto, "\t");
2151 }
2152 (void) printf("\n");
2153 }
2154
2155 /*
2156 * show_group(group, verbose, properties, proto, subgroup)
2157 *
2158 * helper function to show the contents of a group.
2159 */
2160
2161 static void
show_group(sa_group_t group,int verbose,int properties,char * proto,char * subgroup)2162 show_group(sa_group_t group, int verbose, int properties, char *proto,
2163 char *subgroup)
2164 {
2165 sa_share_t share;
2166 char *groupname;
2167 char *zfs = NULL;
2168 int iszfs = 0;
2169 char *sharepath;
2170
2171 groupname = sa_get_group_attr(group, "name");
2172 if (groupname != NULL) {
2173 if (proto != NULL && !has_protocol(group, proto)) {
2174 sa_free_attr_string(groupname);
2175 return;
2176 }
2177 /*
2178 * check to see if the group is managed by ZFS. If
2179 * there is an attribute, then it is. A non-NULL zfs
2180 * variable will trigger the different way to display
2181 * and will remove the transient property indicator
2182 * from the output.
2183 */
2184 zfs = sa_get_group_attr(group, "zfs");
2185 if (zfs != NULL) {
2186 iszfs = 1;
2187 sa_free_attr_string(zfs);
2188 }
2189 share = sa_get_share(group, NULL);
2190 if (subgroup == NULL)
2191 (void) printf("%s", groupname);
2192 else
2193 (void) printf(" %s/%s", subgroup, groupname);
2194 if (properties)
2195 show_properties(group, proto, "");
2196 (void) printf("\n");
2197 if (strcmp(groupname, "zfs") == 0) {
2198 sa_group_t zgroup;
2199
2200 for (zgroup = sa_get_sub_group(group);
2201 zgroup != NULL;
2202 zgroup = sa_get_next_group(zgroup)) {
2203 show_group(zgroup, verbose, properties, proto,
2204 "zfs");
2205 }
2206 sa_free_attr_string(groupname);
2207 return;
2208 }
2209 /*
2210 * Have a group, so list the contents. Resource and
2211 * description are only listed if verbose is set.
2212 */
2213 for (share = sa_get_share(group, NULL);
2214 share != NULL;
2215 share = sa_get_next_share(share)) {
2216 sharepath = sa_get_share_attr(share, "path");
2217 if (sharepath != NULL) {
2218 show_share(share, verbose, properties, proto,
2219 iszfs, sharepath);
2220 sa_free_attr_string(sharepath);
2221 }
2222 }
2223 }
2224 if (groupname != NULL) {
2225 sa_free_attr_string(groupname);
2226 }
2227 }
2228
2229 /*
2230 * show_group_xml_init()
2231 *
2232 * Create an XML document that will be used to display config info via
2233 * XML format.
2234 */
2235
2236 xmlDocPtr
show_group_xml_init()2237 show_group_xml_init()
2238 {
2239 xmlDocPtr doc;
2240 xmlNodePtr root;
2241
2242 doc = xmlNewDoc((xmlChar *)"1.0");
2243 if (doc != NULL) {
2244 root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
2245 if (root != NULL)
2246 (void) xmlDocSetRootElement(doc, root);
2247 }
2248 return (doc);
2249 }
2250
2251 /*
2252 * show_group_xml(doc, group)
2253 *
2254 * Copy the group info into the XML doc.
2255 */
2256
2257 static void
show_group_xml(xmlDocPtr doc,sa_group_t group)2258 show_group_xml(xmlDocPtr doc, sa_group_t group)
2259 {
2260 xmlNodePtr node;
2261 xmlNodePtr root;
2262
2263 root = xmlDocGetRootElement(doc);
2264 node = xmlCopyNode((xmlNodePtr)group, 1);
2265 if (node != NULL && root != NULL) {
2266 (void) xmlAddChild(root, node);
2267 /*
2268 * In the future, we may have interally used tags that
2269 * should not appear in the XML output. Remove
2270 * anything we don't want to show here.
2271 */
2272 }
2273 }
2274
2275 /*
2276 * sa_show(flags, argc, argv)
2277 *
2278 * Implements the show subcommand.
2279 */
2280
2281 int
sa_show(sa_handle_t handle,int flags,int argc,char * argv[])2282 sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
2283 {
2284 sa_group_t group;
2285 int verbose = 0;
2286 int properties = 0;
2287 int c;
2288 int ret = SA_OK;
2289 char *protocol = NULL;
2290 int xml = 0;
2291 xmlDocPtr doc;
2292 #ifdef lint
2293 flags = flags;
2294 #endif
2295
2296 while ((c = getopt(argc, argv, "?hvP:px")) != EOF) {
2297 switch (c) {
2298 case 'v':
2299 verbose++;
2300 break;
2301 case 'p':
2302 properties++;
2303 break;
2304 case 'P':
2305 if (protocol != NULL) {
2306 (void) printf(gettext(
2307 "Specifying multiple protocols "
2308 "not supported: %s\n"),
2309 protocol);
2310 return (SA_SYNTAX_ERR);
2311 }
2312 protocol = optarg;
2313 if (!sa_valid_protocol(protocol)) {
2314 (void) printf(gettext(
2315 "Invalid protocol specified: %s\n"),
2316 protocol);
2317 return (SA_INVALID_PROTOCOL);
2318 }
2319 break;
2320 case 'x':
2321 xml++;
2322 break;
2323 case 'h':
2324 /* optopt on valid arg isn't defined */
2325 optopt = c;
2326 /*FALLTHROUGH*/
2327 case '?':
2328 default:
2329 /*
2330 * Since a bad option gets to here, sort it
2331 * out and return a syntax error return value
2332 * if necessary.
2333 */
2334 switch (optopt) {
2335 default:
2336 ret = SA_SYNTAX_ERR;
2337 break;
2338 case 'h':
2339 case '?':
2340 break;
2341 }
2342 (void) printf(gettext("usage: %s\n"),
2343 sa_get_usage(USAGE_SHOW));
2344 return (ret);
2345 }
2346 }
2347
2348 if (xml) {
2349 doc = show_group_xml_init();
2350 if (doc == NULL)
2351 ret = SA_NO_MEMORY;
2352 }
2353
2354 if (optind == argc) {
2355 /* No group specified so go through them all */
2356 for (group = sa_get_group(handle, NULL);
2357 group != NULL;
2358 group = sa_get_next_group(group)) {
2359 /*
2360 * Have a group so check if one we want and then list
2361 * contents with appropriate options.
2362 */
2363 if (xml)
2364 show_group_xml(doc, group);
2365 else
2366 show_group(group, verbose, properties, protocol,
2367 NULL);
2368 }
2369 } else {
2370 /* Have a specified list of groups */
2371 for (; optind < argc; optind++) {
2372 group = sa_get_group(handle, argv[optind]);
2373 if (group != NULL) {
2374 if (xml)
2375 show_group_xml(doc, group);
2376 else
2377 show_group(group, verbose, properties,
2378 protocol, NULL);
2379 } else {
2380 (void) printf(gettext("%s: not found\n"),
2381 argv[optind]);
2382 ret = SA_NO_SUCH_GROUP;
2383 }
2384 }
2385 }
2386 if (xml && ret == SA_OK) {
2387 (void) xmlDocFormatDump(stdout, doc, 1);
2388 xmlFreeDoc(doc);
2389 }
2390 return (ret);
2391
2392 }
2393
2394 /*
2395 * enable_share(group, share, update_legacy)
2396 *
2397 * helper function to enable a share if the group is enabled.
2398 */
2399
2400 static int
enable_share(sa_handle_t handle,sa_group_t group,sa_share_t share,int update_legacy)2401 enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
2402 int update_legacy)
2403 {
2404 char *value;
2405 int enabled;
2406 sa_optionset_t optionset;
2407 int err;
2408 int ret = SA_OK;
2409 char *zfs = NULL;
2410 int iszfs = 0;
2411 int isshare;
2412
2413 /*
2414 * need to enable this share if the group is enabled but not
2415 * otherwise. The enable is also done on each protocol
2416 * represented in the group.
2417 */
2418 value = sa_get_group_attr(group, "state");
2419 enabled = value != NULL && strcmp(value, "enabled") == 0;
2420 if (value != NULL)
2421 sa_free_attr_string(value);
2422 /* remove legacy config if necessary */
2423 if (update_legacy)
2424 ret = sa_delete_legacy(share, NULL);
2425 zfs = sa_get_group_attr(group, "zfs");
2426 if (zfs != NULL) {
2427 iszfs++;
2428 sa_free_attr_string(zfs);
2429 }
2430
2431 /*
2432 * Step through each optionset at the group level and
2433 * enable the share based on the protocol type. This
2434 * works because protocols must be set on the group
2435 * for the protocol to be enabled.
2436 */
2437 isshare = sa_is_share(share);
2438 for (optionset = sa_get_optionset(group, NULL);
2439 optionset != NULL && ret == SA_OK;
2440 optionset = sa_get_next_optionset(optionset)) {
2441 value = sa_get_optionset_attr(optionset, "type");
2442 if (value != NULL) {
2443 if (enabled) {
2444 if (isshare) {
2445 err = sa_enable_share(share, value);
2446 } else {
2447 err = sa_enable_resource(share, value);
2448 if (err == SA_NOT_SUPPORTED) {
2449 sa_share_t parent;
2450 parent = sa_get_resource_parent(
2451 share);
2452 if (parent != NULL)
2453 err = sa_enable_share(
2454 parent, value);
2455 }
2456 }
2457 if (err != SA_OK) {
2458 ret = err;
2459 (void) printf(gettext(
2460 "Failed to enable share for "
2461 "\"%s\": %s\n"),
2462 value, sa_errorstr(ret));
2463 }
2464 }
2465 /*
2466 * If we want to update the legacy, use a copy of
2467 * share so we can avoid breaking the loop we are in
2468 * since we might also need to go up the tree to the
2469 * parent.
2470 */
2471 if (update_legacy && !iszfs) {
2472 sa_share_t update = share;
2473 if (!sa_is_share(share)) {
2474 update = sa_get_resource_parent(share);
2475 }
2476 (void) sa_update_legacy(update, value);
2477 }
2478 sa_free_attr_string(value);
2479 }
2480 }
2481 if (ret == SA_OK)
2482 (void) sa_update_config(handle);
2483 return (ret);
2484 }
2485
2486 /*
2487 * sa_require_resource(group)
2488 *
2489 * if any of the defined protocols on the group require resource
2490 * names, then all shares must have them.
2491 */
2492
2493 static int
sa_require_resource(sa_group_t group)2494 sa_require_resource(sa_group_t group)
2495 {
2496 sa_optionset_t optionset;
2497
2498 for (optionset = sa_get_optionset(group, NULL);
2499 optionset != NULL;
2500 optionset = sa_get_next_optionset(optionset)) {
2501 char *proto;
2502
2503 proto = sa_get_optionset_attr(optionset, "type");
2504 if (proto != NULL) {
2505 uint64_t features;
2506
2507 features = sa_proto_get_featureset(proto);
2508 if (features & SA_FEATURE_RESOURCE) {
2509 sa_free_attr_string(proto);
2510 return (B_TRUE);
2511 }
2512 sa_free_attr_string(proto);
2513 }
2514 }
2515 return (B_FALSE);
2516 }
2517
2518 /*
2519 * sa_addshare(flags, argc, argv)
2520 *
2521 * implements add-share subcommand.
2522 */
2523
2524 static int
sa_addshare(sa_handle_t handle,int flags,int argc,char * argv[])2525 sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
2526 {
2527 int verbose = 0;
2528 int dryrun = 0;
2529 int c;
2530 int ret = SA_OK;
2531 sa_group_t group;
2532 sa_share_t share;
2533 sa_resource_t resource = NULL;
2534 char *sharepath = NULL;
2535 char *description = NULL;
2536 char *rsrcname = NULL;
2537 char *rsrc = NULL;
2538 int persist = SA_SHARE_PERMANENT; /* default to persist */
2539 int auth;
2540 char dir[MAXPATHLEN];
2541
2542 while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
2543 switch (c) {
2544 case 'n':
2545 dryrun++;
2546 break;
2547 case 'v':
2548 verbose++;
2549 break;
2550 case 'd':
2551 description = optarg;
2552 break;
2553 case 'r':
2554 if (rsrcname != NULL) {
2555 (void) printf(gettext("Adding multiple "
2556 "resource names not"
2557 " supported\n"));
2558 return (SA_SYNTAX_ERR);
2559 }
2560 rsrcname = optarg;
2561 break;
2562 case 's':
2563 /*
2564 * Save share path into group. Currently limit
2565 * to one share per command.
2566 */
2567 if (sharepath != NULL) {
2568 (void) printf(gettext(
2569 "Adding multiple shares not supported\n"));
2570 return (SA_SYNTAX_ERR);
2571 }
2572 sharepath = optarg;
2573 break;
2574 case 't':
2575 persist = SA_SHARE_TRANSIENT;
2576 break;
2577 case 'h':
2578 /* optopt on valid arg isn't defined */
2579 optopt = c;
2580 /*FALLTHROUGH*/
2581 case '?':
2582 default:
2583 /*
2584 * Since a bad option gets to here, sort it
2585 * out and return a syntax error return value
2586 * if necessary.
2587 */
2588 switch (optopt) {
2589 default:
2590 ret = SA_SYNTAX_ERR;
2591 break;
2592 case 'h':
2593 case '?':
2594 break;
2595 }
2596 (void) printf(gettext("usage: %s\n"),
2597 sa_get_usage(USAGE_ADD_SHARE));
2598 return (ret);
2599 }
2600 }
2601
2602 if (optind >= argc) {
2603 (void) printf(gettext("usage: %s\n"),
2604 sa_get_usage(USAGE_ADD_SHARE));
2605 if (dryrun || sharepath != NULL || description != NULL ||
2606 rsrcname != NULL || verbose || persist) {
2607 (void) printf(gettext("\tgroup must be specified\n"));
2608 ret = SA_NO_SUCH_GROUP;
2609 } else {
2610 ret = SA_OK;
2611 }
2612 } else {
2613 if (sharepath == NULL) {
2614 (void) printf(gettext("usage: %s\n"),
2615 sa_get_usage(USAGE_ADD_SHARE));
2616 (void) printf(gettext(
2617 "\t-s sharepath must be specified\n"));
2618 ret = SA_BAD_PATH;
2619 }
2620 if (ret == SA_OK) {
2621 if (realpath(sharepath, dir) == NULL) {
2622 ret = SA_BAD_PATH;
2623 (void) printf(gettext("Path "
2624 "is not valid: %s\n"),
2625 sharepath);
2626 } else {
2627 sharepath = dir;
2628 }
2629 }
2630 if (ret == SA_OK && rsrcname != NULL) {
2631 /* check for valid syntax */
2632 if (validresource(rsrcname)) {
2633 rsrc = conv_to_utf8(rsrcname);
2634 resource = sa_find_resource(handle, rsrc);
2635 if (resource != NULL) {
2636 /*
2637 * Resource names must be
2638 * unique in the system
2639 */
2640 ret = SA_DUPLICATE_NAME;
2641 (void) printf(gettext("usage: %s\n"),
2642 sa_get_usage(USAGE_ADD_SHARE));
2643 (void) printf(gettext(
2644 "\tresource names must be unique "
2645 "in the system\n"));
2646 }
2647 } else {
2648 (void) printf(gettext("usage: %s\n"),
2649 sa_get_usage(USAGE_ADD_SHARE));
2650 (void) printf(gettext(
2651 "\tresource names use restricted "
2652 "character set\n"));
2653 ret = SA_INVALID_NAME;
2654 }
2655 }
2656
2657 if (ret != SA_OK) {
2658 if (rsrc != NULL && rsrcname != rsrc)
2659 sa_free_attr_string(rsrc);
2660 return (ret);
2661 }
2662
2663 share = sa_find_share(handle, sharepath);
2664 if (share != NULL) {
2665 if (rsrcname == NULL) {
2666 /*
2667 * Can only have a duplicate share if a new
2668 * resource name is being added.
2669 */
2670 ret = SA_DUPLICATE_NAME;
2671 (void) printf(gettext("Share path already "
2672 "shared: %s\n"), sharepath);
2673 }
2674 }
2675 if (ret != SA_OK)
2676 return (ret);
2677
2678 group = sa_get_group(handle, argv[optind]);
2679 if (group != NULL) {
2680 if (sa_require_resource(group) == B_TRUE &&
2681 rsrcname == NULL) {
2682 (void) printf(gettext(
2683 "Resource name is required "
2684 "by at least one enabled protocol "
2685 "in group\n"));
2686 return (SA_RESOURCE_REQUIRED);
2687 }
2688 if (share == NULL && ret == SA_OK) {
2689 if (dryrun)
2690 ret = sa_check_path(group, sharepath,
2691 SA_CHECK_NORMAL);
2692 else
2693 share = sa_add_share(group, sharepath,
2694 persist, &ret);
2695 }
2696 /*
2697 * Make sure this isn't an attempt to put a resourced
2698 * share into a different group than it already is in.
2699 */
2700 if (share != NULL) {
2701 sa_group_t parent;
2702 parent = sa_get_parent_group(share);
2703 if (parent != group) {
2704 ret = SA_DUPLICATE_NAME;
2705 (void) printf(gettext(
2706 "Share path already "
2707 "shared: %s\n"), sharepath);
2708 }
2709 }
2710 if (!dryrun && share == NULL) {
2711 (void) printf(gettext(
2712 "Could not add share: %s\n"),
2713 sa_errorstr(ret));
2714 } else {
2715 auth = check_authorizations(argv[optind],
2716 flags);
2717 if (!dryrun && ret == SA_OK) {
2718 if (rsrcname != NULL) {
2719 resource = sa_add_resource(
2720 share,
2721 rsrc,
2722 SA_SHARE_PERMANENT,
2723 &ret);
2724 }
2725 if (ret == SA_OK &&
2726 description != NULL) {
2727 if (resource != NULL)
2728 ret =
2729 set_resource_desc(
2730 resource,
2731 description);
2732 else
2733 ret =
2734 set_share_desc(
2735 share,
2736 description);
2737 }
2738 if (ret == SA_OK) {
2739 /* now enable the share(s) */
2740 if (resource != NULL) {
2741 ret = enable_share(
2742 handle,
2743 group,
2744 resource,
2745 1);
2746 } else {
2747 ret = enable_share(
2748 handle,
2749 group,
2750 share,
2751 1);
2752 }
2753 ret = sa_update_config(handle);
2754 }
2755 switch (ret) {
2756 case SA_DUPLICATE_NAME:
2757 (void) printf(gettext(
2758 "Resource name in"
2759 "use: %s\n"),
2760 rsrcname);
2761 break;
2762 default:
2763 (void) printf(gettext(
2764 "Could not set "
2765 "attribute: %s\n"),
2766 sa_errorstr(ret));
2767 break;
2768 case SA_OK:
2769 break;
2770 }
2771 } else if (dryrun && ret == SA_OK &&
2772 !auth && verbose) {
2773 (void) printf(gettext(
2774 "Command would fail: %s\n"),
2775 sa_errorstr(SA_NO_PERMISSION));
2776 ret = SA_NO_PERMISSION;
2777 }
2778 }
2779 } else {
2780 switch (ret) {
2781 default:
2782 (void) printf(gettext(
2783 "Group \"%s\" not found\n"), argv[optind]);
2784 ret = SA_NO_SUCH_GROUP;
2785 break;
2786 case SA_BAD_PATH:
2787 case SA_DUPLICATE_NAME:
2788 break;
2789 }
2790 }
2791 }
2792 return (ret);
2793 }
2794
2795 /*
2796 * sa_moveshare(flags, argc, argv)
2797 *
2798 * implements move-share subcommand.
2799 */
2800
2801 int
sa_moveshare(sa_handle_t handle,int flags,int argc,char * argv[])2802 sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
2803 {
2804 int verbose = 0;
2805 int dryrun = 0;
2806 int c;
2807 int ret = SA_OK;
2808 sa_group_t group;
2809 sa_share_t share;
2810 char *rsrcname = NULL;
2811 char *sharepath = NULL;
2812 int authsrc = 0, authdst = 0;
2813 char dir[MAXPATHLEN];
2814
2815 while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) {
2816 switch (c) {
2817 case 'n':
2818 dryrun++;
2819 break;
2820 case 'v':
2821 verbose++;
2822 break;
2823 case 'r':
2824 if (rsrcname != NULL) {
2825 (void) printf(gettext(
2826 "Moving multiple resource names not"
2827 " supported\n"));
2828 return (SA_SYNTAX_ERR);
2829 }
2830 rsrcname = optarg;
2831 break;
2832 case 's':
2833 /*
2834 * Remove share path from group. Currently limit
2835 * to one share per command.
2836 */
2837 if (sharepath != NULL) {
2838 (void) printf(gettext("Moving multiple shares"
2839 " not supported\n"));
2840 return (SA_SYNTAX_ERR);
2841 }
2842 sharepath = optarg;
2843 break;
2844 case 'h':
2845 /* optopt on valid arg isn't defined */
2846 optopt = c;
2847 /*FALLTHROUGH*/
2848 case '?':
2849 default:
2850 /*
2851 * Since a bad option gets to here, sort it
2852 * out and return a syntax error return value
2853 * if necessary.
2854 */
2855 switch (optopt) {
2856 default:
2857 ret = SA_SYNTAX_ERR;
2858 break;
2859 case 'h':
2860 case '?':
2861 break;
2862 }
2863 (void) printf(gettext("usage: %s\n"),
2864 sa_get_usage(USAGE_MOVE_SHARE));
2865 return (ret);
2866 }
2867 }
2868
2869 if (optind >= argc || sharepath == NULL) {
2870 (void) printf(gettext("usage: %s\n"),
2871 sa_get_usage(USAGE_MOVE_SHARE));
2872 if (dryrun || verbose || sharepath != NULL) {
2873 (void) printf(gettext("\tgroup must be specified\n"));
2874 ret = SA_NO_SUCH_GROUP;
2875 } else {
2876 if (sharepath == NULL) {
2877 ret = SA_SYNTAX_ERR;
2878 (void) printf(gettext(
2879 "\tsharepath must be specified\n"));
2880 } else {
2881 ret = SA_OK;
2882 }
2883 }
2884 } else {
2885 sa_group_t parent;
2886 char *zfsold;
2887 char *zfsnew;
2888
2889 if (sharepath == NULL) {
2890 (void) printf(gettext(
2891 "sharepath must be specified with the -s "
2892 "option\n"));
2893 return (SA_BAD_PATH);
2894 }
2895 group = sa_get_group(handle, argv[optind]);
2896 if (group == NULL) {
2897 (void) printf(gettext("Group \"%s\" not found\n"),
2898 argv[optind]);
2899 return (SA_NO_SUCH_GROUP);
2900 }
2901 share = sa_find_share(handle, sharepath);
2902 /*
2903 * If a share wasn't found, it may have been a symlink
2904 * or has a trailing '/'. Try again after resolving
2905 * with realpath().
2906 */
2907 if (share == NULL) {
2908 if (realpath(sharepath, dir) == NULL) {
2909 (void) printf(gettext("Path "
2910 "is not valid: %s\n"),
2911 sharepath);
2912 return (SA_BAD_PATH);
2913 }
2914 sharepath = dir;
2915 share = sa_find_share(handle, sharepath);
2916 }
2917 if (share == NULL) {
2918 (void) printf(gettext("Share not found: %s\n"),
2919 sharepath);
2920 return (SA_NO_SUCH_PATH);
2921 }
2922 authdst = check_authorizations(argv[optind], flags);
2923
2924 parent = sa_get_parent_group(share);
2925 if (parent != NULL) {
2926 char *pname;
2927 pname = sa_get_group_attr(parent, "name");
2928 if (pname != NULL) {
2929 authsrc = check_authorizations(pname, flags);
2930 sa_free_attr_string(pname);
2931 }
2932 zfsold = sa_get_group_attr(parent, "zfs");
2933 zfsnew = sa_get_group_attr(group, "zfs");
2934 if ((zfsold != NULL && zfsnew == NULL) ||
2935 (zfsold == NULL && zfsnew != NULL)) {
2936 ret = SA_NOT_ALLOWED;
2937 }
2938 if (zfsold != NULL)
2939 sa_free_attr_string(zfsold);
2940 if (zfsnew != NULL)
2941 sa_free_attr_string(zfsnew);
2942 }
2943
2944 if (ret == SA_OK && parent != group && !dryrun) {
2945 char *oldstate;
2946 /*
2947 * Note that the share may need to be
2948 * "unshared" if the new group is disabled and
2949 * the old was enabled or it may need to be
2950 * share to update if the new group is
2951 * enabled. We disable before the move and
2952 * will have to enable after the move in order
2953 * to cleanup entries for protocols that
2954 * aren't in the new group.
2955 */
2956 oldstate = sa_get_group_attr(parent, "state");
2957 if (oldstate != NULL) {
2958 /* enable_share determines what to do */
2959 if (strcmp(oldstate, "enabled") == 0)
2960 (void) sa_disable_share(share, NULL);
2961 sa_free_attr_string(oldstate);
2962 }
2963 }
2964
2965 if (!dryrun && ret == SA_OK)
2966 ret = sa_move_share(group, share);
2967
2968 /*
2969 * Reenable and update any config information.
2970 */
2971 if (ret == SA_OK && parent != group && !dryrun) {
2972 ret = sa_update_config(handle);
2973
2974 (void) enable_share(handle, group, share, 1);
2975 }
2976
2977 if (ret != SA_OK)
2978 (void) printf(gettext("Could not move share: %s\n"),
2979 sa_errorstr(ret));
2980
2981 if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
2982 verbose) {
2983 (void) printf(gettext("Command would fail: %s\n"),
2984 sa_errorstr(SA_NO_PERMISSION));
2985 }
2986 }
2987 return (ret);
2988 }
2989
2990 /*
2991 * sa_removeshare(flags, argc, argv)
2992 *
2993 * implements remove-share subcommand.
2994 */
2995
2996 int
sa_removeshare(sa_handle_t handle,int flags,int argc,char * argv[])2997 sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
2998 {
2999 int verbose = 0;
3000 int dryrun = 0;
3001 int force = 0;
3002 int c;
3003 int ret = SA_OK;
3004 sa_group_t group;
3005 sa_resource_t resource = NULL;
3006 sa_share_t share = NULL;
3007 char *rsrcname = NULL;
3008 char *sharepath = NULL;
3009 char dir[MAXPATHLEN];
3010 int auth;
3011
3012 while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) {
3013 switch (c) {
3014 case 'n':
3015 dryrun++;
3016 break;
3017 case 'v':
3018 verbose++;
3019 break;
3020 case 'f':
3021 force++;
3022 break;
3023 case 's':
3024 /*
3025 * Remove share path from group. Currently limit
3026 * to one share per command.
3027 */
3028 if (sharepath != NULL) {
3029 (void) printf(gettext(
3030 "Removing multiple shares not "
3031 "supported\n"));
3032 return (SA_SYNTAX_ERR);
3033 }
3034 sharepath = optarg;
3035 break;
3036 case 'r':
3037 /*
3038 * Remove share from group if last resource or remove
3039 * resource from share if multiple resources.
3040 */
3041 if (rsrcname != NULL) {
3042 (void) printf(gettext(
3043 "Removing multiple resource names not "
3044 "supported\n"));
3045 return (SA_SYNTAX_ERR);
3046 }
3047 rsrcname = optarg;
3048 break;
3049 case 'h':
3050 /* optopt on valid arg isn't defined */
3051 optopt = c;
3052 /*FALLTHROUGH*/
3053 case '?':
3054 default:
3055 /*
3056 * Since a bad option gets to here, sort it
3057 * out and return a syntax error return value
3058 * if necessary.
3059 */
3060 switch (optopt) {
3061 default:
3062 ret = SA_SYNTAX_ERR;
3063 break;
3064 case 'h':
3065 case '?':
3066 break;
3067 }
3068 (void) printf(gettext("usage: %s\n"),
3069 sa_get_usage(USAGE_REMOVE_SHARE));
3070 return (ret);
3071 }
3072 }
3073
3074 if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) {
3075 if (sharepath == NULL && rsrcname == NULL) {
3076 (void) printf(gettext("usage: %s\n"),
3077 sa_get_usage(USAGE_REMOVE_SHARE));
3078 (void) printf(gettext("\t-s sharepath or -r resource"
3079 " must be specified\n"));
3080 ret = SA_BAD_PATH;
3081 } else {
3082 ret = SA_OK;
3083 }
3084 }
3085 if (ret != SA_OK) {
3086 return (ret);
3087 }
3088
3089 if (optind < argc) {
3090 if ((optind + 1) < argc) {
3091 (void) printf(gettext("Extraneous group(s) at end of "
3092 "command\n"));
3093 ret = SA_SYNTAX_ERR;
3094 } else {
3095 group = sa_get_group(handle, argv[optind]);
3096 if (group == NULL) {
3097 (void) printf(gettext(
3098 "Group \"%s\" not found\n"), argv[optind]);
3099 ret = SA_NO_SUCH_GROUP;
3100 }
3101 }
3102 } else {
3103 group = NULL;
3104 }
3105
3106 if (rsrcname != NULL) {
3107 resource = sa_find_resource(handle, rsrcname);
3108 if (resource == NULL) {
3109 ret = SA_NO_SUCH_RESOURCE;
3110 (void) printf(gettext(
3111 "Resource name not found for share: %s\n"),
3112 rsrcname);
3113 }
3114 }
3115
3116 /*
3117 * Lookup the path in the internal configuration. Care
3118 * must be taken to handle the case where the
3119 * underlying path has been removed since we need to
3120 * be able to deal with that as well.
3121 */
3122 if (ret == SA_OK) {
3123 if (sharepath != NULL) {
3124 if (group != NULL)
3125 share = sa_get_share(group, sharepath);
3126 else
3127 share = sa_find_share(handle, sharepath);
3128 }
3129
3130 if (resource != NULL) {
3131 sa_share_t rsrcshare;
3132 rsrcshare = sa_get_resource_parent(resource);
3133 if (share == NULL)
3134 share = rsrcshare;
3135 else if (share != rsrcshare) {
3136 ret = SA_NO_SUCH_RESOURCE;
3137 (void) printf(gettext(
3138 "Bad resource name for share: %s\n"),
3139 rsrcname);
3140 share = NULL;
3141 }
3142 }
3143
3144 /*
3145 * If we didn't find the share with the provided path,
3146 * it may be a symlink so attempt to resolve it using
3147 * realpath and try again. Realpath will resolve any
3148 * symlinks and place them in "dir". Note that
3149 * sharepath is only used for the lookup the first
3150 * time and later for error messages. dir will be used
3151 * on the second attempt. Once a share is found, all
3152 * operations are based off of the share variable.
3153 */
3154 if (share == NULL) {
3155 if (realpath(sharepath, dir) == NULL) {
3156 ret = SA_BAD_PATH;
3157 (void) printf(gettext(
3158 "Path is not valid: %s\n"), sharepath);
3159 } else {
3160 if (group != NULL)
3161 share = sa_get_share(group, dir);
3162 else
3163 share = sa_find_share(handle, dir);
3164 }
3165 }
3166 }
3167
3168 /*
3169 * If there hasn't been an error, there was likely a
3170 * path found. If not, give the appropriate error
3171 * message and set the return error. If it was found,
3172 * then disable the share and then remove it from the
3173 * configuration.
3174 */
3175 if (ret != SA_OK) {
3176 return (ret);
3177 }
3178 if (share == NULL) {
3179 if (group != NULL)
3180 (void) printf(gettext("Share not found in group %s:"
3181 " %s\n"), argv[optind], sharepath);
3182 else
3183 (void) printf(gettext("Share not found: %s\n"),
3184 sharepath);
3185 ret = SA_NO_SUCH_PATH;
3186 } else {
3187 if (group == NULL)
3188 group = sa_get_parent_group(share);
3189 if (!dryrun) {
3190 if (ret == SA_OK) {
3191 if (resource != NULL)
3192 ret = sa_disable_resource(resource,
3193 NULL);
3194 else
3195 ret = sa_disable_share(share, NULL);
3196 /*
3197 * We don't care if it fails since it
3198 * could be disabled already. Some
3199 * unexpected errors could occur that
3200 * prevent removal, so also check for
3201 * force being set.
3202 */
3203 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3204 ret == SA_NOT_SUPPORTED ||
3205 ret == SA_SYSTEM_ERR || force) &&
3206 resource == NULL)
3207 ret = sa_remove_share(share);
3208
3209 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3210 ret == SA_NOT_SUPPORTED ||
3211 ret == SA_SYSTEM_ERR || force) &&
3212 resource != NULL) {
3213 ret = sa_remove_resource(resource);
3214 if (ret == SA_OK) {
3215 /*
3216 * If this was the
3217 * last one, remove
3218 * the share as well.
3219 */
3220 resource =
3221 sa_get_share_resource(
3222 share, NULL);
3223 if (resource == NULL)
3224 ret = sa_remove_share(
3225 share);
3226 }
3227 }
3228 if (ret == SA_OK)
3229 ret = sa_update_config(handle);
3230 }
3231 if (ret != SA_OK)
3232 (void) printf(gettext("Could not remove share:"
3233 " %s\n"), sa_errorstr(ret));
3234 } else if (ret == SA_OK) {
3235 char *pname;
3236 pname = sa_get_group_attr(group, "name");
3237 if (pname != NULL) {
3238 auth = check_authorizations(pname, flags);
3239 sa_free_attr_string(pname);
3240 }
3241 if (!auth && verbose) {
3242 (void) printf(gettext(
3243 "Command would fail: %s\n"),
3244 sa_errorstr(SA_NO_PERMISSION));
3245 }
3246 }
3247 }
3248 return (ret);
3249 }
3250
3251 /*
3252 * sa_set_share(flags, argc, argv)
3253 *
3254 * implements set-share subcommand.
3255 */
3256
3257 int
sa_set_share(sa_handle_t handle,int flags,int argc,char * argv[])3258 sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
3259 {
3260 int dryrun = 0;
3261 int c;
3262 int ret = SA_OK;
3263 sa_group_t group, sharegroup;
3264 sa_share_t share = NULL;
3265 sa_resource_t resource = NULL;
3266 char *sharepath = NULL;
3267 char *description = NULL;
3268 char *rsrcname = NULL;
3269 char *rsrc = NULL;
3270 char *newname = NULL;
3271 char *newrsrc;
3272 char *groupname = NULL;
3273 int auth;
3274 int verbose = 0;
3275
3276 while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
3277 switch (c) {
3278 case 'n':
3279 dryrun++;
3280 break;
3281 case 'd':
3282 description = optarg;
3283 break;
3284 case 'v':
3285 verbose++;
3286 break;
3287 case 'r':
3288 /*
3289 * Update share by resource name
3290 */
3291 if (rsrcname != NULL) {
3292 (void) printf(gettext(
3293 "Updating multiple resource names not "
3294 "supported\n"));
3295 return (SA_SYNTAX_ERR);
3296 }
3297 rsrcname = optarg;
3298 break;
3299 case 's':
3300 /*
3301 * Save share path into group. Currently limit
3302 * to one share per command.
3303 */
3304 if (sharepath != NULL) {
3305 (void) printf(gettext(
3306 "Updating multiple shares not "
3307 "supported\n"));
3308 return (SA_SYNTAX_ERR);
3309 }
3310 sharepath = optarg;
3311 break;
3312 case 'h':
3313 /* optopt on valid arg isn't defined */
3314 optopt = c;
3315 /*FALLTHROUGH*/
3316 case '?':
3317 default:
3318 /*
3319 * Since a bad option gets to here, sort it
3320 * out and return a syntax error return value
3321 * if necessary.
3322 */
3323 switch (optopt) {
3324 default:
3325 ret = SA_SYNTAX_ERR;
3326 break;
3327 case 'h':
3328 case '?':
3329 break;
3330 }
3331 (void) printf(gettext("usage: %s\n"),
3332 sa_get_usage(USAGE_SET_SHARE));
3333 return (ret);
3334 }
3335 }
3336
3337 if (optind >= argc && sharepath == NULL && rsrcname == NULL) {
3338 if (sharepath == NULL) {
3339 (void) printf(gettext("usage: %s\n"),
3340 sa_get_usage(USAGE_SET_SHARE));
3341 (void) printf(gettext("\tgroup must be specified\n"));
3342 ret = SA_BAD_PATH;
3343 } else {
3344 ret = SA_OK;
3345 }
3346 }
3347 if ((optind + 1) < argc) {
3348 (void) printf(gettext("usage: %s\n"),
3349 sa_get_usage(USAGE_SET_SHARE));
3350 (void) printf(gettext("\tExtraneous group(s) at end\n"));
3351 ret = SA_SYNTAX_ERR;
3352 }
3353
3354 /*
3355 * Must have at least one of sharepath and rsrcrname.
3356 * It is a syntax error to be missing both.
3357 */
3358 if (sharepath == NULL && rsrcname == NULL) {
3359 (void) printf(gettext("usage: %s\n"),
3360 sa_get_usage(USAGE_SET_SHARE));
3361 ret = SA_SYNTAX_ERR;
3362 }
3363
3364 if (ret != SA_OK)
3365 return (ret);
3366
3367 if (optind < argc) {
3368 groupname = argv[optind];
3369 group = sa_get_group(handle, groupname);
3370 } else {
3371 group = NULL;
3372 groupname = NULL;
3373 }
3374 if (rsrcname != NULL) {
3375 /*
3376 * If rsrcname exists, split rename syntax and then
3377 * convert to utf 8 if no errors.
3378 */
3379 newname = strchr(rsrcname, '=');
3380 if (newname != NULL) {
3381 *newname++ = '\0';
3382 }
3383 if (!validresource(rsrcname)) {
3384 ret = SA_INVALID_NAME;
3385 (void) printf(gettext("Invalid resource name: "
3386 "\"%s\"\n"), rsrcname);
3387 } else {
3388 rsrc = conv_to_utf8(rsrcname);
3389 }
3390 if (newname != NULL) {
3391 if (!validresource(newname)) {
3392 ret = SA_INVALID_NAME;
3393 (void) printf(gettext("Invalid resource name: "
3394 "%s\n"), newname);
3395 newname = NULL;
3396 } else {
3397 newrsrc = conv_to_utf8(newname);
3398 }
3399 }
3400 }
3401
3402 if (ret != SA_OK) {
3403 if (rsrcname != NULL && rsrcname != rsrc)
3404 sa_free_attr_string(rsrc);
3405 if (newname != NULL && newname != newrsrc)
3406 sa_free_attr_string(newrsrc);
3407 return (ret);
3408 }
3409
3410 if (sharepath != NULL) {
3411 share = sa_find_share(handle, sharepath);
3412 } else if (rsrcname != NULL) {
3413 resource = sa_find_resource(handle, rsrc);
3414 if (resource != NULL)
3415 share = sa_get_resource_parent(resource);
3416 else
3417 ret = SA_NO_SUCH_RESOURCE;
3418 }
3419 if (share != NULL) {
3420 sharegroup = sa_get_parent_group(share);
3421 if (group != NULL && group != sharegroup) {
3422 (void) printf(gettext("Group \"%s\" does not contain "
3423 "share %s\n"),
3424 argv[optind], sharepath);
3425 ret = SA_BAD_PATH;
3426 } else {
3427 int delgroupname = 0;
3428 if (groupname == NULL) {
3429 groupname = sa_get_group_attr(sharegroup,
3430 "name");
3431 delgroupname = 1;
3432 }
3433 if (groupname != NULL) {
3434 auth = check_authorizations(groupname, flags);
3435 if (delgroupname) {
3436 sa_free_attr_string(groupname);
3437 groupname = NULL;
3438 }
3439 } else {
3440 ret = SA_NO_MEMORY;
3441 }
3442 if (rsrcname != NULL) {
3443 resource = sa_find_resource(handle, rsrc);
3444 if (!dryrun) {
3445 if (newname != NULL &&
3446 resource != NULL)
3447 ret = sa_rename_resource(
3448 resource, newrsrc);
3449 else if (newname != NULL)
3450 ret = SA_NO_SUCH_RESOURCE;
3451 if (newname != NULL &&
3452 newname != newrsrc)
3453 sa_free_attr_string(newrsrc);
3454 }
3455 if (rsrc != rsrcname)
3456 sa_free_attr_string(rsrc);
3457 }
3458
3459 /*
3460 * If the user has set a description, it will be
3461 * on the resource if -r was used otherwise it
3462 * must be on the share.
3463 */
3464 if (!dryrun && ret == SA_OK && description != NULL) {
3465 char *desc;
3466 desc = conv_to_utf8(description);
3467 if (resource != NULL)
3468 ret = sa_set_resource_description(
3469 resource, desc);
3470 else
3471 ret = sa_set_share_description(share,
3472 desc);
3473 if (desc != description)
3474 sa_free_share_description(desc);
3475 }
3476 }
3477 if (!dryrun && ret == SA_OK) {
3478 if (resource != NULL)
3479 (void) sa_enable_resource(resource, NULL);
3480 ret = sa_update_config(handle);
3481 }
3482 switch (ret) {
3483 case SA_DUPLICATE_NAME:
3484 (void) printf(gettext("Resource name in use: %s\n"),
3485 rsrcname);
3486 break;
3487 default:
3488 (void) printf(gettext("Could not set: %s\n"),
3489 sa_errorstr(ret));
3490 break;
3491 case SA_OK:
3492 if (dryrun && !auth && verbose) {
3493 (void) printf(gettext(
3494 "Command would fail: %s\n"),
3495 sa_errorstr(SA_NO_PERMISSION));
3496 }
3497 break;
3498 }
3499 } else {
3500 switch (ret) {
3501 case SA_NO_SUCH_RESOURCE:
3502 (void) printf(gettext("Resource \"%s\" not found\n"),
3503 rsrcname);
3504 break;
3505 default:
3506 if (sharepath != NULL) {
3507 (void) printf(
3508 gettext("Share path \"%s\" not found\n"),
3509 sharepath);
3510 ret = SA_NO_SUCH_PATH;
3511 } else {
3512 (void) printf(gettext("Set failed: %s\n"),
3513 sa_errorstr(ret));
3514 }
3515 }
3516 }
3517
3518 return (ret);
3519 }
3520
3521 /*
3522 * add_security(group, sectype, optlist, proto, *err)
3523 *
3524 * Helper function to add a security option (named optionset) to the
3525 * group.
3526 */
3527
3528 static int
add_security(sa_group_t group,char * sectype,struct options * optlist,char * proto,int * err)3529 add_security(sa_group_t group, char *sectype,
3530 struct options *optlist, char *proto, int *err)
3531 {
3532 sa_security_t security;
3533 int ret = SA_OK;
3534 int result = 0;
3535 sa_handle_t handle;
3536
3537 sectype = sa_proto_space_alias(proto, sectype);
3538 security = sa_get_security(group, sectype, proto);
3539 if (security == NULL)
3540 security = sa_create_security(group, sectype, proto);
3541
3542 if (sectype != NULL)
3543 sa_free_attr_string(sectype);
3544
3545 if (security == NULL)
3546 goto done;
3547
3548 handle = sa_find_group_handle(group);
3549 if (handle == NULL) {
3550 ret = SA_CONFIG_ERR;
3551 goto done;
3552 }
3553 while (optlist != NULL) {
3554 sa_property_t prop;
3555 prop = sa_get_property(security, optlist->optname);
3556 if (prop == NULL) {
3557 /*
3558 * Add the property, but only if it is
3559 * a non-NULL or non-zero length value
3560 */
3561 if (optlist->optvalue != NULL) {
3562 prop = sa_create_property(optlist->optname,
3563 optlist->optvalue);
3564 if (prop != NULL) {
3565 ret = sa_valid_property(handle,
3566 security, proto, prop);
3567 if (ret != SA_OK) {
3568 (void) sa_remove_property(prop);
3569 (void) printf(gettext(
3570 "Could not add "
3571 "property %s: %s\n"),
3572 optlist->optname,
3573 sa_errorstr(ret));
3574 }
3575 if (ret == SA_OK) {
3576 ret = sa_add_property(security,
3577 prop);
3578 if (ret != SA_OK) {
3579 (void) printf(gettext(
3580 "Could not add "
3581 "property (%s=%s):"
3582 " %s\n"),
3583 optlist->optname,
3584 optlist->optvalue,
3585 sa_errorstr(ret));
3586 } else {
3587 result = 1;
3588 }
3589 }
3590 }
3591 }
3592 } else {
3593 ret = sa_update_property(prop, optlist->optvalue);
3594 result = 1; /* should check if really changed */
3595 }
3596 optlist = optlist->next;
3597 }
3598 /*
3599 * When done, properties may have all been removed but
3600 * we need to keep the security type itself until
3601 * explicitly removed.
3602 */
3603 if (result)
3604 ret = sa_commit_properties(security, 0);
3605 done:
3606 *err = ret;
3607 return (result);
3608 }
3609
3610 /*
3611 * zfscheck(group, share)
3612 *
3613 * For the special case where a share was provided, make sure it is a
3614 * compatible path for a ZFS property change. The only path
3615 * acceptable is the path that defines the zfs sub-group (dataset with
3616 * the sharenfs property set) and not one of the paths that inherited
3617 * the NFS properties. Returns SA_OK if it is usable and
3618 * SA_NOT_ALLOWED if it isn't.
3619 *
3620 * If group is not a ZFS group/subgroup, we assume OK since the check
3621 * on return will catch errors for those cases. What we are looking
3622 * for here is that the group is ZFS and the share is not the defining
3623 * share. All else is SA_OK.
3624 */
3625
3626 static int
zfscheck(sa_group_t group,sa_share_t share)3627 zfscheck(sa_group_t group, sa_share_t share)
3628 {
3629 int ret = SA_OK;
3630 char *attr;
3631
3632 if (sa_group_is_zfs(group)) {
3633 /*
3634 * The group is a ZFS group. Does the share represent
3635 * the dataset that defined the group? It is only OK
3636 * if the attribute "subgroup" exists on the share and
3637 * has a value of "true".
3638 */
3639
3640 ret = SA_NOT_ALLOWED;
3641 attr = sa_get_share_attr(share, "subgroup");
3642 if (attr != NULL) {
3643 if (strcmp(attr, "true") == 0)
3644 ret = SA_OK;
3645 sa_free_attr_string(attr);
3646 }
3647 }
3648 return (ret);
3649 }
3650
3651 /*
3652 * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
3653 *
3654 * This function implements "set" when a name space (-S) is not
3655 * specified. It is a basic set. Options and other CLI parsing has
3656 * already been done.
3657 *
3658 * "rsrcname" is a "resource name". If it is non-NULL, it must match
3659 * the sharepath if present or group if present, otherwise it is used
3660 * to set options.
3661 *
3662 * Resource names may take options if the protocol supports it. If the
3663 * protocol doesn't support resource level options, rsrcname is just
3664 * an alias for the share.
3665 */
3666
3667 static int
basic_set(sa_handle_t handle,char * groupname,struct options * optlist,char * protocol,char * sharepath,char * rsrcname,int dryrun)3668 basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
3669 char *protocol, char *sharepath, char *rsrcname, int dryrun)
3670 {
3671 sa_group_t group;
3672 int ret = SA_OK;
3673 int change = 0;
3674 struct list *worklist = NULL;
3675
3676 group = sa_get_group(handle, groupname);
3677 if (group != NULL) {
3678 sa_share_t share = NULL;
3679 sa_resource_t resource = NULL;
3680
3681 /*
3682 * If there is a sharepath, make sure it belongs to
3683 * the group.
3684 */
3685 if (sharepath != NULL) {
3686 share = sa_get_share(group, sharepath);
3687 if (share == NULL) {
3688 (void) printf(gettext(
3689 "Share does not exist in group %s\n"),
3690 groupname, sharepath);
3691 ret = SA_NO_SUCH_PATH;
3692 } else {
3693 /* if ZFS and OK, then only group */
3694 ret = zfscheck(group, share);
3695 if (ret == SA_OK &&
3696 sa_group_is_zfs(group))
3697 share = NULL;
3698 if (ret == SA_NOT_ALLOWED)
3699 (void) printf(gettext(
3700 "Properties on ZFS group shares "
3701 "not supported: %s\n"), sharepath);
3702 }
3703 }
3704
3705 /*
3706 * If a resource name exists, make sure it belongs to
3707 * the share if present else it belongs to the
3708 * group. Also check the protocol to see if it
3709 * supports resource level properties or not. If not,
3710 * use share only.
3711 */
3712 if (rsrcname != NULL) {
3713 if (share != NULL) {
3714 resource = sa_get_share_resource(share,
3715 rsrcname);
3716 if (resource == NULL)
3717 ret = SA_NO_SUCH_RESOURCE;
3718 } else {
3719 resource = sa_get_resource(group, rsrcname);
3720 if (resource != NULL)
3721 share = sa_get_resource_parent(
3722 resource);
3723 else
3724 ret = SA_NO_SUCH_RESOURCE;
3725 }
3726 if (ret == SA_OK && resource != NULL) {
3727 uint64_t features;
3728 /*
3729 * Check to see if the resource can take
3730 * properties. If so, stick the resource into
3731 * "share" so it will all just work.
3732 */
3733 features = sa_proto_get_featureset(protocol);
3734 if (features & SA_FEATURE_RESOURCE)
3735 share = (sa_share_t)resource;
3736 }
3737 }
3738
3739 if (ret == SA_OK) {
3740 /* group must exist */
3741 ret = valid_options(handle, optlist, protocol,
3742 share == NULL ? group : share, NULL);
3743 if (ret == SA_OK && !dryrun) {
3744 if (share != NULL)
3745 change |= add_optionset(share, optlist,
3746 protocol, &ret);
3747 else
3748 change |= add_optionset(group, optlist,
3749 protocol, &ret);
3750 if (ret == SA_OK && change)
3751 worklist = add_list(worklist, group,
3752 share, protocol);
3753 }
3754 }
3755 free_opt(optlist);
3756 } else {
3757 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3758 ret = SA_NO_SUCH_GROUP;
3759 }
3760 /*
3761 * we have a group and potentially legal additions
3762 */
3763
3764 /*
3765 * Commit to configuration if not a dryrunp and properties
3766 * have changed.
3767 */
3768 if (!dryrun && ret == SA_OK && change && worklist != NULL)
3769 /* properties changed, so update all shares */
3770 (void) enable_all_groups(handle, worklist, 0, 0, protocol,
3771 B_TRUE);
3772
3773 if (worklist != NULL)
3774 free_list(worklist);
3775 return (ret);
3776 }
3777
3778 /*
3779 * space_set(groupname, optlist, protocol, sharepath, dryrun)
3780 *
3781 * This function implements "set" when a name space (-S) is
3782 * specified. It is a namespace set. Options and other CLI parsing has
3783 * already been done.
3784 */
3785
3786 static int
space_set(sa_handle_t handle,char * groupname,struct options * optlist,char * protocol,char * sharepath,int dryrun,char * sectype)3787 space_set(sa_handle_t handle, char *groupname, struct options *optlist,
3788 char *protocol, char *sharepath, int dryrun, char *sectype)
3789 {
3790 sa_group_t group;
3791 int ret = SA_OK;
3792 int change = 0;
3793 struct list *worklist = NULL;
3794
3795 /*
3796 * make sure protcol and sectype are valid
3797 */
3798
3799 if (sa_proto_valid_space(protocol, sectype) == 0) {
3800 (void) printf(gettext("Option space \"%s\" not valid "
3801 "for protocol.\n"), sectype);
3802 return (SA_INVALID_SECURITY);
3803 }
3804
3805 group = sa_get_group(handle, groupname);
3806 if (group != NULL) {
3807 sa_share_t share = NULL;
3808 if (sharepath != NULL) {
3809 share = sa_get_share(group, sharepath);
3810 if (share == NULL) {
3811 (void) printf(gettext(
3812 "Share does not exist in group %s\n"),
3813 groupname, sharepath);
3814 ret = SA_NO_SUCH_PATH;
3815 } else {
3816 /* if ZFS and OK, then only group */
3817 ret = zfscheck(group, share);
3818 if (ret == SA_OK &&
3819 sa_group_is_zfs(group))
3820 share = NULL;
3821 if (ret == SA_NOT_ALLOWED)
3822 (void) printf(gettext(
3823 "Properties on ZFS group shares "
3824 "not supported: %s\n"), sharepath);
3825 }
3826 }
3827 if (ret == SA_OK) {
3828 /* group must exist */
3829 ret = valid_options(handle, optlist, protocol,
3830 share == NULL ? group : share, sectype);
3831 if (ret == SA_OK && !dryrun) {
3832 if (share != NULL)
3833 change = add_security(share, sectype,
3834 optlist, protocol, &ret);
3835 else
3836 change = add_security(group, sectype,
3837 optlist, protocol, &ret);
3838 if (ret != SA_OK)
3839 (void) printf(gettext(
3840 "Could not set property: %s\n"),
3841 sa_errorstr(ret));
3842 }
3843 if (ret == SA_OK && change)
3844 worklist = add_list(worklist, group, share,
3845 protocol);
3846 }
3847 free_opt(optlist);
3848 } else {
3849 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3850 ret = SA_NO_SUCH_GROUP;
3851 }
3852
3853 /*
3854 * We have a group and potentially legal additions.
3855 */
3856
3857 /* Commit to configuration if not a dryrun */
3858 if (!dryrun && ret == 0) {
3859 if (change && worklist != NULL) {
3860 /* properties changed, so update all shares */
3861 (void) enable_all_groups(handle, worklist, 0, 0,
3862 protocol, B_TRUE);
3863 }
3864 ret = sa_update_config(handle);
3865 }
3866 if (worklist != NULL)
3867 free_list(worklist);
3868 return (ret);
3869 }
3870
3871 /*
3872 * sa_set(flags, argc, argv)
3873 *
3874 * Implements the set subcommand. It keys off of -S to determine which
3875 * set of operations to actually do.
3876 */
3877
3878 int
sa_set(sa_handle_t handle,int flags,int argc,char * argv[])3879 sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
3880 {
3881 char *groupname;
3882 int verbose = 0;
3883 int dryrun = 0;
3884 int c;
3885 char *protocol = NULL;
3886 int ret = SA_OK;
3887 struct options *optlist = NULL;
3888 char *rsrcname = NULL;
3889 char *sharepath = NULL;
3890 char *optset = NULL;
3891 int auth;
3892
3893 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
3894 switch (c) {
3895 case 'v':
3896 verbose++;
3897 break;
3898 case 'n':
3899 dryrun++;
3900 break;
3901 case 'P':
3902 if (protocol != NULL) {
3903 (void) printf(gettext(
3904 "Specifying multiple protocols "
3905 "not supported: %s\n"), protocol);
3906 return (SA_SYNTAX_ERR);
3907 }
3908 protocol = optarg;
3909 if (!sa_valid_protocol(protocol)) {
3910 (void) printf(gettext(
3911 "Invalid protocol specified: %s\n"),
3912 protocol);
3913 return (SA_INVALID_PROTOCOL);
3914 }
3915 break;
3916 case 'p':
3917 ret = add_opt(&optlist, optarg, 0);
3918 switch (ret) {
3919 case OPT_ADD_SYNTAX:
3920 (void) printf(gettext("Property syntax error:"
3921 " %s\n"), optarg);
3922 return (SA_SYNTAX_ERR);
3923 case OPT_ADD_MEMORY:
3924 (void) printf(gettext("No memory to set "
3925 "property: %s\n"), optarg);
3926 return (SA_NO_MEMORY);
3927 default:
3928 break;
3929 }
3930 break;
3931 case 'r':
3932 if (rsrcname != NULL) {
3933 (void) printf(gettext(
3934 "Setting multiple resource names not"
3935 " supported\n"));
3936 return (SA_SYNTAX_ERR);
3937 }
3938 rsrcname = optarg;
3939 break;
3940 case 's':
3941 if (sharepath != NULL) {
3942 (void) printf(gettext(
3943 "Setting multiple shares not supported\n"));
3944 return (SA_SYNTAX_ERR);
3945 }
3946 sharepath = optarg;
3947 break;
3948 case 'S':
3949 if (optset != NULL) {
3950 (void) printf(gettext(
3951 "Specifying multiple property "
3952 "spaces not supported: %s\n"), optset);
3953 return (SA_SYNTAX_ERR);
3954 }
3955 optset = optarg;
3956 break;
3957 case 'h':
3958 /* optopt on valid arg isn't defined */
3959 optopt = c;
3960 /*FALLTHROUGH*/
3961 case '?':
3962 default:
3963 /*
3964 * Since a bad option gets to here, sort it
3965 * out and return a syntax error return value
3966 * if necessary.
3967 */
3968 switch (optopt) {
3969 default:
3970 ret = SA_SYNTAX_ERR;
3971 break;
3972 case 'h':
3973 case '?':
3974 break;
3975 }
3976 (void) printf(gettext("usage: %s\n"),
3977 sa_get_usage(USAGE_SET));
3978 return (ret);
3979 }
3980 }
3981
3982 if (optlist != NULL)
3983 ret = chk_opt(optlist, optset != NULL, protocol);
3984
3985 if (optind >= argc || (optlist == NULL && optset == NULL) ||
3986 protocol == NULL || ret != OPT_ADD_OK) {
3987 char *sep = "\t";
3988
3989 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
3990 if (optind >= argc) {
3991 (void) printf(gettext("%sgroup must be specified"),
3992 sep);
3993 sep = ", ";
3994 }
3995 if (optlist == NULL) {
3996 (void) printf(gettext("%sat least one property must be"
3997 " specified"), sep);
3998 sep = ", ";
3999 }
4000 if (protocol == NULL) {
4001 (void) printf(gettext("%sprotocol must be specified"),
4002 sep);
4003 sep = ", ";
4004 }
4005 (void) printf("\n");
4006 ret = SA_SYNTAX_ERR;
4007 } else {
4008 /*
4009 * Group already exists so we can proceed after a few
4010 * additional checks related to ZFS handling.
4011 */
4012
4013 groupname = argv[optind];
4014 if (strcmp(groupname, "zfs") == 0) {
4015 (void) printf(gettext("Changing properties for group "
4016 "\"zfs\" not allowed\n"));
4017 return (SA_NOT_ALLOWED);
4018 }
4019
4020 auth = check_authorizations(groupname, flags);
4021 if (optset == NULL)
4022 ret = basic_set(handle, groupname, optlist, protocol,
4023 sharepath, rsrcname, dryrun);
4024 else
4025 ret = space_set(handle, groupname, optlist, protocol,
4026 sharepath, dryrun, optset);
4027 if (dryrun && ret == SA_OK && !auth && verbose) {
4028 (void) printf(gettext("Command would fail: %s\n"),
4029 sa_errorstr(SA_NO_PERMISSION));
4030 }
4031 }
4032 return (ret);
4033 }
4034
4035 /*
4036 * remove_options(group, optlist, proto, *err)
4037 *
4038 * Helper function to actually remove options from a group after all
4039 * preprocessing is done.
4040 */
4041
4042 static int
remove_options(sa_group_t group,struct options * optlist,char * proto,int * err)4043 remove_options(sa_group_t group, struct options *optlist,
4044 char *proto, int *err)
4045 {
4046 struct options *cur;
4047 sa_optionset_t optionset;
4048 sa_property_t prop;
4049 int change = 0;
4050 int ret = SA_OK;
4051
4052 optionset = sa_get_optionset(group, proto);
4053 if (optionset != NULL) {
4054 for (cur = optlist; cur != NULL; cur = cur->next) {
4055 prop = sa_get_property(optionset, cur->optname);
4056 if (prop != NULL) {
4057 ret = sa_remove_property(prop);
4058 if (ret != SA_OK)
4059 break;
4060 change = 1;
4061 }
4062 }
4063 }
4064 if (ret == SA_OK && change)
4065 ret = sa_commit_properties(optionset, 0);
4066
4067 if (err != NULL)
4068 *err = ret;
4069 return (change);
4070 }
4071
4072 /*
4073 * valid_unset(group, optlist, proto)
4074 *
4075 * Sanity check the optlist to make sure they can be removed. Issue an
4076 * error if a property doesn't exist.
4077 */
4078
4079 static int
valid_unset(sa_group_t group,struct options * optlist,char * proto)4080 valid_unset(sa_group_t group, struct options *optlist, char *proto)
4081 {
4082 struct options *cur;
4083 sa_optionset_t optionset;
4084 sa_property_t prop;
4085 int ret = SA_OK;
4086
4087 optionset = sa_get_optionset(group, proto);
4088 if (optionset != NULL) {
4089 for (cur = optlist; cur != NULL; cur = cur->next) {
4090 prop = sa_get_property(optionset, cur->optname);
4091 if (prop == NULL) {
4092 (void) printf(gettext(
4093 "Could not unset property %s: not set\n"),
4094 cur->optname);
4095 ret = SA_NO_SUCH_PROP;
4096 }
4097 }
4098 }
4099 return (ret);
4100 }
4101
4102 /*
4103 * valid_unset_security(group, optlist, proto)
4104 *
4105 * Sanity check the optlist to make sure they can be removed. Issue an
4106 * error if a property doesn't exist.
4107 */
4108
4109 static int
valid_unset_security(sa_group_t group,struct options * optlist,char * proto,char * sectype)4110 valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
4111 char *sectype)
4112 {
4113 struct options *cur;
4114 sa_security_t security;
4115 sa_property_t prop;
4116 int ret = SA_OK;
4117 char *sec;
4118
4119 sec = sa_proto_space_alias(proto, sectype);
4120 security = sa_get_security(group, sec, proto);
4121 if (security != NULL) {
4122 for (cur = optlist; cur != NULL; cur = cur->next) {
4123 prop = sa_get_property(security, cur->optname);
4124 if (prop == NULL) {
4125 (void) printf(gettext(
4126 "Could not unset property %s: not set\n"),
4127 cur->optname);
4128 ret = SA_NO_SUCH_PROP;
4129 }
4130 }
4131 } else {
4132 (void) printf(gettext(
4133 "Could not unset %s: space not defined\n"), sectype);
4134 ret = SA_NO_SUCH_SECURITY;
4135 }
4136 if (sec != NULL)
4137 sa_free_attr_string(sec);
4138 return (ret);
4139 }
4140
4141 /*
4142 * remove_security(group, optlist, proto)
4143 *
4144 * Remove the properties since they were checked as valid.
4145 */
4146
4147 static int
remove_security(sa_group_t group,char * sectype,struct options * optlist,char * proto,int * err)4148 remove_security(sa_group_t group, char *sectype,
4149 struct options *optlist, char *proto, int *err)
4150 {
4151 sa_security_t security;
4152 int ret = SA_OK;
4153 int change = 0;
4154
4155 sectype = sa_proto_space_alias(proto, sectype);
4156 security = sa_get_security(group, sectype, proto);
4157 if (sectype != NULL)
4158 sa_free_attr_string(sectype);
4159
4160 if (security != NULL) {
4161 while (optlist != NULL) {
4162 sa_property_t prop;
4163 prop = sa_get_property(security, optlist->optname);
4164 if (prop != NULL) {
4165 ret = sa_remove_property(prop);
4166 if (ret != SA_OK)
4167 break;
4168 change = 1;
4169 }
4170 optlist = optlist->next;
4171 }
4172 /*
4173 * when done, properties may have all been removed but
4174 * we need to keep the security type itself until
4175 * explicitly removed.
4176 */
4177 if (ret == SA_OK && change)
4178 ret = sa_commit_properties(security, 0);
4179 } else {
4180 ret = SA_NO_SUCH_PROP;
4181 }
4182 if (err != NULL)
4183 *err = ret;
4184 return (change);
4185 }
4186
4187 /*
4188 * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
4189 *
4190 * Unset non-named optionset properties.
4191 */
4192
4193 static int
basic_unset(sa_handle_t handle,char * groupname,struct options * optlist,char * protocol,char * sharepath,char * rsrcname,int dryrun)4194 basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4195 char *protocol, char *sharepath, char *rsrcname, int dryrun)
4196 {
4197 sa_group_t group;
4198 int ret = SA_OK;
4199 int change = 0;
4200 struct list *worklist = NULL;
4201 sa_share_t share = NULL;
4202 sa_resource_t resource = NULL;
4203
4204 group = sa_get_group(handle, groupname);
4205 if (group == NULL)
4206 return (ret);
4207
4208 /*
4209 * If there is a sharepath, make sure it belongs to
4210 * the group.
4211 */
4212 if (sharepath != NULL) {
4213 share = sa_get_share(group, sharepath);
4214 if (share == NULL) {
4215 (void) printf(gettext(
4216 "Share does not exist in group %s\n"),
4217 groupname, sharepath);
4218 ret = SA_NO_SUCH_PATH;
4219 }
4220 }
4221 /*
4222 * If a resource name exists, make sure it belongs to
4223 * the share if present else it belongs to the
4224 * group. Also check the protocol to see if it
4225 * supports resource level properties or not. If not,
4226 * use share only.
4227 */
4228 if (rsrcname != NULL) {
4229 if (share != NULL) {
4230 resource = sa_get_share_resource(share, rsrcname);
4231 if (resource == NULL)
4232 ret = SA_NO_SUCH_RESOURCE;
4233 } else {
4234 resource = sa_get_resource(group, rsrcname);
4235 if (resource != NULL) {
4236 share = sa_get_resource_parent(resource);
4237 } else {
4238 ret = SA_NO_SUCH_RESOURCE;
4239 }
4240 }
4241 if (ret == SA_OK && resource != NULL) {
4242 uint64_t features;
4243 /*
4244 * Check to see if the resource can take
4245 * properties. If so, stick the resource into
4246 * "share" so it will all just work.
4247 */
4248 features = sa_proto_get_featureset(protocol);
4249 if (features & SA_FEATURE_RESOURCE)
4250 share = (sa_share_t)resource;
4251 }
4252 }
4253
4254 if (ret == SA_OK) {
4255 /* group must exist */
4256 ret = valid_unset(share != NULL ? share : group,
4257 optlist, protocol);
4258 if (ret == SA_OK && !dryrun) {
4259 if (share != NULL) {
4260 sa_optionset_t optionset;
4261 sa_property_t prop;
4262 change |= remove_options(share, optlist,
4263 protocol, &ret);
4264 /*
4265 * If a share optionset is
4266 * empty, remove it.
4267 */
4268 optionset = sa_get_optionset((sa_share_t)share,
4269 protocol);
4270 if (optionset != NULL) {
4271 prop = sa_get_property(optionset, NULL);
4272 if (prop == NULL)
4273 (void) sa_destroy_optionset(
4274 optionset);
4275 }
4276 } else {
4277 change |= remove_options(group,
4278 optlist, protocol, &ret);
4279 }
4280 if (ret == SA_OK && change)
4281 worklist = add_list(worklist, group, share,
4282 protocol);
4283 if (ret != SA_OK)
4284 (void) printf(gettext(
4285 "Could not remove properties: "
4286 "%s\n"), sa_errorstr(ret));
4287 }
4288 } else {
4289 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4290 ret = SA_NO_SUCH_GROUP;
4291 }
4292 free_opt(optlist);
4293
4294 /*
4295 * We have a group and potentially legal additions
4296 *
4297 * Commit to configuration if not a dryrun
4298 */
4299 if (!dryrun && ret == SA_OK) {
4300 if (change && worklist != NULL) {
4301 /* properties changed, so update all shares */
4302 (void) enable_all_groups(handle, worklist, 0, 0,
4303 protocol, B_TRUE);
4304 }
4305 }
4306 if (worklist != NULL)
4307 free_list(worklist);
4308 return (ret);
4309 }
4310
4311 /*
4312 * space_unset(groupname, optlist, protocol, sharepath, dryrun)
4313 *
4314 * Unset named optionset properties.
4315 */
4316 static int
space_unset(sa_handle_t handle,char * groupname,struct options * optlist,char * protocol,char * sharepath,int dryrun,char * sectype)4317 space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4318 char *protocol, char *sharepath, int dryrun, char *sectype)
4319 {
4320 sa_group_t group;
4321 int ret = SA_OK;
4322 int change = 0;
4323 struct list *worklist = NULL;
4324 sa_share_t share = NULL;
4325
4326 group = sa_get_group(handle, groupname);
4327 if (group == NULL) {
4328 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4329 return (SA_NO_SUCH_GROUP);
4330 }
4331 if (sharepath != NULL) {
4332 share = sa_get_share(group, sharepath);
4333 if (share == NULL) {
4334 (void) printf(gettext(
4335 "Share does not exist in group %s\n"),
4336 groupname, sharepath);
4337 return (SA_NO_SUCH_PATH);
4338 }
4339 }
4340 ret = valid_unset_security(share != NULL ? share : group,
4341 optlist, protocol, sectype);
4342
4343 if (ret == SA_OK && !dryrun) {
4344 if (optlist != NULL) {
4345 if (share != NULL) {
4346 sa_security_t optionset;
4347 sa_property_t prop;
4348 change = remove_security(share,
4349 sectype, optlist, protocol, &ret);
4350
4351 /* If a share security is empty, remove it */
4352 optionset = sa_get_security((sa_group_t)share,
4353 sectype, protocol);
4354 if (optionset != NULL) {
4355 prop = sa_get_property(optionset,
4356 NULL);
4357 if (prop == NULL)
4358 ret = sa_destroy_security(
4359 optionset);
4360 }
4361 } else {
4362 change = remove_security(group, sectype,
4363 optlist, protocol, &ret);
4364 }
4365 } else {
4366 sa_security_t security;
4367 char *sec;
4368 sec = sa_proto_space_alias(protocol, sectype);
4369 security = sa_get_security(group, sec, protocol);
4370 if (sec != NULL)
4371 sa_free_attr_string(sec);
4372 if (security != NULL) {
4373 ret = sa_destroy_security(security);
4374 if (ret == SA_OK)
4375 change = 1;
4376 } else {
4377 ret = SA_NO_SUCH_PROP;
4378 }
4379 }
4380 if (ret != SA_OK)
4381 (void) printf(gettext("Could not unset property: %s\n"),
4382 sa_errorstr(ret));
4383 }
4384
4385 if (ret == SA_OK && change)
4386 worklist = add_list(worklist, group, 0, protocol);
4387
4388 free_opt(optlist);
4389 /*
4390 * We have a group and potentially legal additions
4391 */
4392
4393 /* Commit to configuration if not a dryrun */
4394 if (!dryrun && ret == 0) {
4395 /* properties changed, so update all shares */
4396 if (change && worklist != NULL)
4397 (void) enable_all_groups(handle, worklist, 0, 0,
4398 protocol, B_TRUE);
4399 ret = sa_update_config(handle);
4400 }
4401 if (worklist != NULL)
4402 free_list(worklist);
4403 return (ret);
4404 }
4405
4406 /*
4407 * sa_unset(flags, argc, argv)
4408 *
4409 * Implements the unset subcommand. Parsing done here and then basic
4410 * or space versions of the real code are called.
4411 */
4412
4413 int
sa_unset(sa_handle_t handle,int flags,int argc,char * argv[])4414 sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
4415 {
4416 char *groupname;
4417 int verbose = 0;
4418 int dryrun = 0;
4419 int c;
4420 char *protocol = NULL;
4421 int ret = SA_OK;
4422 struct options *optlist = NULL;
4423 char *rsrcname = NULL;
4424 char *sharepath = NULL;
4425 char *optset = NULL;
4426 int auth;
4427
4428 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
4429 switch (c) {
4430 case 'v':
4431 verbose++;
4432 break;
4433 case 'n':
4434 dryrun++;
4435 break;
4436 case 'P':
4437 if (protocol != NULL) {
4438 (void) printf(gettext(
4439 "Specifying multiple protocols "
4440 "not supported: %s\n"), protocol);
4441 return (SA_SYNTAX_ERR);
4442 }
4443 protocol = optarg;
4444 if (!sa_valid_protocol(protocol)) {
4445 (void) printf(gettext(
4446 "Invalid protocol specified: %s\n"),
4447 protocol);
4448 return (SA_INVALID_PROTOCOL);
4449 }
4450 break;
4451 case 'p':
4452 ret = add_opt(&optlist, optarg, 1);
4453 switch (ret) {
4454 case OPT_ADD_SYNTAX:
4455 (void) printf(gettext("Property syntax error "
4456 "for property %s\n"), optarg);
4457 return (SA_SYNTAX_ERR);
4458
4459 case OPT_ADD_PROPERTY:
4460 (void) printf(gettext("Properties need to be "
4461 "set with set command: %s\n"), optarg);
4462 return (SA_SYNTAX_ERR);
4463
4464 default:
4465 break;
4466 }
4467 break;
4468 case 'r':
4469 /*
4470 * Unset properties on resource if applicable or on
4471 * share if resource for this protocol doesn't use
4472 * resources.
4473 */
4474 if (rsrcname != NULL) {
4475 (void) printf(gettext(
4476 "Unsetting multiple resource "
4477 "names not supported\n"));
4478 return (SA_SYNTAX_ERR);
4479 }
4480 rsrcname = optarg;
4481 break;
4482 case 's':
4483 if (sharepath != NULL) {
4484 (void) printf(gettext(
4485 "Adding multiple shares not supported\n"));
4486 return (SA_SYNTAX_ERR);
4487 }
4488 sharepath = optarg;
4489 break;
4490 case 'S':
4491 if (optset != NULL) {
4492 (void) printf(gettext(
4493 "Specifying multiple property "
4494 "spaces not supported: %s\n"), optset);
4495 return (SA_SYNTAX_ERR);
4496 }
4497 optset = optarg;
4498 break;
4499 case 'h':
4500 /* optopt on valid arg isn't defined */
4501 optopt = c;
4502 /*FALLTHROUGH*/
4503 case '?':
4504 default:
4505 /*
4506 * Since a bad option gets to here, sort it
4507 * out and return a syntax error return value
4508 * if necessary.
4509 */
4510 switch (optopt) {
4511 default:
4512 ret = SA_SYNTAX_ERR;
4513 break;
4514 case 'h':
4515 case '?':
4516 break;
4517 }
4518 (void) printf(gettext("usage: %s\n"),
4519 sa_get_usage(USAGE_UNSET));
4520 return (ret);
4521 }
4522 }
4523
4524 if (optlist != NULL)
4525 ret = chk_opt(optlist, optset != NULL, protocol);
4526
4527 if (optind >= argc || (optlist == NULL && optset == NULL) ||
4528 protocol == NULL) {
4529 char *sep = "\t";
4530 (void) printf(gettext("usage: %s\n"),
4531 sa_get_usage(USAGE_UNSET));
4532 if (optind >= argc) {
4533 (void) printf(gettext("%sgroup must be specified"),
4534 sep);
4535 sep = ", ";
4536 }
4537 if (optlist == NULL) {
4538 (void) printf(gettext("%sat least one property must "
4539 "be specified"), sep);
4540 sep = ", ";
4541 }
4542 if (protocol == NULL) {
4543 (void) printf(gettext("%sprotocol must be specified"),
4544 sep);
4545 sep = ", ";
4546 }
4547 (void) printf("\n");
4548 ret = SA_SYNTAX_ERR;
4549 } else {
4550
4551 /*
4552 * If a group already exists, we can only add a new
4553 * protocol to it and not create a new one or add the
4554 * same protocol again.
4555 */
4556
4557 groupname = argv[optind];
4558 auth = check_authorizations(groupname, flags);
4559 if (optset == NULL)
4560 ret = basic_unset(handle, groupname, optlist, protocol,
4561 sharepath, rsrcname, dryrun);
4562 else
4563 ret = space_unset(handle, groupname, optlist, protocol,
4564 sharepath, dryrun, optset);
4565
4566 if (dryrun && ret == SA_OK && !auth && verbose)
4567 (void) printf(gettext("Command would fail: %s\n"),
4568 sa_errorstr(SA_NO_PERMISSION));
4569 }
4570 return (ret);
4571 }
4572
4573 /*
4574 * sa_enable_group(flags, argc, argv)
4575 *
4576 * Implements the enable subcommand
4577 */
4578
4579 int
sa_enable_group(sa_handle_t handle,int flags,int argc,char * argv[])4580 sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4581 {
4582 int verbose = 0;
4583 int dryrun = 0;
4584 int all = 0;
4585 int c;
4586 int ret = SA_OK;
4587 char *protocol = NULL;
4588 char *state;
4589 struct list *worklist = NULL;
4590 int auth = 1;
4591 sa_group_t group;
4592
4593 while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
4594 switch (c) {
4595 case 'a':
4596 all = 1;
4597 break;
4598 case 'n':
4599 dryrun++;
4600 break;
4601 case 'P':
4602 if (protocol != NULL) {
4603 (void) printf(gettext(
4604 "Specifying multiple protocols "
4605 "not supported: %s\n"), protocol);
4606 return (SA_SYNTAX_ERR);
4607 }
4608 protocol = optarg;
4609 if (!sa_valid_protocol(protocol)) {
4610 (void) printf(gettext(
4611 "Invalid protocol specified: %s\n"),
4612 protocol);
4613 return (SA_INVALID_PROTOCOL);
4614 }
4615 break;
4616 case 'v':
4617 verbose++;
4618 break;
4619 case 'h':
4620 /* optopt on valid arg isn't defined */
4621 optopt = c;
4622 /*FALLTHROUGH*/
4623 case '?':
4624 default:
4625 /*
4626 * Since a bad option gets to here, sort it
4627 * out and return a syntax error return value
4628 * if necessary.
4629 */
4630 switch (optopt) {
4631 default:
4632 ret = SA_SYNTAX_ERR;
4633 break;
4634 case 'h':
4635 case '?':
4636 (void) printf(gettext("usage: %s\n"),
4637 sa_get_usage(USAGE_ENABLE));
4638 return (ret);
4639 }
4640 }
4641 }
4642
4643 if (optind == argc && !all) {
4644 (void) printf(gettext("usage: %s\n"),
4645 sa_get_usage(USAGE_ENABLE));
4646 (void) printf(gettext("\tmust specify group\n"));
4647 return (SA_NO_SUCH_PATH);
4648 }
4649 if (!all) {
4650 while (optind < argc) {
4651 group = sa_get_group(handle, argv[optind]);
4652 if (group != NULL) {
4653 auth &= check_authorizations(argv[optind],
4654 flags);
4655 state = sa_get_group_attr(group, "state");
4656 if (state != NULL &&
4657 strcmp(state, "enabled") == 0) {
4658 /* already enabled */
4659 if (verbose)
4660 (void) printf(gettext(
4661 "Group \"%s\" is already "
4662 "enabled\n"),
4663 argv[optind]);
4664 ret = SA_BUSY; /* already enabled */
4665 } else {
4666 worklist = add_list(worklist, group,
4667 0, protocol);
4668 if (verbose)
4669 (void) printf(gettext(
4670 "Enabling group \"%s\"\n"),
4671 argv[optind]);
4672 }
4673 if (state != NULL)
4674 sa_free_attr_string(state);
4675 } else {
4676 ret = SA_NO_SUCH_GROUP;
4677 }
4678 optind++;
4679 }
4680 } else {
4681 for (group = sa_get_group(handle, NULL);
4682 group != NULL;
4683 group = sa_get_next_group(group)) {
4684 worklist = add_list(worklist, group, 0, protocol);
4685 }
4686 }
4687 if (!dryrun && ret == SA_OK)
4688 ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE);
4689
4690 if (ret != SA_OK && ret != SA_BUSY)
4691 (void) printf(gettext("Could not enable group: %s\n"),
4692 sa_errorstr(ret));
4693 if (ret == SA_BUSY)
4694 ret = SA_OK;
4695
4696 if (worklist != NULL)
4697 free_list(worklist);
4698 if (dryrun && ret == SA_OK && !auth && verbose) {
4699 (void) printf(gettext("Command would fail: %s\n"),
4700 sa_errorstr(SA_NO_PERMISSION));
4701 }
4702 return (ret);
4703 }
4704
4705 /*
4706 * disable_group(group, proto)
4707 *
4708 * Disable all the shares in the specified group.. This is a helper
4709 * for disable_all_groups in order to simplify regular and subgroup
4710 * (zfs) disabling. Group has already been checked for non-NULL.
4711 */
4712
4713 static int
disable_group(sa_group_t group,char * proto)4714 disable_group(sa_group_t group, char *proto)
4715 {
4716 sa_share_t share;
4717 int ret = SA_OK;
4718
4719 /*
4720 * If the protocol isn't enabled, skip it and treat as
4721 * successful.
4722 */
4723 if (!has_protocol(group, proto))
4724 return (ret);
4725
4726 for (share = sa_get_share(group, NULL);
4727 share != NULL && ret == SA_OK;
4728 share = sa_get_next_share(share)) {
4729 ret = sa_disable_share(share, proto);
4730 if (ret == SA_NO_SUCH_PATH) {
4731 /*
4732 * this is OK since the path is gone. we can't
4733 * re-share it anyway so no error.
4734 */
4735 ret = SA_OK;
4736 }
4737 }
4738 return (ret);
4739 }
4740
4741 /*
4742 * disable_all_groups(work, setstate)
4743 *
4744 * helper function that disables the shares in the list of groups
4745 * provided. It optionally marks the group as disabled. Used by both
4746 * enable and start subcommands.
4747 */
4748
4749 static int
disable_all_groups(sa_handle_t handle,struct list * work,int setstate)4750 disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
4751 {
4752 int ret = SA_OK;
4753 sa_group_t subgroup, group;
4754
4755 while (work != NULL && ret == SA_OK) {
4756 group = (sa_group_t)work->item;
4757 if (setstate)
4758 ret = sa_set_group_attr(group, "state", "disabled");
4759 if (ret == SA_OK) {
4760 char *name;
4761 name = sa_get_group_attr(group, "name");
4762 if (name != NULL && strcmp(name, "zfs") == 0) {
4763 /* need to get the sub-groups for stopping */
4764 for (subgroup = sa_get_sub_group(group);
4765 subgroup != NULL;
4766 subgroup = sa_get_next_group(subgroup)) {
4767 ret = disable_group(subgroup,
4768 work->proto);
4769 }
4770 } else {
4771 ret = disable_group(group, work->proto);
4772 }
4773 if (name != NULL)
4774 sa_free_attr_string(name);
4775 /*
4776 * We don't want to "disable" since it won't come
4777 * up after a reboot. The SMF framework should do
4778 * the right thing. On enable we do want to do
4779 * something.
4780 */
4781 }
4782 work = work->next;
4783 }
4784 if (ret == SA_OK)
4785 ret = sa_update_config(handle);
4786 return (ret);
4787 }
4788
4789 /*
4790 * sa_disable_group(flags, argc, argv)
4791 *
4792 * Implements the disable subcommand
4793 */
4794
4795 int
sa_disable_group(sa_handle_t handle,int flags,int argc,char * argv[])4796 sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4797 {
4798 int verbose = 0;
4799 int dryrun = 0;
4800 int all = 0;
4801 int c;
4802 int ret = SA_OK;
4803 char *protocol = NULL;
4804 char *state;
4805 struct list *worklist = NULL;
4806 sa_group_t group;
4807 int auth = 1;
4808
4809 while ((c = getopt(argc, argv, "?havn")) != EOF) {
4810 switch (c) {
4811 case 'a':
4812 all = 1;
4813 break;
4814 case 'n':
4815 dryrun++;
4816 break;
4817 case 'P':
4818 if (protocol != NULL) {
4819 (void) printf(gettext(
4820 "Specifying multiple protocols "
4821 "not supported: %s\n"), protocol);
4822 return (SA_SYNTAX_ERR);
4823 }
4824 protocol = optarg;
4825 if (!sa_valid_protocol(protocol)) {
4826 (void) printf(gettext(
4827 "Invalid protocol specified: %s\n"),
4828 protocol);
4829 return (SA_INVALID_PROTOCOL);
4830 }
4831 break;
4832 case 'v':
4833 verbose++;
4834 break;
4835 case 'h':
4836 /* optopt on valid arg isn't defined */
4837 optopt = c;
4838 /*FALLTHROUGH*/
4839 case '?':
4840 default:
4841 /*
4842 * Since a bad option gets to here, sort it
4843 * out and return a syntax error return value
4844 * if necessary.
4845 */
4846 switch (optopt) {
4847 default:
4848 ret = SA_SYNTAX_ERR;
4849 break;
4850 case 'h':
4851 case '?':
4852 break;
4853 }
4854 (void) printf(gettext("usage: %s\n"),
4855 sa_get_usage(USAGE_DISABLE));
4856 return (ret);
4857 }
4858 }
4859
4860 if (optind == argc && !all) {
4861 (void) printf(gettext("usage: %s\n"),
4862 sa_get_usage(USAGE_DISABLE));
4863 (void) printf(gettext("\tmust specify group\n"));
4864 return (SA_NO_SUCH_PATH);
4865 }
4866 if (!all) {
4867 while (optind < argc) {
4868 group = sa_get_group(handle, argv[optind]);
4869 if (group != NULL) {
4870 auth &= check_authorizations(argv[optind],
4871 flags);
4872 state = sa_get_group_attr(group, "state");
4873 if (state == NULL ||
4874 strcmp(state, "disabled") == 0) {
4875 /* already disabled */
4876 if (verbose)
4877 (void) printf(gettext(
4878 "Group \"%s\" is "
4879 "already disabled\n"),
4880 argv[optind]);
4881 ret = SA_BUSY; /* already disabled */
4882 } else {
4883 worklist = add_list(worklist, group, 0,
4884 protocol);
4885 if (verbose)
4886 (void) printf(gettext(
4887 "Disabling group "
4888 "\"%s\"\n"), argv[optind]);
4889 }
4890 if (state != NULL)
4891 sa_free_attr_string(state);
4892 } else {
4893 ret = SA_NO_SUCH_GROUP;
4894 }
4895 optind++;
4896 }
4897 } else {
4898 for (group = sa_get_group(handle, NULL);
4899 group != NULL;
4900 group = sa_get_next_group(group))
4901 worklist = add_list(worklist, group, 0, protocol);
4902 }
4903
4904 if (ret == SA_OK && !dryrun)
4905 ret = disable_all_groups(handle, worklist, 1);
4906 if (ret != SA_OK && ret != SA_BUSY)
4907 (void) printf(gettext("Could not disable group: %s\n"),
4908 sa_errorstr(ret));
4909 if (ret == SA_BUSY)
4910 ret = SA_OK;
4911 if (worklist != NULL)
4912 free_list(worklist);
4913 if (dryrun && ret == SA_OK && !auth && verbose)
4914 (void) printf(gettext("Command would fail: %s\n"),
4915 sa_errorstr(SA_NO_PERMISSION));
4916 return (ret);
4917 }
4918
4919 /*
4920 * sa_start_group(flags, argc, argv)
4921 *
4922 * Implements the start command.
4923 * This is similar to enable except it doesn't change the state
4924 * of the group(s) and only enables shares if the group is already
4925 * enabled.
4926 */
4927
4928 int
sa_start_group(sa_handle_t handle,int flags,int argc,char * argv[])4929 sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
4930 {
4931 int verbose = 0;
4932 int all = 0;
4933 int c;
4934 int ret = SMF_EXIT_OK;
4935 char *protocol = NULL;
4936 char *state;
4937 struct list *worklist = NULL;
4938 sa_group_t group;
4939 #ifdef lint
4940 flags = flags;
4941 #endif
4942
4943 while ((c = getopt(argc, argv, "?havP:")) != EOF) {
4944 switch (c) {
4945 case 'a':
4946 all = 1;
4947 break;
4948 case 'P':
4949 if (protocol != NULL) {
4950 (void) printf(gettext(
4951 "Specifying multiple protocols "
4952 "not supported: %s\n"), protocol);
4953 return (SA_SYNTAX_ERR);
4954 }
4955 protocol = optarg;
4956 if (!sa_valid_protocol(protocol)) {
4957 (void) printf(gettext(
4958 "Invalid protocol specified: %s\n"),
4959 protocol);
4960 return (SA_INVALID_PROTOCOL);
4961 }
4962 break;
4963 case 'v':
4964 verbose++;
4965 break;
4966 case 'h':
4967 /* optopt on valid arg isn't defined */
4968 optopt = c;
4969 /*FALLTHROUGH*/
4970 case '?':
4971 default:
4972 /*
4973 * Since a bad option gets to here, sort it
4974 * out and return a syntax error return value
4975 * if necessary.
4976 */
4977 ret = SA_OK;
4978 switch (optopt) {
4979 default:
4980 ret = SA_SYNTAX_ERR;
4981 break;
4982 case 'h':
4983 case '?':
4984 break;
4985 }
4986 (void) printf(gettext("usage: %s\n"),
4987 sa_get_usage(USAGE_START));
4988 return (ret);
4989 }
4990 }
4991
4992 if (optind == argc && !all) {
4993 (void) printf(gettext("usage: %s\n"),
4994 sa_get_usage(USAGE_START));
4995 return (SMF_EXIT_ERR_FATAL);
4996 }
4997
4998 if (!all) {
4999 while (optind < argc) {
5000 group = sa_get_group(handle, argv[optind]);
5001 if (group != NULL) {
5002 state = sa_get_group_attr(group, "state");
5003 if (state == NULL ||
5004 strcmp(state, "enabled") == 0) {
5005 worklist = add_list(worklist, group, 0,
5006 protocol);
5007 if (verbose)
5008 (void) printf(gettext(
5009 "Starting group \"%s\"\n"),
5010 argv[optind]);
5011 } else {
5012 /*
5013 * Determine if there are any
5014 * protocols. If there aren't any,
5015 * then there isn't anything to do in
5016 * any case so no error.
5017 */
5018 if (sa_get_optionset(group,
5019 protocol) != NULL) {
5020 ret = SMF_EXIT_OK;
5021 }
5022 }
5023 if (state != NULL)
5024 sa_free_attr_string(state);
5025 }
5026 optind++;
5027 }
5028 } else {
5029 for (group = sa_get_group(handle, NULL);
5030 group != NULL;
5031 group = sa_get_next_group(group)) {
5032 state = sa_get_group_attr(group, "state");
5033 if (state == NULL || strcmp(state, "enabled") == 0)
5034 worklist = add_list(worklist, group, 0,
5035 protocol);
5036 if (state != NULL)
5037 sa_free_attr_string(state);
5038 }
5039 }
5040
5041 (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE);
5042
5043 if (worklist != NULL)
5044 free_list(worklist);
5045 return (ret);
5046 }
5047
5048 /*
5049 * sa_stop_group(flags, argc, argv)
5050 *
5051 * Implements the stop command.
5052 * This is similar to disable except it doesn't change the state
5053 * of the group(s) and only disables shares if the group is already
5054 * enabled.
5055 */
5056 int
sa_stop_group(sa_handle_t handle,int flags,int argc,char * argv[])5057 sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
5058 {
5059 int verbose = 0;
5060 int all = 0;
5061 int c;
5062 int ret = SMF_EXIT_OK;
5063 char *protocol = NULL;
5064 char *state;
5065 struct list *worklist = NULL;
5066 sa_group_t group;
5067 #ifdef lint
5068 flags = flags;
5069 #endif
5070
5071 while ((c = getopt(argc, argv, "?havP:")) != EOF) {
5072 switch (c) {
5073 case 'a':
5074 all = 1;
5075 break;
5076 case 'P':
5077 if (protocol != NULL) {
5078 (void) printf(gettext(
5079 "Specifying multiple protocols "
5080 "not supported: %s\n"), protocol);
5081 return (SA_SYNTAX_ERR);
5082 }
5083 protocol = optarg;
5084 if (!sa_valid_protocol(protocol)) {
5085 (void) printf(gettext(
5086 "Invalid protocol specified: %s\n"),
5087 protocol);
5088 return (SA_INVALID_PROTOCOL);
5089 }
5090 break;
5091 case 'v':
5092 verbose++;
5093 break;
5094 case 'h':
5095 /* optopt on valid arg isn't defined */
5096 optopt = c;
5097 /*FALLTHROUGH*/
5098 case '?':
5099 default:
5100 /*
5101 * Since a bad option gets to here, sort it
5102 * out and return a syntax error return value
5103 * if necessary.
5104 */
5105 ret = SA_OK;
5106 switch (optopt) {
5107 default:
5108 ret = SA_SYNTAX_ERR;
5109 break;
5110 case 'h':
5111 case '?':
5112 break;
5113 }
5114 (void) printf(gettext("usage: %s\n"),
5115 sa_get_usage(USAGE_STOP));
5116 return (ret);
5117 }
5118 }
5119
5120 if (optind == argc && !all) {
5121 (void) printf(gettext("usage: %s\n"),
5122 sa_get_usage(USAGE_STOP));
5123 return (SMF_EXIT_ERR_FATAL);
5124 } else if (!all) {
5125 while (optind < argc) {
5126 group = sa_get_group(handle, argv[optind]);
5127 if (group != NULL) {
5128 state = sa_get_group_attr(group, "state");
5129 if (state == NULL ||
5130 strcmp(state, "enabled") == 0) {
5131 worklist = add_list(worklist, group, 0,
5132 protocol);
5133 if (verbose)
5134 (void) printf(gettext(
5135 "Stopping group \"%s\"\n"),
5136 argv[optind]);
5137 } else {
5138 ret = SMF_EXIT_OK;
5139 }
5140 if (state != NULL)
5141 sa_free_attr_string(state);
5142 }
5143 optind++;
5144 }
5145 } else {
5146 for (group = sa_get_group(handle, NULL);
5147 group != NULL;
5148 group = sa_get_next_group(group)) {
5149 state = sa_get_group_attr(group, "state");
5150 if (state == NULL || strcmp(state, "enabled") == 0)
5151 worklist = add_list(worklist, group, 0,
5152 protocol);
5153 if (state != NULL)
5154 sa_free_attr_string(state);
5155 }
5156 }
5157 (void) disable_all_groups(handle, worklist, 0);
5158 ret = sa_update_config(handle);
5159
5160 if (worklist != NULL)
5161 free_list(worklist);
5162 return (ret);
5163 }
5164
5165 /*
5166 * remove_all_options(share, proto)
5167 *
5168 * Removes all options on a share.
5169 */
5170
5171 static void
remove_all_options(sa_share_t share,char * proto)5172 remove_all_options(sa_share_t share, char *proto)
5173 {
5174 sa_optionset_t optionset;
5175 sa_security_t security;
5176 sa_security_t prevsec = NULL;
5177
5178 optionset = sa_get_optionset(share, proto);
5179 if (optionset != NULL)
5180 (void) sa_destroy_optionset(optionset);
5181 for (security = sa_get_security(share, NULL, NULL);
5182 security != NULL;
5183 security = sa_get_next_security(security)) {
5184 char *type;
5185 /*
5186 * We walk through the list. prevsec keeps the
5187 * previous security so we can delete it without
5188 * destroying the list.
5189 */
5190 if (prevsec != NULL) {
5191 /* remove the previously seen security */
5192 (void) sa_destroy_security(prevsec);
5193 /* set to NULL so we don't try multiple times */
5194 prevsec = NULL;
5195 }
5196 type = sa_get_security_attr(security, "type");
5197 if (type != NULL) {
5198 /*
5199 * if the security matches the specified protocol, we
5200 * want to remove it. prevsec holds it until either
5201 * the next pass or we fall out of the loop.
5202 */
5203 if (strcmp(type, proto) == 0)
5204 prevsec = security;
5205 sa_free_attr_string(type);
5206 }
5207 }
5208 /* in case there is one left */
5209 if (prevsec != NULL)
5210 (void) sa_destroy_security(prevsec);
5211 }
5212
5213
5214 /*
5215 * for legacy support, we need to handle the old syntax. This is what
5216 * we get if sharemgr is called with the name "share" rather than
5217 * sharemgr.
5218 */
5219
5220 static int
format_legacy_path(char * buff,int buffsize,char * proto,char * cmd)5221 format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
5222 {
5223 int err;
5224
5225 err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
5226 if (err > buffsize)
5227 return (-1);
5228 return (0);
5229 }
5230
5231
5232 /*
5233 * check_legacy_cmd(proto, cmd)
5234 *
5235 * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
5236 * executable.
5237 */
5238
5239 static int
check_legacy_cmd(char * path)5240 check_legacy_cmd(char *path)
5241 {
5242 struct stat st;
5243 int ret = 0;
5244
5245 if (stat(path, &st) == 0) {
5246 if (S_ISREG(st.st_mode) &&
5247 st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
5248 ret = 1;
5249 }
5250 return (ret);
5251 }
5252
5253 /*
5254 * run_legacy_command(proto, cmd, argv)
5255 *
5256 * We know the command exists, so attempt to execute it with all the
5257 * arguments. This implements full legacy share support for those
5258 * protocols that don't have plugin providers.
5259 */
5260
5261 static int
run_legacy_command(char * path,char * argv[])5262 run_legacy_command(char *path, char *argv[])
5263 {
5264 int ret;
5265
5266 ret = execv(path, argv);
5267 if (ret < 0) {
5268 switch (errno) {
5269 case EACCES:
5270 ret = SA_NO_PERMISSION;
5271 break;
5272 default:
5273 ret = SA_SYSTEM_ERR;
5274 break;
5275 }
5276 }
5277 return (ret);
5278 }
5279
5280 /*
5281 * out_share(out, group, proto)
5282 *
5283 * Display the share information in the format that the "share"
5284 * command has traditionally used.
5285 */
5286
5287 static void
out_share(FILE * out,sa_group_t group,char * proto)5288 out_share(FILE *out, sa_group_t group, char *proto)
5289 {
5290 sa_share_t share;
5291 char resfmt[128];
5292 char *defprop;
5293
5294 /*
5295 * The original share command defaulted to displaying NFS
5296 * shares or allowed a protocol to be specified. We want to
5297 * skip those shares that are not the specified protocol.
5298 */
5299 if (proto != NULL && sa_get_optionset(group, proto) == NULL)
5300 return;
5301
5302 if (proto == NULL)
5303 proto = "nfs";
5304
5305 /*
5306 * get the default property string. NFS uses "rw" but
5307 * everything else will use "".
5308 */
5309 if (proto != NULL && strcmp(proto, "nfs") != 0)
5310 defprop = "\"\"";
5311 else
5312 defprop = "rw";
5313
5314 for (share = sa_get_share(group, NULL);
5315 share != NULL;
5316 share = sa_get_next_share(share)) {
5317 char *path;
5318 char *type;
5319 char *resource;
5320 char *description;
5321 char *groupname;
5322 char *sharedstate;
5323 int shared = 1;
5324 char *soptions;
5325 char shareopts[MAXNAMLEN];
5326
5327 sharedstate = sa_get_share_attr(share, "shared");
5328 path = sa_get_share_attr(share, "path");
5329 type = sa_get_share_attr(share, "type");
5330 resource = get_resource(share);
5331 groupname = sa_get_group_attr(group, "name");
5332
5333 if (groupname != NULL && strcmp(groupname, "default") == 0) {
5334 sa_free_attr_string(groupname);
5335 groupname = NULL;
5336 }
5337 description = sa_get_share_description(share);
5338
5339 /*
5340 * Want the sharetab version if it exists, defaulting
5341 * to NFS if no protocol specified.
5342 */
5343 (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto);
5344 soptions = sa_get_share_attr(share, shareopts);
5345
5346 if (sharedstate == NULL)
5347 shared = 0;
5348
5349 if (soptions == NULL)
5350 soptions = sa_proto_legacy_format(proto, share, 1);
5351
5352 if (shared) {
5353 /* only active shares go here */
5354 (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
5355 resource != NULL ? resource : "-",
5356 groupname != NULL ? "@" : "",
5357 groupname != NULL ? groupname : "");
5358 (void) fprintf(out, "%-14.14s %s %s \"%s\" \n",
5359 resfmt, (path != NULL) ? path : "",
5360 (soptions != NULL && strlen(soptions) > 0) ?
5361 soptions : defprop,
5362 (description != NULL) ? description : "");
5363 }
5364
5365 if (path != NULL)
5366 sa_free_attr_string(path);
5367 if (type != NULL)
5368 sa_free_attr_string(type);
5369 if (resource != NULL)
5370 sa_free_attr_string(resource);
5371 if (groupname != NULL)
5372 sa_free_attr_string(groupname);
5373 if (description != NULL)
5374 sa_free_share_description(description);
5375 if (sharedstate != NULL)
5376 sa_free_attr_string(sharedstate);
5377 if (soptions != NULL)
5378 sa_format_free(soptions);
5379 }
5380 }
5381
5382 /*
5383 * output_legacy_file(out, proto)
5384 *
5385 * Walk all of the groups for the specified protocol and call
5386 * out_share() to format and write in the format displayed by the
5387 * "share" command with no arguments.
5388 */
5389
5390 static void
output_legacy_file(FILE * out,char * proto,sa_handle_t handle)5391 output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
5392 {
5393 sa_group_t group;
5394
5395 for (group = sa_get_group(handle, NULL);
5396 group != NULL;
5397 group = sa_get_next_group(group)) {
5398 char *zfs;
5399
5400 /*
5401 * Go through all the groups and ZFS
5402 * sub-groups. out_share() will format the shares in
5403 * the group appropriately.
5404 */
5405
5406 zfs = sa_get_group_attr(group, "zfs");
5407 if (zfs != NULL) {
5408 sa_group_t zgroup;
5409 sa_free_attr_string(zfs);
5410 for (zgroup = sa_get_sub_group(group);
5411 zgroup != NULL;
5412 zgroup = sa_get_next_group(zgroup)) {
5413
5414 /* got a group, so display it */
5415 out_share(out, zgroup, proto);
5416 }
5417 } else {
5418 out_share(out, group, proto);
5419 }
5420 }
5421 }
5422
5423 int
sa_legacy_share(sa_handle_t handle,int flags,int argc,char * argv[])5424 sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
5425 {
5426 char *protocol = "nfs";
5427 char *options = NULL;
5428 char *description = NULL;
5429 char *groupname = NULL;
5430 char *sharepath = NULL;
5431 char *resource = NULL;
5432 char *groupstatus = NULL;
5433 int persist = SA_SHARE_TRANSIENT;
5434 int argsused = 0;
5435 int c;
5436 int ret = SA_OK;
5437 int zfs = 0;
5438 int true_legacy = 0;
5439 int curtype = SA_SHARE_TRANSIENT;
5440 char cmd[MAXPATHLEN];
5441 sa_group_t group = NULL;
5442 sa_resource_t rsrc = NULL;
5443 sa_share_t share;
5444 char dir[MAXPATHLEN];
5445 uint64_t features;
5446 #ifdef lint
5447 flags = flags;
5448 #endif
5449
5450 while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
5451 switch (c) {
5452 case 'd':
5453 description = optarg;
5454 argsused++;
5455 break;
5456 case 'F':
5457 protocol = optarg;
5458 if (!sa_valid_protocol(protocol)) {
5459 if (format_legacy_path(cmd, MAXPATHLEN,
5460 protocol, "share") == 0 &&
5461 check_legacy_cmd(cmd)) {
5462 true_legacy++;
5463 } else {
5464 (void) fprintf(stderr, gettext(
5465 "Invalid protocol specified: "
5466 "%s\n"), protocol);
5467 return (SA_INVALID_PROTOCOL);
5468 }
5469 }
5470 break;
5471 case 'o':
5472 options = optarg;
5473 argsused++;
5474 break;
5475 case 'p':
5476 persist = SA_SHARE_PERMANENT;
5477 argsused++;
5478 break;
5479 case 'h':
5480 /* optopt on valid arg isn't defined */
5481 optopt = c;
5482 /*FALLTHROUGH*/
5483 case '?':
5484 default:
5485 /*
5486 * Since a bad option gets to here, sort it
5487 * out and return a syntax error return value
5488 * if necessary.
5489 */
5490 switch (optopt) {
5491 default:
5492 ret = SA_LEGACY_ERR;
5493 break;
5494 case 'h':
5495 case '?':
5496 break;
5497 }
5498 (void) fprintf(stderr, gettext("usage: %s\n"),
5499 sa_get_usage(USAGE_SHARE));
5500 return (ret);
5501 }
5502 }
5503
5504 /* Have the info so construct what is needed */
5505 if (!argsused && optind == argc) {
5506 /* display current info in share format */
5507 (void) output_legacy_file(stdout, protocol, handle);
5508 return (ret);
5509 }
5510
5511 /* We are modifying the configuration */
5512 if (optind == argc) {
5513 (void) fprintf(stderr, gettext("usage: %s\n"),
5514 sa_get_usage(USAGE_SHARE));
5515 return (SA_LEGACY_ERR);
5516 }
5517 if (true_legacy) {
5518 /* If still using legacy share/unshare, exec it */
5519 ret = run_legacy_command(cmd, argv);
5520 return (ret);
5521 }
5522
5523 sharepath = argv[optind++];
5524 if (optind < argc) {
5525 resource = argv[optind];
5526 groupname = strchr(resource, '@');
5527 if (groupname != NULL)
5528 *groupname++ = '\0';
5529 }
5530 if (realpath(sharepath, dir) == NULL)
5531 ret = SA_BAD_PATH;
5532 else
5533 sharepath = dir;
5534 if (ret == SA_OK)
5535 share = sa_find_share(handle, sharepath);
5536 else
5537 share = NULL;
5538
5539 features = sa_proto_get_featureset(protocol);
5540
5541 if (groupname != NULL) {
5542 ret = SA_NOT_ALLOWED;
5543 } else if (ret == SA_OK) {
5544 char *legacygroup;
5545 /*
5546 * The legacy group is always present and zfs groups
5547 * come and go. zfs shares may be in sub-groups and
5548 * the zfs share will already be in that group so it
5549 * isn't an error. If the protocol is "smb", the group
5550 * "smb" is used when "default" would otherwise be
5551 * used. "default" is NFS only and "smb" is SMB only.
5552 */
5553 if (strcmp(protocol, "smb") == 0)
5554 legacygroup = "smb";
5555 else
5556 legacygroup = "default";
5557
5558 /*
5559 * If the share exists (not NULL), then make sure it
5560 * is one we want to handle by getting the parent
5561 * group.
5562 */
5563 if (share != NULL) {
5564 group = sa_get_parent_group(share);
5565 } else {
5566 group = sa_get_group(handle, legacygroup);
5567 if (group == NULL && strcmp(legacygroup, "smb") == 0) {
5568 /*
5569 * This group may not exist, so create
5570 * as necessary. It only contains the
5571 * "smb" protocol.
5572 */
5573 group = sa_create_group(handle, legacygroup,
5574 &ret);
5575 if (group != NULL)
5576 (void) sa_create_optionset(group,
5577 protocol);
5578 }
5579 }
5580
5581 if (group == NULL) {
5582 ret = SA_SYSTEM_ERR;
5583 goto err;
5584 }
5585
5586 groupstatus = group_status(group);
5587 if (share == NULL) {
5588 share = sa_add_share(group, sharepath,
5589 persist, &ret);
5590 if (share == NULL &&
5591 ret == SA_DUPLICATE_NAME) {
5592 /*
5593 * Could be a ZFS path being started
5594 */
5595 if (sa_zfs_is_shared(handle,
5596 sharepath)) {
5597 ret = SA_OK;
5598 group = sa_get_group(handle,
5599 "zfs");
5600 if (group == NULL) {
5601 /*
5602 * This shouldn't
5603 * happen.
5604 */
5605 ret = SA_CONFIG_ERR;
5606 } else {
5607 share = sa_add_share(
5608 group, sharepath,
5609 persist, &ret);
5610 }
5611 }
5612 }
5613 } else {
5614 char *type;
5615 /*
5616 * May want to change persist state, but the
5617 * important thing is to change options. We
5618 * need to change them regardless of the
5619 * source.
5620 */
5621
5622 if (sa_zfs_is_shared(handle, sharepath)) {
5623 zfs = 1;
5624 }
5625 remove_all_options(share, protocol);
5626 type = sa_get_share_attr(share, "type");
5627 if (type != NULL &&
5628 strcmp(type, "transient") != 0) {
5629 curtype = SA_SHARE_PERMANENT;
5630 }
5631 if (type != NULL)
5632 sa_free_attr_string(type);
5633 if (curtype != persist) {
5634 (void) sa_set_share_attr(share, "type",
5635 persist == SA_SHARE_PERMANENT ?
5636 "persist" : "transient");
5637 }
5638 }
5639
5640 /*
5641 * If there is a resource name, we may
5642 * actually care about it if this is share for
5643 * a protocol that uses resource level sharing
5644 * (SMB). We need to find the resource and, if
5645 * it exists, make sure it belongs to the
5646 * current share. If it doesn't exist, attempt
5647 * to create it.
5648 */
5649
5650 if (ret == SA_OK && resource != NULL) {
5651 rsrc = sa_find_resource(handle, resource);
5652 if (rsrc != NULL) {
5653 if (share != sa_get_resource_parent(rsrc))
5654 ret = SA_DUPLICATE_NAME;
5655 } else {
5656 rsrc = sa_add_resource(share, resource,
5657 persist, &ret);
5658 }
5659 if (features & SA_FEATURE_RESOURCE)
5660 share = rsrc;
5661 }
5662
5663 /* Have a group to hold this share path */
5664 if (ret == SA_OK && options != NULL &&
5665 strlen(options) > 0) {
5666 ret = sa_parse_legacy_options(share,
5667 options,
5668 protocol);
5669 }
5670 if (!zfs) {
5671 /*
5672 * ZFS shares never have a description
5673 * and we can't store the values so
5674 * don't try.
5675 */
5676 if (ret == SA_OK && description != NULL)
5677 ret = sa_set_share_description(share,
5678 description);
5679 }
5680 if (ret == SA_OK &&
5681 strcmp(groupstatus, "enabled") == 0) {
5682 if (rsrc != share)
5683 ret = sa_enable_share(share, protocol);
5684 else
5685 ret = sa_enable_resource(rsrc,
5686 protocol);
5687 if (ret == SA_OK &&
5688 persist == SA_SHARE_PERMANENT) {
5689 (void) sa_update_legacy(share,
5690 protocol);
5691 }
5692 if (ret == SA_OK)
5693 ret = sa_update_config(handle);
5694 }
5695 }
5696 err:
5697 if (ret != SA_OK) {
5698 (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
5699 sharepath, sa_errorstr(ret));
5700 ret = SA_LEGACY_ERR;
5701 }
5702 return (ret);
5703 }
5704
5705 /*
5706 * sa_legacy_unshare(flags, argc, argv)
5707 *
5708 * Implements the original unshare command.
5709 */
5710 int
sa_legacy_unshare(sa_handle_t handle,int flags,int argc,char * argv[])5711 sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
5712 {
5713 char *protocol = "nfs"; /* for now */
5714 char *options = NULL;
5715 char *sharepath = NULL;
5716 int persist = SA_SHARE_TRANSIENT;
5717 int argsused = 0;
5718 int c;
5719 int ret = SA_OK;
5720 int true_legacy = 0;
5721 uint64_t features = 0;
5722 sa_resource_t resource = NULL;
5723 char cmd[MAXPATHLEN];
5724 #ifdef lint
5725 flags = flags;
5726 options = options;
5727 #endif
5728
5729 while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
5730 switch (c) {
5731 case 'F':
5732 protocol = optarg;
5733 if (!sa_valid_protocol(protocol)) {
5734 if (format_legacy_path(cmd, MAXPATHLEN,
5735 protocol, "unshare") == 0 &&
5736 check_legacy_cmd(cmd)) {
5737 true_legacy++;
5738 } else {
5739 (void) printf(gettext(
5740 "Invalid file system name\n"));
5741 return (SA_INVALID_PROTOCOL);
5742 }
5743 }
5744 break;
5745 case 'o':
5746 options = optarg;
5747 argsused++;
5748 break;
5749 case 'p':
5750 persist = SA_SHARE_PERMANENT;
5751 argsused++;
5752 break;
5753 case 'h':
5754 /* optopt on valid arg isn't defined */
5755 optopt = c;
5756 /*FALLTHROUGH*/
5757 case '?':
5758 default:
5759 /*
5760 * Since a bad option gets to here, sort it
5761 * out and return a syntax error return value
5762 * if necessary.
5763 */
5764 switch (optopt) {
5765 default:
5766 ret = SA_LEGACY_ERR;
5767 break;
5768 case 'h':
5769 case '?':
5770 break;
5771 }
5772 (void) printf(gettext("usage: %s\n"),
5773 sa_get_usage(USAGE_UNSHARE));
5774 return (ret);
5775 }
5776 }
5777
5778 /* Have the info so construct what is needed */
5779 if (optind == argc || (optind + 1) < argc || options != NULL) {
5780 ret = SA_SYNTAX_ERR;
5781 } else {
5782 sa_share_t share;
5783 char dir[MAXPATHLEN];
5784 if (true_legacy) {
5785 /* if still using legacy share/unshare, exec it */
5786 ret = run_legacy_command(cmd, argv);
5787 return (ret);
5788 }
5789 /*
5790 * Find the path in the internal configuration. If it
5791 * isn't found, attempt to resolve the path via
5792 * realpath() and try again.
5793 */
5794 sharepath = argv[optind++];
5795 share = sa_find_share(handle, sharepath);
5796 if (share == NULL) {
5797 if (realpath(sharepath, dir) == NULL) {
5798 ret = SA_NO_SUCH_PATH;
5799 } else {
5800 share = sa_find_share(handle, dir);
5801 }
5802 }
5803 if (share == NULL) {
5804 /* Could be a resource name so check that next */
5805 features = sa_proto_get_featureset(protocol);
5806 resource = sa_find_resource(handle, sharepath);
5807 if (resource != NULL) {
5808 share = sa_get_resource_parent(resource);
5809 if (features & SA_FEATURE_RESOURCE)
5810 (void) sa_disable_resource(resource,
5811 protocol);
5812 if (persist == SA_SHARE_PERMANENT) {
5813 ret = sa_remove_resource(resource);
5814 if (ret == SA_OK)
5815 ret = sa_update_config(handle);
5816 }
5817 /*
5818 * If we still have a resource on the
5819 * share, we don't disable the share
5820 * itself. IF there aren't anymore, we
5821 * need to remove the share. The
5822 * removal will be done in the next
5823 * section if appropriate.
5824 */
5825 resource = sa_get_share_resource(share, NULL);
5826 if (resource != NULL)
5827 share = NULL;
5828 } else if (ret == SA_OK) {
5829 /* Didn't find path and no resource */
5830 ret = SA_BAD_PATH;
5831 }
5832 }
5833 if (share != NULL && resource == NULL) {
5834 ret = sa_disable_share(share, protocol);
5835 /*
5836 * Errors are ok and removal should still occur. The
5837 * legacy unshare is more forgiving of errors than the
5838 * remove-share subcommand which may need the force
5839 * flag set for some error conditions. That is, the
5840 * "unshare" command will always unshare if it can
5841 * while "remove-share" might require the force option.
5842 */
5843 if (persist == SA_SHARE_PERMANENT) {
5844 ret = sa_remove_share(share);
5845 if (ret == SA_OK)
5846 ret = sa_update_config(handle);
5847 }
5848 } else if (ret == SA_OK && share == NULL && resource == NULL) {
5849 /*
5850 * If both share and resource are NULL, then
5851 * share not found. If one or the other was
5852 * found or there was an earlier error, we
5853 * assume it was handled earlier.
5854 */
5855 ret = SA_NOT_SHARED;
5856 }
5857 }
5858 switch (ret) {
5859 default:
5860 (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
5861 ret = SA_LEGACY_ERR;
5862 break;
5863 case SA_SYNTAX_ERR:
5864 (void) printf(gettext("usage: %s\n"),
5865 sa_get_usage(USAGE_UNSHARE));
5866 break;
5867 case SA_OK:
5868 break;
5869 }
5870 return (ret);
5871 }
5872
5873 /*
5874 * Common commands that implement the sub-commands used by all
5875 * protocols. The entries are found via the lookup command
5876 */
5877
5878 static sa_command_t commands[] = {
5879 {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
5880 {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
5881 {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
5882 {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
5883 {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
5884 {"list", 0, sa_list, USAGE_LIST},
5885 {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
5886 {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
5887 {"set", 0, sa_set, USAGE_SET, SVC_SET},
5888 {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
5889 {"show", 0, sa_show, USAGE_SHOW},
5890 {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
5891 {"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
5892 SVC_SET|SVC_ACTION},
5893 {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
5894 {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
5895 {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
5896 {NULL, 0, NULL, NULL}
5897 };
5898
5899 static char *
sa_get_usage(sa_usage_t index)5900 sa_get_usage(sa_usage_t index)
5901 {
5902 char *ret = NULL;
5903 switch (index) {
5904 case USAGE_ADD_SHARE:
5905 ret = gettext("add-share [-nth] [-r resource-name] "
5906 "[-d \"description text\"] -s sharepath group");
5907 break;
5908 case USAGE_CREATE:
5909 ret = gettext(
5910 "create [-nvh] [-P proto [-p property=value]] group");
5911 break;
5912 case USAGE_DELETE:
5913 ret = gettext("delete [-nvh] [-P proto] [-f] group");
5914 break;
5915 case USAGE_DISABLE:
5916 ret = gettext("disable [-nvh] {-a | group ...}");
5917 break;
5918 case USAGE_ENABLE:
5919 ret = gettext("enable [-nvh] {-a | group ...}");
5920 break;
5921 case USAGE_LIST:
5922 ret = gettext("list [-vh] [-P proto]");
5923 break;
5924 case USAGE_MOVE_SHARE:
5925 ret = gettext(
5926 "move-share [-nvh] -s sharepath destination-group");
5927 break;
5928 case USAGE_REMOVE_SHARE:
5929 ret = gettext(
5930 "remove-share [-fnvh] {-s sharepath | -r resource} "
5931 "group");
5932 break;
5933 case USAGE_SET:
5934 ret = gettext("set [-nvh] -P proto [-S optspace] "
5935 "[-p property=value]* [-s sharepath] [-r resource]] "
5936 "group");
5937 break;
5938 case USAGE_SET_SECURITY:
5939 ret = gettext("set-security [-nvh] -P proto -S security-type "
5940 "[-p property=value]* group");
5941 break;
5942 case USAGE_SET_SHARE:
5943 ret = gettext("set-share [-nh] [-r resource] "
5944 "[-d \"description text\"] -s sharepath group");
5945 break;
5946 case USAGE_SHOW:
5947 ret = gettext("show [-pvxh] [-P proto] [group ...]");
5948 break;
5949 case USAGE_SHARE:
5950 ret = gettext("share [-F fstype] [-p] [-o optionlist]"
5951 "[-d description] [pathname [resourcename]]");
5952 break;
5953 case USAGE_START:
5954 ret = gettext("start [-vh] [-P proto] {-a | group ...}");
5955 break;
5956 case USAGE_STOP:
5957 ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
5958 break;
5959 case USAGE_UNSET:
5960 ret = gettext("unset [-nvh] -P proto [-S optspace] "
5961 "[-p property]* group");
5962 break;
5963 case USAGE_UNSET_SECURITY:
5964 ret = gettext("unset-security [-nvh] -P proto "
5965 "-S security-type [-p property]* group");
5966 break;
5967 case USAGE_UNSHARE:
5968 ret = gettext(
5969 "unshare [-F fstype] [-p] [-o optionlist] sharepath");
5970 break;
5971 }
5972 return (ret);
5973 }
5974
5975 /*
5976 * sa_lookup(cmd, proto)
5977 *
5978 * Lookup the sub-command. proto isn't currently used, but it may
5979 * eventually provide a way to provide protocol specific sub-commands.
5980 */
5981 sa_command_t *
sa_lookup(char * cmd,char * proto)5982 sa_lookup(char *cmd, char *proto)
5983 {
5984 int i;
5985 size_t len;
5986 #ifdef lint
5987 proto = proto;
5988 #endif
5989
5990 len = strlen(cmd);
5991 for (i = 0; commands[i].cmdname != NULL; i++) {
5992 if (strncmp(cmd, commands[i].cmdname, len) == 0)
5993 return (&commands[i]);
5994 }
5995 return (NULL);
5996 }
5997
5998 void
sub_command_help(char * proto)5999 sub_command_help(char *proto)
6000 {
6001 int i;
6002 #ifdef lint
6003 proto = proto;
6004 #endif
6005
6006 (void) printf(gettext("\tsub-commands:\n"));
6007 for (i = 0; commands[i].cmdname != NULL; i++) {
6008 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
6009 (void) printf("\t%s\n",
6010 sa_get_usage((sa_usage_t)commands[i].cmdidx));
6011 }
6012 }
6013