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