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