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