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