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 2006 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 52 static char *sa_get_usage(sa_usage_t); 53 54 /* 55 * Implementation of the common sub-commands supported by sharemgr. 56 * A number of helper functions are also included. 57 */ 58 59 /* 60 * has_protocol(group, proto) 61 * If the group has an optionset with the specified protocol, 62 * return true (1) otherwise false (0). 63 */ 64 static int 65 has_protocol(sa_group_t group, char *protocol) 66 { 67 sa_optionset_t optionset; 68 int result = 0; 69 70 optionset = sa_get_optionset(group, protocol); 71 if (optionset != NULL) { 72 result++; 73 } 74 return (result); 75 } 76 77 /* 78 * add_list(list, item) 79 * Adds a new list member that points to item to the list. 80 * If list is NULL, it starts a new list. The function returns 81 * the first member of the list. 82 */ 83 struct list * 84 add_list(struct list *listp, void *item, void *data) 85 { 86 struct list *new, *tmp; 87 88 new = malloc(sizeof (struct list)); 89 if (new != NULL) { 90 new->next = NULL; 91 new->item = item; 92 new->itemdata = data; 93 } else { 94 return (listp); 95 } 96 97 if (listp == NULL) 98 return (new); 99 100 for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 101 /* get to end of list */ 102 } 103 tmp->next = new; 104 return (listp); 105 } 106 107 /* 108 * free_list(list) 109 * Given a list, free all the members of the list; 110 */ 111 static void 112 free_list(struct list *listp) 113 { 114 struct list *tmp; 115 while (listp != NULL) { 116 tmp = listp; 117 listp = listp->next; 118 free(tmp); 119 } 120 } 121 122 /* 123 * check_authorization(instname, which) 124 * 125 * Checks to see if the specific type of authorization in which is 126 * enabled for the user in this SMF service instance. 127 */ 128 129 static int 130 check_authorization(char *instname, int which) 131 { 132 scf_handle_t *handle = NULL; 133 scf_simple_prop_t *prop = NULL; 134 char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 135 char *authstr = NULL; 136 ssize_t numauths; 137 int ret = 1; 138 uid_t uid; 139 struct passwd *pw = NULL; 140 141 uid = getuid(); 142 pw = getpwuid(uid); 143 if (pw == NULL) 144 ret = 0; 145 146 if (ret == 1) { 147 /* since names are restricted to SA_MAX_NAME_LEN won't overflow */ 148 (void) snprintf(svcstring, sizeof (svcstring), 149 "%s:%s", SA_SVC_FMRI_BASE, instname); 150 handle = scf_handle_create(SCF_VERSION); 151 if (handle != NULL) { 152 if (scf_handle_bind(handle) == 0) { 153 switch (which) { 154 case SVC_SET: 155 prop = scf_simple_prop_get(handle, svcstring, 156 "general", 157 SVC_AUTH_VALUE); 158 break; 159 case SVC_ACTION: 160 prop = scf_simple_prop_get(handle, svcstring, 161 "general", 162 SVC_AUTH_ACTION); 163 break; 164 } 165 } 166 } 167 } 168 /* make sure we have an authorization string property */ 169 if (prop != NULL) { 170 int i; 171 numauths = scf_simple_prop_numvalues(prop); 172 for (ret = 0, i = 0; i < numauths; i++) { 173 authstr = scf_simple_prop_next_astring(prop); 174 if (authstr != NULL) { 175 /* check if this user has one of the strings */ 176 if (chkauthattr(authstr, pw->pw_name)) { 177 ret = 1; 178 break; 179 } 180 } 181 } 182 endauthattr(); 183 scf_simple_prop_free(prop); 184 } else { 185 /* no authorization string defined */ 186 ret = 0; 187 } 188 if (handle != NULL) 189 scf_handle_destroy(handle); 190 return (ret); 191 } 192 193 /* 194 * check_authorizations(instname, flags) 195 * 196 * check all the needed authorizations for the user in this service 197 * instance. Return value of 1(true) or 0(false) indicates whether 198 * there are authorizations for the user or not. 199 */ 200 201 static int 202 check_authorizations(char *instname, int flags) 203 { 204 int ret1 = 0; 205 int ret2 = 0; 206 int ret; 207 208 if (flags & SVC_SET) 209 ret1 = check_authorization(instname, SVC_SET); 210 if (flags & SVC_ACTION) 211 ret2 = check_authorization(instname, SVC_ACTION); 212 switch (flags) { 213 case SVC_ACTION: 214 ret = ret2; 215 break; 216 case SVC_SET: 217 ret = ret1; 218 break; 219 case SVC_ACTION|SVC_SET: 220 ret = ret1 & ret2; 221 break; 222 default: 223 /* if not flags set, we assume we don't need authorizations */ 224 ret = 1; 225 } 226 return (ret); 227 } 228 229 /* 230 * enable_all_groups(list, setstate, online, update) 231 * Given a list of groups, enable each one found. If update is 232 * not NULL, then update all the shares for the protocol that was 233 * passed in. 234 */ 235 static int 236 enable_all_groups(struct list *work, int setstate, int online, char *update) 237 { 238 sa_share_t share; 239 int ret = SA_OK; 240 char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 241 char *state; 242 char *name; 243 char *zfs = NULL; 244 int dozfs = 0; 245 sa_group_t group; 246 247 while (work != NULL && ret == SA_OK) { 248 group = (sa_group_t)work->item; 249 /* if itemdata != NULL then a single share */ 250 if (work->itemdata != NULL) { 251 ret = sa_enable_share((sa_share_t)work->itemdata, NULL); 252 } 253 if (setstate) 254 ret = sa_set_group_attr(group, "state", 255 "enabled"); 256 if (ret == SA_OK) { 257 /* if itemdata == NULL then the whole group */ 258 if (work->itemdata == NULL) { 259 for (share = sa_get_share(group, NULL); 260 share != NULL; share = sa_get_next_share(share)) { 261 if (update != NULL) 262 (void) sa_update_legacy(share, update); 263 ret = sa_enable_share(share, NULL); 264 } 265 } 266 if (online) { 267 name = sa_get_group_attr(group, "name"); 268 zfs = sa_get_group_attr(group, "zfs"); 269 if (name != NULL) { 270 if (zfs == NULL) { 271 (void) snprintf(instance, sizeof (instance), 272 "%s:%s", 273 SA_SVC_FMRI_BASE, name); 274 state = smf_get_state(instance); 275 if (state == NULL || 276 strcmp(state, "online") != 0) { 277 (void) smf_enable_instance(instance, 0); 278 free(state); 279 } 280 } else { 281 dozfs++; 282 sa_free_attr_string(zfs); 283 zfs = NULL; 284 } 285 if (name != NULL) 286 sa_free_attr_string(name); 287 } 288 } else { 289 zfs = sa_get_group_attr(group, "zfs"); 290 if (zfs != NULL) { 291 dozfs++; 292 sa_free_attr_string(zfs); 293 zfs = NULL; 294 } 295 } 296 work = work->next; 297 } 298 } 299 if (ret == SA_OK) { 300 ret = sa_update_config(); 301 } 302 /* do ZFS last to allow everything to get updated */ 303 if (ret == SA_OK && dozfs) { 304 FILE *sys; 305 int err; 306 sys = popen(ZFS_SHAREALL, "r"); 307 if (sys != NULL) { 308 err = pclose(sys); 309 if (err != 0) 310 ret = SA_SYSTEM_ERR; 311 } else { 312 ret = SA_SYSTEM_ERR; 313 } 314 } 315 return (ret); 316 } 317 318 /* 319 * chk_opt(optlistp, security, proto) 320 * 321 * Do a sanity check on the optlist provided for the protocol. This 322 * is a syntax check and verification that the property is either a 323 * general or specific to a names optionset. 324 */ 325 326 static int 327 chk_opt(struct options *optlistp, int security, char *proto) 328 { 329 struct options *optlist; 330 char *sep = ""; 331 int notfirst = 0; 332 int ret; 333 334 for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 335 char *optname; 336 337 optname = optlist->optname; 338 ret = OPT_ADD_OK; 339 /* extract property/value pair */ 340 if (sa_is_security(optname, proto)) { 341 if (!security) 342 ret = OPT_ADD_SECURITY; 343 } else { 344 if (security) 345 ret = OPT_ADD_PROPERTY; 346 } 347 if (ret != OPT_ADD_OK) { 348 if (notfirst == 0) 349 (void) printf(gettext("Property syntax error: ")); 350 switch (ret) { 351 case OPT_ADD_SYNTAX: 352 (void) printf(gettext("%ssyntax error: %s"), 353 sep, optname); 354 sep = ", "; 355 break; 356 case OPT_ADD_SECURITY: 357 (void) printf(gettext("%s%s requires -S"), 358 optname, sep); 359 sep = ", "; 360 break; 361 case OPT_ADD_PROPERTY: 362 (void) printf(gettext("%s%s not supported with -S"), 363 optname, sep); 364 sep = ", "; 365 break; 366 } 367 notfirst++; 368 } 369 } 370 if (notfirst) { 371 (void) printf("\n"); 372 ret = SA_SYNTAX_ERR; 373 } 374 return (ret); 375 } 376 377 /* 378 * free_opt(optlist) 379 * Free the specified option list. 380 */ 381 static void 382 free_opt(struct options *optlist) 383 { 384 struct options *nextopt; 385 while (optlist != NULL) { 386 nextopt = optlist->next; 387 free(optlist); 388 optlist = nextopt; 389 } 390 } 391 392 /* 393 * check property list for valid properties 394 * A null value is a remove which is always valid. 395 */ 396 static int 397 valid_options(struct options *optlist, char *proto, void *object, char *sec) 398 { 399 int ret = SA_OK; 400 struct options *cur; 401 sa_property_t prop; 402 sa_optionset_t parent = NULL; 403 404 if (object != NULL) { 405 if (sec == NULL) 406 parent = sa_get_optionset(object, proto); 407 else 408 parent = sa_get_security(object, sec, proto); 409 } 410 411 for (cur = optlist; cur != NULL; cur = cur->next) { 412 if (cur->optvalue != NULL) { 413 prop = sa_create_property(cur->optname, cur->optvalue); 414 if (prop == NULL) 415 ret = SA_NO_MEMORY; 416 if (ret != SA_OK || 417 (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 418 (void) printf(gettext("Could not add property %s: %s\n"), 419 cur->optname, 420 sa_errorstr(ret)); 421 } 422 (void) sa_remove_property(prop); 423 } 424 } 425 return (ret); 426 } 427 428 /* 429 * add_optionset(group, optlist, protocol, *err) 430 * Add the options in optlist to an optionset and then add the optionset 431 * to the group. 432 * 433 * The return value indicates if there was a "change" while errors are 434 * returned via the *err parameters. 435 */ 436 static int 437 add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 438 { 439 sa_optionset_t optionset; 440 int ret = SA_OK; 441 int result = 0; 442 443 optionset = sa_get_optionset(group, proto); 444 if (optionset == NULL) { 445 optionset = sa_create_optionset(group, proto); 446 result = 1; /* adding a protocol is a change */ 447 } 448 if (optionset != NULL) { 449 while (optlist != NULL) { 450 sa_property_t prop; 451 prop = sa_get_property(optionset, optlist->optname); 452 if (prop == NULL) { 453 /* 454 * add the property, but only if it is 455 * a non-NULL or non-zero length value 456 */ 457 if (optlist->optvalue != NULL) { 458 prop = sa_create_property(optlist->optname, 459 optlist->optvalue); 460 if (prop != NULL) { 461 ret = sa_valid_property(optionset, proto, prop); 462 if (ret != SA_OK) { 463 (void) sa_remove_property(prop); 464 (void) printf(gettext("Could not add property " 465 "%s: %s\n"), 466 optlist->optname, 467 sa_errorstr(ret)); 468 } 469 } 470 if (ret == SA_OK) { 471 ret = sa_add_property(optionset, prop); 472 if (ret != SA_OK) { 473 (void) printf(gettext("Could not add property" 474 " %s: %s\n"), 475 optlist->optname, 476 sa_errorstr(ret)); 477 } else { 478 /* there was a change */ 479 result = 1; 480 } 481 } 482 } 483 } else { 484 ret = sa_update_property(prop, optlist->optvalue); 485 /* should check to see if value changed */ 486 if (ret != SA_OK) { 487 (void) printf(gettext("Could not update " 488 "property %s: %s\n"), 489 optlist->optname, 490 sa_errorstr(ret)); 491 } else { 492 result = 1; 493 } 494 } 495 optlist = optlist->next; 496 } 497 ret = sa_commit_properties(optionset, 0); 498 } 499 if (err != NULL) 500 *err = ret; 501 return (result); 502 } 503 504 /* 505 * sa_create(flags, argc, argv) 506 * create a new group 507 * this may or may not have a protocol associated with it. 508 * No protocol means "all" protocols in this case. 509 */ 510 static int 511 sa_create(int flags, int argc, char *argv[]) 512 { 513 char *groupname; 514 515 sa_group_t group; 516 int verbose = 0; 517 int dryrun = 0; 518 int c; 519 char *protocol = NULL; 520 int ret = SA_OK; 521 struct options *optlist = NULL; 522 int err = 0; 523 int auth; 524 525 while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) { 526 switch (c) { 527 case 'v': 528 verbose++; 529 break; 530 case 'n': 531 dryrun++; 532 break; 533 case 'P': 534 protocol = optarg; 535 if (!sa_valid_protocol(protocol)) { 536 (void) printf(gettext("Invalid protocol specified: %s\n"), 537 protocol); 538 return (SA_INVALID_PROTOCOL); 539 } 540 break; 541 case 'p': 542 ret = add_opt(&optlist, optarg, 0); 543 switch (ret) { 544 case OPT_ADD_SYNTAX: 545 (void) printf(gettext("Property syntax error for " 546 "property: %s\n"), 547 optarg); 548 return (SA_SYNTAX_ERR); 549 case OPT_ADD_SECURITY: 550 (void) printf(gettext("Security properties need " 551 "to be set with set-security: %s\n"), 552 optarg); 553 return (SA_SYNTAX_ERR); 554 default: 555 break; 556 } 557 558 break; 559 default: 560 case 'h': 561 case '?': 562 (void) printf(gettext("usage: %s\n"), 563 sa_get_usage(USAGE_CREATE)); 564 return (0); 565 } 566 } 567 568 if (optind >= argc) { 569 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 570 (void) printf(gettext("\tgroup must be specified.\n")); 571 return (SA_BAD_PATH); 572 } 573 574 if ((optind + 1) < argc) { 575 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 576 (void) printf(gettext("\textraneous group(s) at end\n")); 577 return (SA_SYNTAX_ERR); 578 } 579 580 if (protocol == NULL && optlist != NULL) { 581 /* lookup default protocol */ 582 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 583 (void) printf(gettext("\tprotocol must be specified " 584 "with properties\n")); 585 return (SA_INVALID_PROTOCOL); 586 } 587 588 if (optlist != NULL) 589 ret = chk_opt(optlist, 0, protocol); 590 if (ret == OPT_ADD_SECURITY) { 591 (void) printf(gettext("Security properties not " 592 "supported with create\n")); 593 return (SA_SYNTAX_ERR); 594 } 595 596 /* 597 * if a group already exists, we can only add a new protocol 598 * to it and not create a new one or add the same protocol 599 * again. 600 */ 601 602 groupname = argv[optind]; 603 604 auth = check_authorizations(groupname, flags); 605 606 group = sa_get_group(groupname); 607 if (group != NULL) { 608 /* group exists so must be a protocol add */ 609 if (protocol != NULL) { 610 if (has_protocol(group, protocol)) { 611 (void) printf(gettext("Group \"%s\" already exists" 612 " with protocol %s\n"), 613 groupname, protocol); 614 ret = SA_DUPLICATE_NAME; 615 } 616 } else { 617 /* must add new protocol */ 618 (void) printf(gettext("Group already exists and no protocol" 619 " specified.\n")); 620 ret = SA_DUPLICATE_NAME; 621 } 622 } else { 623 /* 624 * is it a valid name? Must comply with SMF instance 625 * name restrictions. 626 */ 627 if (!sa_valid_group_name(groupname)) { 628 ret = SA_INVALID_NAME; 629 (void) printf(gettext("Invalid group name: %s\n"), groupname); 630 } 631 } 632 if (ret == SA_OK) { 633 /* check protocol vs optlist */ 634 if (optlist != NULL) { 635 /* check options, if any, for validity */ 636 ret = valid_options(optlist, protocol, group, NULL); 637 } 638 } 639 if (ret == SA_OK && !dryrun) { 640 if (group == NULL) { 641 group = sa_create_group((char *)groupname, &err); 642 } 643 if (group != NULL) { 644 sa_optionset_t optionset; 645 if (optlist != NULL) { 646 (void) add_optionset(group, optlist, protocol, &ret); 647 } else if (protocol != NULL) { 648 optionset = sa_create_optionset(group, protocol); 649 if (optionset == NULL) 650 ret = SA_NO_MEMORY; 651 } else if (protocol == NULL) { 652 char **protolist; 653 int numprotos, i; 654 numprotos = sa_get_protocols(&protolist); 655 for (i = 0; i < numprotos; i++) { 656 optionset = sa_create_optionset(group, protolist[i]); 657 } 658 if (protolist != NULL) 659 free(protolist); 660 } 661 /* 662 * we have a group and legal additions 663 */ 664 if (ret == SA_OK) { 665 /* 666 * commit to configuration for protocols that 667 * need to do block updates. For NFS, this 668 * doesn't do anything but it will be run for 669 * all protocols that implement the 670 * appropriate plugin. 671 */ 672 ret = sa_update_config(); 673 } else { 674 if (group != NULL) 675 (void) sa_remove_group(group); 676 } 677 } else { 678 ret = err; 679 (void) printf(gettext("Could not create group: %s\n"), 680 sa_errorstr(ret)); 681 } 682 } 683 if (dryrun && ret == SA_OK && !auth && verbose) { 684 (void) printf(gettext("Command would fail: %s\n"), 685 sa_errorstr(SA_NO_PERMISSION)); 686 ret = SA_NO_PERMISSION; 687 } 688 free_opt(optlist); 689 return (ret); 690 } 691 692 /* 693 * group_status(group) 694 * 695 * return the current status (enabled/disabled) of the group. 696 */ 697 698 static char * 699 group_status(sa_group_t group) 700 { 701 char *state; 702 int enabled = 0; 703 704 state = sa_get_group_attr(group, "state"); 705 if (state != NULL) { 706 if (strcmp(state, "enabled") == 0) { 707 enabled = 1; 708 } 709 sa_free_attr_string(state); 710 } 711 return (enabled ? gettext("enabled") : gettext("disabled")); 712 } 713 714 /* 715 * sa_delete(flags, argc, argv) 716 * 717 * Delete a group. 718 */ 719 720 static int 721 sa_delete(int flags, int argc, char *argv[]) 722 { 723 char *groupname; 724 sa_group_t group; 725 sa_share_t share; 726 int verbose = 0; 727 int dryrun = 0; 728 int force = 0; 729 int c; 730 char *protocol = NULL; 731 char *sectype = NULL; 732 int ret = SA_OK; 733 int auth; 734 735 while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 736 switch (c) { 737 case 'v': 738 verbose++; 739 break; 740 case 'n': 741 dryrun++; 742 break; 743 case 'P': 744 protocol = optarg; 745 if (!sa_valid_protocol(protocol)) { 746 (void) printf(gettext("Invalid protocol specified: %s\n"), 747 protocol); 748 return (SA_INVALID_PROTOCOL); 749 } 750 break; 751 case 'S': 752 sectype = optarg; 753 break; 754 case 'f': 755 force++; 756 break; 757 default: 758 case 'h': 759 case '?': 760 (void) printf(gettext("usage: %s\n"), 761 sa_get_usage(USAGE_DELETE)); 762 return (0); 763 } 764 } 765 766 if (optind >= argc) { 767 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 768 (void) printf(gettext("\tgroup must be specified.\n")); 769 return (SA_SYNTAX_ERR); 770 } 771 772 if ((optind + 1) < argc) { 773 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 774 (void) printf(gettext("\textraneous group(s) at end\n")); 775 return (SA_SYNTAX_ERR); 776 } 777 778 if (sectype != NULL && protocol == NULL) { 779 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 780 (void) printf(gettext("\tsecurity requires protocol to be " 781 "specified.\n")); 782 return (SA_SYNTAX_ERR); 783 } 784 785 /* 786 * Determine if the group already exists since it must in 787 * order to be removed. 788 * 789 * We can delete when: 790 * 791 * - group is empty 792 * - force flag is set 793 * - if protocol specified, only delete the protocol 794 */ 795 796 groupname = argv[optind]; 797 group = sa_get_group(groupname); 798 if (group == NULL) { 799 ret = SA_NO_SUCH_GROUP; 800 } else { 801 auth = check_authorizations(groupname, flags); 802 if (protocol == NULL) { 803 share = sa_get_share(group, NULL); 804 if (share != NULL) 805 ret = SA_BUSY; 806 if (share == NULL || (share != NULL && force == 1)) { 807 ret = SA_OK; 808 if (!dryrun) { 809 while (share != NULL) { 810 sa_share_t next_share; 811 next_share = sa_get_next_share(share); 812 /* 813 * need to do the disable of each 814 * share, but don't actually do 815 * anything on a dryrun. 816 */ 817 ret = sa_disable_share(share, NULL); 818 ret = sa_remove_share(share); 819 share = next_share; 820 } 821 ret = sa_remove_group(group); 822 } 823 } 824 /* commit to configuration if not a dryrun */ 825 if (!dryrun && ret == SA_OK) { 826 ret = sa_update_config(); 827 } 828 } else { 829 /* a protocol delete */ 830 sa_optionset_t optionset; 831 sa_security_t security; 832 if (sectype != NULL) { 833 /* only delete specified security */ 834 security = sa_get_security(group, sectype, protocol); 835 if (security != NULL && !dryrun) { 836 ret = sa_destroy_security(security); 837 } else { 838 ret = SA_INVALID_PROTOCOL; 839 } 840 } else { 841 optionset = sa_get_optionset(group, protocol); 842 if (optionset != NULL && !dryrun) { 843 /* have an optionset with protocol to delete */ 844 ret = sa_destroy_optionset(optionset); 845 /* 846 * now find all security sets for the protocol 847 * and remove them. Don't remove other 848 * protocols. 849 */ 850 for (security = sa_get_security(group, NULL, NULL); 851 ret == SA_OK && security != NULL; 852 security = sa_get_next_security(security)) { 853 char *secprot; 854 855 secprot = sa_get_security_attr(security, "type"); 856 if (secprot != NULL && 857 strcmp(secprot, protocol) == 0) 858 ret = sa_destroy_security(security); 859 if (secprot != NULL) 860 sa_free_attr_string(secprot); 861 } 862 } else { 863 if (!dryrun) 864 ret = SA_INVALID_PROTOCOL; 865 } 866 } 867 } 868 } 869 if (ret != SA_OK) { 870 (void) printf(gettext("Could not delete group: %s\n"), 871 sa_errorstr(ret)); 872 } else if (dryrun && !auth && verbose) { 873 (void) printf(gettext("Command would fail: %s\n"), 874 sa_errorstr(SA_NO_PERMISSION)); 875 } 876 return (ret); 877 } 878 879 /* 880 * strndupr(*buff, str, buffsize) 881 * 882 * used with small strings to duplicate and possibly increase the 883 * buffer size of a string. 884 */ 885 static char * 886 strndupr(char *buff, char *str, int *buffsize) 887 { 888 int limit; 889 char *orig_buff = buff; 890 891 if (buff == NULL) { 892 buff = (char *)malloc(64); 893 if (buff == NULL) 894 return (NULL); 895 *buffsize = 64; 896 buff[0] = '\0'; 897 } 898 limit = strlen(buff) + strlen(str) + 1; 899 if (limit > *buffsize) { 900 limit = *buffsize = *buffsize + ((limit / 64) + 64); 901 buff = realloc(buff, limit); 902 } 903 if (buff != NULL) { 904 (void) strcat(buff, str); 905 } else { 906 /* if it fails, fail it hard */ 907 if (orig_buff != NULL) 908 free(orig_buff); 909 } 910 return (buff); 911 } 912 913 /* 914 * group_proto(group) 915 * 916 * return a string of all the protocols (space separated) associated 917 * with this group. 918 */ 919 920 static char * 921 group_proto(sa_group_t group) 922 { 923 sa_optionset_t optionset; 924 char *proto; 925 char *buff = NULL; 926 int buffsize = 0; 927 int addspace = 0; 928 /* 929 * get the protocol list by finding the optionsets on this 930 * group and extracting the type value. The initial call to 931 * strndupr() initailizes buff. 932 */ 933 buff = strndupr(buff, "", &buffsize); 934 if (buff != NULL) { 935 for (optionset = sa_get_optionset(group, NULL); 936 optionset != NULL && buff != NULL; 937 optionset = sa_get_next_optionset(optionset)) { 938 /* 939 * extract out the protocol type from this optionset 940 * and append it to the buffer "buff". strndupr() will 941 * reallocate space as necessay. 942 */ 943 proto = sa_get_optionset_attr(optionset, "type"); 944 if (proto != NULL) { 945 if (addspace++) 946 buff = strndupr(buff, " ", &buffsize); 947 buff = strndupr(buff, proto, &buffsize); 948 sa_free_attr_string(proto); 949 } 950 } 951 } 952 return (buff); 953 } 954 955 /* 956 * sa_list(flags, argc, argv) 957 * 958 * implements the "list" subcommand to list groups and optionally 959 * their state and protocols. 960 */ 961 962 static int 963 sa_list(int flags, int argc, char *argv[]) 964 { 965 sa_group_t group; 966 int verbose = 0; 967 int c; 968 char *protocol = NULL; 969 #ifdef lint 970 flags = flags; 971 #endif 972 973 while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 974 switch (c) { 975 case 'v': 976 verbose++; 977 break; 978 case 'P': 979 protocol = optarg; 980 if (!sa_valid_protocol(protocol)) { 981 (void) printf(gettext("Invalid protocol specified:" 982 "%s\n"), 983 protocol); 984 return (SA_INVALID_PROTOCOL); 985 } 986 break; 987 default: 988 case 'h': 989 case '?': 990 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_LIST)); 991 return (0); 992 } 993 } 994 995 for (group = sa_get_group(NULL); group != NULL; 996 group = sa_get_next_group(group)) { 997 char *name; 998 char *proto; 999 if (protocol == NULL || has_protocol(group, protocol)) { 1000 name = sa_get_group_attr(group, "name"); 1001 if (name != NULL && (verbose > 1 || name[0] != '#')) { 1002 (void) printf("%s", (char *)name); 1003 if (verbose) { 1004 /* 1005 * need the list of protocols 1006 * and current status once 1007 * available. 1008 */ 1009 (void) printf("\t%s", group_status(group)); 1010 proto = group_proto(group); 1011 if (proto != NULL) { 1012 (void) printf("\t%s", (char *)proto); 1013 free(proto); 1014 } 1015 } 1016 (void) printf("\n"); 1017 } 1018 if (name != NULL) 1019 sa_free_attr_string(name); 1020 } 1021 } 1022 return (0); 1023 } 1024 1025 /* 1026 * out_properties(optionset, proto, sec) 1027 * 1028 * Format the properties and encode the protocol and optional named 1029 * optionset into the string. 1030 * 1031 * format is protocol[:name]=(property-list) 1032 */ 1033 1034 static void 1035 out_properties(sa_optionset_t optionset, char *proto, char *sec) 1036 { 1037 char *type; 1038 char *value; 1039 int spacer; 1040 sa_property_t prop; 1041 1042 if (sec == NULL) { 1043 (void) printf(" %s=(", proto ? proto : gettext("all")); 1044 } else { 1045 (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 1046 } 1047 1048 for (spacer = 0, prop = sa_get_property(optionset, NULL); 1049 prop != NULL; prop = sa_get_next_property(prop)) { 1050 1051 /* 1052 * extract the property name/value and output with 1053 * appropriate spacing. I.e. no prefixed space the 1054 * first time through but a space on subsequent 1055 * properties. 1056 */ 1057 type = sa_get_property_attr(prop, "type"); 1058 value = sa_get_property_attr(prop, "value"); 1059 if (type != NULL) { 1060 (void) printf("%s%s=", spacer ? " " : "", type); 1061 spacer = 1; 1062 if (value != NULL) 1063 (void) printf("\"%s\"", value); 1064 else 1065 (void) printf("\"\""); 1066 } 1067 if (type != NULL) 1068 sa_free_attr_string(type); 1069 if (value != NULL) 1070 sa_free_attr_string(value); 1071 } 1072 (void) printf(")"); 1073 } 1074 1075 /* 1076 * show_properties(group, protocol, prefix) 1077 * 1078 * print the properties for a group. If protocol is NULL, do all 1079 * protocols otherwise only the specified protocol. All security 1080 * (named groups specific to the protocol) are included. 1081 * 1082 * The "prefix" is always applied. The caller knows whether it wants 1083 * some type of prefix string (white space) or not. Once the prefix 1084 * has been output, it is reduced to the zero length string for the 1085 * remainder of the property output. 1086 */ 1087 1088 static void 1089 show_properties(sa_group_t group, char *protocol, char *prefix) 1090 { 1091 sa_optionset_t optionset; 1092 sa_security_t security; 1093 char *value; 1094 char *secvalue; 1095 1096 if (protocol != NULL) { 1097 optionset = sa_get_optionset(group, protocol); 1098 if (optionset != NULL) { 1099 (void) printf("%s", prefix); 1100 prefix = ""; 1101 out_properties(optionset, protocol, NULL); 1102 } 1103 security = sa_get_security(group, protocol, NULL); 1104 if (security != NULL) { 1105 (void) printf("%s", prefix); 1106 prefix = ""; 1107 out_properties(security, protocol, NULL); 1108 } 1109 } else { 1110 for (optionset = sa_get_optionset(group, protocol); 1111 optionset != NULL; 1112 optionset = sa_get_next_optionset(optionset)) { 1113 1114 value = sa_get_optionset_attr(optionset, "type"); 1115 (void) printf("%s", prefix); 1116 prefix = ""; 1117 out_properties(optionset, value, 0); 1118 if (value != NULL) 1119 sa_free_attr_string(value); 1120 } 1121 for (security = sa_get_security(group, NULL, protocol); 1122 security != NULL; 1123 security = sa_get_next_security(security)) { 1124 1125 value = sa_get_security_attr(security, "type"); 1126 secvalue = sa_get_security_attr(security, "sectype"); 1127 (void) printf("%s", prefix); 1128 prefix = ""; 1129 out_properties(security, value, secvalue); 1130 if (value != NULL) 1131 sa_free_attr_string(value); 1132 if (secvalue != NULL) 1133 sa_free_attr_string(secvalue); 1134 } 1135 } 1136 } 1137 1138 /* 1139 * show_group(group, verbose, properties, proto, subgroup) 1140 * 1141 * helper function to show the contents of a group. 1142 */ 1143 1144 static void 1145 show_group(sa_group_t group, int verbose, int properties, char *proto, 1146 char *subgroup) 1147 { 1148 sa_share_t share; 1149 char *groupname; 1150 char *sharepath; 1151 char *resource; 1152 char *description; 1153 char *type; 1154 char *zfs = NULL; 1155 int iszfs = 0; 1156 1157 groupname = sa_get_group_attr(group, "name"); 1158 if (groupname != NULL) { 1159 if (proto != NULL && !has_protocol(group, proto)) { 1160 sa_free_attr_string(groupname); 1161 return; 1162 } 1163 /* 1164 * check to see if the group is managed by ZFS. If 1165 * there is an attribute, then it is. A non-NULL zfs 1166 * variable will trigger the different way to display 1167 * and will remove the transient property indicator 1168 * from the output. 1169 */ 1170 zfs = sa_get_group_attr(group, "zfs"); 1171 if (zfs != NULL) { 1172 iszfs = 1; 1173 sa_free_attr_string(zfs); 1174 } 1175 share = sa_get_share(group, NULL); 1176 if (subgroup == NULL) 1177 (void) printf("%s", groupname); 1178 else 1179 (void) printf(" %s/%s", subgroup, groupname); 1180 if (properties) { 1181 show_properties(group, proto, ""); 1182 } 1183 (void) printf("\n"); 1184 if (strcmp(groupname, "zfs") == 0) { 1185 sa_group_t zgroup; 1186 1187 for (zgroup = sa_get_sub_group(group); zgroup != NULL; 1188 zgroup = sa_get_next_group(zgroup)) { 1189 show_group(zgroup, verbose, properties, proto, "zfs"); 1190 } 1191 sa_free_attr_string(groupname); 1192 return; 1193 } 1194 /* 1195 * have a group, so list the contents. Resource and 1196 * description are only listed if verbose is set. 1197 */ 1198 for (share = sa_get_share(group, NULL); share != NULL; 1199 share = sa_get_next_share(share)) { 1200 sharepath = sa_get_share_attr(share, "path"); 1201 if (sharepath != NULL) { 1202 if (verbose) { 1203 resource = sa_get_share_attr(share, "resource"); 1204 description = sa_get_share_description(share); 1205 type = sa_get_share_attr(share, "type"); 1206 if (type != NULL && !iszfs && 1207 strcmp(type, "transient") == 0) 1208 (void) printf("\t* "); 1209 else 1210 (void) printf("\t "); 1211 if (resource != NULL && strlen(resource) > 0) { 1212 (void) printf("%s=%s", resource, sharepath); 1213 } else { 1214 (void) printf("%s", sharepath); 1215 } 1216 if (resource != NULL) 1217 sa_free_attr_string(resource); 1218 if (properties) 1219 show_properties(share, NULL, "\t"); 1220 if (description != NULL) { 1221 if (strlen(description) > 0) { 1222 (void) printf("\t\"%s\"", description); 1223 } 1224 sa_free_share_description(description); 1225 } 1226 if (type != NULL) 1227 sa_free_attr_string(type); 1228 } else { 1229 (void) printf("\t%s", sharepath); 1230 if (properties) 1231 show_properties(share, NULL, "\t"); 1232 } 1233 (void) printf("\n"); 1234 sa_free_attr_string(sharepath); 1235 } 1236 } 1237 } 1238 if (groupname != NULL) { 1239 sa_free_attr_string(groupname); 1240 } 1241 } 1242 1243 /* 1244 * show_group_xml_init() 1245 * 1246 * Create an XML document that will be used to display config info via 1247 * XML format. 1248 */ 1249 1250 xmlDocPtr 1251 show_group_xml_init() 1252 { 1253 xmlDocPtr doc; 1254 xmlNodePtr root; 1255 1256 doc = xmlNewDoc((xmlChar *)"1.0"); 1257 if (doc != NULL) { 1258 root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 1259 if (root != NULL) 1260 xmlDocSetRootElement(doc, root); 1261 } 1262 return (doc); 1263 } 1264 1265 /* 1266 * show_group_xml(doc, group) 1267 * 1268 * Copy the group info into the XML doc. 1269 */ 1270 1271 static void 1272 show_group_xml(xmlDocPtr doc, sa_group_t group) 1273 { 1274 xmlNodePtr node; 1275 xmlNodePtr root; 1276 1277 root = xmlDocGetRootElement(doc); 1278 node = xmlCopyNode((xmlNodePtr)group, 1); 1279 if (node != NULL && root != NULL) { 1280 xmlAddChild(root, node); 1281 /* 1282 * In the future, we may have interally used tags that 1283 * should not appear in the XML output. Remove 1284 * anything we don't want to show here. 1285 */ 1286 } 1287 } 1288 1289 /* 1290 * sa_show(flags, argc, argv) 1291 * 1292 * Implements the show subcommand. 1293 */ 1294 1295 int 1296 sa_show(int flags, int argc, char *argv[]) 1297 { 1298 sa_group_t group; 1299 int verbose = 0; 1300 int properties = 0; 1301 int c; 1302 int ret = SA_OK; 1303 char *protocol = NULL; 1304 int xml = 0; 1305 xmlDocPtr doc; 1306 #ifdef lint 1307 flags = flags; 1308 #endif 1309 1310 while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 1311 switch (c) { 1312 case 'v': 1313 verbose++; 1314 break; 1315 case 'p': 1316 properties++; 1317 break; 1318 case 'P': 1319 protocol = optarg; 1320 if (!sa_valid_protocol(protocol)) { 1321 (void) printf(gettext("Invalid protocol specified: %s\n"), 1322 protocol); 1323 return (SA_INVALID_PROTOCOL); 1324 } 1325 break; 1326 case 'x': 1327 xml++; 1328 break; 1329 default: 1330 case 'h': 1331 case '?': 1332 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SHOW)); 1333 return (0); 1334 } 1335 } 1336 1337 if (xml) { 1338 doc = show_group_xml_init(); 1339 if (doc == NULL) 1340 ret = SA_NO_MEMORY; 1341 } 1342 1343 if (optind == argc) { 1344 /* no group specified so go through them all */ 1345 for (group = sa_get_group(NULL); group != NULL; 1346 group = sa_get_next_group(group)) { 1347 /* 1348 * have a group so check if one we want and then list 1349 * contents with appropriate options. 1350 */ 1351 if (xml) 1352 show_group_xml(doc, group); 1353 else 1354 show_group(group, verbose, properties, protocol, NULL); 1355 } 1356 } else { 1357 /* have a specified list of groups */ 1358 for (; optind < argc; optind++) { 1359 group = sa_get_group(argv[optind]); 1360 if (group != NULL) { 1361 if (xml) 1362 show_group_xml(doc, group); 1363 else 1364 show_group(group, verbose, properties, protocol, NULL); 1365 } else { 1366 (void) printf(gettext("%s: not found\n"), argv[optind]); 1367 ret = SA_NO_SUCH_GROUP; 1368 } 1369 } 1370 } 1371 if (xml && ret == SA_OK) { 1372 xmlDocFormatDump(stdout, doc, 1); 1373 xmlFreeDoc(doc); 1374 } 1375 return (ret); 1376 1377 } 1378 1379 /* 1380 * enable_share(group, share, update_legacy) 1381 * 1382 * helper function to enable a share if the group is enabled. 1383 */ 1384 1385 static int 1386 enable_share(sa_group_t group, sa_share_t share, int update_legacy) 1387 { 1388 char *value; 1389 int enabled; 1390 sa_optionset_t optionset; 1391 int ret = SA_OK; 1392 char *zfs = NULL; 1393 int iszfs = 0; 1394 1395 /* 1396 * need to enable this share if the group is enabled but not 1397 * otherwise. The enable is also done on each protocol 1398 * represented in the group. 1399 */ 1400 value = sa_get_group_attr(group, "state"); 1401 enabled = value != NULL && strcmp(value, "enabled") == 0; 1402 if (value != NULL) 1403 sa_free_attr_string(value); 1404 /* remove legacy config if necessary */ 1405 if (update_legacy) 1406 ret = sa_delete_legacy(share); 1407 zfs = sa_get_group_attr(group, "zfs"); 1408 if (zfs != NULL) { 1409 iszfs++; 1410 sa_free_attr_string(zfs); 1411 } 1412 1413 /* 1414 * Step through each optionset at the group level and 1415 * enable the share based on the protocol type. This 1416 * works because protocols must be set on the group 1417 * for the protocol to be enabled. 1418 */ 1419 for (optionset = sa_get_optionset(group, NULL); 1420 optionset != NULL && ret == SA_OK; 1421 optionset = sa_get_next_optionset(optionset)) { 1422 value = sa_get_optionset_attr(optionset, "type"); 1423 if (value != NULL) { 1424 if (enabled) 1425 ret = sa_enable_share(share, value); 1426 if (update_legacy && !iszfs) 1427 (void) sa_update_legacy(share, value); 1428 sa_free_attr_string(value); 1429 } 1430 } 1431 if (ret == SA_OK) 1432 (void) sa_update_config(); 1433 return (ret); 1434 } 1435 1436 /* 1437 * sa_addshare(flags, argc, argv) 1438 * 1439 * implements add-share subcommand. 1440 */ 1441 1442 int 1443 sa_addshare(int flags, int argc, char *argv[]) 1444 { 1445 int verbose = 0; 1446 int dryrun = 0; 1447 int c; 1448 int ret = SA_OK; 1449 sa_group_t group; 1450 sa_share_t share; 1451 char *sharepath = NULL; 1452 char *description = NULL; 1453 char *resource = NULL; 1454 int persist = SA_SHARE_PERMANENT; /* default to persist */ 1455 int auth; 1456 char dir[MAXPATHLEN]; 1457 1458 while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 1459 switch (c) { 1460 case 'n': 1461 dryrun++; 1462 break; 1463 case 'v': 1464 verbose++; 1465 break; 1466 case 'd': 1467 description = optarg; 1468 break; 1469 case 'r': 1470 resource = optarg; 1471 break; 1472 case 's': 1473 /* 1474 * save share path into group. Currently limit 1475 * to one share per command. 1476 */ 1477 if (sharepath != NULL) { 1478 (void) printf(gettext("Adding multiple shares not" 1479 "supported\n")); 1480 return (1); 1481 } 1482 sharepath = optarg; 1483 break; 1484 case 't': 1485 persist = SA_SHARE_TRANSIENT; 1486 break; 1487 default: 1488 case 'h': 1489 case '?': 1490 (void) printf(gettext("usage: %s\n"), 1491 sa_get_usage(USAGE_ADD_SHARE)); 1492 return (0); 1493 } 1494 } 1495 1496 if (optind >= argc) { 1497 (void) printf(gettext("usage: %s\n"), 1498 sa_get_usage(USAGE_ADD_SHARE)); 1499 if (dryrun || sharepath != NULL || description != NULL || 1500 resource != NULL || verbose || persist) { 1501 (void) printf(gettext("\tgroup must be specified\n")); 1502 ret = SA_NO_SUCH_GROUP; 1503 } else { 1504 ret = SA_OK; 1505 } 1506 } else { 1507 if (sharepath == NULL) { 1508 (void) printf(gettext("usage: %s\n"), 1509 sa_get_usage(USAGE_ADD_SHARE)); 1510 (void) printf(gettext("\t-s sharepath must be specified\n")); 1511 ret = SA_BAD_PATH; 1512 } 1513 if (ret == SA_OK) { 1514 if (realpath(sharepath, dir) == NULL) { 1515 ret = SA_BAD_PATH; 1516 (void) printf(gettext("Path is not valid: %s\n"), 1517 sharepath); 1518 } else { 1519 sharepath = dir; 1520 } 1521 } 1522 if (ret == SA_OK && resource != NULL) { 1523 /* check for valid syntax */ 1524 if (strpbrk(resource, " \t/") != NULL) { 1525 (void) printf(gettext("usage: %s\n"), 1526 sa_get_usage(USAGE_ADD_SHARE)); 1527 (void) printf(gettext("\tresource must not contain white" 1528 "space or '/' characters\n")); 1529 ret = SA_BAD_PATH; 1530 } 1531 } 1532 if (ret == SA_OK) { 1533 group = sa_get_group(argv[optind]); 1534 if (group != NULL) { 1535 auth = check_authorizations(argv[optind], flags); 1536 share = sa_find_share(sharepath); 1537 if (share != NULL) { 1538 group = sa_get_parent_group(share); 1539 if (group != NULL) { 1540 char *groupname; 1541 groupname = sa_get_group_attr(group, "name"); 1542 if (groupname != NULL) { 1543 (void) printf(gettext("Share path already " 1544 "shared in group " 1545 "\"%s\": %s\n"), 1546 groupname, sharepath); 1547 sa_free_attr_string(groupname); 1548 } else { 1549 (void) printf(gettext("Share path already" 1550 "shared: %s\n"), 1551 groupname, sharepath); 1552 } 1553 } else { 1554 (void) printf(gettext("Share path %s already " 1555 "shared\n"), 1556 sharepath); 1557 } 1558 ret = SA_DUPLICATE_NAME; 1559 } else { 1560 /* 1561 * need to check that resource name is unique 1562 * at some point. 1563 */ 1564 if (dryrun) 1565 ret = sa_check_path(group, sharepath); 1566 else 1567 share = sa_add_share(group, sharepath, 1568 persist, &ret); 1569 if (!dryrun && share == NULL) { 1570 (void) printf(gettext("Could not add share: " 1571 "%s\n"), 1572 sa_errorstr(ret)); 1573 } else { 1574 if (!dryrun && ret == SA_OK) { 1575 if (resource != NULL) { 1576 if (strpbrk(resource, " \t/") == NULL) { 1577 ret = sa_set_share_attr(share, 1578 "resource", 1579 resource); 1580 } 1581 } 1582 if (ret == SA_OK && description != NULL) { 1583 ret = sa_set_share_description(share, 1584 description); 1585 } 1586 if (ret == SA_OK) { 1587 /* now enable the share(s) */ 1588 ret = enable_share(group, share, 1); 1589 ret = sa_update_config(); 1590 } 1591 switch (ret) { 1592 case SA_DUPLICATE_NAME: 1593 (void) printf(gettext("Resource name in" 1594 "use: %s\n"), 1595 resource); 1596 break; 1597 default: 1598 (void) printf(gettext("Could not set " 1599 "attribute: %s\n"), 1600 sa_errorstr(ret)); 1601 break; 1602 case SA_OK: 1603 break; 1604 } 1605 } else if (dryrun && ret == SA_OK && 1606 !auth && verbose) { 1607 (void) printf(gettext("Command would fail: " 1608 "%s\n"), 1609 sa_errorstr(SA_NO_PERMISSION)); 1610 ret = SA_NO_PERMISSION; 1611 } 1612 } 1613 } 1614 } else { 1615 (void) printf(gettext("Group \"%s\" not found\n"), 1616 argv[optind]); 1617 ret = SA_NO_SUCH_GROUP; 1618 } 1619 } 1620 } 1621 return (ret); 1622 } 1623 1624 /* 1625 * sa_moveshare(flags, argc, argv) 1626 * 1627 * implements move-share subcommand. 1628 */ 1629 1630 int 1631 sa_moveshare(int flags, int argc, char *argv[]) 1632 { 1633 int verbose = 0; 1634 int dryrun = 0; 1635 int c; 1636 int ret = SA_OK; 1637 sa_group_t group; 1638 sa_share_t share; 1639 char *sharepath = NULL; 1640 int authsrc = 0, authdst = 0; 1641 1642 while ((c = getopt(argc, argv, "?hvns:")) != EOF) { 1643 switch (c) { 1644 case 'n': 1645 dryrun++; 1646 break; 1647 case 'v': 1648 verbose++; 1649 break; 1650 case 's': 1651 /* 1652 * remove share path from group. Currently limit 1653 * to one share per command. 1654 */ 1655 if (sharepath != NULL) { 1656 (void) printf(gettext("Moving multiple shares not" 1657 "supported\n")); 1658 return (SA_BAD_PATH); 1659 } 1660 sharepath = optarg; 1661 break; 1662 default: 1663 case 'h': 1664 case '?': 1665 (void) printf(gettext("usage: %s\n"), 1666 sa_get_usage(USAGE_MOVE_SHARE)); 1667 return (0); 1668 } 1669 } 1670 1671 if (optind >= argc || sharepath == NULL) { 1672 (void) printf(gettext("usage: %s\n"), 1673 sa_get_usage(USAGE_MOVE_SHARE)); 1674 if (dryrun || verbose || sharepath != NULL) { 1675 (void) printf(gettext("\tgroup must be specified\n")); 1676 ret = SA_NO_SUCH_GROUP; 1677 } else { 1678 if (sharepath == NULL) { 1679 ret = SA_SYNTAX_ERR; 1680 (void) printf(gettext("\tsharepath must be specified\n")); 1681 } else 1682 ret = SA_OK; 1683 } 1684 } else { 1685 if (sharepath == NULL) { 1686 (void) printf(gettext("sharepath must be specified with " 1687 "the -s option\n")); 1688 ret = SA_BAD_PATH; 1689 } else { 1690 group = sa_get_group(argv[optind]); 1691 if (group != NULL) { 1692 share = sa_find_share(sharepath); 1693 authdst = check_authorizations(argv[optind], flags); 1694 if (share == NULL) { 1695 (void) printf(gettext("Share not found: %s\n"), 1696 sharepath); 1697 ret = SA_NO_SUCH_PATH; 1698 } else { 1699 sa_group_t parent; 1700 char *zfsold; 1701 char *zfsnew; 1702 1703 parent = sa_get_parent_group(share); 1704 if (parent != NULL) { 1705 char *pname; 1706 pname = sa_get_group_attr(parent, "name"); 1707 if (pname != NULL) { 1708 authsrc = check_authorizations(pname, flags); 1709 sa_free_attr_string(pname); 1710 } 1711 zfsold = sa_get_group_attr(parent, "zfs"); 1712 zfsnew = sa_get_group_attr(group, "zfs"); 1713 if ((zfsold != NULL && zfsnew == NULL) || 1714 (zfsold == NULL && zfsnew != NULL)) { 1715 ret = SA_NOT_ALLOWED; 1716 } 1717 if (zfsold != NULL) 1718 sa_free_attr_string(zfsold); 1719 if (zfsnew != NULL) 1720 sa_free_attr_string(zfsnew); 1721 } 1722 if (!dryrun && ret == SA_OK) { 1723 ret = sa_move_share(group, share); 1724 } 1725 if (ret == SA_OK && parent != group && !dryrun) { 1726 char *oldstate; 1727 ret = sa_update_config(); 1728 /* 1729 * note that the share may need to be 1730 * "unshared" if the new group is 1731 * disabled and the old was enabled or 1732 * it may need to be share to update 1733 * if the new group is enabled. 1734 */ 1735 oldstate = sa_get_group_attr(parent, "state"); 1736 /* enable_share determines what to do */ 1737 if (strcmp(oldstate, "enabled") == 0) { 1738 (void) sa_disable_share(share, NULL); 1739 } 1740 (void) enable_share(group, share, 1); 1741 if (oldstate != NULL) 1742 sa_free_attr_string(oldstate); 1743 } 1744 if (ret != SA_OK) { 1745 (void) printf(gettext("Could not move share: %s\n"), 1746 sa_errorstr(ret)); 1747 } 1748 if (dryrun && ret == SA_OK && !(authsrc & authdst) && 1749 verbose) { 1750 (void) printf(gettext("Command would fail: %s\n"), 1751 sa_errorstr(SA_NO_PERMISSION)); 1752 } 1753 } 1754 } else { 1755 (void) printf(gettext("Group \"%s\" not found\n"), 1756 argv[optind]); 1757 ret = SA_NO_SUCH_GROUP; 1758 } 1759 } 1760 } 1761 return (ret); 1762 } 1763 1764 /* 1765 * sa_removeshare(flags, argc, argv) 1766 * 1767 * implements remove-share subcommand. 1768 */ 1769 1770 int 1771 sa_removeshare(int flags, int argc, char *argv[]) 1772 { 1773 int verbose = 0; 1774 int dryrun = 0; 1775 int force = 0; 1776 int c; 1777 int ret = SA_OK; 1778 sa_group_t group; 1779 sa_share_t share; 1780 char *sharepath = NULL; 1781 char dir[MAXPATHLEN]; 1782 int auth; 1783 1784 while ((c = getopt(argc, argv, "?hfns:v")) != EOF) { 1785 switch (c) { 1786 case 'n': 1787 dryrun++; 1788 break; 1789 case 'v': 1790 verbose++; 1791 break; 1792 case 'f': 1793 force++; 1794 break; 1795 case 's': 1796 /* 1797 * remove share path from group. Currently limit 1798 * to one share per command. 1799 */ 1800 if (sharepath != NULL) { 1801 (void) printf(gettext("Removing multiple shares not" 1802 "supported\n")); 1803 return (SA_SYNTAX_ERR); 1804 } 1805 sharepath = optarg; 1806 break; 1807 default: 1808 case 'h': 1809 case '?': 1810 (void) printf(gettext("usage: %s\n"), 1811 sa_get_usage(USAGE_REMOVE_SHARE)); 1812 return (0); 1813 } 1814 } 1815 1816 if (optind >= argc || sharepath == NULL) { 1817 if (sharepath == NULL) { 1818 (void) printf(gettext("usage: %s\n"), 1819 sa_get_usage(USAGE_REMOVE_SHARE)); 1820 (void) printf(gettext("\t-s sharepath must be specified\n")); 1821 ret = SA_BAD_PATH; 1822 } else { 1823 ret = SA_OK; 1824 } 1825 } 1826 if (ret == SA_OK) { 1827 if (optind < argc) { 1828 if ((optind + 1) < argc) { 1829 (void) printf(gettext("Extraneous group(s) at end of " 1830 "command\n")); 1831 ret = SA_SYNTAX_ERR; 1832 } else { 1833 group = sa_get_group(argv[optind]); 1834 if (group == NULL) { 1835 (void) printf(gettext("Group \"%s\" not found\n"), 1836 argv[optind]); 1837 ret = SA_NO_SUCH_GROUP; 1838 } 1839 } 1840 } else { 1841 group = NULL; 1842 } 1843 if (ret == SA_OK) { 1844 if (realpath(sharepath, dir) == NULL) { 1845 ret = SA_BAD_PATH; 1846 (void) printf(gettext("Path is not valid: %s\n"), 1847 sharepath); 1848 } else { 1849 sharepath = dir; 1850 } 1851 } 1852 if (ret == SA_OK) { 1853 if (group != NULL) 1854 share = sa_get_share(group, sharepath); 1855 else 1856 share = sa_find_share(sharepath); 1857 if (share == NULL) { 1858 if (group != NULL) 1859 (void) printf(gettext("Share not found in group %s:" 1860 "%s\n"), 1861 argv[optind], sharepath); 1862 else 1863 (void) printf(gettext("Share not found: %s\n"), 1864 sharepath); 1865 ret = SA_NO_SUCH_PATH; 1866 } else { 1867 if (group == NULL) 1868 group = sa_get_parent_group(share); 1869 if (!dryrun) { 1870 if (ret == SA_OK) { 1871 ret = sa_disable_share(share, NULL); 1872 /* 1873 * we don't care if it fails since it 1874 * could be disabled already. 1875 */ 1876 if (ret == SA_OK || ret == SA_NO_SUCH_PATH || 1877 ret == SA_NOT_SUPPORTED) { 1878 ret = sa_remove_share(share); 1879 } 1880 if (ret == SA_OK) 1881 ret = sa_update_config(); 1882 } 1883 if (ret != SA_OK) { 1884 (void) printf(gettext("Could not remove share:" 1885 " %s\n"), 1886 sa_errorstr(ret)); 1887 } 1888 } else if (ret == SA_OK) { 1889 char *pname; 1890 pname = sa_get_group_attr(group, "name"); 1891 if (pname != NULL) { 1892 auth = check_authorizations(pname, flags); 1893 sa_free_attr_string(pname); 1894 } 1895 if (!auth && verbose) { 1896 (void) printf(gettext("Command would fail: %s\n"), 1897 sa_errorstr(SA_NO_PERMISSION)); 1898 } 1899 } 1900 } 1901 } 1902 } 1903 return (ret); 1904 } 1905 1906 /* 1907 * sa_set_share(flags, argc, argv) 1908 * 1909 * implements set-share subcommand. 1910 */ 1911 1912 int 1913 sa_set_share(int flags, int argc, char *argv[]) 1914 { 1915 int dryrun = 0; 1916 int c; 1917 int ret = SA_OK; 1918 sa_group_t group, sharegroup; 1919 sa_share_t share; 1920 char *sharepath = NULL; 1921 char *description = NULL; 1922 char *resource = NULL; 1923 int auth; 1924 int verbose = 0; 1925 1926 while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 1927 switch (c) { 1928 case 'n': 1929 dryrun++; 1930 break; 1931 case 'd': 1932 description = optarg; 1933 break; 1934 case 'r': 1935 resource = optarg; 1936 break; 1937 case 'v': 1938 verbose++; 1939 break; 1940 case 's': 1941 /* 1942 * save share path into group. Currently limit 1943 * to one share per command. 1944 */ 1945 if (sharepath != NULL) { 1946 (void) printf(gettext("Updating multiple shares not" 1947 "supported\n")); 1948 return (SA_BAD_PATH); 1949 } 1950 sharepath = optarg; 1951 break; 1952 default: 1953 case 'h': 1954 case '?': 1955 (void) printf(gettext("usage: %s\n"), 1956 sa_get_usage(USAGE_SET_SHARE)); 1957 return (SA_OK); 1958 } 1959 } 1960 if (optind >= argc || sharepath == NULL) { 1961 if (sharepath == NULL) { 1962 (void) printf(gettext("usage: %s\n"), 1963 sa_get_usage(USAGE_SET_SHARE)); 1964 (void) printf(gettext("\tgroup must be specified\n")); 1965 ret = SA_BAD_PATH; 1966 } else { 1967 ret = SA_OK; 1968 } 1969 } 1970 if ((optind + 1) < argc) { 1971 (void) printf(gettext("usage: %s\n"), 1972 sa_get_usage(USAGE_SET_SHARE)); 1973 (void) printf(gettext("\tExtraneous group(s) at end\n")); 1974 ret = SA_SYNTAX_ERR; 1975 } 1976 if (ret == SA_OK) { 1977 char *groupname; 1978 if (optind < argc) { 1979 groupname = argv[optind]; 1980 group = sa_get_group(groupname); 1981 } else { 1982 group = NULL; 1983 groupname = NULL; 1984 } 1985 share = sa_find_share(sharepath); 1986 if (share != NULL) { 1987 sharegroup = sa_get_parent_group(share); 1988 if (group != NULL && group != sharegroup) { 1989 (void) printf(gettext("Group \"%s\" does not contain " 1990 "share %s\n"), 1991 argv[optind], sharepath); 1992 ret = SA_BAD_PATH; 1993 } else { 1994 int delgroupname = 0; 1995 if (groupname == NULL) { 1996 groupname = sa_get_group_attr(sharegroup, "name"); 1997 delgroupname = 1; 1998 } 1999 if (groupname != NULL) { 2000 auth = check_authorizations(groupname, flags); 2001 if (delgroupname) { 2002 sa_free_attr_string(groupname); 2003 groupname = NULL; 2004 } 2005 } else { 2006 ret = SA_NO_MEMORY; 2007 } 2008 if (resource != NULL) { 2009 if (strpbrk(resource, " \t/") == NULL) { 2010 if (!dryrun) { 2011 ret = sa_set_share_attr(share, "resource", 2012 resource); 2013 } else { 2014 sa_share_t resshare; 2015 resshare = sa_get_resource(sharegroup, 2016 resource); 2017 if (resshare != NULL && resshare != share) 2018 ret = SA_DUPLICATE_NAME; 2019 } 2020 } else { 2021 ret = SA_BAD_PATH; 2022 (void) printf(gettext("Resource must not contain " 2023 "white space or '/'\n")); 2024 } 2025 } 2026 if (ret == SA_OK && description != NULL) { 2027 ret = sa_set_share_description(share, description); 2028 } 2029 } 2030 if (!dryrun && ret == SA_OK) { 2031 ret = sa_update_config(); 2032 } 2033 switch (ret) { 2034 case SA_DUPLICATE_NAME: 2035 (void) printf(gettext("Resource name in use: %s\n"), 2036 resource); 2037 break; 2038 default: 2039 (void) printf(gettext("Could not set attribute: %s\n"), 2040 sa_errorstr(ret)); 2041 break; 2042 case SA_OK: 2043 if (dryrun && !auth && verbose) { 2044 (void) printf(gettext("Command would fail: %s\n"), 2045 sa_errorstr(SA_NO_PERMISSION)); 2046 } 2047 break; 2048 } 2049 } else { 2050 (void) printf(gettext("Share path \"%s\" not found\n"), 2051 sharepath); 2052 ret = SA_NO_SUCH_PATH; 2053 } 2054 } 2055 return (ret); 2056 } 2057 2058 /* 2059 * add_security(group, sectype, optlist, proto, *err) 2060 * 2061 * Helper function to add a security option (named optionset) to the 2062 * group. 2063 */ 2064 2065 static int 2066 add_security(sa_group_t group, char *sectype, 2067 struct options *optlist, char *proto, int *err) 2068 { 2069 sa_security_t security; 2070 int ret = SA_OK; 2071 int result = 0; 2072 2073 sectype = sa_proto_space_alias(proto, sectype); 2074 security = sa_get_security(group, sectype, proto); 2075 if (security == NULL) { 2076 security = sa_create_security(group, sectype, proto); 2077 } 2078 if (sectype != NULL) 2079 sa_free_attr_string(sectype); 2080 if (security != NULL) { 2081 while (optlist != NULL) { 2082 sa_property_t prop; 2083 prop = sa_get_property(security, optlist->optname); 2084 if (prop == NULL) { 2085 /* 2086 * add the property, but only if it is 2087 * a non-NULL or non-zero length value 2088 */ 2089 if (optlist->optvalue != NULL) { 2090 prop = sa_create_property(optlist->optname, 2091 optlist->optvalue); 2092 if (prop != NULL) { 2093 ret = sa_valid_property(security, proto, prop); 2094 if (ret != SA_OK) { 2095 (void) sa_remove_property(prop); 2096 (void) printf(gettext("Could not add " 2097 "property %s: %s\n"), 2098 optlist->optname, 2099 sa_errorstr(ret)); 2100 } 2101 if (ret == SA_OK) { 2102 ret = sa_add_property(security, prop); 2103 if (ret != SA_OK) { 2104 (void) printf(gettext("Could not add " 2105 "property (%s=%s): %s\n"), 2106 optlist->optname, 2107 optlist->optvalue, 2108 sa_errorstr(ret)); 2109 } else { 2110 result = 1; 2111 } 2112 } 2113 } 2114 } 2115 } else { 2116 ret = sa_update_property(prop, optlist->optvalue); 2117 result = 1; /* should check if really changed */ 2118 } 2119 optlist = optlist->next; 2120 } 2121 /* 2122 * when done, properties may have all been removed but 2123 * we need to keep the security type itself until 2124 * explicitly removed. 2125 */ 2126 if (result) 2127 ret = sa_commit_properties(security, 0); 2128 } 2129 *err = ret; 2130 return (result); 2131 } 2132 2133 /* 2134 * basic_set(groupname, optlist, protocol, sharepath, dryrun) 2135 * 2136 * This function implements "set" when a name space (-S) is not 2137 * specified. It is a basic set. Options and other CLI parsing has 2138 * already been done. 2139 */ 2140 2141 static int 2142 basic_set(char *groupname, struct options *optlist, char *protocol, 2143 char *sharepath, int dryrun) 2144 { 2145 sa_group_t group; 2146 int ret = SA_OK; 2147 int change = 0; 2148 struct list *worklist = NULL; 2149 2150 group = sa_get_group(groupname); 2151 if (group != NULL) { 2152 sa_share_t share = NULL; 2153 if (sharepath != NULL) { 2154 share = sa_get_share(group, sharepath); 2155 if (share == NULL) { 2156 (void) printf(gettext("Share does not exist in group %s\n"), 2157 groupname, sharepath); 2158 ret = SA_NO_SUCH_PATH; 2159 } 2160 } 2161 if (ret == SA_OK) { 2162 /* group must exist */ 2163 ret = valid_options(optlist, protocol, 2164 share == NULL ? group : share, NULL); 2165 if (ret == SA_OK && !dryrun) { 2166 if (share != NULL) 2167 change |= add_optionset(share, optlist, protocol, 2168 &ret); 2169 else 2170 change |= add_optionset(group, optlist, protocol, 2171 &ret); 2172 if (ret == SA_OK && change) { 2173 worklist = add_list(worklist, group, share); 2174 } 2175 } 2176 } 2177 free_opt(optlist); 2178 } else { 2179 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2180 ret = SA_NO_SUCH_GROUP; 2181 } 2182 /* 2183 * we have a group and potentially legal additions 2184 */ 2185 2186 /* commit to configuration if not a dryrun */ 2187 if (!dryrun && ret == SA_OK) { 2188 if (change && worklist != NULL) { 2189 /* properties changed, so update all shares */ 2190 (void) enable_all_groups(worklist, 0, 0, protocol); 2191 } 2192 } 2193 if (worklist != NULL) 2194 free_list(worklist); 2195 return (ret); 2196 } 2197 2198 /* 2199 * space_set(groupname, optlist, protocol, sharepath, dryrun) 2200 * 2201 * This function implements "set" when a name space (-S) is 2202 * specified. It is a namespace set. Options and other CLI parsing has 2203 * already been done. 2204 */ 2205 2206 static int 2207 space_set(char *groupname, struct options *optlist, char *protocol, 2208 char *sharepath, int dryrun, char *sectype) 2209 { 2210 sa_group_t group; 2211 int ret = SA_OK; 2212 int change = 0; 2213 struct list *worklist = NULL; 2214 2215 /* 2216 * make sure protcol and sectype are valid 2217 */ 2218 2219 if (sa_proto_valid_space(protocol, sectype) == 0) { 2220 (void) printf(gettext("Option space \"%s\" not valid " 2221 "for protocol.\n"), 2222 sectype); 2223 return (SA_INVALID_SECURITY); 2224 } 2225 2226 group = sa_get_group(groupname); 2227 if (group != NULL) { 2228 sa_share_t share = NULL; 2229 if (sharepath != NULL) { 2230 share = sa_get_share(group, sharepath); 2231 if (share == NULL) { 2232 (void) printf(gettext("Share does not exist in group %s\n"), 2233 groupname, sharepath); 2234 ret = SA_NO_SUCH_PATH; 2235 } 2236 } 2237 if (ret == SA_OK) { 2238 /* group must exist */ 2239 ret = valid_options(optlist, protocol, 2240 share == NULL ? group : share, sectype); 2241 if (ret == SA_OK && !dryrun) { 2242 if (share != NULL) 2243 change = add_security(share, sectype, optlist, 2244 protocol, 2245 &ret); 2246 else 2247 change = add_security(group, sectype, optlist, 2248 protocol, 2249 &ret); 2250 if (ret != SA_OK) 2251 (void) printf(gettext("Could not set property: %s\n"), 2252 sa_errorstr(ret)); 2253 } 2254 if (ret == SA_OK && change) 2255 worklist = add_list(worklist, group, share); 2256 } 2257 free_opt(optlist); 2258 } else { 2259 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2260 ret = SA_NO_SUCH_GROUP; 2261 } 2262 /* 2263 * we have a group and potentially legal additions 2264 */ 2265 2266 /* commit to configuration if not a dryrun */ 2267 if (!dryrun && ret == 0) { 2268 if (change && worklist != NULL) { 2269 /* properties changed, so update all shares */ 2270 (void) enable_all_groups(worklist, 0, 0, protocol); 2271 } 2272 ret = sa_update_config(); 2273 } 2274 if (worklist != NULL) 2275 free_list(worklist); 2276 return (ret); 2277 } 2278 2279 /* 2280 * sa_set(flags, argc, argv) 2281 * 2282 * Implements the set subcommand. It keys off of -S to determine which 2283 * set of operations to actually do. 2284 */ 2285 2286 int 2287 sa_set(int flags, int argc, char *argv[]) 2288 { 2289 char *groupname; 2290 int verbose = 0; 2291 int dryrun = 0; 2292 int c; 2293 char *protocol = NULL; 2294 int ret = SA_OK; 2295 struct options *optlist = NULL; 2296 char *sharepath = NULL; 2297 char *optset = NULL; 2298 int auth; 2299 2300 while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2301 switch (c) { 2302 case 'v': 2303 verbose++; 2304 break; 2305 case 'n': 2306 dryrun++; 2307 break; 2308 case 'P': 2309 protocol = optarg; 2310 if (!sa_valid_protocol(protocol)) { 2311 (void) printf(gettext("Invalid protocol specified:" 2312 "%s\n"), 2313 protocol); 2314 return (SA_INVALID_PROTOCOL); 2315 } 2316 break; 2317 case 'p': 2318 ret = add_opt(&optlist, optarg, 0); 2319 switch (ret) { 2320 case OPT_ADD_SYNTAX: 2321 (void) printf(gettext("Property syntax error: %s\n"), 2322 optarg); 2323 return (SA_SYNTAX_ERR); 2324 case OPT_ADD_MEMORY: 2325 (void) printf(gettext("No memory to set property: %s\n"), 2326 optarg); 2327 return (SA_NO_MEMORY); 2328 default: 2329 break; 2330 } 2331 break; 2332 case 's': 2333 sharepath = optarg; 2334 break; 2335 case 'S': 2336 optset = optarg; 2337 break; 2338 default: 2339 case 'h': 2340 case '?': 2341 (void) printf(gettext("usage: %s\n"), 2342 sa_get_usage(USAGE_SET)); 2343 return (SA_OK); 2344 } 2345 } 2346 2347 if (optlist != NULL) 2348 ret = chk_opt(optlist, optset != NULL, protocol); 2349 2350 if (optind >= argc || (optlist == NULL && optset == NULL) || 2351 protocol == NULL || 2352 ret != OPT_ADD_OK) { 2353 char *sep = "\t"; 2354 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 2355 if (optind >= argc) { 2356 (void) printf(gettext("%sgroup must be specified"), sep); 2357 sep = ", "; 2358 } 2359 if (optlist == NULL) { 2360 (void) printf(gettext("%sat least one property must be" 2361 " specified"), sep); 2362 sep = ", "; 2363 } 2364 if (protocol == NULL) { 2365 (void) printf(gettext("%sprotocol must be specified"), sep); 2366 sep = ", "; 2367 } 2368 (void) printf("\n"); 2369 ret = SA_SYNTAX_ERR; 2370 } else { 2371 /* 2372 * if a group already exists, we can only add a new 2373 * protocol to it and not create a new one or add the 2374 * same protocol again. 2375 */ 2376 2377 groupname = argv[optind]; 2378 auth = check_authorizations(groupname, flags); 2379 if (optset == NULL) 2380 ret = basic_set(groupname, optlist, protocol, 2381 sharepath, dryrun); 2382 else 2383 ret = space_set(groupname, optlist, protocol, 2384 sharepath, dryrun, optset); 2385 if (dryrun && ret == SA_OK && !auth && verbose) { 2386 (void) printf(gettext("Command would fail: %s\n"), 2387 sa_errorstr(SA_NO_PERMISSION)); 2388 } 2389 } 2390 return (ret); 2391 } 2392 2393 /* 2394 * remove_options(group, optlist, proto, *err) 2395 * 2396 * helper function to actually remove options from a group after all 2397 * preprocessing is done. 2398 */ 2399 2400 static int 2401 remove_options(sa_group_t group, struct options *optlist, 2402 char *proto, int *err) 2403 { 2404 struct options *cur; 2405 sa_optionset_t optionset; 2406 sa_property_t prop; 2407 int change = 0; 2408 int ret = SA_OK; 2409 2410 optionset = sa_get_optionset(group, proto); 2411 if (optionset != NULL) { 2412 for (cur = optlist; cur != NULL; cur = cur->next) { 2413 prop = sa_get_property(optionset, cur->optname); 2414 if (prop != NULL) { 2415 ret = sa_remove_property(prop); 2416 if (ret != SA_OK) 2417 break; 2418 change = 1; 2419 } 2420 } 2421 } 2422 if (ret == SA_OK && change) 2423 ret = sa_commit_properties(optionset, 0); 2424 2425 if (err != NULL) 2426 *err = ret; 2427 return (change); 2428 } 2429 2430 /* 2431 * valid_unset(group, optlist, proto) 2432 * 2433 * Sanity check the optlist to make sure they can be removed. Issue an 2434 * error if a property doesn't exist. 2435 */ 2436 2437 static int 2438 valid_unset(sa_group_t group, struct options *optlist, char *proto) 2439 { 2440 struct options *cur; 2441 sa_optionset_t optionset; 2442 sa_property_t prop; 2443 int ret = SA_OK; 2444 2445 optionset = sa_get_optionset(group, proto); 2446 if (optionset != NULL) { 2447 for (cur = optlist; cur != NULL; cur = cur->next) { 2448 prop = sa_get_property(optionset, cur->optname); 2449 if (prop == NULL) { 2450 (void) printf(gettext("Could not unset property %s:" 2451 " not set\n"), 2452 cur->optname); 2453 ret = SA_NO_SUCH_PROP; 2454 } 2455 } 2456 } 2457 return (ret); 2458 } 2459 2460 /* 2461 * valid_unset_security(group, optlist, proto) 2462 * 2463 * Sanity check the optlist to make sure they can be removed. Issue an 2464 * error if a property doesn't exist. 2465 */ 2466 2467 static int 2468 valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 2469 char *sectype) 2470 { 2471 struct options *cur; 2472 sa_security_t security; 2473 sa_property_t prop; 2474 int ret = SA_OK; 2475 char *sec; 2476 2477 sec = sa_proto_space_alias(proto, sectype); 2478 security = sa_get_security(group, sec, proto); 2479 if (security != NULL) { 2480 for (cur = optlist; cur != NULL; cur = cur->next) { 2481 prop = sa_get_property(security, cur->optname); 2482 if (prop == NULL) { 2483 (void) printf(gettext("Could not unset property %s:" 2484 " not set\n"), 2485 cur->optname); 2486 ret = SA_NO_SUCH_PROP; 2487 } 2488 } 2489 } else { 2490 (void) printf(gettext("Could not unset %s: space not defined\n"), 2491 sectype); 2492 ret = SA_NO_SUCH_SECURITY; 2493 } 2494 if (sec != NULL) 2495 sa_free_attr_string(sec); 2496 return (ret); 2497 } 2498 2499 /* 2500 * remove_security(group, optlist, proto) 2501 * 2502 * Remove the properties since they were checked as valid. 2503 */ 2504 2505 static int 2506 remove_security(sa_group_t group, char *sectype, 2507 struct options *optlist, char *proto, int *err) 2508 { 2509 sa_security_t security; 2510 int ret = SA_OK; 2511 int change = 0; 2512 2513 sectype = sa_proto_space_alias(proto, sectype); 2514 security = sa_get_security(group, sectype, proto); 2515 if (sectype != NULL) 2516 sa_free_attr_string(sectype); 2517 2518 if (security != NULL) { 2519 while (optlist != NULL) { 2520 sa_property_t prop; 2521 prop = sa_get_property(security, optlist->optname); 2522 if (prop != NULL) { 2523 ret = sa_remove_property(prop); 2524 if (ret != SA_OK) 2525 break; 2526 change = 1; 2527 } 2528 optlist = optlist->next; 2529 } 2530 /* 2531 * when done, properties may have all been removed but 2532 * we need to keep the security type itself until 2533 * explicitly removed. 2534 */ 2535 if (ret == SA_OK && change) 2536 ret = sa_commit_properties(security, 0); 2537 } else { 2538 ret = SA_NO_SUCH_PROP; 2539 } 2540 if (err != NULL) 2541 *err = ret; 2542 return (change); 2543 } 2544 2545 /* 2546 * basic_unset(groupname, optlist, protocol, sharepath, dryrun) 2547 * 2548 * unset non-named optionset properties. 2549 */ 2550 2551 static int 2552 basic_unset(char *groupname, struct options *optlist, char *protocol, 2553 char *sharepath, int dryrun) 2554 { 2555 sa_group_t group; 2556 int ret = SA_OK; 2557 int change = 0; 2558 struct list *worklist = NULL; 2559 2560 group = sa_get_group(groupname); 2561 if (group != NULL) { 2562 sa_share_t share = NULL; 2563 if (sharepath != NULL) { 2564 share = sa_get_share(group, sharepath); 2565 if (share == NULL) { 2566 (void) printf(gettext("Share does not exist in group %s\n"), 2567 groupname, sharepath); 2568 ret = SA_NO_SUCH_PATH; 2569 } 2570 } 2571 if (ret == SA_OK) { 2572 /* group must exist */ 2573 ret = valid_unset(share != NULL ? share : group, 2574 optlist, protocol); 2575 if (ret == SA_OK && !dryrun) { 2576 if (share != NULL) { 2577 sa_optionset_t optionset; 2578 sa_property_t prop; 2579 change |= remove_options(share, optlist, protocol, 2580 &ret); 2581 /* if a share optionset is empty, remove it */ 2582 optionset = sa_get_optionset((sa_share_t)share, 2583 protocol); 2584 if (optionset != NULL) { 2585 prop = sa_get_property(optionset, NULL); 2586 if (prop == NULL) 2587 (void) sa_destroy_optionset(optionset); 2588 } 2589 } else { 2590 change |= remove_options(group, optlist, protocol, 2591 &ret); 2592 } 2593 if (ret == SA_OK && change) 2594 worklist = add_list(worklist, group, share); 2595 if (ret != SA_OK) 2596 (void) printf(gettext("Could not remove properties:" 2597 "%s\n"), 2598 sa_errorstr(ret)); 2599 } 2600 } else { 2601 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2602 ret = SA_NO_SUCH_GROUP; 2603 } 2604 free_opt(optlist); 2605 } 2606 2607 /* 2608 * we have a group and potentially legal additions 2609 */ 2610 /* commit to configuration if not a dryrun */ 2611 if (!dryrun && ret == SA_OK) { 2612 if (change && worklist != NULL) { 2613 /* properties changed, so update all shares */ 2614 (void) enable_all_groups(worklist, 0, 0, protocol); 2615 } 2616 } 2617 if (worklist != NULL) 2618 free_list(worklist); 2619 return (ret); 2620 } 2621 2622 /* 2623 * space_unset(groupname, optlist, protocol, sharepath, dryrun) 2624 * 2625 * unset named optionset properties. 2626 */ 2627 static int 2628 space_unset(char *groupname, struct options *optlist, char *protocol, 2629 char *sharepath, int dryrun, char *sectype) 2630 { 2631 sa_group_t group; 2632 int ret = SA_OK; 2633 int change = 0; 2634 struct list *worklist = NULL; 2635 2636 group = sa_get_group(groupname); 2637 if (group != NULL) { 2638 sa_share_t share = NULL; 2639 if (sharepath != NULL) { 2640 share = sa_get_share(group, sharepath); 2641 if (share == NULL) { 2642 (void) printf(gettext("Share does not exist in group %s\n"), 2643 groupname, sharepath); 2644 ret = SA_NO_SUCH_PATH; 2645 } 2646 } 2647 if (ret == SA_OK) { 2648 ret = valid_unset_security(share != NULL ? share : group, 2649 optlist, protocol, sectype); 2650 if (ret == SA_OK && !dryrun) { 2651 if (optlist != NULL) { 2652 if (share != NULL) { 2653 sa_security_t optionset; 2654 sa_property_t prop; 2655 change = remove_security(share, sectype, 2656 optlist, protocol, 2657 &ret); 2658 /* if a share security is empty, remove it */ 2659 optionset = sa_get_security((sa_group_t)share, 2660 sectype, 2661 protocol); 2662 if (optionset != NULL) { 2663 prop = sa_get_property(optionset, NULL); 2664 if (prop == NULL) 2665 ret = sa_destroy_security(optionset); 2666 } 2667 } else { 2668 change = remove_security(group, sectype, 2669 optlist, protocol, 2670 &ret); 2671 } 2672 } else { 2673 sa_security_t security; 2674 char *sec; 2675 sec = sa_proto_space_alias(protocol, sectype); 2676 security = sa_get_security(group, sec, protocol); 2677 if (sec != NULL) 2678 sa_free_attr_string(sec); 2679 if (security != NULL) { 2680 ret = sa_destroy_security(security); 2681 if (ret == SA_OK) 2682 change = 1; 2683 } else { 2684 ret = SA_NO_SUCH_PROP; 2685 } 2686 } 2687 if (ret != SA_OK) 2688 (void) printf(gettext("Could not unset property: %s\n"), 2689 sa_errorstr(ret)); 2690 } 2691 2692 if (ret == SA_OK && change) 2693 worklist = add_list(worklist, group, 0); 2694 } 2695 } else { 2696 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2697 ret = SA_NO_SUCH_GROUP; 2698 } 2699 free_opt(optlist); 2700 /* 2701 * we have a group and potentially legal additions 2702 */ 2703 2704 /* commit to configuration if not a dryrun */ 2705 if (!dryrun && ret == 0) { 2706 if (change && worklist != NULL) { 2707 /* properties changed, so update all shares */ 2708 (void) enable_all_groups(worklist, 0, 0, protocol); 2709 } 2710 ret = sa_update_config(); 2711 } 2712 if (worklist != NULL) 2713 free_list(worklist); 2714 return (ret); 2715 } 2716 2717 /* 2718 * sa_unset(flags, argc, argv) 2719 * 2720 * implements the unset subcommand. Parsing done here and then basic 2721 * or space versions of the real code are called. 2722 */ 2723 2724 int 2725 sa_unset(int flags, int argc, char *argv[]) 2726 { 2727 char *groupname; 2728 int verbose = 0; 2729 int dryrun = 0; 2730 int c; 2731 char *protocol = NULL; 2732 int ret = SA_OK; 2733 struct options *optlist = NULL; 2734 char *sharepath = NULL; 2735 char *optset = NULL; 2736 int auth; 2737 2738 while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2739 switch (c) { 2740 case 'v': 2741 verbose++; 2742 break; 2743 case 'n': 2744 dryrun++; 2745 break; 2746 case 'P': 2747 protocol = optarg; 2748 if (!sa_valid_protocol(protocol)) { 2749 (void) printf(gettext("Invalid protocol specified: %s\n"), 2750 protocol); 2751 return (SA_INVALID_PROTOCOL); 2752 } 2753 break; 2754 case 'p': 2755 ret = add_opt(&optlist, optarg, 1); 2756 switch (ret) { 2757 case OPT_ADD_SYNTAX: 2758 (void) printf(gettext("Property syntax error for " 2759 "property %s\n"), 2760 optarg); 2761 return (SA_SYNTAX_ERR); 2762 case OPT_ADD_PROPERTY: 2763 (void) printf(gettext("Properties need to be set" 2764 " with set command: %s\n"), 2765 optarg); 2766 return (SA_SYNTAX_ERR); 2767 default: 2768 break; 2769 } 2770 break; 2771 case 's': 2772 sharepath = optarg; 2773 break; 2774 case 'S': 2775 optset = optarg; 2776 break; 2777 default: 2778 case 'h': 2779 case '?': 2780 (void) printf(gettext("usage: %s\n"), 2781 sa_get_usage(USAGE_UNSET)); 2782 return (SA_OK); 2783 } 2784 } 2785 2786 if (optlist != NULL) 2787 ret = chk_opt(optlist, optset != NULL, protocol); 2788 2789 if (optind >= argc || (optlist == NULL && optset == NULL) || 2790 protocol == NULL) { 2791 char *sep = "\t"; 2792 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET)); 2793 if (optind >= argc) { 2794 (void) printf(gettext("%sgroup must be specified"), sep); 2795 sep = ", "; 2796 } 2797 if (optlist == NULL) { 2798 (void) printf(gettext("%sat least one property must be " 2799 "specified"), 2800 sep); 2801 sep = ", "; 2802 } 2803 if (protocol == NULL) { 2804 (void) printf(gettext("%sprotocol must be specified"), sep); 2805 sep = ", "; 2806 } 2807 (void) printf("\n"); 2808 ret = SA_SYNTAX_ERR; 2809 } else { 2810 2811 /* 2812 * if a group already exists, we can only add a new 2813 * protocol to it and not create a new one or add the 2814 * same protocol again. 2815 */ 2816 2817 groupname = argv[optind]; 2818 auth = check_authorizations(groupname, flags); 2819 if (optset == NULL) 2820 ret = basic_unset(groupname, optlist, protocol, 2821 sharepath, dryrun); 2822 else 2823 ret = space_unset(groupname, optlist, protocol, 2824 sharepath, dryrun, optset); 2825 2826 if (dryrun && ret == SA_OK && !auth && verbose) { 2827 (void) printf(gettext("Command would fail: %s\n"), 2828 sa_errorstr(SA_NO_PERMISSION)); 2829 } 2830 } 2831 return (ret); 2832 } 2833 2834 /* 2835 * sa_enable_group(flags, argc, argv) 2836 * 2837 * Implements the enable subcommand 2838 */ 2839 2840 int 2841 sa_enable_group(int flags, int argc, char *argv[]) 2842 { 2843 int verbose = 0; 2844 int dryrun = 0; 2845 int all = 0; 2846 int c; 2847 int ret = SA_OK; 2848 char *protocol = NULL; 2849 char *state; 2850 struct list *worklist = NULL; 2851 int auth = 1; 2852 2853 while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 2854 switch (c) { 2855 case 'a': 2856 all = 1; 2857 break; 2858 case 'n': 2859 dryrun++; 2860 break; 2861 case 'P': 2862 protocol = optarg; 2863 if (!sa_valid_protocol(protocol)) { 2864 (void) printf(gettext("Invalid protocol specified: %s\n"), 2865 protocol); 2866 return (SA_INVALID_PROTOCOL); 2867 } 2868 break; 2869 case 'v': 2870 verbose++; 2871 break; 2872 default: 2873 case 'h': 2874 case '?': 2875 (void) printf(gettext("usage: %s\n"), 2876 sa_get_usage(USAGE_ENABLE)); 2877 return (0); 2878 } 2879 } 2880 2881 if (optind == argc && !all) { 2882 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE)); 2883 (void) printf(gettext("\tmust specify group\n")); 2884 ret = SA_NO_SUCH_PATH; 2885 } else { 2886 sa_group_t group; 2887 if (!all) { 2888 while (optind < argc) { 2889 group = sa_get_group(argv[optind]); 2890 if (group != NULL) { 2891 auth &= check_authorizations(argv[optind], flags); 2892 state = sa_get_group_attr(group, "state"); 2893 if (state != NULL && 2894 strcmp(state, "enabled") == 0) { 2895 /* already enabled */ 2896 if (verbose) 2897 (void) printf(gettext("Group \"%s\" is already " 2898 "enabled\n"), 2899 argv[optind]); 2900 ret = SA_BUSY; /* already enabled */ 2901 } else { 2902 worklist = add_list(worklist, group, 0); 2903 if (verbose) 2904 (void) printf(gettext("Enabling group " 2905 "\"%s\"\n"), 2906 argv[optind]); 2907 } 2908 if (state != NULL) 2909 sa_free_attr_string(state); 2910 } else { 2911 ret = SA_NO_SUCH_GROUP; 2912 } 2913 optind++; 2914 } 2915 } else { 2916 for (group = sa_get_group(NULL); group != NULL; 2917 group = sa_get_next_group(group)) { 2918 worklist = add_list(worklist, group, 0); 2919 } 2920 } 2921 if (!dryrun && ret == SA_OK) { 2922 ret = enable_all_groups(worklist, 1, 0, NULL); 2923 } 2924 if (ret != SA_OK && ret != SA_BUSY) 2925 (void) printf(gettext("Could not enable group: %s\n"), 2926 sa_errorstr(ret)); 2927 if (ret == SA_BUSY) 2928 ret = SA_OK; 2929 } 2930 if (worklist != NULL) 2931 free_list(worklist); 2932 if (dryrun && ret == SA_OK && !auth && verbose) { 2933 (void) printf(gettext("Command would fail: %s\n"), 2934 sa_errorstr(SA_NO_PERMISSION)); 2935 } 2936 return (ret); 2937 } 2938 2939 /* 2940 * disable_group(group, setstate) 2941 * 2942 * disable all the shares in the specified group honoring the setstate 2943 * argument. This is a helper for disable_all_groups in order to 2944 * simplify regular and subgroup (zfs) disabling. Group has already 2945 * been checked for non-NULL. 2946 */ 2947 2948 static int 2949 disable_group(sa_group_t group) 2950 { 2951 sa_share_t share; 2952 int ret = SA_OK; 2953 2954 for (share = sa_get_share(group, NULL); 2955 share != NULL && ret == SA_OK; 2956 share = sa_get_next_share(share)) { 2957 ret = sa_disable_share(share, NULL); 2958 if (ret == SA_NO_SUCH_PATH) { 2959 /* 2960 * this is OK since the path is gone. we can't 2961 * re-share it anyway so no error. 2962 */ 2963 ret = SA_OK; 2964 } 2965 } 2966 return (ret); 2967 } 2968 2969 2970 /* 2971 * disable_all_groups(work, setstate) 2972 * 2973 * helper function that disables the shares in the list of groups 2974 * provided. It optionally marks the group as disabled. Used by both 2975 * enable and start subcommands. 2976 */ 2977 2978 static int 2979 disable_all_groups(struct list *work, int setstate) 2980 { 2981 int ret = SA_OK; 2982 sa_group_t subgroup, group; 2983 2984 while (work != NULL && ret == SA_OK) { 2985 group = (sa_group_t)work->item; 2986 if (setstate) 2987 ret = sa_set_group_attr(group, "state", "disabled"); 2988 if (ret == SA_OK) { 2989 char *name; 2990 name = sa_get_group_attr(group, "name"); 2991 if (name != NULL && strcmp(name, "zfs") == 0) { 2992 /* need to get the sub-groups for stopping */ 2993 for (subgroup = sa_get_sub_group(group); subgroup != NULL; 2994 subgroup = sa_get_next_group(subgroup)) { 2995 ret = disable_group(subgroup); 2996 } 2997 } else { 2998 ret = disable_group(group); 2999 } 3000 /* 3001 * we don't want to "disable" since it won't come 3002 * up after a reboot. The SMF framework should do 3003 * the right thing. On enable we do want to do 3004 * something. 3005 */ 3006 } 3007 work = work->next; 3008 } 3009 if (ret == SA_OK) 3010 ret = sa_update_config(); 3011 return (ret); 3012 } 3013 3014 /* 3015 * sa_disable_group(flags, argc, argv) 3016 * 3017 * Implements the disable subcommand 3018 */ 3019 3020 int 3021 sa_disable_group(int flags, int argc, char *argv[]) 3022 { 3023 int verbose = 0; 3024 int dryrun = 0; 3025 int all = 0; 3026 int c; 3027 int ret = SA_OK; 3028 char *protocol; 3029 char *state; 3030 struct list *worklist = NULL; 3031 int auth = 1; 3032 3033 while ((c = getopt(argc, argv, "?havn")) != EOF) { 3034 switch (c) { 3035 case 'a': 3036 all = 1; 3037 break; 3038 case 'n': 3039 dryrun++; 3040 break; 3041 case 'P': 3042 protocol = optarg; 3043 if (!sa_valid_protocol(protocol)) { 3044 (void) printf(gettext("Invalid protocol specified: %s\n"), 3045 protocol); 3046 return (SA_INVALID_PROTOCOL); 3047 } 3048 break; 3049 case 'v': 3050 verbose++; 3051 break; 3052 default: 3053 case 'h': 3054 case '?': 3055 (void) printf(gettext("usage: %s\n"), 3056 sa_get_usage(USAGE_DISABLE)); 3057 return (0); 3058 } 3059 } 3060 3061 if (optind == argc && !all) { 3062 (void) printf(gettext("usage: %s\n"), 3063 sa_get_usage(USAGE_DISABLE)); 3064 (void) printf(gettext("\tmust specify group\n")); 3065 ret = SA_NO_SUCH_PATH; 3066 } else { 3067 sa_group_t group; 3068 if (!all) { 3069 while (optind < argc) { 3070 group = sa_get_group(argv[optind]); 3071 if (group != NULL) { 3072 auth &= check_authorizations(argv[optind], flags); 3073 state = sa_get_group_attr(group, "state"); 3074 if (state == NULL || 3075 strcmp(state, "disabled") == 0) { 3076 /* already disabled */ 3077 if (verbose) 3078 (void) printf(gettext("Group \"%s\" is " 3079 "already disabled\n"), 3080 argv[optind]); 3081 ret = SA_BUSY; /* already disable */ 3082 } else { 3083 worklist = add_list(worklist, group, 0); 3084 if (verbose) 3085 (void) printf(gettext("Disabling group " 3086 "\"%s\"\n"), 3087 argv[optind]); 3088 } 3089 if (state != NULL) 3090 sa_free_attr_string(state); 3091 } else { 3092 ret = SA_NO_SUCH_GROUP; 3093 } 3094 optind++; 3095 } 3096 } else { 3097 for (group = sa_get_group(NULL); group != NULL; 3098 group = sa_get_next_group(group)) { 3099 worklist = add_list(worklist, group, 0); 3100 } 3101 } 3102 if (ret == SA_OK && !dryrun) { 3103 ret = disable_all_groups(worklist, 1); 3104 } 3105 if (ret != SA_OK && ret != SA_BUSY) 3106 (void) printf(gettext("Could not disable group: %s\n"), 3107 sa_errorstr(ret)); 3108 if (ret == SA_BUSY) 3109 ret = SA_OK; 3110 } 3111 if (worklist != NULL) 3112 free_list(worklist); 3113 if (dryrun && ret == SA_OK && !auth && verbose) { 3114 (void) printf(gettext("Command would fail: %s\n"), 3115 sa_errorstr(SA_NO_PERMISSION)); 3116 } 3117 return (ret); 3118 } 3119 3120 /* 3121 * check_sharetab() 3122 * 3123 * Checks to see if the /etc/dfs/sharetab file is stale (exists from 3124 * before the current boot). If it is, truncate it since nothing is 3125 * really shared. 3126 */ 3127 3128 static void 3129 check_sharetab() 3130 { 3131 int fd; 3132 struct utmpx *utmpxp; 3133 struct stat st; 3134 3135 fd = open(SA_LEGACY_SHARETAB, O_RDWR); 3136 if (fd >= 0) { 3137 /* 3138 * Attempt to get a lock on the file. Whgen we get 3139 * one, then check to see if it is older than the boot 3140 * time. Truncate if older than boot. 3141 */ 3142 (void) lockf(fd, F_LOCK, 0); 3143 if ((fstat(fd, &st) == 0) && /* does sharetab exist? */ 3144 (utmpxp = getutxent()) != NULL && /* does utmpx exist? */ 3145 (utmpxp->ut_xtime > st.st_mtime)) /* sharetab older? */ 3146 (void) ftruncate(fd, 0); 3147 3148 (void) lockf(fd, F_ULOCK, 0); 3149 (void) close(fd); 3150 endutxent(); 3151 } 3152 } 3153 3154 /* 3155 * sa_start_group(flags, argc, argv) 3156 * 3157 * Implements the start command. 3158 * This is similar to enable except it doesn't change the state 3159 * of the group(s) and only enables shares if the group is already 3160 * enabled. 3161 */ 3162 3163 int 3164 sa_start_group(int flags, int argc, char *argv[]) 3165 { 3166 int verbose = 0; 3167 int all = 0; 3168 int c; 3169 int ret = SMF_EXIT_OK; 3170 char *protocol = NULL; 3171 char *state; 3172 struct list *worklist = NULL; 3173 #ifdef lint 3174 flags = flags; 3175 #endif 3176 3177 while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3178 switch (c) { 3179 case 'a': 3180 all = 1; 3181 break; 3182 case 'P': 3183 protocol = optarg; 3184 if (!sa_valid_protocol(protocol)) { 3185 (void) printf(gettext("Invalid protocol specified: %s\n"), 3186 protocol); 3187 return (SA_INVALID_PROTOCOL); 3188 } 3189 break; 3190 case 'v': 3191 verbose++; 3192 break; 3193 default: 3194 case 'h': 3195 case '?': 3196 (void) printf(gettext("usage: %s\n"), 3197 sa_get_usage(USAGE_START)); 3198 return (SA_OK); 3199 } 3200 } 3201 3202 if (optind == argc && !all) { 3203 (void) printf(gettext("usage: %s\n"), 3204 sa_get_usage(USAGE_START)); 3205 ret = SMF_EXIT_ERR_FATAL; 3206 } else { 3207 sa_group_t group; 3208 3209 check_sharetab(); 3210 3211 if (!all) { 3212 while (optind < argc) { 3213 group = sa_get_group(argv[optind]); 3214 if (group != NULL) { 3215 state = sa_get_group_attr(group, "state"); 3216 if (state == NULL || 3217 strcmp(state, "enabled") == 0) { 3218 worklist = add_list(worklist, group, 0); 3219 if (verbose) 3220 (void) printf(gettext("Starting group " 3221 "\"%s\"\n"), 3222 argv[optind]); 3223 } else { 3224 /* 3225 * determine if there are any 3226 * protocols. if there aren't any, 3227 * then there isn't anything to do in 3228 * any case so no error. 3229 */ 3230 if (sa_get_optionset(group, protocol) != NULL) { 3231 ret = SMF_EXIT_OK; 3232 } 3233 } 3234 if (state != NULL) 3235 sa_free_attr_string(state); 3236 } 3237 optind++; 3238 } 3239 } else { 3240 for (group = sa_get_group(NULL); group != NULL; 3241 group = sa_get_next_group(group)) { 3242 state = sa_get_group_attr(group, "state"); 3243 if (state == NULL || strcmp(state, "enabled") == 0) 3244 worklist = add_list(worklist, group, 0); 3245 if (state != NULL) 3246 sa_free_attr_string(state); 3247 } 3248 } 3249 (void) enable_all_groups(worklist, 0, 1, NULL); 3250 } 3251 if (worklist != NULL) 3252 free_list(worklist); 3253 return (ret); 3254 } 3255 3256 /* 3257 * sa_stop_group(flags, argc, argv) 3258 * 3259 * Implements the stop command. 3260 * This is similar to disable except it doesn't change the state 3261 * of the group(s) and only disables shares if the group is already 3262 * enabled. 3263 */ 3264 3265 int 3266 sa_stop_group(int flags, int argc, char *argv[]) 3267 { 3268 int verbose = 0; 3269 int all = 0; 3270 int c; 3271 int ret = SMF_EXIT_OK; 3272 char *protocol = NULL; 3273 char *state; 3274 struct list *worklist = NULL; 3275 #ifdef lint 3276 flags = flags; 3277 #endif 3278 3279 while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3280 switch (c) { 3281 case 'a': 3282 all = 1; 3283 break; 3284 case 'P': 3285 protocol = optarg; 3286 if (!sa_valid_protocol(protocol)) { 3287 (void) printf(gettext("Invalid protocol specified: %s\n"), 3288 protocol); 3289 return (SA_INVALID_PROTOCOL); 3290 } 3291 break; 3292 case 'v': 3293 verbose++; 3294 break; 3295 default: 3296 case 'h': 3297 case '?': 3298 (void) printf(gettext("usage: %s\n"), 3299 sa_get_usage(USAGE_STOP)); 3300 return (0); 3301 } 3302 } 3303 3304 if (optind == argc && !all) { 3305 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP)); 3306 ret = SMF_EXIT_ERR_FATAL; 3307 } else { 3308 sa_group_t group; 3309 if (!all) { 3310 while (optind < argc) { 3311 group = sa_get_group(argv[optind]); 3312 if (group != NULL) { 3313 state = sa_get_group_attr(group, "state"); 3314 if (state == NULL || 3315 strcmp(state, "enabled") == 0) { 3316 worklist = add_list(worklist, group, 0); 3317 if (verbose) 3318 (void) printf(gettext("Stopping group " 3319 "\"%s\"\n"), 3320 argv[optind]); 3321 } else { 3322 ret = SMF_EXIT_OK; 3323 } 3324 if (state != NULL) 3325 sa_free_attr_string(state); 3326 } 3327 optind++; 3328 } 3329 } else { 3330 for (group = sa_get_group(NULL); group != NULL; 3331 group = sa_get_next_group(group)) { 3332 state = sa_get_group_attr(group, "state"); 3333 if (state == NULL || strcmp(state, "enabled") == 0) 3334 worklist = add_list(worklist, group, 0); 3335 if (state != NULL) 3336 sa_free_attr_string(state); 3337 } 3338 } 3339 (void) disable_all_groups(worklist, 0); 3340 ret = sa_update_config(); 3341 } 3342 if (worklist != NULL) 3343 free_list(worklist); 3344 return (ret); 3345 } 3346 3347 /* 3348 * remove_all_options(share, proto) 3349 * 3350 * Removes all options on a share. 3351 */ 3352 3353 static void 3354 remove_all_options(sa_share_t share, char *proto) 3355 { 3356 sa_optionset_t optionset; 3357 sa_security_t security; 3358 sa_security_t prevsec = NULL; 3359 3360 optionset = sa_get_optionset(share, proto); 3361 if (optionset != NULL) 3362 (void) sa_destroy_optionset(optionset); 3363 for (security = sa_get_security(share, NULL, NULL); 3364 security != NULL; 3365 security = sa_get_next_security(security)) { 3366 char *type; 3367 /* 3368 * we walk through the list. prevsec keeps the 3369 * previous security so we can delete it without 3370 * destroying the list. 3371 */ 3372 if (prevsec != NULL) { 3373 /* remove the previously seen security */ 3374 (void) sa_destroy_security(prevsec); 3375 /* set to NULL so we don't try multiple times */ 3376 prevsec = NULL; 3377 } 3378 type = sa_get_security_attr(security, "type"); 3379 if (type != NULL) { 3380 /* 3381 * if the security matches the specified protocol, we 3382 * want to remove it. prevsec holds it until either 3383 * the next pass or we fall out of the loop. 3384 */ 3385 if (strcmp(type, proto) == 0) 3386 prevsec = security; 3387 sa_free_attr_string(type); 3388 } 3389 } 3390 /* in case there is one left */ 3391 if (prevsec != NULL) 3392 (void) sa_destroy_security(prevsec); 3393 } 3394 3395 3396 /* 3397 * for legacy support, we need to handle the old syntax. This is what 3398 * we get if sharemgr is called with the name "share" rather than 3399 * sharemgr. 3400 */ 3401 3402 static int 3403 format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 3404 { 3405 int err; 3406 3407 err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 3408 if (err > buffsize) 3409 return (-1); 3410 return (0); 3411 } 3412 3413 3414 /* 3415 * check_legacy_cmd(proto, cmd) 3416 * 3417 * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 3418 * executable. 3419 */ 3420 3421 static int 3422 check_legacy_cmd(char *path) 3423 { 3424 struct stat st; 3425 int ret = 0; 3426 3427 if (stat(path, &st) == 0) { 3428 if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 3429 ret = 1; 3430 } 3431 return (ret); 3432 } 3433 3434 /* 3435 * run_legacy_command(proto, cmd, argv) 3436 * 3437 * we know the command exists, so attempt to execute it with all the 3438 * arguments. This implements full legacy share support for those 3439 * protocols that don't have plugin providers. 3440 */ 3441 3442 static int 3443 run_legacy_command(char *path, char *argv[]) 3444 { 3445 int ret; 3446 3447 ret = execv(path, argv); 3448 if (ret < 0) { 3449 switch (errno) { 3450 case EACCES: 3451 ret = SA_NO_PERMISSION; 3452 break; 3453 default: 3454 ret = SA_SYSTEM_ERR; 3455 break; 3456 } 3457 } 3458 return (ret); 3459 } 3460 3461 /* 3462 * out_share(out, group, proto, options) 3463 * 3464 * Display the share information in the format that the "share" 3465 * command has traditionally used. 3466 */ 3467 3468 static void 3469 out_share(FILE *out, sa_group_t group, char *proto, char *options) 3470 { 3471 sa_share_t share; 3472 char resfmt[128]; 3473 3474 for (share = sa_get_share(group, NULL); share != NULL; 3475 share = sa_get_next_share(share)) { 3476 char *path; 3477 char *type; 3478 char *resource; 3479 char *description; 3480 char *groupname; 3481 char *sharedstate; 3482 int shared = 1; 3483 char *soptions; 3484 3485 sharedstate = sa_get_share_attr(share, "shared"); 3486 path = sa_get_share_attr(share, "path"); 3487 type = sa_get_share_attr(share, "type"); 3488 resource = sa_get_share_attr(share, "resource"); 3489 groupname = sa_get_group_attr(group, "name"); 3490 3491 if (groupname != NULL && strcmp(groupname, "default") == 0) { 3492 sa_free_attr_string(groupname); 3493 groupname = NULL; 3494 } 3495 description = sa_get_share_description(share); 3496 soptions = options; 3497 3498 if (sharedstate == NULL) 3499 shared = 0; 3500 3501 soptions = sa_proto_legacy_format(proto, share, 1); 3502 3503 if (shared) { 3504 /* only persisting share go here */ 3505 (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 3506 resource != NULL ? resource : "-", 3507 groupname != NULL ? "@" : "", 3508 groupname != NULL ? groupname : ""); 3509 (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 3510 resfmt, 3511 path, 3512 (soptions != NULL && strlen(soptions) > 0) ? 3513 soptions : "rw", 3514 (description != NULL) ? description : ""); 3515 } 3516 3517 if (path != NULL) 3518 sa_free_attr_string(path); 3519 if (type != NULL) 3520 sa_free_attr_string(type); 3521 if (resource != NULL) 3522 sa_free_attr_string(resource); 3523 if (groupname != NULL) 3524 sa_free_attr_string(groupname); 3525 if (description != NULL) 3526 sa_free_share_description(description); 3527 if (sharedstate != NULL) 3528 sa_free_attr_string(sharedstate); 3529 if (soptions != NULL && soptions != options) 3530 sa_format_free(soptions); 3531 } 3532 } 3533 3534 /* 3535 * output_legacy_file(out, proto) 3536 * 3537 * Walk all of the groups for the specified protocol and call 3538 * out_share() to format and write in the format displayed by the 3539 * "share" command with no arguments. 3540 */ 3541 3542 static void 3543 output_legacy_file(FILE *out, char *proto) 3544 { 3545 sa_group_t group; 3546 3547 for (group = sa_get_group(NULL); group != NULL; 3548 group = sa_get_next_group(group)) { 3549 char *options; 3550 char *zfs; 3551 3552 /* 3553 * get default options preformated, being careful to 3554 * handle legacy shares differently from new style 3555 * shares. Legacy share have options on the share. 3556 */ 3557 3558 zfs = sa_get_group_attr(group, "zfs"); 3559 if (zfs != NULL) { 3560 sa_group_t zgroup; 3561 sa_free_attr_string(zfs); 3562 options = sa_proto_legacy_format(proto, group, 1); 3563 for (zgroup = sa_get_sub_group(group); zgroup != NULL; 3564 zgroup = sa_get_next_group(zgroup)) { 3565 3566 /* got a group, so display it */ 3567 out_share(out, zgroup, proto, options); 3568 } 3569 } else { 3570 options = sa_proto_legacy_format(proto, group, 1); 3571 out_share(out, group, proto, options); 3572 } 3573 if (options != NULL) 3574 free(options); 3575 } 3576 } 3577 3578 int 3579 sa_legacy_share(int flags, int argc, char *argv[]) 3580 { 3581 char *protocol = "nfs"; 3582 char *options = NULL; 3583 char *description = NULL; 3584 char *groupname = NULL; 3585 char *sharepath = NULL; 3586 char *resource = NULL; 3587 char *groupstatus = NULL; 3588 int persist = SA_SHARE_TRANSIENT; 3589 int argsused = 0; 3590 int c; 3591 int ret = SA_OK; 3592 int zfs = 0; 3593 int true_legacy = 0; 3594 int curtype = SA_SHARE_TRANSIENT; 3595 char cmd[MAXPATHLEN]; 3596 #ifdef lint 3597 flags = flags; 3598 #endif 3599 3600 while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 3601 switch (c) { 3602 case 'd': 3603 description = optarg; 3604 argsused++; 3605 break; 3606 case 'F': 3607 protocol = optarg; 3608 if (!sa_valid_protocol(protocol)) { 3609 if (format_legacy_path(cmd, MAXPATHLEN, 3610 protocol, "share") == 0 && check_legacy_cmd(cmd)) { 3611 true_legacy++; 3612 } else { 3613 (void) fprintf(stderr, 3614 gettext("Invalid protocol specified:" 3615 "%s\n"), 3616 protocol); 3617 return (SA_INVALID_PROTOCOL); 3618 } 3619 } 3620 break; 3621 case 'o': 3622 options = optarg; 3623 argsused++; 3624 break; 3625 case 'p': 3626 persist = SA_SHARE_PERMANENT; 3627 argsused++; 3628 break; 3629 case 'h': 3630 case '?': 3631 default: 3632 (void) fprintf(stderr, gettext("usage: %s\n"), 3633 sa_get_usage(USAGE_SHARE)); 3634 return (SA_OK); 3635 } 3636 } 3637 3638 /* have the info so construct what is needed */ 3639 if (!argsused && optind == argc) { 3640 /* display current info in share format */ 3641 (void) output_legacy_file(stdout, "nfs"); 3642 } else { 3643 sa_group_t group = NULL; 3644 sa_share_t share; 3645 char dir[MAXPATHLEN]; 3646 3647 /* we are modifying the configuration */ 3648 if (optind == argc) { 3649 (void) fprintf(stderr, gettext("usage: %s\n"), 3650 sa_get_usage(USAGE_SHARE)); 3651 return (SA_LEGACY_ERR); 3652 } 3653 3654 if (true_legacy) { 3655 /* if still using legacy share/unshare, exec it */ 3656 ret = run_legacy_command(cmd, argv); 3657 return (ret); 3658 } 3659 3660 sharepath = argv[optind++]; 3661 if (optind < argc) { 3662 resource = argv[optind]; 3663 groupname = strchr(resource, '@'); 3664 if (groupname != NULL) 3665 *groupname++ = '\0'; 3666 } 3667 if (realpath(sharepath, dir) == NULL) 3668 ret = SA_BAD_PATH; 3669 else 3670 sharepath = dir; 3671 if (ret == SA_OK) { 3672 share = sa_find_share(sharepath); 3673 } else { 3674 share = NULL; 3675 } 3676 if (groupname != NULL) { 3677 ret = SA_NOT_ALLOWED; 3678 } else if (ret == SA_OK) { 3679 char *legacygroup = "default"; 3680 /* 3681 * the legacy group is always present and zfs groups 3682 * come and go. zfs shares may be in sub-groups and 3683 * the zfs share will already be in that group so it 3684 * isn't an error. 3685 */ 3686 if (share != NULL) { 3687 /* 3688 * if the share exists, then make sure it is one we 3689 * want to handle. 3690 */ 3691 group = sa_get_parent_group(share); 3692 } else { 3693 group = sa_get_group(legacygroup); 3694 } 3695 if (group != NULL) { 3696 groupstatus = group_status(group); 3697 if (share == NULL) { 3698 share = sa_add_share(group, sharepath, persist, &ret); 3699 if (share == NULL && ret == SA_DUPLICATE_NAME) { 3700 /* could be a ZFS path being started */ 3701 if (sa_zfs_is_shared(sharepath)) { 3702 ret = SA_OK; 3703 group = sa_get_group("zfs"); 3704 if (group == NULL) { 3705 /* this shouldn't happen */ 3706 ret = SA_CONFIG_ERR; 3707 } 3708 if (group != NULL) { 3709 share = sa_add_share(group, sharepath, 3710 persist, &ret); 3711 } 3712 } 3713 } 3714 } else { 3715 /* 3716 * may want to change persist state, but the 3717 * important thing is to change options unless 3718 * this is ZFS where we just want to do the 3719 * enable since everything is current. 3720 */ 3721 if (!sa_zfs_is_shared(sharepath)) { 3722 char *type; 3723 remove_all_options(share, protocol); 3724 type = sa_get_share_attr(share, "type"); 3725 if (type != NULL && 3726 strcmp(type, "transient") != 0) { 3727 curtype = SA_SHARE_PERMANENT; 3728 } 3729 if (type != NULL) 3730 sa_free_attr_string(type); 3731 if (curtype != persist) { 3732 (void) sa_set_share_attr(share, "type", 3733 persist == SA_SHARE_PERMANENT ? 3734 "persist" : "transient"); 3735 } 3736 } else { 3737 zfs++; 3738 } 3739 } 3740 if (!zfs) { 3741 /* have a group to hold this share path */ 3742 if (ret == SA_OK && options != NULL && 3743 strlen(options) > 0) { 3744 ret = sa_parse_legacy_options(share, 3745 options, 3746 protocol); 3747 } 3748 if (ret == SA_OK && description != NULL) 3749 ret = sa_set_share_description(share, description); 3750 if (ret == SA_OK && resource != NULL) 3751 ret = sa_set_share_attr(share, "resource", 3752 resource); 3753 } 3754 if (ret == SA_OK) { 3755 if (strcmp(groupstatus, "enabled") == 0) 3756 ret = sa_enable_share(share, protocol); 3757 if (ret == SA_OK && persist == SA_SHARE_PERMANENT) { 3758 (void) sa_update_legacy(share, protocol); 3759 } 3760 if (ret == SA_OK) 3761 ret = sa_update_config(); 3762 } 3763 } else { 3764 ret = SA_SYSTEM_ERR; 3765 } 3766 } 3767 } 3768 if (ret != SA_OK) { 3769 (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 3770 sharepath, sa_errorstr(ret)); 3771 ret = SA_LEGACY_ERR; 3772 3773 } 3774 return (ret); 3775 } 3776 3777 /* 3778 * sa_legacy_unshare(flags, argc, argv) 3779 * 3780 * Implements the original unshare command. 3781 */ 3782 3783 int 3784 sa_legacy_unshare(int flags, int argc, char *argv[]) 3785 { 3786 char *protocol = "nfs"; /* for now */ 3787 char *options = NULL; 3788 char *sharepath = NULL; 3789 int persist = SA_SHARE_TRANSIENT; 3790 int argsused = 0; 3791 int c; 3792 int ret = SA_OK; 3793 int true_legacy = 0; 3794 char cmd[MAXPATHLEN]; 3795 #ifdef lint 3796 flags = flags; 3797 options = options; 3798 #endif 3799 3800 while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 3801 switch (c) { 3802 case 'h': 3803 case '?': 3804 break; 3805 case 'F': 3806 protocol = optarg; 3807 if (!sa_valid_protocol(protocol)) { 3808 if (format_legacy_path(cmd, MAXPATHLEN, 3809 protocol, "unshare") == 0 && 3810 check_legacy_cmd(cmd)) { 3811 true_legacy++; 3812 } else { 3813 (void) printf(gettext("Invalid file system name\n")); 3814 return (SA_INVALID_PROTOCOL); 3815 } 3816 } 3817 break; 3818 case 'o': 3819 options = optarg; 3820 argsused++; 3821 break; 3822 case 'p': 3823 persist = SA_SHARE_PERMANENT; 3824 argsused++; 3825 break; 3826 default: 3827 (void) printf(gettext("usage: %s\n"), 3828 sa_get_usage(USAGE_UNSHARE)); 3829 return (SA_OK); 3830 } 3831 } 3832 3833 /* have the info so construct what is needed */ 3834 if (optind == argc || (optind + 1) < argc) { 3835 ret = SA_SYNTAX_ERR; 3836 } else { 3837 sa_share_t share; 3838 char dir[MAXPATHLEN]; 3839 if (true_legacy) { 3840 /* if still using legacy share/unshare, exec it */ 3841 ret = run_legacy_command(cmd, argv); 3842 return (ret); 3843 } 3844 sharepath = argv[optind++]; 3845 if (realpath(sharepath, dir) == NULL) { 3846 ret = SA_NO_SUCH_PATH; 3847 } else { 3848 sharepath = dir; 3849 share = sa_find_share(sharepath); 3850 if (share != NULL) { 3851 ret = sa_disable_share(share, protocol); 3852 if (ret == SA_OK) { 3853 if (persist == SA_SHARE_PERMANENT) 3854 ret = sa_remove_share(share); 3855 ret = sa_update_config(); 3856 } 3857 } else { 3858 ret = SA_NOT_SHARED; 3859 } 3860 } 3861 } 3862 switch (ret) { 3863 default: 3864 (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 3865 ret = SA_LEGACY_ERR; 3866 break; 3867 case SA_SYNTAX_ERR: 3868 (void) printf(gettext("usage: %s\n"), 3869 sa_get_usage(USAGE_UNSHARE)); 3870 break; 3871 case SA_OK: 3872 break; 3873 } 3874 return (ret); 3875 } 3876 3877 /* 3878 * common commands that implement the sub-commands used by all 3879 * protcols. The entries are found via the lookup command 3880 */ 3881 3882 static sa_command_t commands[] = { 3883 {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 3884 {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 3885 {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 3886 {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 3887 {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 3888 {"list", 0, sa_list, USAGE_LIST}, 3889 {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 3890 {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 3891 {"set", 0, sa_set, USAGE_SET, SVC_SET}, 3892 {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 3893 {"show", 0, sa_show, USAGE_SHOW}, 3894 {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 3895 {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 3896 SVC_SET|SVC_ACTION}, 3897 {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 3898 {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 3899 {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 3900 {NULL, 0, NULL, NULL} 3901 }; 3902 3903 static char * 3904 sa_get_usage(sa_usage_t index) 3905 { 3906 char *ret = NULL; 3907 switch (index) { 3908 case USAGE_ADD_SHARE: 3909 ret = gettext("add-share [-nth] [-r resource-name] " 3910 "[-d \"description text\"] -s sharepath group"); 3911 break; 3912 case USAGE_CREATE: 3913 ret = gettext("create [-nvh] [-P proto [-p property=value]] group"); 3914 break; 3915 case USAGE_DELETE: 3916 ret = gettext("delete [-nvh] [-P proto] [-f] group"); 3917 break; 3918 case USAGE_DISABLE: 3919 ret = gettext("disable [-nvh] {-a | group ...}"); 3920 break; 3921 case USAGE_ENABLE: 3922 ret = gettext("enable [-nvh] {-a | group ...}"); 3923 break; 3924 case USAGE_LIST: 3925 ret = gettext("list [-vh] [-P proto]"); 3926 break; 3927 case USAGE_MOVE_SHARE: 3928 ret = gettext("move-share [-nvh] -s sharepath destination-group"); 3929 break; 3930 case USAGE_REMOVE_SHARE: 3931 ret = gettext("remove-share [-fnvh] -s sharepath group"); 3932 break; 3933 case USAGE_SET: 3934 ret = gettext("set [-nvh] -P proto [-S optspace] " 3935 "[-p property=value]* [-s sharepath] group"); 3936 break; 3937 case USAGE_SET_SECURITY: 3938 ret = gettext("set-security [-nvh] -P proto -S security-type " 3939 "[-p property=value]* group"); 3940 break; 3941 case USAGE_SET_SHARE: 3942 ret = gettext("set-share [-nh] [-r resource] " 3943 "[-d \"description text\"] -s sharepath group"); 3944 break; 3945 case USAGE_SHOW: 3946 ret = gettext("show [-pvxh] [-P proto] [group ...]"); 3947 break; 3948 case USAGE_SHARE: 3949 ret = gettext("share [-F fstype] [-p] [-o optionlist]" 3950 "[-d description] [pathname [resourcename]]"); 3951 break; 3952 case USAGE_START: 3953 ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 3954 break; 3955 case USAGE_STOP: 3956 ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 3957 break; 3958 case USAGE_UNSET: 3959 ret = gettext("unset [-nvh] -P proto [-S optspace] " 3960 "[-p property]* group"); 3961 break; 3962 case USAGE_UNSET_SECURITY: 3963 ret = gettext("unset-security [-nvh] -P proto -S security-type " 3964 "[-p property]* group"); 3965 break; 3966 case USAGE_UNSHARE: 3967 ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath"); 3968 break; 3969 } 3970 return (ret); 3971 } 3972 3973 /* 3974 * sa_lookup(cmd, proto) 3975 * 3976 * Lookup the sub-command. proto isn't currently used, but it may 3977 * eventually provide a way to provide protocol specific sub-commands. 3978 */ 3979 3980 sa_command_t * 3981 sa_lookup(char *cmd, char *proto) 3982 { 3983 int i; 3984 size_t len; 3985 #ifdef lint 3986 proto = proto; 3987 #endif 3988 3989 len = strlen(cmd); 3990 for (i = 0; commands[i].cmdname != NULL; i++) { 3991 if (strncmp(cmd, commands[i].cmdname, len) == 0) 3992 return (&commands[i]); 3993 } 3994 return (NULL); 3995 } 3996 3997 void 3998 sub_command_help(char *proto) 3999 { 4000 int i; 4001 #ifdef lint 4002 proto = proto; 4003 #endif 4004 4005 (void) printf(gettext("\tsub-commands:\n")); 4006 for (i = 0; commands[i].cmdname != NULL; i++) { 4007 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 4008 (void) printf("\t%s\n", 4009 sa_get_usage((sa_usage_t)commands[i].cmdidx)); 4010 } 4011 } 4012