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