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; 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 int auth; 3021 3022 while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) { 3023 switch (c) { 3024 case 'n': 3025 dryrun++; 3026 break; 3027 case 'v': 3028 verbose++; 3029 break; 3030 case 'f': 3031 force++; 3032 break; 3033 case 's': 3034 /* 3035 * Remove share path from group. Currently limit 3036 * to one share per command. 3037 */ 3038 if (sharepath != NULL) { 3039 (void) printf(gettext( 3040 "Removing multiple shares not " 3041 "supported\n")); 3042 return (SA_SYNTAX_ERR); 3043 } 3044 sharepath = optarg; 3045 break; 3046 case 'r': 3047 /* 3048 * Remove share from group if last resource or remove 3049 * resource from share if multiple resources. 3050 */ 3051 if (rsrcname != NULL) { 3052 (void) printf(gettext( 3053 "Removing multiple resource names not " 3054 "supported\n")); 3055 return (SA_SYNTAX_ERR); 3056 } 3057 rsrcname = optarg; 3058 break; 3059 case 'h': 3060 /* optopt on valid arg isn't defined */ 3061 optopt = c; 3062 /*FALLTHROUGH*/ 3063 case '?': 3064 default: 3065 /* 3066 * Since a bad option gets to here, sort it 3067 * out and return a syntax error return value 3068 * if necessary. 3069 */ 3070 switch (optopt) { 3071 default: 3072 ret = SA_SYNTAX_ERR; 3073 break; 3074 case 'h': 3075 case '?': 3076 break; 3077 } 3078 (void) printf(gettext("usage: %s\n"), 3079 sa_get_usage(USAGE_REMOVE_SHARE)); 3080 return (ret); 3081 } 3082 } 3083 3084 if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) { 3085 if (sharepath == NULL && rsrcname == NULL) { 3086 (void) printf(gettext("usage: %s\n"), 3087 sa_get_usage(USAGE_REMOVE_SHARE)); 3088 (void) printf(gettext("\t-s sharepath or -r resource" 3089 " must be specified\n")); 3090 ret = SA_BAD_PATH; 3091 } else { 3092 ret = SA_OK; 3093 } 3094 } 3095 if (ret != SA_OK) { 3096 return (ret); 3097 } 3098 3099 if (optind < argc) { 3100 if ((optind + 1) < argc) { 3101 (void) printf(gettext("Extraneous group(s) at end of " 3102 "command\n")); 3103 ret = SA_SYNTAX_ERR; 3104 } else { 3105 group = sa_get_group(handle, argv[optind]); 3106 if (group == NULL) { 3107 (void) printf(gettext( 3108 "Group \"%s\" not found\n"), argv[optind]); 3109 ret = SA_NO_SUCH_GROUP; 3110 } 3111 } 3112 } else { 3113 group = NULL; 3114 } 3115 3116 if (rsrcname != NULL) { 3117 resource = sa_find_resource(handle, rsrcname); 3118 if (resource == NULL) { 3119 ret = SA_NO_SUCH_RESOURCE; 3120 (void) printf(gettext( 3121 "Resource name not found for share: %s\n"), 3122 rsrcname); 3123 } 3124 } 3125 3126 /* 3127 * Lookup the path in the internal configuration. Care 3128 * must be taken to handle the case where the 3129 * underlying path has been removed since we need to 3130 * be able to deal with that as well. 3131 */ 3132 if (ret == SA_OK) { 3133 if (sharepath != NULL) { 3134 if (group != NULL) 3135 share = sa_get_share(group, sharepath); 3136 else 3137 share = sa_find_share(handle, sharepath); 3138 } 3139 3140 if (resource != NULL) { 3141 sa_share_t rsrcshare; 3142 rsrcshare = sa_get_resource_parent(resource); 3143 if (share == NULL) 3144 share = rsrcshare; 3145 else if (share != rsrcshare) { 3146 ret = SA_NO_SUCH_RESOURCE; 3147 (void) printf(gettext( 3148 "Bad resource name for share: %s\n"), 3149 rsrcname); 3150 share = NULL; 3151 } 3152 } 3153 3154 /* 3155 * If we didn't find the share with the provided path, 3156 * it may be a symlink so attempt to resolve it using 3157 * realpath and try again. Realpath will resolve any 3158 * symlinks and place them in "dir". Note that 3159 * sharepath is only used for the lookup the first 3160 * time and later for error messages. dir will be used 3161 * on the second attempt. Once a share is found, all 3162 * operations are based off of the share variable. 3163 */ 3164 if (share == NULL) { 3165 if (realpath(sharepath, dir) == NULL) { 3166 ret = SA_BAD_PATH; 3167 (void) printf(gettext( 3168 "Path is not valid: %s\n"), sharepath); 3169 } else { 3170 if (group != NULL) 3171 share = sa_get_share(group, dir); 3172 else 3173 share = sa_find_share(handle, dir); 3174 } 3175 } 3176 } 3177 3178 /* 3179 * If there hasn't been an error, there was likely a 3180 * path found. If not, give the appropriate error 3181 * message and set the return error. If it was found, 3182 * then disable the share and then remove it from the 3183 * configuration. 3184 */ 3185 if (ret != SA_OK) { 3186 return (ret); 3187 } 3188 if (share == NULL) { 3189 if (group != NULL) 3190 (void) printf(gettext("Share not found in group %s:" 3191 " %s\n"), argv[optind], sharepath); 3192 else 3193 (void) printf(gettext("Share not found: %s\n"), 3194 sharepath); 3195 ret = SA_NO_SUCH_PATH; 3196 } else { 3197 if (group == NULL) 3198 group = sa_get_parent_group(share); 3199 if (!dryrun) { 3200 if (ret == SA_OK) { 3201 if (resource != NULL) 3202 ret = sa_disable_resource(resource, 3203 NULL); 3204 else 3205 ret = sa_disable_share(share, NULL); 3206 /* 3207 * We don't care if it fails since it 3208 * could be disabled already. Some 3209 * unexpected errors could occur that 3210 * prevent removal, so also check for 3211 * force being set. 3212 */ 3213 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 3214 ret == SA_NOT_SUPPORTED || 3215 ret == SA_SYSTEM_ERR || force) && 3216 resource == NULL) 3217 ret = sa_remove_share(share); 3218 3219 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 3220 ret == SA_NOT_SUPPORTED || 3221 ret == SA_SYSTEM_ERR || force) && 3222 resource != NULL) { 3223 ret = sa_remove_resource(resource); 3224 if (ret == SA_OK) { 3225 /* 3226 * If this was the 3227 * last one, remove 3228 * the share as well. 3229 */ 3230 resource = 3231 sa_get_share_resource( 3232 share, NULL); 3233 if (resource == NULL) 3234 ret = sa_remove_share( 3235 share); 3236 } 3237 } 3238 if (ret == SA_OK) 3239 ret = sa_update_config(handle); 3240 } 3241 if (ret != SA_OK) 3242 (void) printf(gettext("Could not remove share:" 3243 " %s\n"), sa_errorstr(ret)); 3244 } else if (ret == SA_OK) { 3245 char *pname; 3246 pname = sa_get_group_attr(group, "name"); 3247 if (pname != NULL) { 3248 auth = check_authorizations(pname, flags); 3249 sa_free_attr_string(pname); 3250 } 3251 if (!auth && verbose) { 3252 (void) printf(gettext( 3253 "Command would fail: %s\n"), 3254 sa_errorstr(SA_NO_PERMISSION)); 3255 } 3256 } 3257 } 3258 return (ret); 3259 } 3260 3261 /* 3262 * sa_set_share(flags, argc, argv) 3263 * 3264 * implements set-share subcommand. 3265 */ 3266 3267 int 3268 sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 3269 { 3270 int dryrun = 0; 3271 int c; 3272 int ret = SA_OK; 3273 sa_group_t group, sharegroup; 3274 sa_share_t share = NULL; 3275 sa_resource_t resource = NULL; 3276 char *sharepath = NULL; 3277 char *description = NULL; 3278 char *rsrcname = NULL; 3279 char *rsrc = NULL; 3280 char *newname = NULL; 3281 char *newrsrc; 3282 char *groupname = NULL; 3283 int auth; 3284 int verbose = 0; 3285 3286 while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 3287 switch (c) { 3288 case 'n': 3289 dryrun++; 3290 break; 3291 case 'd': 3292 description = optarg; 3293 break; 3294 case 'v': 3295 verbose++; 3296 break; 3297 case 'r': 3298 /* 3299 * Update share by resource name 3300 */ 3301 if (rsrcname != NULL) { 3302 (void) printf(gettext( 3303 "Updating multiple resource names not " 3304 "supported\n")); 3305 return (SA_SYNTAX_ERR); 3306 } 3307 rsrcname = optarg; 3308 break; 3309 case 's': 3310 /* 3311 * Save share path into group. Currently limit 3312 * to one share per command. 3313 */ 3314 if (sharepath != NULL) { 3315 (void) printf(gettext( 3316 "Updating multiple shares not " 3317 "supported\n")); 3318 return (SA_SYNTAX_ERR); 3319 } 3320 sharepath = optarg; 3321 break; 3322 case 'h': 3323 /* optopt on valid arg isn't defined */ 3324 optopt = c; 3325 /*FALLTHROUGH*/ 3326 case '?': 3327 default: 3328 /* 3329 * Since a bad option gets to here, sort it 3330 * out and return a syntax error return value 3331 * if necessary. 3332 */ 3333 switch (optopt) { 3334 default: 3335 ret = SA_SYNTAX_ERR; 3336 break; 3337 case 'h': 3338 case '?': 3339 break; 3340 } 3341 (void) printf(gettext("usage: %s\n"), 3342 sa_get_usage(USAGE_SET_SHARE)); 3343 return (ret); 3344 } 3345 } 3346 3347 if (optind >= argc && sharepath == NULL && rsrcname == NULL) { 3348 if (sharepath == NULL) { 3349 (void) printf(gettext("usage: %s\n"), 3350 sa_get_usage(USAGE_SET_SHARE)); 3351 (void) printf(gettext("\tgroup must be specified\n")); 3352 ret = SA_BAD_PATH; 3353 } else { 3354 ret = SA_OK; 3355 } 3356 } 3357 if ((optind + 1) < argc) { 3358 (void) printf(gettext("usage: %s\n"), 3359 sa_get_usage(USAGE_SET_SHARE)); 3360 (void) printf(gettext("\tExtraneous group(s) at end\n")); 3361 ret = SA_SYNTAX_ERR; 3362 } 3363 3364 /* 3365 * Must have at least one of sharepath and rsrcrname. 3366 * It is a syntax error to be missing both. 3367 */ 3368 if (sharepath == NULL && rsrcname == NULL) { 3369 (void) printf(gettext("usage: %s\n"), 3370 sa_get_usage(USAGE_SET_SHARE)); 3371 ret = SA_SYNTAX_ERR; 3372 } 3373 3374 if (ret != SA_OK) 3375 return (ret); 3376 3377 if (optind < argc) { 3378 groupname = argv[optind]; 3379 group = sa_get_group(handle, groupname); 3380 } else { 3381 group = NULL; 3382 groupname = NULL; 3383 } 3384 if (rsrcname != NULL) { 3385 /* 3386 * If rsrcname exists, split rename syntax and then 3387 * convert to utf 8 if no errors. 3388 */ 3389 newname = strchr(rsrcname, '='); 3390 if (newname != NULL) { 3391 *newname++ = '\0'; 3392 } 3393 if (!validresource(rsrcname)) { 3394 ret = SA_INVALID_NAME; 3395 (void) printf(gettext("Invalid resource name: " 3396 "\"%s\"\n"), rsrcname); 3397 } else { 3398 rsrc = conv_to_utf8(rsrcname); 3399 } 3400 if (newname != NULL) { 3401 if (!validresource(newname)) { 3402 ret = SA_INVALID_NAME; 3403 (void) printf(gettext("Invalid resource name: " 3404 "%s\n"), newname); 3405 newname = NULL; 3406 } else { 3407 newrsrc = conv_to_utf8(newname); 3408 } 3409 } 3410 } 3411 3412 if (ret != SA_OK) { 3413 if (rsrcname != NULL && rsrcname != rsrc) 3414 sa_free_attr_string(rsrc); 3415 if (newname != NULL && newname != newrsrc) 3416 sa_free_attr_string(newrsrc); 3417 return (ret); 3418 } 3419 3420 if (sharepath != NULL) { 3421 share = sa_find_share(handle, sharepath); 3422 } else if (rsrcname != NULL) { 3423 resource = sa_find_resource(handle, rsrc); 3424 if (resource != NULL) 3425 share = sa_get_resource_parent(resource); 3426 else 3427 ret = SA_NO_SUCH_RESOURCE; 3428 } 3429 if (share != NULL) { 3430 sharegroup = sa_get_parent_group(share); 3431 if (group != NULL && group != sharegroup) { 3432 (void) printf(gettext("Group \"%s\" does not contain " 3433 "share %s\n"), 3434 argv[optind], sharepath); 3435 ret = SA_BAD_PATH; 3436 } else { 3437 int delgroupname = 0; 3438 if (groupname == NULL) { 3439 groupname = sa_get_group_attr(sharegroup, 3440 "name"); 3441 delgroupname = 1; 3442 } 3443 if (groupname != NULL) { 3444 auth = check_authorizations(groupname, flags); 3445 if (delgroupname) { 3446 sa_free_attr_string(groupname); 3447 groupname = NULL; 3448 } 3449 } else { 3450 ret = SA_NO_MEMORY; 3451 } 3452 if (rsrcname != NULL) { 3453 resource = sa_find_resource(handle, rsrc); 3454 if (!dryrun) { 3455 if (newname != NULL && 3456 resource != NULL) 3457 ret = sa_rename_resource( 3458 resource, newrsrc); 3459 else if (newname != NULL) 3460 ret = SA_NO_SUCH_RESOURCE; 3461 if (newname != NULL && 3462 newname != newrsrc) 3463 sa_free_attr_string(newrsrc); 3464 } 3465 if (rsrc != rsrcname) 3466 sa_free_attr_string(rsrc); 3467 } 3468 3469 /* 3470 * If the user has set a description, it will be 3471 * on the resource if -r was used otherwise it 3472 * must be on the share. 3473 */ 3474 if (!dryrun && ret == SA_OK && description != NULL) { 3475 char *desc; 3476 desc = conv_to_utf8(description); 3477 if (resource != NULL) 3478 ret = sa_set_resource_description( 3479 resource, desc); 3480 else 3481 ret = sa_set_share_description(share, 3482 desc); 3483 if (desc != description) 3484 sa_free_share_description(desc); 3485 } 3486 } 3487 if (!dryrun && ret == SA_OK) { 3488 if (resource != NULL) 3489 (void) sa_enable_resource(resource, NULL); 3490 ret = sa_update_config(handle); 3491 } 3492 switch (ret) { 3493 case SA_DUPLICATE_NAME: 3494 (void) printf(gettext("Resource name in use: %s\n"), 3495 rsrcname); 3496 break; 3497 default: 3498 (void) printf(gettext("Could not set: %s\n"), 3499 sa_errorstr(ret)); 3500 break; 3501 case SA_OK: 3502 if (dryrun && !auth && verbose) { 3503 (void) printf(gettext( 3504 "Command would fail: %s\n"), 3505 sa_errorstr(SA_NO_PERMISSION)); 3506 } 3507 break; 3508 } 3509 } else { 3510 switch (ret) { 3511 case SA_NO_SUCH_RESOURCE: 3512 (void) printf(gettext("Resource \"%s\" not found\n"), 3513 rsrcname); 3514 break; 3515 default: 3516 if (sharepath != NULL) { 3517 (void) printf( 3518 gettext("Share path \"%s\" not found\n"), 3519 sharepath); 3520 ret = SA_NO_SUCH_PATH; 3521 } else { 3522 (void) printf(gettext("Set failed: %s\n"), 3523 sa_errorstr(ret)); 3524 } 3525 } 3526 } 3527 3528 return (ret); 3529 } 3530 3531 /* 3532 * add_security(group, sectype, optlist, proto, *err) 3533 * 3534 * Helper function to add a security option (named optionset) to the 3535 * group. 3536 */ 3537 3538 static int 3539 add_security(sa_group_t group, char *sectype, 3540 struct options *optlist, char *proto, int *err) 3541 { 3542 sa_security_t security; 3543 int ret = SA_OK; 3544 int result = 0; 3545 sa_handle_t handle; 3546 3547 sectype = sa_proto_space_alias(proto, sectype); 3548 security = sa_get_security(group, sectype, proto); 3549 if (security == NULL) 3550 security = sa_create_security(group, sectype, proto); 3551 3552 if (sectype != NULL) 3553 sa_free_attr_string(sectype); 3554 3555 if (security == NULL) 3556 goto done; 3557 3558 handle = sa_find_group_handle(group); 3559 if (handle == NULL) { 3560 ret = SA_CONFIG_ERR; 3561 goto done; 3562 } 3563 while (optlist != NULL) { 3564 sa_property_t prop; 3565 prop = sa_get_property(security, optlist->optname); 3566 if (prop == NULL) { 3567 /* 3568 * Add the property, but only if it is 3569 * a non-NULL or non-zero length value 3570 */ 3571 if (optlist->optvalue != NULL) { 3572 prop = sa_create_property(optlist->optname, 3573 optlist->optvalue); 3574 if (prop != NULL) { 3575 ret = sa_valid_property(handle, 3576 security, proto, prop); 3577 if (ret != SA_OK) { 3578 (void) sa_remove_property(prop); 3579 (void) printf(gettext( 3580 "Could not add " 3581 "property %s: %s\n"), 3582 optlist->optname, 3583 sa_errorstr(ret)); 3584 } 3585 if (ret == SA_OK) { 3586 ret = sa_add_property(security, 3587 prop); 3588 if (ret != SA_OK) { 3589 (void) printf(gettext( 3590 "Could not add " 3591 "property (%s=%s):" 3592 " %s\n"), 3593 optlist->optname, 3594 optlist->optvalue, 3595 sa_errorstr(ret)); 3596 } else { 3597 result = 1; 3598 } 3599 } 3600 } 3601 } 3602 } else { 3603 ret = sa_update_property(prop, optlist->optvalue); 3604 result = 1; /* should check if really changed */ 3605 } 3606 optlist = optlist->next; 3607 } 3608 /* 3609 * When done, properties may have all been removed but 3610 * we need to keep the security type itself until 3611 * explicitly removed. 3612 */ 3613 if (result) 3614 ret = sa_commit_properties(security, 0); 3615 done: 3616 *err = ret; 3617 return (result); 3618 } 3619 3620 /* 3621 * zfscheck(group, share) 3622 * 3623 * For the special case where a share was provided, make sure it is a 3624 * compatible path for a ZFS property change. The only path 3625 * acceptable is the path that defines the zfs sub-group (dataset with 3626 * the sharenfs property set) and not one of the paths that inherited 3627 * the NFS properties. Returns SA_OK if it is usable and 3628 * SA_NOT_ALLOWED if it isn't. 3629 * 3630 * If group is not a ZFS group/subgroup, we assume OK since the check 3631 * on return will catch errors for those cases. What we are looking 3632 * for here is that the group is ZFS and the share is not the defining 3633 * share. All else is SA_OK. 3634 */ 3635 3636 static int 3637 zfscheck(sa_group_t group, sa_share_t share) 3638 { 3639 int ret = SA_OK; 3640 char *attr; 3641 3642 if (sa_group_is_zfs(group)) { 3643 /* 3644 * The group is a ZFS group. Does the share represent 3645 * the dataset that defined the group? It is only OK 3646 * if the attribute "subgroup" exists on the share and 3647 * has a value of "true". 3648 */ 3649 3650 ret = SA_NOT_ALLOWED; 3651 attr = sa_get_share_attr(share, "subgroup"); 3652 if (attr != NULL) { 3653 if (strcmp(attr, "true") == 0) 3654 ret = SA_OK; 3655 sa_free_attr_string(attr); 3656 } 3657 } 3658 return (ret); 3659 } 3660 3661 /* 3662 * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 3663 * 3664 * This function implements "set" when a name space (-S) is not 3665 * specified. It is a basic set. Options and other CLI parsing has 3666 * already been done. 3667 * 3668 * "rsrcname" is a "resource name". If it is non-NULL, it must match 3669 * the sharepath if present or group if present, otherwise it is used 3670 * to set options. 3671 * 3672 * Resource names may take options if the protocol supports it. If the 3673 * protocol doesn't support resource level options, rsrcname is just 3674 * an alias for the share. 3675 */ 3676 3677 static int 3678 basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 3679 char *protocol, char *sharepath, char *rsrcname, int dryrun) 3680 { 3681 sa_group_t group; 3682 int ret = SA_OK; 3683 int change = 0; 3684 struct list *worklist = NULL; 3685 3686 group = sa_get_group(handle, groupname); 3687 if (group != NULL) { 3688 sa_share_t share = NULL; 3689 sa_resource_t resource = NULL; 3690 3691 /* 3692 * If there is a sharepath, make sure it belongs to 3693 * the group. 3694 */ 3695 if (sharepath != NULL) { 3696 share = sa_get_share(group, sharepath); 3697 if (share == NULL) { 3698 (void) printf(gettext( 3699 "Share does not exist in group %s\n"), 3700 groupname, sharepath); 3701 ret = SA_NO_SUCH_PATH; 3702 } else { 3703 /* if ZFS and OK, then only group */ 3704 ret = zfscheck(group, share); 3705 if (ret == SA_OK && 3706 sa_group_is_zfs(group)) 3707 share = NULL; 3708 if (ret == SA_NOT_ALLOWED) 3709 (void) printf(gettext( 3710 "Properties on ZFS group shares " 3711 "not supported: %s\n"), sharepath); 3712 } 3713 } 3714 3715 /* 3716 * If a resource name exists, make sure it belongs to 3717 * the share if present else it belongs to the 3718 * group. Also check the protocol to see if it 3719 * supports resource level properties or not. If not, 3720 * use share only. 3721 */ 3722 if (rsrcname != NULL) { 3723 if (share != NULL) { 3724 resource = sa_get_share_resource(share, 3725 rsrcname); 3726 if (resource == NULL) 3727 ret = SA_NO_SUCH_RESOURCE; 3728 } else { 3729 resource = sa_get_resource(group, rsrcname); 3730 if (resource != NULL) 3731 share = sa_get_resource_parent( 3732 resource); 3733 else 3734 ret = SA_NO_SUCH_RESOURCE; 3735 } 3736 if (ret == SA_OK && resource != NULL) { 3737 uint64_t features; 3738 /* 3739 * Check to see if the resource can take 3740 * properties. If so, stick the resource into 3741 * "share" so it will all just work. 3742 */ 3743 features = sa_proto_get_featureset(protocol); 3744 if (features & SA_FEATURE_RESOURCE) 3745 share = (sa_share_t)resource; 3746 } 3747 } 3748 3749 if (ret == SA_OK) { 3750 /* group must exist */ 3751 ret = valid_options(handle, optlist, protocol, 3752 share == NULL ? group : share, NULL); 3753 if (ret == SA_OK && !dryrun) { 3754 if (share != NULL) 3755 change |= add_optionset(share, optlist, 3756 protocol, &ret); 3757 else 3758 change |= add_optionset(group, optlist, 3759 protocol, &ret); 3760 if (ret == SA_OK && change) 3761 worklist = add_list(worklist, group, 3762 share, protocol); 3763 } 3764 } 3765 free_opt(optlist); 3766 } else { 3767 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 3768 ret = SA_NO_SUCH_GROUP; 3769 } 3770 /* 3771 * we have a group and potentially legal additions 3772 */ 3773 3774 /* 3775 * Commit to configuration if not a dryrunp and properties 3776 * have changed. 3777 */ 3778 if (!dryrun && ret == SA_OK && change && worklist != NULL) 3779 /* properties changed, so update all shares */ 3780 (void) enable_all_groups(handle, worklist, 0, 0, protocol, 3781 B_TRUE); 3782 3783 if (worklist != NULL) 3784 free_list(worklist); 3785 return (ret); 3786 } 3787 3788 /* 3789 * space_set(groupname, optlist, protocol, sharepath, dryrun) 3790 * 3791 * This function implements "set" when a name space (-S) is 3792 * specified. It is a namespace set. Options and other CLI parsing has 3793 * already been done. 3794 */ 3795 3796 static int 3797 space_set(sa_handle_t handle, char *groupname, struct options *optlist, 3798 char *protocol, char *sharepath, int dryrun, char *sectype) 3799 { 3800 sa_group_t group; 3801 int ret = SA_OK; 3802 int change = 0; 3803 struct list *worklist = NULL; 3804 3805 /* 3806 * make sure protcol and sectype are valid 3807 */ 3808 3809 if (sa_proto_valid_space(protocol, sectype) == 0) { 3810 (void) printf(gettext("Option space \"%s\" not valid " 3811 "for protocol.\n"), sectype); 3812 return (SA_INVALID_SECURITY); 3813 } 3814 3815 group = sa_get_group(handle, groupname); 3816 if (group != NULL) { 3817 sa_share_t share = NULL; 3818 if (sharepath != NULL) { 3819 share = sa_get_share(group, sharepath); 3820 if (share == NULL) { 3821 (void) printf(gettext( 3822 "Share does not exist in group %s\n"), 3823 groupname, sharepath); 3824 ret = SA_NO_SUCH_PATH; 3825 } else { 3826 /* if ZFS and OK, then only group */ 3827 ret = zfscheck(group, share); 3828 if (ret == SA_OK && 3829 sa_group_is_zfs(group)) 3830 share = NULL; 3831 if (ret == SA_NOT_ALLOWED) 3832 (void) printf(gettext( 3833 "Properties on ZFS group shares " 3834 "not supported: %s\n"), sharepath); 3835 } 3836 } 3837 if (ret == SA_OK) { 3838 /* group must exist */ 3839 ret = valid_options(handle, optlist, protocol, 3840 share == NULL ? group : share, sectype); 3841 if (ret == SA_OK && !dryrun) { 3842 if (share != NULL) 3843 change = add_security(share, sectype, 3844 optlist, protocol, &ret); 3845 else 3846 change = add_security(group, sectype, 3847 optlist, protocol, &ret); 3848 if (ret != SA_OK) 3849 (void) printf(gettext( 3850 "Could not set property: %s\n"), 3851 sa_errorstr(ret)); 3852 } 3853 if (ret == SA_OK && change) 3854 worklist = add_list(worklist, group, share, 3855 protocol); 3856 } 3857 free_opt(optlist); 3858 } else { 3859 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 3860 ret = SA_NO_SUCH_GROUP; 3861 } 3862 3863 /* 3864 * We have a group and potentially legal additions. 3865 */ 3866 3867 /* Commit to configuration if not a dryrun */ 3868 if (!dryrun && ret == 0) { 3869 if (change && worklist != NULL) { 3870 /* properties changed, so update all shares */ 3871 (void) enable_all_groups(handle, worklist, 0, 0, 3872 protocol, B_TRUE); 3873 } 3874 ret = sa_update_config(handle); 3875 } 3876 if (worklist != NULL) 3877 free_list(worklist); 3878 return (ret); 3879 } 3880 3881 /* 3882 * sa_set(flags, argc, argv) 3883 * 3884 * Implements the set subcommand. It keys off of -S to determine which 3885 * set of operations to actually do. 3886 */ 3887 3888 int 3889 sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 3890 { 3891 char *groupname; 3892 int verbose = 0; 3893 int dryrun = 0; 3894 int c; 3895 char *protocol = NULL; 3896 int ret = SA_OK; 3897 struct options *optlist = NULL; 3898 char *rsrcname = NULL; 3899 char *sharepath = NULL; 3900 char *optset = NULL; 3901 int auth; 3902 3903 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 3904 switch (c) { 3905 case 'v': 3906 verbose++; 3907 break; 3908 case 'n': 3909 dryrun++; 3910 break; 3911 case 'P': 3912 if (protocol != NULL) { 3913 (void) printf(gettext( 3914 "Specifying multiple protocols " 3915 "not supported: %s\n"), protocol); 3916 return (SA_SYNTAX_ERR); 3917 } 3918 protocol = optarg; 3919 if (!sa_valid_protocol(protocol)) { 3920 (void) printf(gettext( 3921 "Invalid protocol specified: %s\n"), 3922 protocol); 3923 return (SA_INVALID_PROTOCOL); 3924 } 3925 break; 3926 case 'p': 3927 ret = add_opt(&optlist, optarg, 0); 3928 switch (ret) { 3929 case OPT_ADD_SYNTAX: 3930 (void) printf(gettext("Property syntax error:" 3931 " %s\n"), optarg); 3932 return (SA_SYNTAX_ERR); 3933 case OPT_ADD_MEMORY: 3934 (void) printf(gettext("No memory to set " 3935 "property: %s\n"), optarg); 3936 return (SA_NO_MEMORY); 3937 default: 3938 break; 3939 } 3940 break; 3941 case 'r': 3942 if (rsrcname != NULL) { 3943 (void) printf(gettext( 3944 "Setting multiple resource names not" 3945 " supported\n")); 3946 return (SA_SYNTAX_ERR); 3947 } 3948 rsrcname = optarg; 3949 break; 3950 case 's': 3951 if (sharepath != NULL) { 3952 (void) printf(gettext( 3953 "Setting multiple shares not supported\n")); 3954 return (SA_SYNTAX_ERR); 3955 } 3956 sharepath = optarg; 3957 break; 3958 case 'S': 3959 if (optset != NULL) { 3960 (void) printf(gettext( 3961 "Specifying multiple property " 3962 "spaces not supported: %s\n"), optset); 3963 return (SA_SYNTAX_ERR); 3964 } 3965 optset = optarg; 3966 break; 3967 case 'h': 3968 /* optopt on valid arg isn't defined */ 3969 optopt = c; 3970 /*FALLTHROUGH*/ 3971 case '?': 3972 default: 3973 /* 3974 * Since a bad option gets to here, sort it 3975 * out and return a syntax error return value 3976 * if necessary. 3977 */ 3978 switch (optopt) { 3979 default: 3980 ret = SA_SYNTAX_ERR; 3981 break; 3982 case 'h': 3983 case '?': 3984 break; 3985 } 3986 (void) printf(gettext("usage: %s\n"), 3987 sa_get_usage(USAGE_SET)); 3988 return (ret); 3989 } 3990 } 3991 3992 if (optlist != NULL) 3993 ret = chk_opt(optlist, optset != NULL, protocol); 3994 3995 if (optind >= argc || (optlist == NULL && optset == NULL) || 3996 protocol == NULL || ret != OPT_ADD_OK) { 3997 char *sep = "\t"; 3998 3999 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 4000 if (optind >= argc) { 4001 (void) printf(gettext("%sgroup must be specified"), 4002 sep); 4003 sep = ", "; 4004 } 4005 if (optlist == NULL) { 4006 (void) printf(gettext("%sat least one property must be" 4007 " specified"), sep); 4008 sep = ", "; 4009 } 4010 if (protocol == NULL) { 4011 (void) printf(gettext("%sprotocol must be specified"), 4012 sep); 4013 sep = ", "; 4014 } 4015 (void) printf("\n"); 4016 ret = SA_SYNTAX_ERR; 4017 } else { 4018 /* 4019 * Group already exists so we can proceed after a few 4020 * additional checks related to ZFS handling. 4021 */ 4022 4023 groupname = argv[optind]; 4024 if (strcmp(groupname, "zfs") == 0) { 4025 (void) printf(gettext("Changing properties for group " 4026 "\"zfs\" not allowed\n")); 4027 return (SA_NOT_ALLOWED); 4028 } 4029 4030 auth = check_authorizations(groupname, flags); 4031 if (optset == NULL) 4032 ret = basic_set(handle, groupname, optlist, protocol, 4033 sharepath, rsrcname, dryrun); 4034 else 4035 ret = space_set(handle, groupname, optlist, protocol, 4036 sharepath, dryrun, optset); 4037 if (dryrun && ret == SA_OK && !auth && verbose) { 4038 (void) printf(gettext("Command would fail: %s\n"), 4039 sa_errorstr(SA_NO_PERMISSION)); 4040 } 4041 } 4042 return (ret); 4043 } 4044 4045 /* 4046 * remove_options(group, optlist, proto, *err) 4047 * 4048 * Helper function to actually remove options from a group after all 4049 * preprocessing is done. 4050 */ 4051 4052 static int 4053 remove_options(sa_group_t group, struct options *optlist, 4054 char *proto, int *err) 4055 { 4056 struct options *cur; 4057 sa_optionset_t optionset; 4058 sa_property_t prop; 4059 int change = 0; 4060 int ret = SA_OK; 4061 4062 optionset = sa_get_optionset(group, proto); 4063 if (optionset != NULL) { 4064 for (cur = optlist; cur != NULL; cur = cur->next) { 4065 prop = sa_get_property(optionset, cur->optname); 4066 if (prop != NULL) { 4067 ret = sa_remove_property(prop); 4068 if (ret != SA_OK) 4069 break; 4070 change = 1; 4071 } 4072 } 4073 } 4074 if (ret == SA_OK && change) 4075 ret = sa_commit_properties(optionset, 0); 4076 4077 if (err != NULL) 4078 *err = ret; 4079 return (change); 4080 } 4081 4082 /* 4083 * valid_unset(group, optlist, proto) 4084 * 4085 * Sanity check the optlist to make sure they can be removed. Issue an 4086 * error if a property doesn't exist. 4087 */ 4088 4089 static int 4090 valid_unset(sa_group_t group, struct options *optlist, char *proto) 4091 { 4092 struct options *cur; 4093 sa_optionset_t optionset; 4094 sa_property_t prop; 4095 int ret = SA_OK; 4096 4097 optionset = sa_get_optionset(group, proto); 4098 if (optionset != NULL) { 4099 for (cur = optlist; cur != NULL; cur = cur->next) { 4100 prop = sa_get_property(optionset, cur->optname); 4101 if (prop == NULL) { 4102 (void) printf(gettext( 4103 "Could not unset property %s: not set\n"), 4104 cur->optname); 4105 ret = SA_NO_SUCH_PROP; 4106 } 4107 } 4108 } 4109 return (ret); 4110 } 4111 4112 /* 4113 * valid_unset_security(group, optlist, proto) 4114 * 4115 * Sanity check the optlist to make sure they can be removed. Issue an 4116 * error if a property doesn't exist. 4117 */ 4118 4119 static int 4120 valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 4121 char *sectype) 4122 { 4123 struct options *cur; 4124 sa_security_t security; 4125 sa_property_t prop; 4126 int ret = SA_OK; 4127 char *sec; 4128 4129 sec = sa_proto_space_alias(proto, sectype); 4130 security = sa_get_security(group, sec, proto); 4131 if (security != NULL) { 4132 for (cur = optlist; cur != NULL; cur = cur->next) { 4133 prop = sa_get_property(security, cur->optname); 4134 if (prop == NULL) { 4135 (void) printf(gettext( 4136 "Could not unset property %s: not set\n"), 4137 cur->optname); 4138 ret = SA_NO_SUCH_PROP; 4139 } 4140 } 4141 } else { 4142 (void) printf(gettext( 4143 "Could not unset %s: space not defined\n"), sectype); 4144 ret = SA_NO_SUCH_SECURITY; 4145 } 4146 if (sec != NULL) 4147 sa_free_attr_string(sec); 4148 return (ret); 4149 } 4150 4151 /* 4152 * remove_security(group, optlist, proto) 4153 * 4154 * Remove the properties since they were checked as valid. 4155 */ 4156 4157 static int 4158 remove_security(sa_group_t group, char *sectype, 4159 struct options *optlist, char *proto, int *err) 4160 { 4161 sa_security_t security; 4162 int ret = SA_OK; 4163 int change = 0; 4164 4165 sectype = sa_proto_space_alias(proto, sectype); 4166 security = sa_get_security(group, sectype, proto); 4167 if (sectype != NULL) 4168 sa_free_attr_string(sectype); 4169 4170 if (security != NULL) { 4171 while (optlist != NULL) { 4172 sa_property_t prop; 4173 prop = sa_get_property(security, optlist->optname); 4174 if (prop != NULL) { 4175 ret = sa_remove_property(prop); 4176 if (ret != SA_OK) 4177 break; 4178 change = 1; 4179 } 4180 optlist = optlist->next; 4181 } 4182 /* 4183 * when done, properties may have all been removed but 4184 * we need to keep the security type itself until 4185 * explicitly removed. 4186 */ 4187 if (ret == SA_OK && change) 4188 ret = sa_commit_properties(security, 0); 4189 } else { 4190 ret = SA_NO_SUCH_PROP; 4191 } 4192 if (err != NULL) 4193 *err = ret; 4194 return (change); 4195 } 4196 4197 /* 4198 * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 4199 * 4200 * Unset non-named optionset properties. 4201 */ 4202 4203 static int 4204 basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 4205 char *protocol, char *sharepath, char *rsrcname, int dryrun) 4206 { 4207 sa_group_t group; 4208 int ret = SA_OK; 4209 int change = 0; 4210 struct list *worklist = NULL; 4211 sa_share_t share = NULL; 4212 sa_resource_t resource = NULL; 4213 4214 group = sa_get_group(handle, groupname); 4215 if (group == NULL) 4216 return (ret); 4217 4218 /* 4219 * If there is a sharepath, make sure it belongs to 4220 * the group. 4221 */ 4222 if (sharepath != NULL) { 4223 share = sa_get_share(group, sharepath); 4224 if (share == NULL) { 4225 (void) printf(gettext( 4226 "Share does not exist in group %s\n"), 4227 groupname, sharepath); 4228 ret = SA_NO_SUCH_PATH; 4229 } 4230 } 4231 /* 4232 * If a resource name exists, make sure it belongs to 4233 * the share if present else it belongs to the 4234 * group. Also check the protocol to see if it 4235 * supports resource level properties or not. If not, 4236 * use share only. 4237 */ 4238 if (rsrcname != NULL) { 4239 if (share != NULL) { 4240 resource = sa_get_share_resource(share, rsrcname); 4241 if (resource == NULL) 4242 ret = SA_NO_SUCH_RESOURCE; 4243 } else { 4244 resource = sa_get_resource(group, rsrcname); 4245 if (resource != NULL) { 4246 share = sa_get_resource_parent(resource); 4247 } else { 4248 ret = SA_NO_SUCH_RESOURCE; 4249 } 4250 } 4251 if (ret == SA_OK && resource != NULL) { 4252 uint64_t features; 4253 /* 4254 * Check to see if the resource can take 4255 * properties. If so, stick the resource into 4256 * "share" so it will all just work. 4257 */ 4258 features = sa_proto_get_featureset(protocol); 4259 if (features & SA_FEATURE_RESOURCE) 4260 share = (sa_share_t)resource; 4261 } 4262 } 4263 4264 if (ret == SA_OK) { 4265 /* group must exist */ 4266 ret = valid_unset(share != NULL ? share : group, 4267 optlist, protocol); 4268 if (ret == SA_OK && !dryrun) { 4269 if (share != NULL) { 4270 sa_optionset_t optionset; 4271 sa_property_t prop; 4272 change |= remove_options(share, optlist, 4273 protocol, &ret); 4274 /* 4275 * If a share optionset is 4276 * empty, remove it. 4277 */ 4278 optionset = sa_get_optionset((sa_share_t)share, 4279 protocol); 4280 if (optionset != NULL) { 4281 prop = sa_get_property(optionset, NULL); 4282 if (prop == NULL) 4283 (void) sa_destroy_optionset( 4284 optionset); 4285 } 4286 } else { 4287 change |= remove_options(group, 4288 optlist, protocol, &ret); 4289 } 4290 if (ret == SA_OK && change) 4291 worklist = add_list(worklist, group, share, 4292 protocol); 4293 if (ret != SA_OK) 4294 (void) printf(gettext( 4295 "Could not remove properties: " 4296 "%s\n"), sa_errorstr(ret)); 4297 } 4298 } else { 4299 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 4300 ret = SA_NO_SUCH_GROUP; 4301 } 4302 free_opt(optlist); 4303 4304 /* 4305 * We have a group and potentially legal additions 4306 * 4307 * Commit to configuration if not a dryrun 4308 */ 4309 if (!dryrun && ret == SA_OK) { 4310 if (change && worklist != NULL) { 4311 /* properties changed, so update all shares */ 4312 (void) enable_all_groups(handle, worklist, 0, 0, 4313 protocol, B_TRUE); 4314 } 4315 } 4316 if (worklist != NULL) 4317 free_list(worklist); 4318 return (ret); 4319 } 4320 4321 /* 4322 * space_unset(groupname, optlist, protocol, sharepath, dryrun) 4323 * 4324 * Unset named optionset properties. 4325 */ 4326 static int 4327 space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 4328 char *protocol, char *sharepath, int dryrun, char *sectype) 4329 { 4330 sa_group_t group; 4331 int ret = SA_OK; 4332 int change = 0; 4333 struct list *worklist = NULL; 4334 sa_share_t share = NULL; 4335 4336 group = sa_get_group(handle, groupname); 4337 if (group == NULL) { 4338 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 4339 return (SA_NO_SUCH_GROUP); 4340 } 4341 if (sharepath != NULL) { 4342 share = sa_get_share(group, sharepath); 4343 if (share == NULL) { 4344 (void) printf(gettext( 4345 "Share does not exist in group %s\n"), 4346 groupname, sharepath); 4347 return (SA_NO_SUCH_PATH); 4348 } 4349 } 4350 ret = valid_unset_security(share != NULL ? share : group, 4351 optlist, protocol, sectype); 4352 4353 if (ret == SA_OK && !dryrun) { 4354 if (optlist != NULL) { 4355 if (share != NULL) { 4356 sa_security_t optionset; 4357 sa_property_t prop; 4358 change = remove_security(share, 4359 sectype, optlist, protocol, &ret); 4360 4361 /* If a share security is empty, remove it */ 4362 optionset = sa_get_security((sa_group_t)share, 4363 sectype, protocol); 4364 if (optionset != NULL) { 4365 prop = sa_get_property(optionset, 4366 NULL); 4367 if (prop == NULL) 4368 ret = sa_destroy_security( 4369 optionset); 4370 } 4371 } else { 4372 change = remove_security(group, sectype, 4373 optlist, protocol, &ret); 4374 } 4375 } else { 4376 sa_security_t security; 4377 char *sec; 4378 sec = sa_proto_space_alias(protocol, sectype); 4379 security = sa_get_security(group, sec, protocol); 4380 if (sec != NULL) 4381 sa_free_attr_string(sec); 4382 if (security != NULL) { 4383 ret = sa_destroy_security(security); 4384 if (ret == SA_OK) 4385 change = 1; 4386 } else { 4387 ret = SA_NO_SUCH_PROP; 4388 } 4389 } 4390 if (ret != SA_OK) 4391 (void) printf(gettext("Could not unset property: %s\n"), 4392 sa_errorstr(ret)); 4393 } 4394 4395 if (ret == SA_OK && change) 4396 worklist = add_list(worklist, group, 0, protocol); 4397 4398 free_opt(optlist); 4399 /* 4400 * We have a group and potentially legal additions 4401 */ 4402 4403 /* Commit to configuration if not a dryrun */ 4404 if (!dryrun && ret == 0) { 4405 /* properties changed, so update all shares */ 4406 if (change && worklist != NULL) 4407 (void) enable_all_groups(handle, worklist, 0, 0, 4408 protocol, B_TRUE); 4409 ret = sa_update_config(handle); 4410 } 4411 if (worklist != NULL) 4412 free_list(worklist); 4413 return (ret); 4414 } 4415 4416 /* 4417 * sa_unset(flags, argc, argv) 4418 * 4419 * Implements the unset subcommand. Parsing done here and then basic 4420 * or space versions of the real code are called. 4421 */ 4422 4423 int 4424 sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 4425 { 4426 char *groupname; 4427 int verbose = 0; 4428 int dryrun = 0; 4429 int c; 4430 char *protocol = NULL; 4431 int ret = SA_OK; 4432 struct options *optlist = NULL; 4433 char *rsrcname = NULL; 4434 char *sharepath = NULL; 4435 char *optset = NULL; 4436 int auth; 4437 4438 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 4439 switch (c) { 4440 case 'v': 4441 verbose++; 4442 break; 4443 case 'n': 4444 dryrun++; 4445 break; 4446 case 'P': 4447 if (protocol != NULL) { 4448 (void) printf(gettext( 4449 "Specifying multiple protocols " 4450 "not supported: %s\n"), protocol); 4451 return (SA_SYNTAX_ERR); 4452 } 4453 protocol = optarg; 4454 if (!sa_valid_protocol(protocol)) { 4455 (void) printf(gettext( 4456 "Invalid protocol specified: %s\n"), 4457 protocol); 4458 return (SA_INVALID_PROTOCOL); 4459 } 4460 break; 4461 case 'p': 4462 ret = add_opt(&optlist, optarg, 1); 4463 switch (ret) { 4464 case OPT_ADD_SYNTAX: 4465 (void) printf(gettext("Property syntax error " 4466 "for property %s\n"), optarg); 4467 return (SA_SYNTAX_ERR); 4468 4469 case OPT_ADD_PROPERTY: 4470 (void) printf(gettext("Properties need to be " 4471 "set with set command: %s\n"), optarg); 4472 return (SA_SYNTAX_ERR); 4473 4474 default: 4475 break; 4476 } 4477 break; 4478 case 'r': 4479 /* 4480 * Unset properties on resource if applicable or on 4481 * share if resource for this protocol doesn't use 4482 * resources. 4483 */ 4484 if (rsrcname != NULL) { 4485 (void) printf(gettext( 4486 "Unsetting multiple resource " 4487 "names not supported\n")); 4488 return (SA_SYNTAX_ERR); 4489 } 4490 rsrcname = optarg; 4491 break; 4492 case 's': 4493 if (sharepath != NULL) { 4494 (void) printf(gettext( 4495 "Adding multiple shares not supported\n")); 4496 return (SA_SYNTAX_ERR); 4497 } 4498 sharepath = optarg; 4499 break; 4500 case 'S': 4501 if (optset != NULL) { 4502 (void) printf(gettext( 4503 "Specifying multiple property " 4504 "spaces not supported: %s\n"), optset); 4505 return (SA_SYNTAX_ERR); 4506 } 4507 optset = optarg; 4508 break; 4509 case 'h': 4510 /* optopt on valid arg isn't defined */ 4511 optopt = c; 4512 /*FALLTHROUGH*/ 4513 case '?': 4514 default: 4515 /* 4516 * Since a bad option gets to here, sort it 4517 * out and return a syntax error return value 4518 * if necessary. 4519 */ 4520 switch (optopt) { 4521 default: 4522 ret = SA_SYNTAX_ERR; 4523 break; 4524 case 'h': 4525 case '?': 4526 break; 4527 } 4528 (void) printf(gettext("usage: %s\n"), 4529 sa_get_usage(USAGE_UNSET)); 4530 return (ret); 4531 } 4532 } 4533 4534 if (optlist != NULL) 4535 ret = chk_opt(optlist, optset != NULL, protocol); 4536 4537 if (optind >= argc || (optlist == NULL && optset == NULL) || 4538 protocol == NULL) { 4539 char *sep = "\t"; 4540 (void) printf(gettext("usage: %s\n"), 4541 sa_get_usage(USAGE_UNSET)); 4542 if (optind >= argc) { 4543 (void) printf(gettext("%sgroup must be specified"), 4544 sep); 4545 sep = ", "; 4546 } 4547 if (optlist == NULL) { 4548 (void) printf(gettext("%sat least one property must " 4549 "be specified"), sep); 4550 sep = ", "; 4551 } 4552 if (protocol == NULL) { 4553 (void) printf(gettext("%sprotocol must be specified"), 4554 sep); 4555 sep = ", "; 4556 } 4557 (void) printf("\n"); 4558 ret = SA_SYNTAX_ERR; 4559 } else { 4560 4561 /* 4562 * If a group already exists, we can only add a new 4563 * protocol to it and not create a new one or add the 4564 * same protocol again. 4565 */ 4566 4567 groupname = argv[optind]; 4568 auth = check_authorizations(groupname, flags); 4569 if (optset == NULL) 4570 ret = basic_unset(handle, groupname, optlist, protocol, 4571 sharepath, rsrcname, dryrun); 4572 else 4573 ret = space_unset(handle, groupname, optlist, protocol, 4574 sharepath, dryrun, optset); 4575 4576 if (dryrun && ret == SA_OK && !auth && verbose) 4577 (void) printf(gettext("Command would fail: %s\n"), 4578 sa_errorstr(SA_NO_PERMISSION)); 4579 } 4580 return (ret); 4581 } 4582 4583 /* 4584 * sa_enable_group(flags, argc, argv) 4585 * 4586 * Implements the enable subcommand 4587 */ 4588 4589 int 4590 sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 4591 { 4592 int verbose = 0; 4593 int dryrun = 0; 4594 int all = 0; 4595 int c; 4596 int ret = SA_OK; 4597 char *protocol = NULL; 4598 char *state; 4599 struct list *worklist = NULL; 4600 int auth = 1; 4601 sa_group_t group; 4602 4603 while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 4604 switch (c) { 4605 case 'a': 4606 all = 1; 4607 break; 4608 case 'n': 4609 dryrun++; 4610 break; 4611 case 'P': 4612 if (protocol != NULL) { 4613 (void) printf(gettext( 4614 "Specifying multiple protocols " 4615 "not supported: %s\n"), protocol); 4616 return (SA_SYNTAX_ERR); 4617 } 4618 protocol = optarg; 4619 if (!sa_valid_protocol(protocol)) { 4620 (void) printf(gettext( 4621 "Invalid protocol specified: %s\n"), 4622 protocol); 4623 return (SA_INVALID_PROTOCOL); 4624 } 4625 break; 4626 case 'v': 4627 verbose++; 4628 break; 4629 case 'h': 4630 /* optopt on valid arg isn't defined */ 4631 optopt = c; 4632 /*FALLTHROUGH*/ 4633 case '?': 4634 default: 4635 /* 4636 * Since a bad option gets to here, sort it 4637 * out and return a syntax error return value 4638 * if necessary. 4639 */ 4640 switch (optopt) { 4641 default: 4642 ret = SA_SYNTAX_ERR; 4643 break; 4644 case 'h': 4645 case '?': 4646 (void) printf(gettext("usage: %s\n"), 4647 sa_get_usage(USAGE_ENABLE)); 4648 return (ret); 4649 } 4650 } 4651 } 4652 4653 if (optind == argc && !all) { 4654 (void) printf(gettext("usage: %s\n"), 4655 sa_get_usage(USAGE_ENABLE)); 4656 (void) printf(gettext("\tmust specify group\n")); 4657 return (SA_NO_SUCH_PATH); 4658 } 4659 if (!all) { 4660 while (optind < argc) { 4661 group = sa_get_group(handle, argv[optind]); 4662 if (group != NULL) { 4663 auth &= check_authorizations(argv[optind], 4664 flags); 4665 state = sa_get_group_attr(group, "state"); 4666 if (state != NULL && 4667 strcmp(state, "enabled") == 0) { 4668 /* already enabled */ 4669 if (verbose) 4670 (void) printf(gettext( 4671 "Group \"%s\" is already " 4672 "enabled\n"), 4673 argv[optind]); 4674 ret = SA_BUSY; /* already enabled */ 4675 } else { 4676 worklist = add_list(worklist, group, 4677 0, protocol); 4678 if (verbose) 4679 (void) printf(gettext( 4680 "Enabling group \"%s\"\n"), 4681 argv[optind]); 4682 } 4683 if (state != NULL) 4684 sa_free_attr_string(state); 4685 } else { 4686 ret = SA_NO_SUCH_GROUP; 4687 } 4688 optind++; 4689 } 4690 } else { 4691 for (group = sa_get_group(handle, NULL); 4692 group != NULL; 4693 group = sa_get_next_group(group)) { 4694 worklist = add_list(worklist, group, 0, protocol); 4695 } 4696 } 4697 if (!dryrun && ret == SA_OK) 4698 ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE); 4699 4700 if (ret != SA_OK && ret != SA_BUSY) 4701 (void) printf(gettext("Could not enable group: %s\n"), 4702 sa_errorstr(ret)); 4703 if (ret == SA_BUSY) 4704 ret = SA_OK; 4705 4706 if (worklist != NULL) 4707 free_list(worklist); 4708 if (dryrun && ret == SA_OK && !auth && verbose) { 4709 (void) printf(gettext("Command would fail: %s\n"), 4710 sa_errorstr(SA_NO_PERMISSION)); 4711 } 4712 return (ret); 4713 } 4714 4715 /* 4716 * disable_group(group, proto) 4717 * 4718 * Disable all the shares in the specified group.. This is a helper 4719 * for disable_all_groups in order to simplify regular and subgroup 4720 * (zfs) disabling. Group has already been checked for non-NULL. 4721 */ 4722 4723 static int 4724 disable_group(sa_group_t group, char *proto) 4725 { 4726 sa_share_t share; 4727 int ret = SA_OK; 4728 4729 /* 4730 * If the protocol isn't enabled, skip it and treat as 4731 * successful. 4732 */ 4733 if (!has_protocol(group, proto)) 4734 return (ret); 4735 4736 for (share = sa_get_share(group, NULL); 4737 share != NULL && ret == SA_OK; 4738 share = sa_get_next_share(share)) { 4739 ret = sa_disable_share(share, proto); 4740 if (ret == SA_NO_SUCH_PATH) { 4741 /* 4742 * this is OK since the path is gone. we can't 4743 * re-share it anyway so no error. 4744 */ 4745 ret = SA_OK; 4746 } 4747 } 4748 return (ret); 4749 } 4750 4751 /* 4752 * disable_all_groups(work, setstate) 4753 * 4754 * helper function that disables the shares in the list of groups 4755 * provided. It optionally marks the group as disabled. Used by both 4756 * enable and start subcommands. 4757 */ 4758 4759 static int 4760 disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 4761 { 4762 int ret = SA_OK; 4763 sa_group_t subgroup, group; 4764 4765 while (work != NULL && ret == SA_OK) { 4766 group = (sa_group_t)work->item; 4767 if (setstate) 4768 ret = sa_set_group_attr(group, "state", "disabled"); 4769 if (ret == SA_OK) { 4770 char *name; 4771 name = sa_get_group_attr(group, "name"); 4772 if (name != NULL && strcmp(name, "zfs") == 0) { 4773 /* need to get the sub-groups for stopping */ 4774 for (subgroup = sa_get_sub_group(group); 4775 subgroup != NULL; 4776 subgroup = sa_get_next_group(subgroup)) { 4777 ret = disable_group(subgroup, 4778 work->proto); 4779 } 4780 } else { 4781 ret = disable_group(group, work->proto); 4782 } 4783 if (name != NULL) 4784 sa_free_attr_string(name); 4785 /* 4786 * We don't want to "disable" since it won't come 4787 * up after a reboot. The SMF framework should do 4788 * the right thing. On enable we do want to do 4789 * something. 4790 */ 4791 } 4792 work = work->next; 4793 } 4794 if (ret == SA_OK) 4795 ret = sa_update_config(handle); 4796 return (ret); 4797 } 4798 4799 /* 4800 * sa_disable_group(flags, argc, argv) 4801 * 4802 * Implements the disable subcommand 4803 */ 4804 4805 int 4806 sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 4807 { 4808 int verbose = 0; 4809 int dryrun = 0; 4810 int all = 0; 4811 int c; 4812 int ret = SA_OK; 4813 char *protocol = NULL; 4814 char *state; 4815 struct list *worklist = NULL; 4816 sa_group_t group; 4817 int auth = 1; 4818 4819 while ((c = getopt(argc, argv, "?havn")) != EOF) { 4820 switch (c) { 4821 case 'a': 4822 all = 1; 4823 break; 4824 case 'n': 4825 dryrun++; 4826 break; 4827 case 'P': 4828 if (protocol != NULL) { 4829 (void) printf(gettext( 4830 "Specifying multiple protocols " 4831 "not supported: %s\n"), protocol); 4832 return (SA_SYNTAX_ERR); 4833 } 4834 protocol = optarg; 4835 if (!sa_valid_protocol(protocol)) { 4836 (void) printf(gettext( 4837 "Invalid protocol specified: %s\n"), 4838 protocol); 4839 return (SA_INVALID_PROTOCOL); 4840 } 4841 break; 4842 case 'v': 4843 verbose++; 4844 break; 4845 case 'h': 4846 /* optopt on valid arg isn't defined */ 4847 optopt = c; 4848 /*FALLTHROUGH*/ 4849 case '?': 4850 default: 4851 /* 4852 * Since a bad option gets to here, sort it 4853 * out and return a syntax error return value 4854 * if necessary. 4855 */ 4856 switch (optopt) { 4857 default: 4858 ret = SA_SYNTAX_ERR; 4859 break; 4860 case 'h': 4861 case '?': 4862 break; 4863 } 4864 (void) printf(gettext("usage: %s\n"), 4865 sa_get_usage(USAGE_DISABLE)); 4866 return (ret); 4867 } 4868 } 4869 4870 if (optind == argc && !all) { 4871 (void) printf(gettext("usage: %s\n"), 4872 sa_get_usage(USAGE_DISABLE)); 4873 (void) printf(gettext("\tmust specify group\n")); 4874 return (SA_NO_SUCH_PATH); 4875 } 4876 if (!all) { 4877 while (optind < argc) { 4878 group = sa_get_group(handle, argv[optind]); 4879 if (group != NULL) { 4880 auth &= check_authorizations(argv[optind], 4881 flags); 4882 state = sa_get_group_attr(group, "state"); 4883 if (state == NULL || 4884 strcmp(state, "disabled") == 0) { 4885 /* already disabled */ 4886 if (verbose) 4887 (void) printf(gettext( 4888 "Group \"%s\" is " 4889 "already disabled\n"), 4890 argv[optind]); 4891 ret = SA_BUSY; /* already disabled */ 4892 } else { 4893 worklist = add_list(worklist, group, 0, 4894 protocol); 4895 if (verbose) 4896 (void) printf(gettext( 4897 "Disabling group " 4898 "\"%s\"\n"), argv[optind]); 4899 } 4900 if (state != NULL) 4901 sa_free_attr_string(state); 4902 } else { 4903 ret = SA_NO_SUCH_GROUP; 4904 } 4905 optind++; 4906 } 4907 } else { 4908 for (group = sa_get_group(handle, NULL); 4909 group != NULL; 4910 group = sa_get_next_group(group)) 4911 worklist = add_list(worklist, group, 0, protocol); 4912 } 4913 4914 if (ret == SA_OK && !dryrun) 4915 ret = disable_all_groups(handle, worklist, 1); 4916 if (ret != SA_OK && ret != SA_BUSY) 4917 (void) printf(gettext("Could not disable group: %s\n"), 4918 sa_errorstr(ret)); 4919 if (ret == SA_BUSY) 4920 ret = SA_OK; 4921 if (worklist != NULL) 4922 free_list(worklist); 4923 if (dryrun && ret == SA_OK && !auth && verbose) 4924 (void) printf(gettext("Command would fail: %s\n"), 4925 sa_errorstr(SA_NO_PERMISSION)); 4926 return (ret); 4927 } 4928 4929 /* 4930 * sa_start_group(flags, argc, argv) 4931 * 4932 * Implements the start command. 4933 * This is similar to enable except it doesn't change the state 4934 * of the group(s) and only enables shares if the group is already 4935 * enabled. 4936 */ 4937 4938 int 4939 sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 4940 { 4941 int verbose = 0; 4942 int all = 0; 4943 int c; 4944 int ret = SMF_EXIT_OK; 4945 char *protocol = NULL; 4946 char *state; 4947 struct list *worklist = NULL; 4948 sa_group_t group; 4949 #ifdef lint 4950 flags = flags; 4951 #endif 4952 4953 while ((c = getopt(argc, argv, "?havP:")) != EOF) { 4954 switch (c) { 4955 case 'a': 4956 all = 1; 4957 break; 4958 case 'P': 4959 if (protocol != NULL) { 4960 (void) printf(gettext( 4961 "Specifying multiple protocols " 4962 "not supported: %s\n"), protocol); 4963 return (SA_SYNTAX_ERR); 4964 } 4965 protocol = optarg; 4966 if (!sa_valid_protocol(protocol)) { 4967 (void) printf(gettext( 4968 "Invalid protocol specified: %s\n"), 4969 protocol); 4970 return (SA_INVALID_PROTOCOL); 4971 } 4972 break; 4973 case 'v': 4974 verbose++; 4975 break; 4976 case 'h': 4977 /* optopt on valid arg isn't defined */ 4978 optopt = c; 4979 /*FALLTHROUGH*/ 4980 case '?': 4981 default: 4982 /* 4983 * Since a bad option gets to here, sort it 4984 * out and return a syntax error return value 4985 * if necessary. 4986 */ 4987 ret = SA_OK; 4988 switch (optopt) { 4989 default: 4990 ret = SA_SYNTAX_ERR; 4991 break; 4992 case 'h': 4993 case '?': 4994 break; 4995 } 4996 (void) printf(gettext("usage: %s\n"), 4997 sa_get_usage(USAGE_START)); 4998 return (ret); 4999 } 5000 } 5001 5002 if (optind == argc && !all) { 5003 (void) printf(gettext("usage: %s\n"), 5004 sa_get_usage(USAGE_START)); 5005 return (SMF_EXIT_ERR_FATAL); 5006 } 5007 5008 if (!all) { 5009 while (optind < argc) { 5010 group = sa_get_group(handle, argv[optind]); 5011 if (group != NULL) { 5012 state = sa_get_group_attr(group, "state"); 5013 if (state == NULL || 5014 strcmp(state, "enabled") == 0) { 5015 worklist = add_list(worklist, group, 0, 5016 protocol); 5017 if (verbose) 5018 (void) printf(gettext( 5019 "Starting group \"%s\"\n"), 5020 argv[optind]); 5021 } else { 5022 /* 5023 * Determine if there are any 5024 * protocols. If there aren't any, 5025 * then there isn't anything to do in 5026 * any case so no error. 5027 */ 5028 if (sa_get_optionset(group, 5029 protocol) != NULL) { 5030 ret = SMF_EXIT_OK; 5031 } 5032 } 5033 if (state != NULL) 5034 sa_free_attr_string(state); 5035 } 5036 optind++; 5037 } 5038 } else { 5039 for (group = sa_get_group(handle, NULL); 5040 group != NULL; 5041 group = sa_get_next_group(group)) { 5042 state = sa_get_group_attr(group, "state"); 5043 if (state == NULL || strcmp(state, "enabled") == 0) 5044 worklist = add_list(worklist, group, 0, 5045 protocol); 5046 if (state != NULL) 5047 sa_free_attr_string(state); 5048 } 5049 } 5050 5051 (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE); 5052 5053 if (worklist != NULL) 5054 free_list(worklist); 5055 return (ret); 5056 } 5057 5058 /* 5059 * sa_stop_group(flags, argc, argv) 5060 * 5061 * Implements the stop command. 5062 * This is similar to disable except it doesn't change the state 5063 * of the group(s) and only disables shares if the group is already 5064 * enabled. 5065 */ 5066 int 5067 sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 5068 { 5069 int verbose = 0; 5070 int all = 0; 5071 int c; 5072 int ret = SMF_EXIT_OK; 5073 char *protocol = NULL; 5074 char *state; 5075 struct list *worklist = NULL; 5076 sa_group_t group; 5077 #ifdef lint 5078 flags = flags; 5079 #endif 5080 5081 while ((c = getopt(argc, argv, "?havP:")) != EOF) { 5082 switch (c) { 5083 case 'a': 5084 all = 1; 5085 break; 5086 case 'P': 5087 if (protocol != NULL) { 5088 (void) printf(gettext( 5089 "Specifying multiple protocols " 5090 "not supported: %s\n"), protocol); 5091 return (SA_SYNTAX_ERR); 5092 } 5093 protocol = optarg; 5094 if (!sa_valid_protocol(protocol)) { 5095 (void) printf(gettext( 5096 "Invalid protocol specified: %s\n"), 5097 protocol); 5098 return (SA_INVALID_PROTOCOL); 5099 } 5100 break; 5101 case 'v': 5102 verbose++; 5103 break; 5104 case 'h': 5105 /* optopt on valid arg isn't defined */ 5106 optopt = c; 5107 /*FALLTHROUGH*/ 5108 case '?': 5109 default: 5110 /* 5111 * Since a bad option gets to here, sort it 5112 * out and return a syntax error return value 5113 * if necessary. 5114 */ 5115 ret = SA_OK; 5116 switch (optopt) { 5117 default: 5118 ret = SA_SYNTAX_ERR; 5119 break; 5120 case 'h': 5121 case '?': 5122 break; 5123 } 5124 (void) printf(gettext("usage: %s\n"), 5125 sa_get_usage(USAGE_STOP)); 5126 return (ret); 5127 } 5128 } 5129 5130 if (optind == argc && !all) { 5131 (void) printf(gettext("usage: %s\n"), 5132 sa_get_usage(USAGE_STOP)); 5133 return (SMF_EXIT_ERR_FATAL); 5134 } else if (!all) { 5135 while (optind < argc) { 5136 group = sa_get_group(handle, argv[optind]); 5137 if (group != NULL) { 5138 state = sa_get_group_attr(group, "state"); 5139 if (state == NULL || 5140 strcmp(state, "enabled") == 0) { 5141 worklist = add_list(worklist, group, 0, 5142 protocol); 5143 if (verbose) 5144 (void) printf(gettext( 5145 "Stopping group \"%s\"\n"), 5146 argv[optind]); 5147 } else { 5148 ret = SMF_EXIT_OK; 5149 } 5150 if (state != NULL) 5151 sa_free_attr_string(state); 5152 } 5153 optind++; 5154 } 5155 } else { 5156 for (group = sa_get_group(handle, NULL); 5157 group != NULL; 5158 group = sa_get_next_group(group)) { 5159 state = sa_get_group_attr(group, "state"); 5160 if (state == NULL || strcmp(state, "enabled") == 0) 5161 worklist = add_list(worklist, group, 0, 5162 protocol); 5163 if (state != NULL) 5164 sa_free_attr_string(state); 5165 } 5166 } 5167 (void) disable_all_groups(handle, worklist, 0); 5168 ret = sa_update_config(handle); 5169 5170 if (worklist != NULL) 5171 free_list(worklist); 5172 return (ret); 5173 } 5174 5175 /* 5176 * remove_all_options(share, proto) 5177 * 5178 * Removes all options on a share. 5179 */ 5180 5181 static void 5182 remove_all_options(sa_share_t share, char *proto) 5183 { 5184 sa_optionset_t optionset; 5185 sa_security_t security; 5186 sa_security_t prevsec = NULL; 5187 5188 optionset = sa_get_optionset(share, proto); 5189 if (optionset != NULL) 5190 (void) sa_destroy_optionset(optionset); 5191 for (security = sa_get_security(share, NULL, NULL); 5192 security != NULL; 5193 security = sa_get_next_security(security)) { 5194 char *type; 5195 /* 5196 * We walk through the list. prevsec keeps the 5197 * previous security so we can delete it without 5198 * destroying the list. 5199 */ 5200 if (prevsec != NULL) { 5201 /* remove the previously seen security */ 5202 (void) sa_destroy_security(prevsec); 5203 /* set to NULL so we don't try multiple times */ 5204 prevsec = NULL; 5205 } 5206 type = sa_get_security_attr(security, "type"); 5207 if (type != NULL) { 5208 /* 5209 * if the security matches the specified protocol, we 5210 * want to remove it. prevsec holds it until either 5211 * the next pass or we fall out of the loop. 5212 */ 5213 if (strcmp(type, proto) == 0) 5214 prevsec = security; 5215 sa_free_attr_string(type); 5216 } 5217 } 5218 /* in case there is one left */ 5219 if (prevsec != NULL) 5220 (void) sa_destroy_security(prevsec); 5221 } 5222 5223 5224 /* 5225 * for legacy support, we need to handle the old syntax. This is what 5226 * we get if sharemgr is called with the name "share" rather than 5227 * sharemgr. 5228 */ 5229 5230 static int 5231 format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 5232 { 5233 int err; 5234 5235 err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 5236 if (err > buffsize) 5237 return (-1); 5238 return (0); 5239 } 5240 5241 5242 /* 5243 * check_legacy_cmd(proto, cmd) 5244 * 5245 * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 5246 * executable. 5247 */ 5248 5249 static int 5250 check_legacy_cmd(char *path) 5251 { 5252 struct stat st; 5253 int ret = 0; 5254 5255 if (stat(path, &st) == 0) { 5256 if (S_ISREG(st.st_mode) && 5257 st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 5258 ret = 1; 5259 } 5260 return (ret); 5261 } 5262 5263 /* 5264 * run_legacy_command(proto, cmd, argv) 5265 * 5266 * We know the command exists, so attempt to execute it with all the 5267 * arguments. This implements full legacy share support for those 5268 * protocols that don't have plugin providers. 5269 */ 5270 5271 static int 5272 run_legacy_command(char *path, char *argv[]) 5273 { 5274 int ret; 5275 5276 ret = execv(path, argv); 5277 if (ret < 0) { 5278 switch (errno) { 5279 case EACCES: 5280 ret = SA_NO_PERMISSION; 5281 break; 5282 default: 5283 ret = SA_SYSTEM_ERR; 5284 break; 5285 } 5286 } 5287 return (ret); 5288 } 5289 5290 /* 5291 * out_share(out, group, proto) 5292 * 5293 * Display the share information in the format that the "share" 5294 * command has traditionally used. 5295 */ 5296 5297 static void 5298 out_share(FILE *out, sa_group_t group, char *proto) 5299 { 5300 sa_share_t share; 5301 char resfmt[128]; 5302 char *defprop; 5303 5304 /* 5305 * The original share command defaulted to displaying NFS 5306 * shares or allowed a protocol to be specified. We want to 5307 * skip those shares that are not the specified protocol. 5308 */ 5309 if (proto != NULL && sa_get_optionset(group, proto) == NULL) 5310 return; 5311 5312 if (proto == NULL) 5313 proto = "nfs"; 5314 5315 /* 5316 * get the default property string. NFS uses "rw" but 5317 * everything else will use "". 5318 */ 5319 if (proto != NULL && strcmp(proto, "nfs") != 0) 5320 defprop = "\"\""; 5321 else 5322 defprop = "rw"; 5323 5324 for (share = sa_get_share(group, NULL); 5325 share != NULL; 5326 share = sa_get_next_share(share)) { 5327 char *path; 5328 char *type; 5329 char *resource; 5330 char *description; 5331 char *groupname; 5332 char *sharedstate; 5333 int shared = 1; 5334 char *soptions; 5335 char shareopts[MAXNAMLEN]; 5336 5337 sharedstate = sa_get_share_attr(share, "shared"); 5338 path = sa_get_share_attr(share, "path"); 5339 type = sa_get_share_attr(share, "type"); 5340 resource = get_resource(share); 5341 groupname = sa_get_group_attr(group, "name"); 5342 5343 if (groupname != NULL && strcmp(groupname, "default") == 0) { 5344 sa_free_attr_string(groupname); 5345 groupname = NULL; 5346 } 5347 description = sa_get_share_description(share); 5348 5349 /* 5350 * Want the sharetab version if it exists, defaulting 5351 * to NFS if no protocol specified. 5352 */ 5353 (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto); 5354 soptions = sa_get_share_attr(share, shareopts); 5355 5356 if (sharedstate == NULL) 5357 shared = 0; 5358 5359 if (soptions == NULL) 5360 soptions = sa_proto_legacy_format(proto, share, 1); 5361 5362 if (shared) { 5363 /* only active shares go here */ 5364 (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 5365 resource != NULL ? resource : "-", 5366 groupname != NULL ? "@" : "", 5367 groupname != NULL ? groupname : ""); 5368 (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 5369 resfmt, (path != NULL) ? path : "", 5370 (soptions != NULL && strlen(soptions) > 0) ? 5371 soptions : defprop, 5372 (description != NULL) ? description : ""); 5373 } 5374 5375 if (path != NULL) 5376 sa_free_attr_string(path); 5377 if (type != NULL) 5378 sa_free_attr_string(type); 5379 if (resource != NULL) 5380 sa_free_attr_string(resource); 5381 if (groupname != NULL) 5382 sa_free_attr_string(groupname); 5383 if (description != NULL) 5384 sa_free_share_description(description); 5385 if (sharedstate != NULL) 5386 sa_free_attr_string(sharedstate); 5387 if (soptions != NULL) 5388 sa_format_free(soptions); 5389 } 5390 } 5391 5392 /* 5393 * output_legacy_file(out, proto) 5394 * 5395 * Walk all of the groups for the specified protocol and call 5396 * out_share() to format and write in the format displayed by the 5397 * "share" command with no arguments. 5398 */ 5399 5400 static void 5401 output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 5402 { 5403 sa_group_t group; 5404 5405 for (group = sa_get_group(handle, NULL); 5406 group != NULL; 5407 group = sa_get_next_group(group)) { 5408 char *zfs; 5409 5410 /* 5411 * Go through all the groups and ZFS 5412 * sub-groups. out_share() will format the shares in 5413 * the group appropriately. 5414 */ 5415 5416 zfs = sa_get_group_attr(group, "zfs"); 5417 if (zfs != NULL) { 5418 sa_group_t zgroup; 5419 sa_free_attr_string(zfs); 5420 for (zgroup = sa_get_sub_group(group); 5421 zgroup != NULL; 5422 zgroup = sa_get_next_group(zgroup)) { 5423 5424 /* got a group, so display it */ 5425 out_share(out, zgroup, proto); 5426 } 5427 } else { 5428 out_share(out, group, proto); 5429 } 5430 } 5431 } 5432 5433 int 5434 sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 5435 { 5436 char *protocol = "nfs"; 5437 char *options = NULL; 5438 char *description = NULL; 5439 char *groupname = NULL; 5440 char *sharepath = NULL; 5441 char *resource = NULL; 5442 char *groupstatus = NULL; 5443 int persist = SA_SHARE_TRANSIENT; 5444 int argsused = 0; 5445 int c; 5446 int ret = SA_OK; 5447 int zfs = 0; 5448 int true_legacy = 0; 5449 int curtype = SA_SHARE_TRANSIENT; 5450 char cmd[MAXPATHLEN]; 5451 sa_group_t group = NULL; 5452 sa_resource_t rsrc = NULL; 5453 sa_share_t share; 5454 char dir[MAXPATHLEN]; 5455 uint64_t features; 5456 #ifdef lint 5457 flags = flags; 5458 #endif 5459 5460 while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 5461 switch (c) { 5462 case 'd': 5463 description = optarg; 5464 argsused++; 5465 break; 5466 case 'F': 5467 protocol = optarg; 5468 if (!sa_valid_protocol(protocol)) { 5469 if (format_legacy_path(cmd, MAXPATHLEN, 5470 protocol, "share") == 0 && 5471 check_legacy_cmd(cmd)) { 5472 true_legacy++; 5473 } else { 5474 (void) fprintf(stderr, gettext( 5475 "Invalid protocol specified: " 5476 "%s\n"), protocol); 5477 return (SA_INVALID_PROTOCOL); 5478 } 5479 } 5480 break; 5481 case 'o': 5482 options = optarg; 5483 argsused++; 5484 break; 5485 case 'p': 5486 persist = SA_SHARE_PERMANENT; 5487 argsused++; 5488 break; 5489 case 'h': 5490 /* optopt on valid arg isn't defined */ 5491 optopt = c; 5492 /*FALLTHROUGH*/ 5493 case '?': 5494 default: 5495 /* 5496 * Since a bad option gets to here, sort it 5497 * out and return a syntax error return value 5498 * if necessary. 5499 */ 5500 switch (optopt) { 5501 default: 5502 ret = SA_LEGACY_ERR; 5503 break; 5504 case 'h': 5505 case '?': 5506 break; 5507 } 5508 (void) fprintf(stderr, gettext("usage: %s\n"), 5509 sa_get_usage(USAGE_SHARE)); 5510 return (ret); 5511 } 5512 } 5513 5514 /* Have the info so construct what is needed */ 5515 if (!argsused && optind == argc) { 5516 /* display current info in share format */ 5517 (void) output_legacy_file(stdout, protocol, handle); 5518 return (ret); 5519 } 5520 5521 /* We are modifying the configuration */ 5522 if (optind == argc) { 5523 (void) fprintf(stderr, gettext("usage: %s\n"), 5524 sa_get_usage(USAGE_SHARE)); 5525 return (SA_LEGACY_ERR); 5526 } 5527 if (true_legacy) { 5528 /* If still using legacy share/unshare, exec it */ 5529 ret = run_legacy_command(cmd, argv); 5530 return (ret); 5531 } 5532 5533 sharepath = argv[optind++]; 5534 if (optind < argc) { 5535 resource = argv[optind]; 5536 groupname = strchr(resource, '@'); 5537 if (groupname != NULL) 5538 *groupname++ = '\0'; 5539 } 5540 if (realpath(sharepath, dir) == NULL) 5541 ret = SA_BAD_PATH; 5542 else 5543 sharepath = dir; 5544 if (ret == SA_OK) 5545 share = sa_find_share(handle, sharepath); 5546 else 5547 share = NULL; 5548 5549 features = sa_proto_get_featureset(protocol); 5550 5551 if (groupname != NULL) { 5552 ret = SA_NOT_ALLOWED; 5553 } else if (ret == SA_OK) { 5554 char *legacygroup; 5555 /* 5556 * The legacy group is always present and zfs groups 5557 * come and go. zfs shares may be in sub-groups and 5558 * the zfs share will already be in that group so it 5559 * isn't an error. If the protocol is "smb", the group 5560 * "smb" is used when "default" would otherwise be 5561 * used. "default" is NFS only and "smb" is SMB only. 5562 */ 5563 if (strcmp(protocol, "smb") == 0) 5564 legacygroup = "smb"; 5565 else 5566 legacygroup = "default"; 5567 5568 /* 5569 * If the share exists (not NULL), then make sure it 5570 * is one we want to handle by getting the parent 5571 * group. 5572 */ 5573 if (share != NULL) { 5574 group = sa_get_parent_group(share); 5575 } else { 5576 group = sa_get_group(handle, legacygroup); 5577 if (group == NULL && strcmp(legacygroup, "smb") == 0) { 5578 /* 5579 * This group may not exist, so create 5580 * as necessary. It only contains the 5581 * "smb" protocol. 5582 */ 5583 group = sa_create_group(handle, legacygroup, 5584 &ret); 5585 if (group != NULL) 5586 (void) sa_create_optionset(group, 5587 protocol); 5588 } 5589 } 5590 5591 if (group == NULL) { 5592 ret = SA_SYSTEM_ERR; 5593 goto err; 5594 } 5595 5596 groupstatus = group_status(group); 5597 if (share == NULL) { 5598 share = sa_add_share(group, sharepath, 5599 persist, &ret); 5600 if (share == NULL && 5601 ret == SA_DUPLICATE_NAME) { 5602 /* 5603 * Could be a ZFS path being started 5604 */ 5605 if (sa_zfs_is_shared(handle, 5606 sharepath)) { 5607 ret = SA_OK; 5608 group = sa_get_group(handle, 5609 "zfs"); 5610 if (group == NULL) { 5611 /* 5612 * This shouldn't 5613 * happen. 5614 */ 5615 ret = SA_CONFIG_ERR; 5616 } else { 5617 share = sa_add_share( 5618 group, sharepath, 5619 persist, &ret); 5620 } 5621 } 5622 } 5623 } else { 5624 char *type; 5625 /* 5626 * May want to change persist state, but the 5627 * important thing is to change options. We 5628 * need to change them regardless of the 5629 * source. 5630 */ 5631 5632 if (sa_zfs_is_shared(handle, sharepath)) { 5633 zfs = 1; 5634 } 5635 remove_all_options(share, protocol); 5636 type = sa_get_share_attr(share, "type"); 5637 if (type != NULL && 5638 strcmp(type, "transient") != 0) { 5639 curtype = SA_SHARE_PERMANENT; 5640 } 5641 if (type != NULL) 5642 sa_free_attr_string(type); 5643 if (curtype != persist) { 5644 (void) sa_set_share_attr(share, "type", 5645 persist == SA_SHARE_PERMANENT ? 5646 "persist" : "transient"); 5647 } 5648 } 5649 5650 /* 5651 * If there is a resource name, we may 5652 * actually care about it if this is share for 5653 * a protocol that uses resource level sharing 5654 * (SMB). We need to find the resource and, if 5655 * it exists, make sure it belongs to the 5656 * current share. If it doesn't exist, attempt 5657 * to create it. 5658 */ 5659 5660 if (ret == SA_OK && resource != NULL) { 5661 rsrc = sa_find_resource(handle, resource); 5662 if (rsrc != NULL) { 5663 if (share != sa_get_resource_parent(rsrc)) 5664 ret = SA_DUPLICATE_NAME; 5665 } else { 5666 rsrc = sa_add_resource(share, resource, 5667 persist, &ret); 5668 } 5669 if (features & SA_FEATURE_RESOURCE) 5670 share = rsrc; 5671 } 5672 5673 /* Have a group to hold this share path */ 5674 if (ret == SA_OK && options != NULL && 5675 strlen(options) > 0) { 5676 ret = sa_parse_legacy_options(share, 5677 options, 5678 protocol); 5679 } 5680 if (!zfs) { 5681 /* 5682 * ZFS shares never have a description 5683 * and we can't store the values so 5684 * don't try. 5685 */ 5686 if (ret == SA_OK && description != NULL) 5687 ret = sa_set_share_description(share, 5688 description); 5689 } 5690 if (ret == SA_OK && 5691 strcmp(groupstatus, "enabled") == 0) { 5692 if (rsrc != share) 5693 ret = sa_enable_share(share, protocol); 5694 else 5695 ret = sa_enable_resource(rsrc, 5696 protocol); 5697 if (ret == SA_OK && 5698 persist == SA_SHARE_PERMANENT) { 5699 (void) sa_update_legacy(share, 5700 protocol); 5701 } 5702 if (ret == SA_OK) 5703 ret = sa_update_config(handle); 5704 } 5705 } 5706 err: 5707 if (ret != SA_OK) { 5708 (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 5709 sharepath, sa_errorstr(ret)); 5710 ret = SA_LEGACY_ERR; 5711 } 5712 return (ret); 5713 } 5714 5715 /* 5716 * sa_legacy_unshare(flags, argc, argv) 5717 * 5718 * Implements the original unshare command. 5719 */ 5720 int 5721 sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 5722 { 5723 char *protocol = "nfs"; /* for now */ 5724 char *options = NULL; 5725 char *sharepath = NULL; 5726 int persist = SA_SHARE_TRANSIENT; 5727 int argsused = 0; 5728 int c; 5729 int ret = SA_OK; 5730 int true_legacy = 0; 5731 uint64_t features = 0; 5732 sa_resource_t resource = NULL; 5733 char cmd[MAXPATHLEN]; 5734 #ifdef lint 5735 flags = flags; 5736 options = options; 5737 #endif 5738 5739 while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 5740 switch (c) { 5741 case 'F': 5742 protocol = optarg; 5743 if (!sa_valid_protocol(protocol)) { 5744 if (format_legacy_path(cmd, MAXPATHLEN, 5745 protocol, "unshare") == 0 && 5746 check_legacy_cmd(cmd)) { 5747 true_legacy++; 5748 } else { 5749 (void) printf(gettext( 5750 "Invalid file system name\n")); 5751 return (SA_INVALID_PROTOCOL); 5752 } 5753 } 5754 break; 5755 case 'o': 5756 options = optarg; 5757 argsused++; 5758 break; 5759 case 'p': 5760 persist = SA_SHARE_PERMANENT; 5761 argsused++; 5762 break; 5763 case 'h': 5764 /* optopt on valid arg isn't defined */ 5765 optopt = c; 5766 /*FALLTHROUGH*/ 5767 case '?': 5768 default: 5769 /* 5770 * Since a bad option gets to here, sort it 5771 * out and return a syntax error return value 5772 * if necessary. 5773 */ 5774 switch (optopt) { 5775 default: 5776 ret = SA_LEGACY_ERR; 5777 break; 5778 case 'h': 5779 case '?': 5780 break; 5781 } 5782 (void) printf(gettext("usage: %s\n"), 5783 sa_get_usage(USAGE_UNSHARE)); 5784 return (ret); 5785 } 5786 } 5787 5788 /* Have the info so construct what is needed */ 5789 if (optind == argc || (optind + 1) < argc || options != NULL) { 5790 ret = SA_SYNTAX_ERR; 5791 } else { 5792 sa_share_t share; 5793 char dir[MAXPATHLEN]; 5794 if (true_legacy) { 5795 /* if still using legacy share/unshare, exec it */ 5796 ret = run_legacy_command(cmd, argv); 5797 return (ret); 5798 } 5799 /* 5800 * Find the path in the internal configuration. If it 5801 * isn't found, attempt to resolve the path via 5802 * realpath() and try again. 5803 */ 5804 sharepath = argv[optind++]; 5805 share = sa_find_share(handle, sharepath); 5806 if (share == NULL) { 5807 if (realpath(sharepath, dir) == NULL) { 5808 ret = SA_NO_SUCH_PATH; 5809 } else { 5810 share = sa_find_share(handle, dir); 5811 } 5812 } 5813 if (share == NULL) { 5814 /* Could be a resource name so check that next */ 5815 features = sa_proto_get_featureset(protocol); 5816 resource = sa_find_resource(handle, sharepath); 5817 if (resource != NULL) { 5818 share = sa_get_resource_parent(resource); 5819 if (features & SA_FEATURE_RESOURCE) 5820 (void) sa_disable_resource(resource, 5821 protocol); 5822 if (persist == SA_SHARE_PERMANENT) { 5823 ret = sa_remove_resource(resource); 5824 if (ret == SA_OK) 5825 ret = sa_update_config(handle); 5826 } 5827 /* 5828 * If we still have a resource on the 5829 * share, we don't disable the share 5830 * itself. IF there aren't anymore, we 5831 * need to remove the share. The 5832 * removal will be done in the next 5833 * section if appropriate. 5834 */ 5835 resource = sa_get_share_resource(share, NULL); 5836 if (resource != NULL) 5837 share = NULL; 5838 } else if (ret == SA_OK) { 5839 /* Didn't find path and no resource */ 5840 ret = SA_BAD_PATH; 5841 } 5842 } 5843 if (share != NULL && resource == NULL) { 5844 ret = sa_disable_share(share, protocol); 5845 /* 5846 * Errors are ok and removal should still occur. The 5847 * legacy unshare is more forgiving of errors than the 5848 * remove-share subcommand which may need the force 5849 * flag set for some error conditions. That is, the 5850 * "unshare" command will always unshare if it can 5851 * while "remove-share" might require the force option. 5852 */ 5853 if (persist == SA_SHARE_PERMANENT) { 5854 ret = sa_remove_share(share); 5855 if (ret == SA_OK) 5856 ret = sa_update_config(handle); 5857 } 5858 } else if (ret == SA_OK && share == NULL && resource == NULL) { 5859 /* 5860 * If both share and resource are NULL, then 5861 * share not found. If one or the other was 5862 * found or there was an earlier error, we 5863 * assume it was handled earlier. 5864 */ 5865 ret = SA_NOT_SHARED; 5866 } 5867 } 5868 switch (ret) { 5869 default: 5870 (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 5871 ret = SA_LEGACY_ERR; 5872 break; 5873 case SA_SYNTAX_ERR: 5874 (void) printf(gettext("usage: %s\n"), 5875 sa_get_usage(USAGE_UNSHARE)); 5876 break; 5877 case SA_OK: 5878 break; 5879 } 5880 return (ret); 5881 } 5882 5883 /* 5884 * Common commands that implement the sub-commands used by all 5885 * protocols. The entries are found via the lookup command 5886 */ 5887 5888 static sa_command_t commands[] = { 5889 {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 5890 {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 5891 {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 5892 {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 5893 {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 5894 {"list", 0, sa_list, USAGE_LIST}, 5895 {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 5896 {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 5897 {"set", 0, sa_set, USAGE_SET, SVC_SET}, 5898 {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 5899 {"show", 0, sa_show, USAGE_SHOW}, 5900 {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 5901 {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 5902 SVC_SET|SVC_ACTION}, 5903 {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 5904 {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 5905 {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 5906 {NULL, 0, NULL, 0} 5907 }; 5908 5909 static char * 5910 sa_get_usage(sa_usage_t index) 5911 { 5912 char *ret = NULL; 5913 switch (index) { 5914 case USAGE_ADD_SHARE: 5915 ret = gettext("add-share [-nth] [-r resource-name] " 5916 "[-d \"description text\"] -s sharepath group"); 5917 break; 5918 case USAGE_CREATE: 5919 ret = gettext( 5920 "create [-nvh] [-P proto [-p property=value]] group"); 5921 break; 5922 case USAGE_DELETE: 5923 ret = gettext("delete [-nvh] [-P proto] [-f] group"); 5924 break; 5925 case USAGE_DISABLE: 5926 ret = gettext("disable [-nvh] {-a | group ...}"); 5927 break; 5928 case USAGE_ENABLE: 5929 ret = gettext("enable [-nvh] {-a | group ...}"); 5930 break; 5931 case USAGE_LIST: 5932 ret = gettext("list [-vh] [-P proto]"); 5933 break; 5934 case USAGE_MOVE_SHARE: 5935 ret = gettext( 5936 "move-share [-nvh] -s sharepath destination-group"); 5937 break; 5938 case USAGE_REMOVE_SHARE: 5939 ret = gettext( 5940 "remove-share [-fnvh] {-s sharepath | -r resource} " 5941 "group"); 5942 break; 5943 case USAGE_SET: 5944 ret = gettext("set [-nvh] -P proto [-S optspace] " 5945 "[-p property=value]* [-s sharepath] [-r resource]] " 5946 "group"); 5947 break; 5948 case USAGE_SET_SECURITY: 5949 ret = gettext("set-security [-nvh] -P proto -S security-type " 5950 "[-p property=value]* group"); 5951 break; 5952 case USAGE_SET_SHARE: 5953 ret = gettext("set-share [-nh] [-r resource] " 5954 "[-d \"description text\"] -s sharepath group"); 5955 break; 5956 case USAGE_SHOW: 5957 ret = gettext("show [-pvxh] [-P proto] [group ...]"); 5958 break; 5959 case USAGE_SHARE: 5960 ret = gettext("share [-F fstype] [-p] [-o optionlist]" 5961 "[-d description] [pathname [resourcename]]"); 5962 break; 5963 case USAGE_START: 5964 ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 5965 break; 5966 case USAGE_STOP: 5967 ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 5968 break; 5969 case USAGE_UNSET: 5970 ret = gettext("unset [-nvh] -P proto [-S optspace] " 5971 "[-p property]* group"); 5972 break; 5973 case USAGE_UNSET_SECURITY: 5974 ret = gettext("unset-security [-nvh] -P proto " 5975 "-S security-type [-p property]* group"); 5976 break; 5977 case USAGE_UNSHARE: 5978 ret = gettext( 5979 "unshare [-F fstype] [-p] [-o optionlist] sharepath"); 5980 break; 5981 } 5982 return (ret); 5983 } 5984 5985 /* 5986 * sa_lookup(cmd, proto) 5987 * 5988 * Lookup the sub-command. proto isn't currently used, but it may 5989 * eventually provide a way to provide protocol specific sub-commands. 5990 */ 5991 sa_command_t * 5992 sa_lookup(char *cmd, char *proto) 5993 { 5994 int i; 5995 size_t len; 5996 #ifdef lint 5997 proto = proto; 5998 #endif 5999 6000 len = strlen(cmd); 6001 for (i = 0; commands[i].cmdname != NULL; i++) { 6002 if (strncmp(cmd, commands[i].cmdname, len) == 0) 6003 return (&commands[i]); 6004 } 6005 return (NULL); 6006 } 6007 6008 void 6009 sub_command_help(char *proto) 6010 { 6011 int i; 6012 #ifdef lint 6013 proto = proto; 6014 #endif 6015 6016 (void) printf(gettext("\tsub-commands:\n")); 6017 for (i = 0; commands[i].cmdname != NULL; i++) { 6018 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 6019 (void) printf("\t%s\n", 6020 sa_get_usage((sa_usage_t)commands[i].cmdidx)); 6021 } 6022 } 6023