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