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