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