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