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