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(sa_handle_t handle, struct list *work, int setstate, 259 int online, 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(handle); 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(sa_handle_t handle, 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(handle, 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(handle, (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(handle); 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(sa_handle_t handle, 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(handle, 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(handle); 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(sa_handle_t handle, 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(handle, 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(sa_handle_t handle, 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(handle, 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(handle, 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_handle_t handle, sa_group_t group, sa_share_t share, 1396 int update_legacy) 1397 { 1398 char *value; 1399 int enabled; 1400 sa_optionset_t optionset; 1401 int ret = SA_OK; 1402 char *zfs = NULL; 1403 int iszfs = 0; 1404 1405 /* 1406 * need to enable this share if the group is enabled but not 1407 * otherwise. The enable is also done on each protocol 1408 * represented in the group. 1409 */ 1410 value = sa_get_group_attr(group, "state"); 1411 enabled = value != NULL && strcmp(value, "enabled") == 0; 1412 if (value != NULL) 1413 sa_free_attr_string(value); 1414 /* remove legacy config if necessary */ 1415 if (update_legacy) 1416 ret = sa_delete_legacy(share); 1417 zfs = sa_get_group_attr(group, "zfs"); 1418 if (zfs != NULL) { 1419 iszfs++; 1420 sa_free_attr_string(zfs); 1421 } 1422 1423 /* 1424 * Step through each optionset at the group level and 1425 * enable the share based on the protocol type. This 1426 * works because protocols must be set on the group 1427 * for the protocol to be enabled. 1428 */ 1429 for (optionset = sa_get_optionset(group, NULL); 1430 optionset != NULL && ret == SA_OK; 1431 optionset = sa_get_next_optionset(optionset)) { 1432 value = sa_get_optionset_attr(optionset, "type"); 1433 if (value != NULL) { 1434 if (enabled) 1435 ret = sa_enable_share(share, value); 1436 if (update_legacy && !iszfs) 1437 (void) sa_update_legacy(share, value); 1438 sa_free_attr_string(value); 1439 } 1440 } 1441 if (ret == SA_OK) 1442 (void) sa_update_config(handle); 1443 return (ret); 1444 } 1445 1446 /* 1447 * sa_addshare(flags, argc, argv) 1448 * 1449 * implements add-share subcommand. 1450 */ 1451 1452 int 1453 sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 1454 { 1455 int verbose = 0; 1456 int dryrun = 0; 1457 int c; 1458 int ret = SA_OK; 1459 sa_group_t group; 1460 sa_share_t share; 1461 char *sharepath = NULL; 1462 char *description = NULL; 1463 char *resource = NULL; 1464 int persist = SA_SHARE_PERMANENT; /* default to persist */ 1465 int auth; 1466 char dir[MAXPATHLEN]; 1467 1468 while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 1469 switch (c) { 1470 case 'n': 1471 dryrun++; 1472 break; 1473 case 'v': 1474 verbose++; 1475 break; 1476 case 'd': 1477 description = optarg; 1478 break; 1479 case 'r': 1480 resource = optarg; 1481 break; 1482 case 's': 1483 /* 1484 * save share path into group. Currently limit 1485 * to one share per command. 1486 */ 1487 if (sharepath != NULL) { 1488 (void) printf(gettext("Adding multiple shares not" 1489 "supported\n")); 1490 return (1); 1491 } 1492 sharepath = optarg; 1493 break; 1494 case 't': 1495 persist = SA_SHARE_TRANSIENT; 1496 break; 1497 default: 1498 case 'h': 1499 case '?': 1500 (void) printf(gettext("usage: %s\n"), 1501 sa_get_usage(USAGE_ADD_SHARE)); 1502 return (0); 1503 } 1504 } 1505 1506 if (optind >= argc) { 1507 (void) printf(gettext("usage: %s\n"), 1508 sa_get_usage(USAGE_ADD_SHARE)); 1509 if (dryrun || sharepath != NULL || description != NULL || 1510 resource != NULL || verbose || persist) { 1511 (void) printf(gettext("\tgroup must be specified\n")); 1512 ret = SA_NO_SUCH_GROUP; 1513 } else { 1514 ret = SA_OK; 1515 } 1516 } else { 1517 if (sharepath == NULL) { 1518 (void) printf(gettext("usage: %s\n"), 1519 sa_get_usage(USAGE_ADD_SHARE)); 1520 (void) printf(gettext("\t-s sharepath must be specified\n")); 1521 ret = SA_BAD_PATH; 1522 } 1523 if (ret == SA_OK) { 1524 if (realpath(sharepath, dir) == NULL) { 1525 ret = SA_BAD_PATH; 1526 (void) printf(gettext("Path is not valid: %s\n"), 1527 sharepath); 1528 } else { 1529 sharepath = dir; 1530 } 1531 } 1532 if (ret == SA_OK && resource != NULL) { 1533 /* check for valid syntax */ 1534 if (strpbrk(resource, " \t/") != NULL) { 1535 (void) printf(gettext("usage: %s\n"), 1536 sa_get_usage(USAGE_ADD_SHARE)); 1537 (void) printf(gettext("\tresource must not contain white" 1538 "space or '/' characters\n")); 1539 ret = SA_BAD_PATH; 1540 } 1541 } 1542 if (ret == SA_OK) { 1543 group = sa_get_group(handle, argv[optind]); 1544 if (group != NULL) { 1545 auth = check_authorizations(argv[optind], flags); 1546 share = sa_find_share(handle, sharepath); 1547 if (share != NULL) { 1548 group = sa_get_parent_group(share); 1549 if (group != NULL) { 1550 char *groupname; 1551 groupname = sa_get_group_attr(group, "name"); 1552 if (groupname != NULL) { 1553 (void) printf(gettext("Share path already " 1554 "shared in group " 1555 "\"%s\": %s\n"), 1556 groupname, sharepath); 1557 sa_free_attr_string(groupname); 1558 } else { 1559 (void) printf(gettext("Share path already" 1560 "shared: %s\n"), 1561 groupname, sharepath); 1562 } 1563 } else { 1564 (void) printf(gettext("Share path %s already " 1565 "shared\n"), 1566 sharepath); 1567 } 1568 ret = SA_DUPLICATE_NAME; 1569 } else { 1570 /* 1571 * need to check that resource name is unique 1572 * at some point. Path checking should use the 1573 * "normal" rules which don't check the repository. 1574 */ 1575 if (dryrun) 1576 ret = sa_check_path(group, sharepath, 1577 SA_CHECK_NORMAL); 1578 else 1579 share = sa_add_share(group, sharepath, 1580 persist, &ret); 1581 if (!dryrun && share == NULL) { 1582 (void) printf(gettext("Could not add share: " 1583 "%s\n"), 1584 sa_errorstr(ret)); 1585 } else { 1586 if (!dryrun && ret == SA_OK) { 1587 if (resource != NULL) { 1588 if (strpbrk(resource, " \t/") == NULL) { 1589 ret = sa_set_share_attr(share, 1590 "resource", 1591 resource); 1592 } 1593 } 1594 if (ret == SA_OK && description != NULL) { 1595 ret = sa_set_share_description(share, 1596 description); 1597 } 1598 if (ret == SA_OK) { 1599 /* now enable the share(s) */ 1600 ret = enable_share(handle, group, share, 1); 1601 ret = sa_update_config(handle); 1602 } 1603 switch (ret) { 1604 case SA_DUPLICATE_NAME: 1605 (void) printf(gettext("Resource name in" 1606 "use: %s\n"), 1607 resource); 1608 break; 1609 default: 1610 (void) printf(gettext("Could not set " 1611 "attribute: %s\n"), 1612 sa_errorstr(ret)); 1613 break; 1614 case SA_OK: 1615 break; 1616 } 1617 } else if (dryrun && ret == SA_OK && 1618 !auth && verbose) { 1619 (void) printf(gettext("Command would fail: " 1620 "%s\n"), 1621 sa_errorstr(SA_NO_PERMISSION)); 1622 ret = SA_NO_PERMISSION; 1623 } 1624 } 1625 } 1626 } else { 1627 (void) printf(gettext("Group \"%s\" not found\n"), 1628 argv[optind]); 1629 ret = SA_NO_SUCH_GROUP; 1630 } 1631 } 1632 } 1633 return (ret); 1634 } 1635 1636 /* 1637 * sa_moveshare(flags, argc, argv) 1638 * 1639 * implements move-share subcommand. 1640 */ 1641 1642 int 1643 sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 1644 { 1645 int verbose = 0; 1646 int dryrun = 0; 1647 int c; 1648 int ret = SA_OK; 1649 sa_group_t group; 1650 sa_share_t share; 1651 char *sharepath = NULL; 1652 int authsrc = 0, authdst = 0; 1653 1654 while ((c = getopt(argc, argv, "?hvns:")) != EOF) { 1655 switch (c) { 1656 case 'n': 1657 dryrun++; 1658 break; 1659 case 'v': 1660 verbose++; 1661 break; 1662 case 's': 1663 /* 1664 * remove share path from group. Currently limit 1665 * to one share per command. 1666 */ 1667 if (sharepath != NULL) { 1668 (void) printf(gettext("Moving multiple shares not" 1669 "supported\n")); 1670 return (SA_BAD_PATH); 1671 } 1672 sharepath = optarg; 1673 break; 1674 default: 1675 case 'h': 1676 case '?': 1677 (void) printf(gettext("usage: %s\n"), 1678 sa_get_usage(USAGE_MOVE_SHARE)); 1679 return (0); 1680 } 1681 } 1682 1683 if (optind >= argc || sharepath == NULL) { 1684 (void) printf(gettext("usage: %s\n"), 1685 sa_get_usage(USAGE_MOVE_SHARE)); 1686 if (dryrun || verbose || sharepath != NULL) { 1687 (void) printf(gettext("\tgroup must be specified\n")); 1688 ret = SA_NO_SUCH_GROUP; 1689 } else { 1690 if (sharepath == NULL) { 1691 ret = SA_SYNTAX_ERR; 1692 (void) printf(gettext("\tsharepath must be specified\n")); 1693 } else 1694 ret = SA_OK; 1695 } 1696 } else { 1697 if (sharepath == NULL) { 1698 (void) printf(gettext("sharepath must be specified with " 1699 "the -s option\n")); 1700 ret = SA_BAD_PATH; 1701 } else { 1702 group = sa_get_group(handle, argv[optind]); 1703 if (group != NULL) { 1704 share = sa_find_share(handle, sharepath); 1705 authdst = check_authorizations(argv[optind], flags); 1706 if (share == NULL) { 1707 (void) printf(gettext("Share not found: %s\n"), 1708 sharepath); 1709 ret = SA_NO_SUCH_PATH; 1710 } else { 1711 sa_group_t parent; 1712 char *zfsold; 1713 char *zfsnew; 1714 1715 parent = sa_get_parent_group(share); 1716 if (parent != NULL) { 1717 char *pname; 1718 pname = sa_get_group_attr(parent, "name"); 1719 if (pname != NULL) { 1720 authsrc = check_authorizations(pname, flags); 1721 sa_free_attr_string(pname); 1722 } 1723 zfsold = sa_get_group_attr(parent, "zfs"); 1724 zfsnew = sa_get_group_attr(group, "zfs"); 1725 if ((zfsold != NULL && zfsnew == NULL) || 1726 (zfsold == NULL && zfsnew != NULL)) { 1727 ret = SA_NOT_ALLOWED; 1728 } 1729 if (zfsold != NULL) 1730 sa_free_attr_string(zfsold); 1731 if (zfsnew != NULL) 1732 sa_free_attr_string(zfsnew); 1733 } 1734 if (!dryrun && ret == SA_OK) { 1735 ret = sa_move_share(group, share); 1736 } 1737 if (ret == SA_OK && parent != group && !dryrun) { 1738 char *oldstate; 1739 ret = sa_update_config(handle); 1740 /* 1741 * note that the share may need to be 1742 * "unshared" if the new group is 1743 * disabled and the old was enabled or 1744 * it may need to be share to update 1745 * if the new group is enabled. 1746 */ 1747 oldstate = sa_get_group_attr(parent, "state"); 1748 /* enable_share determines what to do */ 1749 if (strcmp(oldstate, "enabled") == 0) { 1750 (void) sa_disable_share(share, NULL); 1751 } 1752 (void) enable_share(handle, group, share, 1); 1753 if (oldstate != NULL) 1754 sa_free_attr_string(oldstate); 1755 } 1756 if (ret != SA_OK) { 1757 (void) printf(gettext("Could not move share: %s\n"), 1758 sa_errorstr(ret)); 1759 } 1760 if (dryrun && ret == SA_OK && !(authsrc & authdst) && 1761 verbose) { 1762 (void) printf(gettext("Command would fail: %s\n"), 1763 sa_errorstr(SA_NO_PERMISSION)); 1764 } 1765 } 1766 } else { 1767 (void) printf(gettext("Group \"%s\" not found\n"), 1768 argv[optind]); 1769 ret = SA_NO_SUCH_GROUP; 1770 } 1771 } 1772 } 1773 return (ret); 1774 } 1775 1776 /* 1777 * sa_removeshare(flags, argc, argv) 1778 * 1779 * implements remove-share subcommand. 1780 */ 1781 1782 int 1783 sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 1784 { 1785 int verbose = 0; 1786 int dryrun = 0; 1787 int force = 0; 1788 int c; 1789 int ret = SA_OK; 1790 sa_group_t group; 1791 sa_share_t share; 1792 char *sharepath = NULL; 1793 char dir[MAXPATHLEN]; 1794 int auth; 1795 1796 while ((c = getopt(argc, argv, "?hfns:v")) != EOF) { 1797 switch (c) { 1798 case 'n': 1799 dryrun++; 1800 break; 1801 case 'v': 1802 verbose++; 1803 break; 1804 case 'f': 1805 force++; 1806 break; 1807 case 's': 1808 /* 1809 * remove share path from group. Currently limit 1810 * to one share per command. 1811 */ 1812 if (sharepath != NULL) { 1813 (void) printf(gettext("Removing multiple shares not" 1814 "supported\n")); 1815 return (SA_SYNTAX_ERR); 1816 } 1817 sharepath = optarg; 1818 break; 1819 default: 1820 case 'h': 1821 case '?': 1822 (void) printf(gettext("usage: %s\n"), 1823 sa_get_usage(USAGE_REMOVE_SHARE)); 1824 return (0); 1825 } 1826 } 1827 1828 if (optind >= argc || sharepath == NULL) { 1829 if (sharepath == NULL) { 1830 (void) printf(gettext("usage: %s\n"), 1831 sa_get_usage(USAGE_REMOVE_SHARE)); 1832 (void) printf(gettext("\t-s sharepath must be specified\n")); 1833 ret = SA_BAD_PATH; 1834 } else { 1835 ret = SA_OK; 1836 } 1837 } 1838 if (ret == SA_OK) { 1839 if (optind < argc) { 1840 if ((optind + 1) < argc) { 1841 (void) printf(gettext("Extraneous group(s) at end of " 1842 "command\n")); 1843 ret = SA_SYNTAX_ERR; 1844 } else { 1845 group = sa_get_group(handle, argv[optind]); 1846 if (group == NULL) { 1847 (void) printf(gettext("Group \"%s\" not found\n"), 1848 argv[optind]); 1849 ret = SA_NO_SUCH_GROUP; 1850 } 1851 } 1852 } else { 1853 group = NULL; 1854 } 1855 1856 /* 1857 * Lookup the path in the internal configuration. Care 1858 * must be taken to handle the case where the 1859 * underlying path has been removed since we need to 1860 * be able to deal with that as well. 1861 */ 1862 if (ret == SA_OK) { 1863 if (group != NULL) 1864 share = sa_get_share(group, sharepath); 1865 else 1866 share = sa_find_share(handle, sharepath); 1867 /* 1868 * If we didn't find the share with the provided path, 1869 * it may be a symlink so attempt to resolve it using 1870 * realpath and try again. Realpath will resolve any 1871 * symlinks and place them in "dir". Note that 1872 * sharepath is only used for the lookup the first 1873 * time and later for error messages. dir will be used 1874 * on the second attempt. Once a share is found, all 1875 * operations are based off of the share variable. 1876 */ 1877 if (share == NULL) { 1878 if (realpath(sharepath, dir) == NULL) { 1879 ret = SA_BAD_PATH; 1880 (void) printf(gettext("Path is not valid: %s\n"), 1881 sharepath); 1882 } else { 1883 if (group != NULL) 1884 share = sa_get_share(group, dir); 1885 else 1886 share = sa_find_share(handle, dir); 1887 } 1888 } 1889 } 1890 1891 /* 1892 * If there hasn't been an error, there was likely a 1893 * path found. If not, give the appropriate error 1894 * message and set the return error. If it was found, 1895 * then disable the share and then remove it from the 1896 * configuration. 1897 */ 1898 if (ret == SA_OK) { 1899 if (share == NULL) { 1900 if (group != NULL) 1901 (void) printf(gettext("Share not found in group %s:" 1902 " %s\n"), 1903 argv[optind], sharepath); 1904 else 1905 (void) printf(gettext("Share not found: %s\n"), 1906 sharepath); 1907 ret = SA_NO_SUCH_PATH; 1908 } else { 1909 if (group == NULL) 1910 group = sa_get_parent_group(share); 1911 if (!dryrun) { 1912 if (ret == SA_OK) { 1913 ret = sa_disable_share(share, NULL); 1914 /* 1915 * we don't care if it fails since it 1916 * could be disabled already. Some 1917 * unexpected errors could occur that 1918 * prevent removal, so also check for 1919 * force being set. 1920 */ 1921 if (ret == SA_OK || ret == SA_NO_SUCH_PATH || 1922 ret == SA_NOT_SUPPORTED || 1923 ret == SA_SYSTEM_ERR || force) { 1924 ret = sa_remove_share(share); 1925 } 1926 if (ret == SA_OK) 1927 ret = sa_update_config(handle); 1928 } 1929 if (ret != SA_OK) { 1930 (void) printf(gettext("Could not remove share:" 1931 " %s\n"), 1932 sa_errorstr(ret)); 1933 } 1934 } else if (ret == SA_OK) { 1935 char *pname; 1936 pname = sa_get_group_attr(group, "name"); 1937 if (pname != NULL) { 1938 auth = check_authorizations(pname, flags); 1939 sa_free_attr_string(pname); 1940 } 1941 if (!auth && verbose) { 1942 (void) printf(gettext("Command would fail: %s\n"), 1943 sa_errorstr(SA_NO_PERMISSION)); 1944 } 1945 } 1946 } 1947 } 1948 } 1949 return (ret); 1950 } 1951 1952 /* 1953 * sa_set_share(flags, argc, argv) 1954 * 1955 * implements set-share subcommand. 1956 */ 1957 1958 int 1959 sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 1960 { 1961 int dryrun = 0; 1962 int c; 1963 int ret = SA_OK; 1964 sa_group_t group, sharegroup; 1965 sa_share_t share; 1966 char *sharepath = NULL; 1967 char *description = NULL; 1968 char *resource = NULL; 1969 int auth; 1970 int verbose = 0; 1971 1972 while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 1973 switch (c) { 1974 case 'n': 1975 dryrun++; 1976 break; 1977 case 'd': 1978 description = optarg; 1979 break; 1980 case 'r': 1981 resource = optarg; 1982 break; 1983 case 'v': 1984 verbose++; 1985 break; 1986 case 's': 1987 /* 1988 * save share path into group. Currently limit 1989 * to one share per command. 1990 */ 1991 if (sharepath != NULL) { 1992 (void) printf(gettext("Updating multiple shares not" 1993 "supported\n")); 1994 return (SA_BAD_PATH); 1995 } 1996 sharepath = optarg; 1997 break; 1998 default: 1999 case 'h': 2000 case '?': 2001 (void) printf(gettext("usage: %s\n"), 2002 sa_get_usage(USAGE_SET_SHARE)); 2003 return (SA_OK); 2004 } 2005 } 2006 if (optind >= argc || sharepath == NULL) { 2007 if (sharepath == NULL) { 2008 (void) printf(gettext("usage: %s\n"), 2009 sa_get_usage(USAGE_SET_SHARE)); 2010 (void) printf(gettext("\tgroup must be specified\n")); 2011 ret = SA_BAD_PATH; 2012 } else { 2013 ret = SA_OK; 2014 } 2015 } 2016 if ((optind + 1) < argc) { 2017 (void) printf(gettext("usage: %s\n"), 2018 sa_get_usage(USAGE_SET_SHARE)); 2019 (void) printf(gettext("\tExtraneous group(s) at end\n")); 2020 ret = SA_SYNTAX_ERR; 2021 } 2022 if (ret == SA_OK) { 2023 char *groupname; 2024 if (optind < argc) { 2025 groupname = argv[optind]; 2026 group = sa_get_group(handle, groupname); 2027 } else { 2028 group = NULL; 2029 groupname = NULL; 2030 } 2031 share = sa_find_share(handle, sharepath); 2032 if (share != NULL) { 2033 sharegroup = sa_get_parent_group(share); 2034 if (group != NULL && group != sharegroup) { 2035 (void) printf(gettext("Group \"%s\" does not contain " 2036 "share %s\n"), 2037 argv[optind], sharepath); 2038 ret = SA_BAD_PATH; 2039 } else { 2040 int delgroupname = 0; 2041 if (groupname == NULL) { 2042 groupname = sa_get_group_attr(sharegroup, "name"); 2043 delgroupname = 1; 2044 } 2045 if (groupname != NULL) { 2046 auth = check_authorizations(groupname, flags); 2047 if (delgroupname) { 2048 sa_free_attr_string(groupname); 2049 groupname = NULL; 2050 } 2051 } else { 2052 ret = SA_NO_MEMORY; 2053 } 2054 if (resource != NULL) { 2055 if (strpbrk(resource, " \t/") == NULL) { 2056 if (!dryrun) { 2057 ret = sa_set_share_attr(share, "resource", 2058 resource); 2059 } else { 2060 sa_share_t resshare; 2061 resshare = sa_get_resource(sharegroup, 2062 resource); 2063 if (resshare != NULL && resshare != share) 2064 ret = SA_DUPLICATE_NAME; 2065 } 2066 } else { 2067 ret = SA_BAD_PATH; 2068 (void) printf(gettext("Resource must not contain " 2069 "white space or '/'\n")); 2070 } 2071 } 2072 if (ret == SA_OK && description != NULL) { 2073 ret = sa_set_share_description(share, description); 2074 } 2075 } 2076 if (!dryrun && ret == SA_OK) { 2077 ret = sa_update_config(handle); 2078 } 2079 switch (ret) { 2080 case SA_DUPLICATE_NAME: 2081 (void) printf(gettext("Resource name in use: %s\n"), 2082 resource); 2083 break; 2084 default: 2085 (void) printf(gettext("Could not set attribute: %s\n"), 2086 sa_errorstr(ret)); 2087 break; 2088 case SA_OK: 2089 if (dryrun && !auth && verbose) { 2090 (void) printf(gettext("Command would fail: %s\n"), 2091 sa_errorstr(SA_NO_PERMISSION)); 2092 } 2093 break; 2094 } 2095 } else { 2096 (void) printf(gettext("Share path \"%s\" not found\n"), 2097 sharepath); 2098 ret = SA_NO_SUCH_PATH; 2099 } 2100 } 2101 return (ret); 2102 } 2103 2104 /* 2105 * add_security(group, sectype, optlist, proto, *err) 2106 * 2107 * Helper function to add a security option (named optionset) to the 2108 * group. 2109 */ 2110 2111 static int 2112 add_security(sa_group_t group, char *sectype, 2113 struct options *optlist, char *proto, int *err) 2114 { 2115 sa_security_t security; 2116 int ret = SA_OK; 2117 int result = 0; 2118 2119 sectype = sa_proto_space_alias(proto, sectype); 2120 security = sa_get_security(group, sectype, proto); 2121 if (security == NULL) { 2122 security = sa_create_security(group, sectype, proto); 2123 } 2124 if (sectype != NULL) 2125 sa_free_attr_string(sectype); 2126 if (security != NULL) { 2127 while (optlist != NULL) { 2128 sa_property_t prop; 2129 prop = sa_get_property(security, optlist->optname); 2130 if (prop == NULL) { 2131 /* 2132 * add the property, but only if it is 2133 * a non-NULL or non-zero length value 2134 */ 2135 if (optlist->optvalue != NULL) { 2136 prop = sa_create_property(optlist->optname, 2137 optlist->optvalue); 2138 if (prop != NULL) { 2139 ret = sa_valid_property(security, proto, prop); 2140 if (ret != SA_OK) { 2141 (void) sa_remove_property(prop); 2142 (void) printf(gettext("Could not add " 2143 "property %s: %s\n"), 2144 optlist->optname, 2145 sa_errorstr(ret)); 2146 } 2147 if (ret == SA_OK) { 2148 ret = sa_add_property(security, prop); 2149 if (ret != SA_OK) { 2150 (void) printf(gettext("Could not add " 2151 "property (%s=%s): %s\n"), 2152 optlist->optname, 2153 optlist->optvalue, 2154 sa_errorstr(ret)); 2155 } else { 2156 result = 1; 2157 } 2158 } 2159 } 2160 } 2161 } else { 2162 ret = sa_update_property(prop, optlist->optvalue); 2163 result = 1; /* should check if really changed */ 2164 } 2165 optlist = optlist->next; 2166 } 2167 /* 2168 * when done, properties may have all been removed but 2169 * we need to keep the security type itself until 2170 * explicitly removed. 2171 */ 2172 if (result) 2173 ret = sa_commit_properties(security, 0); 2174 } 2175 *err = ret; 2176 return (result); 2177 } 2178 2179 /* 2180 * basic_set(groupname, optlist, protocol, sharepath, dryrun) 2181 * 2182 * This function implements "set" when a name space (-S) is not 2183 * specified. It is a basic set. Options and other CLI parsing has 2184 * already been done. 2185 */ 2186 2187 static int 2188 basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 2189 char *protocol, char *sharepath, int dryrun) 2190 { 2191 sa_group_t group; 2192 int ret = SA_OK; 2193 int change = 0; 2194 struct list *worklist = NULL; 2195 2196 group = sa_get_group(handle, groupname); 2197 if (group != NULL) { 2198 sa_share_t share = NULL; 2199 if (sharepath != NULL) { 2200 share = sa_get_share(group, sharepath); 2201 if (share == NULL) { 2202 (void) printf(gettext("Share does not exist in group %s\n"), 2203 groupname, sharepath); 2204 ret = SA_NO_SUCH_PATH; 2205 } 2206 } 2207 if (ret == SA_OK) { 2208 /* group must exist */ 2209 ret = valid_options(optlist, protocol, 2210 share == NULL ? group : share, NULL); 2211 if (ret == SA_OK && !dryrun) { 2212 if (share != NULL) 2213 change |= add_optionset(share, optlist, protocol, 2214 &ret); 2215 else 2216 change |= add_optionset(group, optlist, protocol, 2217 &ret); 2218 if (ret == SA_OK && change) { 2219 worklist = add_list(worklist, group, share); 2220 } 2221 } 2222 } 2223 free_opt(optlist); 2224 } else { 2225 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2226 ret = SA_NO_SUCH_GROUP; 2227 } 2228 /* 2229 * we have a group and potentially legal additions 2230 */ 2231 2232 /* commit to configuration if not a dryrun */ 2233 if (!dryrun && ret == SA_OK) { 2234 if (change && worklist != NULL) { 2235 /* properties changed, so update all shares */ 2236 (void) enable_all_groups(handle, worklist, 0, 0, protocol); 2237 } 2238 } 2239 if (worklist != NULL) 2240 free_list(worklist); 2241 return (ret); 2242 } 2243 2244 /* 2245 * space_set(groupname, optlist, protocol, sharepath, dryrun) 2246 * 2247 * This function implements "set" when a name space (-S) is 2248 * specified. It is a namespace set. Options and other CLI parsing has 2249 * already been done. 2250 */ 2251 2252 static int 2253 space_set(sa_handle_t handle, char *groupname, struct options *optlist, 2254 char *protocol, char *sharepath, int dryrun, char *sectype) 2255 { 2256 sa_group_t group; 2257 int ret = SA_OK; 2258 int change = 0; 2259 struct list *worklist = NULL; 2260 2261 /* 2262 * make sure protcol and sectype are valid 2263 */ 2264 2265 if (sa_proto_valid_space(protocol, sectype) == 0) { 2266 (void) printf(gettext("Option space \"%s\" not valid " 2267 "for protocol.\n"), 2268 sectype); 2269 return (SA_INVALID_SECURITY); 2270 } 2271 2272 group = sa_get_group(handle, groupname); 2273 if (group != NULL) { 2274 sa_share_t share = NULL; 2275 if (sharepath != NULL) { 2276 share = sa_get_share(group, sharepath); 2277 if (share == NULL) { 2278 (void) printf(gettext("Share does not exist in group %s\n"), 2279 groupname, sharepath); 2280 ret = SA_NO_SUCH_PATH; 2281 } 2282 } 2283 if (ret == SA_OK) { 2284 /* group must exist */ 2285 ret = valid_options(optlist, protocol, 2286 share == NULL ? group : share, sectype); 2287 if (ret == SA_OK && !dryrun) { 2288 if (share != NULL) 2289 change = add_security(share, sectype, optlist, 2290 protocol, 2291 &ret); 2292 else 2293 change = add_security(group, sectype, optlist, 2294 protocol, 2295 &ret); 2296 if (ret != SA_OK) 2297 (void) printf(gettext("Could not set property: %s\n"), 2298 sa_errorstr(ret)); 2299 } 2300 if (ret == SA_OK && change) 2301 worklist = add_list(worklist, group, share); 2302 } 2303 free_opt(optlist); 2304 } else { 2305 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2306 ret = SA_NO_SUCH_GROUP; 2307 } 2308 /* 2309 * we have a group and potentially legal additions 2310 */ 2311 2312 /* commit to configuration if not a dryrun */ 2313 if (!dryrun && ret == 0) { 2314 if (change && worklist != NULL) { 2315 /* properties changed, so update all shares */ 2316 (void) enable_all_groups(handle, worklist, 0, 0, protocol); 2317 } 2318 ret = sa_update_config(handle); 2319 } 2320 if (worklist != NULL) 2321 free_list(worklist); 2322 return (ret); 2323 } 2324 2325 /* 2326 * sa_set(flags, argc, argv) 2327 * 2328 * Implements the set subcommand. It keys off of -S to determine which 2329 * set of operations to actually do. 2330 */ 2331 2332 int 2333 sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 2334 { 2335 char *groupname; 2336 int verbose = 0; 2337 int dryrun = 0; 2338 int c; 2339 char *protocol = NULL; 2340 int ret = SA_OK; 2341 struct options *optlist = NULL; 2342 char *sharepath = NULL; 2343 char *optset = NULL; 2344 int auth; 2345 2346 while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2347 switch (c) { 2348 case 'v': 2349 verbose++; 2350 break; 2351 case 'n': 2352 dryrun++; 2353 break; 2354 case 'P': 2355 protocol = optarg; 2356 if (!sa_valid_protocol(protocol)) { 2357 (void) printf(gettext("Invalid protocol specified:" 2358 "%s\n"), 2359 protocol); 2360 return (SA_INVALID_PROTOCOL); 2361 } 2362 break; 2363 case 'p': 2364 ret = add_opt(&optlist, optarg, 0); 2365 switch (ret) { 2366 case OPT_ADD_SYNTAX: 2367 (void) printf(gettext("Property syntax error: %s\n"), 2368 optarg); 2369 return (SA_SYNTAX_ERR); 2370 case OPT_ADD_MEMORY: 2371 (void) printf(gettext("No memory to set property: %s\n"), 2372 optarg); 2373 return (SA_NO_MEMORY); 2374 default: 2375 break; 2376 } 2377 break; 2378 case 's': 2379 sharepath = optarg; 2380 break; 2381 case 'S': 2382 optset = optarg; 2383 break; 2384 default: 2385 case 'h': 2386 case '?': 2387 (void) printf(gettext("usage: %s\n"), 2388 sa_get_usage(USAGE_SET)); 2389 return (SA_OK); 2390 } 2391 } 2392 2393 if (optlist != NULL) 2394 ret = chk_opt(optlist, optset != NULL, protocol); 2395 2396 if (optind >= argc || (optlist == NULL && optset == NULL) || 2397 protocol == NULL || 2398 ret != OPT_ADD_OK) { 2399 char *sep = "\t"; 2400 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 2401 if (optind >= argc) { 2402 (void) printf(gettext("%sgroup must be specified"), sep); 2403 sep = ", "; 2404 } 2405 if (optlist == NULL) { 2406 (void) printf(gettext("%sat least one property must be" 2407 " specified"), sep); 2408 sep = ", "; 2409 } 2410 if (protocol == NULL) { 2411 (void) printf(gettext("%sprotocol must be specified"), sep); 2412 sep = ", "; 2413 } 2414 (void) printf("\n"); 2415 ret = SA_SYNTAX_ERR; 2416 } else { 2417 /* 2418 * if a group already exists, we can only add a new 2419 * protocol to it and not create a new one or add the 2420 * same protocol again. 2421 */ 2422 2423 groupname = argv[optind]; 2424 auth = check_authorizations(groupname, flags); 2425 if (optset == NULL) 2426 ret = basic_set(handle, groupname, optlist, protocol, 2427 sharepath, dryrun); 2428 else 2429 ret = space_set(handle, groupname, optlist, protocol, 2430 sharepath, dryrun, optset); 2431 if (dryrun && ret == SA_OK && !auth && verbose) { 2432 (void) printf(gettext("Command would fail: %s\n"), 2433 sa_errorstr(SA_NO_PERMISSION)); 2434 } 2435 } 2436 return (ret); 2437 } 2438 2439 /* 2440 * remove_options(group, optlist, proto, *err) 2441 * 2442 * helper function to actually remove options from a group after all 2443 * preprocessing is done. 2444 */ 2445 2446 static int 2447 remove_options(sa_group_t group, struct options *optlist, 2448 char *proto, int *err) 2449 { 2450 struct options *cur; 2451 sa_optionset_t optionset; 2452 sa_property_t prop; 2453 int change = 0; 2454 int ret = SA_OK; 2455 2456 optionset = sa_get_optionset(group, proto); 2457 if (optionset != NULL) { 2458 for (cur = optlist; cur != NULL; cur = cur->next) { 2459 prop = sa_get_property(optionset, cur->optname); 2460 if (prop != NULL) { 2461 ret = sa_remove_property(prop); 2462 if (ret != SA_OK) 2463 break; 2464 change = 1; 2465 } 2466 } 2467 } 2468 if (ret == SA_OK && change) 2469 ret = sa_commit_properties(optionset, 0); 2470 2471 if (err != NULL) 2472 *err = ret; 2473 return (change); 2474 } 2475 2476 /* 2477 * valid_unset(group, optlist, proto) 2478 * 2479 * Sanity check the optlist to make sure they can be removed. Issue an 2480 * error if a property doesn't exist. 2481 */ 2482 2483 static int 2484 valid_unset(sa_group_t group, struct options *optlist, char *proto) 2485 { 2486 struct options *cur; 2487 sa_optionset_t optionset; 2488 sa_property_t prop; 2489 int ret = SA_OK; 2490 2491 optionset = sa_get_optionset(group, proto); 2492 if (optionset != NULL) { 2493 for (cur = optlist; cur != NULL; cur = cur->next) { 2494 prop = sa_get_property(optionset, cur->optname); 2495 if (prop == NULL) { 2496 (void) printf(gettext("Could not unset property %s:" 2497 " not set\n"), 2498 cur->optname); 2499 ret = SA_NO_SUCH_PROP; 2500 } 2501 } 2502 } 2503 return (ret); 2504 } 2505 2506 /* 2507 * valid_unset_security(group, optlist, proto) 2508 * 2509 * Sanity check the optlist to make sure they can be removed. Issue an 2510 * error if a property doesn't exist. 2511 */ 2512 2513 static int 2514 valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 2515 char *sectype) 2516 { 2517 struct options *cur; 2518 sa_security_t security; 2519 sa_property_t prop; 2520 int ret = SA_OK; 2521 char *sec; 2522 2523 sec = sa_proto_space_alias(proto, sectype); 2524 security = sa_get_security(group, sec, proto); 2525 if (security != NULL) { 2526 for (cur = optlist; cur != NULL; cur = cur->next) { 2527 prop = sa_get_property(security, cur->optname); 2528 if (prop == NULL) { 2529 (void) printf(gettext("Could not unset property %s:" 2530 " not set\n"), 2531 cur->optname); 2532 ret = SA_NO_SUCH_PROP; 2533 } 2534 } 2535 } else { 2536 (void) printf(gettext("Could not unset %s: space not defined\n"), 2537 sectype); 2538 ret = SA_NO_SUCH_SECURITY; 2539 } 2540 if (sec != NULL) 2541 sa_free_attr_string(sec); 2542 return (ret); 2543 } 2544 2545 /* 2546 * remove_security(group, optlist, proto) 2547 * 2548 * Remove the properties since they were checked as valid. 2549 */ 2550 2551 static int 2552 remove_security(sa_group_t group, char *sectype, 2553 struct options *optlist, char *proto, int *err) 2554 { 2555 sa_security_t security; 2556 int ret = SA_OK; 2557 int change = 0; 2558 2559 sectype = sa_proto_space_alias(proto, sectype); 2560 security = sa_get_security(group, sectype, proto); 2561 if (sectype != NULL) 2562 sa_free_attr_string(sectype); 2563 2564 if (security != NULL) { 2565 while (optlist != NULL) { 2566 sa_property_t prop; 2567 prop = sa_get_property(security, optlist->optname); 2568 if (prop != NULL) { 2569 ret = sa_remove_property(prop); 2570 if (ret != SA_OK) 2571 break; 2572 change = 1; 2573 } 2574 optlist = optlist->next; 2575 } 2576 /* 2577 * when done, properties may have all been removed but 2578 * we need to keep the security type itself until 2579 * explicitly removed. 2580 */ 2581 if (ret == SA_OK && change) 2582 ret = sa_commit_properties(security, 0); 2583 } else { 2584 ret = SA_NO_SUCH_PROP; 2585 } 2586 if (err != NULL) 2587 *err = ret; 2588 return (change); 2589 } 2590 2591 /* 2592 * basic_unset(groupname, optlist, protocol, sharepath, dryrun) 2593 * 2594 * unset non-named optionset properties. 2595 */ 2596 2597 static int 2598 basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 2599 char *protocol, char *sharepath, int dryrun) 2600 { 2601 sa_group_t group; 2602 int ret = SA_OK; 2603 int change = 0; 2604 struct list *worklist = NULL; 2605 2606 group = sa_get_group(handle, groupname); 2607 if (group != NULL) { 2608 sa_share_t share = NULL; 2609 if (sharepath != NULL) { 2610 share = sa_get_share(group, sharepath); 2611 if (share == NULL) { 2612 (void) printf(gettext("Share does not exist in group %s\n"), 2613 groupname, sharepath); 2614 ret = SA_NO_SUCH_PATH; 2615 } 2616 } 2617 if (ret == SA_OK) { 2618 /* group must exist */ 2619 ret = valid_unset(share != NULL ? share : group, 2620 optlist, protocol); 2621 if (ret == SA_OK && !dryrun) { 2622 if (share != NULL) { 2623 sa_optionset_t optionset; 2624 sa_property_t prop; 2625 change |= remove_options(share, optlist, protocol, 2626 &ret); 2627 /* if a share optionset is empty, remove it */ 2628 optionset = sa_get_optionset((sa_share_t)share, 2629 protocol); 2630 if (optionset != NULL) { 2631 prop = sa_get_property(optionset, NULL); 2632 if (prop == NULL) 2633 (void) sa_destroy_optionset(optionset); 2634 } 2635 } else { 2636 change |= remove_options(group, optlist, protocol, 2637 &ret); 2638 } 2639 if (ret == SA_OK && change) 2640 worklist = add_list(worklist, group, share); 2641 if (ret != SA_OK) 2642 (void) printf(gettext("Could not remove properties:" 2643 "%s\n"), 2644 sa_errorstr(ret)); 2645 } 2646 } else { 2647 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2648 ret = SA_NO_SUCH_GROUP; 2649 } 2650 free_opt(optlist); 2651 } 2652 2653 /* 2654 * we have a group and potentially legal additions 2655 */ 2656 /* commit to configuration if not a dryrun */ 2657 if (!dryrun && ret == SA_OK) { 2658 if (change && worklist != NULL) { 2659 /* properties changed, so update all shares */ 2660 (void) enable_all_groups(handle, worklist, 0, 0, protocol); 2661 } 2662 } 2663 if (worklist != NULL) 2664 free_list(worklist); 2665 return (ret); 2666 } 2667 2668 /* 2669 * space_unset(groupname, optlist, protocol, sharepath, dryrun) 2670 * 2671 * unset named optionset properties. 2672 */ 2673 static int 2674 space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 2675 char *protocol, char *sharepath, int dryrun, char *sectype) 2676 { 2677 sa_group_t group; 2678 int ret = SA_OK; 2679 int change = 0; 2680 struct list *worklist = NULL; 2681 2682 group = sa_get_group(handle, groupname); 2683 if (group != NULL) { 2684 sa_share_t share = NULL; 2685 if (sharepath != NULL) { 2686 share = sa_get_share(group, sharepath); 2687 if (share == NULL) { 2688 (void) printf(gettext("Share does not exist in group %s\n"), 2689 groupname, sharepath); 2690 ret = SA_NO_SUCH_PATH; 2691 } 2692 } 2693 if (ret == SA_OK) { 2694 ret = valid_unset_security(share != NULL ? share : group, 2695 optlist, protocol, sectype); 2696 if (ret == SA_OK && !dryrun) { 2697 if (optlist != NULL) { 2698 if (share != NULL) { 2699 sa_security_t optionset; 2700 sa_property_t prop; 2701 change = remove_security(share, sectype, 2702 optlist, protocol, 2703 &ret); 2704 /* if a share security is empty, remove it */ 2705 optionset = sa_get_security((sa_group_t)share, 2706 sectype, 2707 protocol); 2708 if (optionset != NULL) { 2709 prop = sa_get_property(optionset, NULL); 2710 if (prop == NULL) 2711 ret = sa_destroy_security(optionset); 2712 } 2713 } else { 2714 change = remove_security(group, sectype, 2715 optlist, protocol, 2716 &ret); 2717 } 2718 } else { 2719 sa_security_t security; 2720 char *sec; 2721 sec = sa_proto_space_alias(protocol, sectype); 2722 security = sa_get_security(group, sec, protocol); 2723 if (sec != NULL) 2724 sa_free_attr_string(sec); 2725 if (security != NULL) { 2726 ret = sa_destroy_security(security); 2727 if (ret == SA_OK) 2728 change = 1; 2729 } else { 2730 ret = SA_NO_SUCH_PROP; 2731 } 2732 } 2733 if (ret != SA_OK) 2734 (void) printf(gettext("Could not unset property: %s\n"), 2735 sa_errorstr(ret)); 2736 } 2737 2738 if (ret == SA_OK && change) 2739 worklist = add_list(worklist, group, 0); 2740 } 2741 } else { 2742 (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2743 ret = SA_NO_SUCH_GROUP; 2744 } 2745 free_opt(optlist); 2746 /* 2747 * we have a group and potentially legal additions 2748 */ 2749 2750 /* commit to configuration if not a dryrun */ 2751 if (!dryrun && ret == 0) { 2752 if (change && worklist != NULL) { 2753 /* properties changed, so update all shares */ 2754 (void) enable_all_groups(handle, worklist, 0, 0, protocol); 2755 } 2756 ret = sa_update_config(handle); 2757 } 2758 if (worklist != NULL) 2759 free_list(worklist); 2760 return (ret); 2761 } 2762 2763 /* 2764 * sa_unset(flags, argc, argv) 2765 * 2766 * implements the unset subcommand. Parsing done here and then basic 2767 * or space versions of the real code are called. 2768 */ 2769 2770 int 2771 sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 2772 { 2773 char *groupname; 2774 int verbose = 0; 2775 int dryrun = 0; 2776 int c; 2777 char *protocol = NULL; 2778 int ret = SA_OK; 2779 struct options *optlist = NULL; 2780 char *sharepath = NULL; 2781 char *optset = NULL; 2782 int auth; 2783 2784 while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2785 switch (c) { 2786 case 'v': 2787 verbose++; 2788 break; 2789 case 'n': 2790 dryrun++; 2791 break; 2792 case 'P': 2793 protocol = optarg; 2794 if (!sa_valid_protocol(protocol)) { 2795 (void) printf(gettext("Invalid protocol specified: %s\n"), 2796 protocol); 2797 return (SA_INVALID_PROTOCOL); 2798 } 2799 break; 2800 case 'p': 2801 ret = add_opt(&optlist, optarg, 1); 2802 switch (ret) { 2803 case OPT_ADD_SYNTAX: 2804 (void) printf(gettext("Property syntax error for " 2805 "property %s\n"), 2806 optarg); 2807 return (SA_SYNTAX_ERR); 2808 case OPT_ADD_PROPERTY: 2809 (void) printf(gettext("Properties need to be set" 2810 " with set command: %s\n"), 2811 optarg); 2812 return (SA_SYNTAX_ERR); 2813 default: 2814 break; 2815 } 2816 break; 2817 case 's': 2818 sharepath = optarg; 2819 break; 2820 case 'S': 2821 optset = optarg; 2822 break; 2823 default: 2824 case 'h': 2825 case '?': 2826 (void) printf(gettext("usage: %s\n"), 2827 sa_get_usage(USAGE_UNSET)); 2828 return (SA_OK); 2829 } 2830 } 2831 2832 if (optlist != NULL) 2833 ret = chk_opt(optlist, optset != NULL, protocol); 2834 2835 if (optind >= argc || (optlist == NULL && optset == NULL) || 2836 protocol == NULL) { 2837 char *sep = "\t"; 2838 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET)); 2839 if (optind >= argc) { 2840 (void) printf(gettext("%sgroup must be specified"), sep); 2841 sep = ", "; 2842 } 2843 if (optlist == NULL) { 2844 (void) printf(gettext("%sat least one property must be " 2845 "specified"), 2846 sep); 2847 sep = ", "; 2848 } 2849 if (protocol == NULL) { 2850 (void) printf(gettext("%sprotocol must be specified"), sep); 2851 sep = ", "; 2852 } 2853 (void) printf("\n"); 2854 ret = SA_SYNTAX_ERR; 2855 } else { 2856 2857 /* 2858 * if a group already exists, we can only add a new 2859 * protocol to it and not create a new one or add the 2860 * same protocol again. 2861 */ 2862 2863 groupname = argv[optind]; 2864 auth = check_authorizations(groupname, flags); 2865 if (optset == NULL) 2866 ret = basic_unset(handle, groupname, optlist, protocol, 2867 sharepath, dryrun); 2868 else 2869 ret = space_unset(handle, groupname, optlist, protocol, 2870 sharepath, dryrun, optset); 2871 2872 if (dryrun && ret == SA_OK && !auth && verbose) { 2873 (void) printf(gettext("Command would fail: %s\n"), 2874 sa_errorstr(SA_NO_PERMISSION)); 2875 } 2876 } 2877 return (ret); 2878 } 2879 2880 /* 2881 * sa_enable_group(flags, argc, argv) 2882 * 2883 * Implements the enable subcommand 2884 */ 2885 2886 int 2887 sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 2888 { 2889 int verbose = 0; 2890 int dryrun = 0; 2891 int all = 0; 2892 int c; 2893 int ret = SA_OK; 2894 char *protocol = NULL; 2895 char *state; 2896 struct list *worklist = NULL; 2897 int auth = 1; 2898 2899 while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 2900 switch (c) { 2901 case 'a': 2902 all = 1; 2903 break; 2904 case 'n': 2905 dryrun++; 2906 break; 2907 case 'P': 2908 protocol = optarg; 2909 if (!sa_valid_protocol(protocol)) { 2910 (void) printf(gettext("Invalid protocol specified: %s\n"), 2911 protocol); 2912 return (SA_INVALID_PROTOCOL); 2913 } 2914 break; 2915 case 'v': 2916 verbose++; 2917 break; 2918 default: 2919 case 'h': 2920 case '?': 2921 (void) printf(gettext("usage: %s\n"), 2922 sa_get_usage(USAGE_ENABLE)); 2923 return (0); 2924 } 2925 } 2926 2927 if (optind == argc && !all) { 2928 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE)); 2929 (void) printf(gettext("\tmust specify group\n")); 2930 ret = SA_NO_SUCH_PATH; 2931 } else { 2932 sa_group_t group; 2933 if (!all) { 2934 while (optind < argc) { 2935 group = sa_get_group(handle, argv[optind]); 2936 if (group != NULL) { 2937 auth &= check_authorizations(argv[optind], flags); 2938 state = sa_get_group_attr(group, "state"); 2939 if (state != NULL && 2940 strcmp(state, "enabled") == 0) { 2941 /* already enabled */ 2942 if (verbose) 2943 (void) printf(gettext("Group \"%s\" is already " 2944 "enabled\n"), 2945 argv[optind]); 2946 ret = SA_BUSY; /* already enabled */ 2947 } else { 2948 worklist = add_list(worklist, group, 0); 2949 if (verbose) 2950 (void) printf(gettext("Enabling group " 2951 "\"%s\"\n"), 2952 argv[optind]); 2953 } 2954 if (state != NULL) 2955 sa_free_attr_string(state); 2956 } else { 2957 ret = SA_NO_SUCH_GROUP; 2958 } 2959 optind++; 2960 } 2961 } else { 2962 for (group = sa_get_group(handle, NULL); group != NULL; 2963 group = sa_get_next_group(group)) { 2964 worklist = add_list(worklist, group, 0); 2965 } 2966 } 2967 if (!dryrun && ret == SA_OK) { 2968 ret = enable_all_groups(handle, worklist, 1, 0, NULL); 2969 } 2970 if (ret != SA_OK && ret != SA_BUSY) 2971 (void) printf(gettext("Could not enable group: %s\n"), 2972 sa_errorstr(ret)); 2973 if (ret == SA_BUSY) 2974 ret = SA_OK; 2975 } 2976 if (worklist != NULL) 2977 free_list(worklist); 2978 if (dryrun && ret == SA_OK && !auth && verbose) { 2979 (void) printf(gettext("Command would fail: %s\n"), 2980 sa_errorstr(SA_NO_PERMISSION)); 2981 } 2982 return (ret); 2983 } 2984 2985 /* 2986 * disable_group(group, setstate) 2987 * 2988 * disable all the shares in the specified group honoring the setstate 2989 * argument. This is a helper for disable_all_groups in order to 2990 * simplify regular and subgroup (zfs) disabling. Group has already 2991 * been checked for non-NULL. 2992 */ 2993 2994 static int 2995 disable_group(sa_group_t group) 2996 { 2997 sa_share_t share; 2998 int ret = SA_OK; 2999 3000 for (share = sa_get_share(group, NULL); 3001 share != NULL && ret == SA_OK; 3002 share = sa_get_next_share(share)) { 3003 ret = sa_disable_share(share, NULL); 3004 if (ret == SA_NO_SUCH_PATH) { 3005 /* 3006 * this is OK since the path is gone. we can't 3007 * re-share it anyway so no error. 3008 */ 3009 ret = SA_OK; 3010 } 3011 } 3012 return (ret); 3013 } 3014 3015 3016 /* 3017 * disable_all_groups(work, setstate) 3018 * 3019 * helper function that disables the shares in the list of groups 3020 * provided. It optionally marks the group as disabled. Used by both 3021 * enable and start subcommands. 3022 */ 3023 3024 static int 3025 disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 3026 { 3027 int ret = SA_OK; 3028 sa_group_t subgroup, group; 3029 3030 while (work != NULL && ret == SA_OK) { 3031 group = (sa_group_t)work->item; 3032 if (setstate) 3033 ret = sa_set_group_attr(group, "state", "disabled"); 3034 if (ret == SA_OK) { 3035 char *name; 3036 name = sa_get_group_attr(group, "name"); 3037 if (name != NULL && strcmp(name, "zfs") == 0) { 3038 /* need to get the sub-groups for stopping */ 3039 for (subgroup = sa_get_sub_group(group); subgroup != NULL; 3040 subgroup = sa_get_next_group(subgroup)) { 3041 ret = disable_group(subgroup); 3042 } 3043 } else { 3044 ret = disable_group(group); 3045 } 3046 /* 3047 * we don't want to "disable" since it won't come 3048 * up after a reboot. The SMF framework should do 3049 * the right thing. On enable we do want to do 3050 * something. 3051 */ 3052 } 3053 work = work->next; 3054 } 3055 if (ret == SA_OK) 3056 ret = sa_update_config(handle); 3057 return (ret); 3058 } 3059 3060 /* 3061 * sa_disable_group(flags, argc, argv) 3062 * 3063 * Implements the disable subcommand 3064 */ 3065 3066 int 3067 sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 3068 { 3069 int verbose = 0; 3070 int dryrun = 0; 3071 int all = 0; 3072 int c; 3073 int ret = SA_OK; 3074 char *protocol; 3075 char *state; 3076 struct list *worklist = NULL; 3077 int auth = 1; 3078 3079 while ((c = getopt(argc, argv, "?havn")) != EOF) { 3080 switch (c) { 3081 case 'a': 3082 all = 1; 3083 break; 3084 case 'n': 3085 dryrun++; 3086 break; 3087 case 'P': 3088 protocol = optarg; 3089 if (!sa_valid_protocol(protocol)) { 3090 (void) printf(gettext("Invalid protocol specified: %s\n"), 3091 protocol); 3092 return (SA_INVALID_PROTOCOL); 3093 } 3094 break; 3095 case 'v': 3096 verbose++; 3097 break; 3098 default: 3099 case 'h': 3100 case '?': 3101 (void) printf(gettext("usage: %s\n"), 3102 sa_get_usage(USAGE_DISABLE)); 3103 return (0); 3104 } 3105 } 3106 3107 if (optind == argc && !all) { 3108 (void) printf(gettext("usage: %s\n"), 3109 sa_get_usage(USAGE_DISABLE)); 3110 (void) printf(gettext("\tmust specify group\n")); 3111 ret = SA_NO_SUCH_PATH; 3112 } else { 3113 sa_group_t group; 3114 if (!all) { 3115 while (optind < argc) { 3116 group = sa_get_group(handle, argv[optind]); 3117 if (group != NULL) { 3118 auth &= check_authorizations(argv[optind], flags); 3119 state = sa_get_group_attr(group, "state"); 3120 if (state == NULL || 3121 strcmp(state, "disabled") == 0) { 3122 /* already disabled */ 3123 if (verbose) 3124 (void) printf(gettext("Group \"%s\" is " 3125 "already disabled\n"), 3126 argv[optind]); 3127 ret = SA_BUSY; /* already disable */ 3128 } else { 3129 worklist = add_list(worklist, group, 0); 3130 if (verbose) 3131 (void) printf(gettext("Disabling group " 3132 "\"%s\"\n"), 3133 argv[optind]); 3134 } 3135 if (state != NULL) 3136 sa_free_attr_string(state); 3137 } else { 3138 ret = SA_NO_SUCH_GROUP; 3139 } 3140 optind++; 3141 } 3142 } else { 3143 for (group = sa_get_group(handle, NULL); group != NULL; 3144 group = sa_get_next_group(group)) { 3145 worklist = add_list(worklist, group, 0); 3146 } 3147 } 3148 if (ret == SA_OK && !dryrun) { 3149 ret = disable_all_groups(handle, worklist, 1); 3150 } 3151 if (ret != SA_OK && ret != SA_BUSY) 3152 (void) printf(gettext("Could not disable group: %s\n"), 3153 sa_errorstr(ret)); 3154 if (ret == SA_BUSY) 3155 ret = SA_OK; 3156 } 3157 if (worklist != NULL) 3158 free_list(worklist); 3159 if (dryrun && ret == SA_OK && !auth && verbose) { 3160 (void) printf(gettext("Command would fail: %s\n"), 3161 sa_errorstr(SA_NO_PERMISSION)); 3162 } 3163 return (ret); 3164 } 3165 3166 /* 3167 * sa_start_group(flags, argc, argv) 3168 * 3169 * Implements the start command. 3170 * This is similar to enable except it doesn't change the state 3171 * of the group(s) and only enables shares if the group is already 3172 * enabled. 3173 */ 3174 3175 int 3176 sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 3177 { 3178 int verbose = 0; 3179 int all = 0; 3180 int c; 3181 int ret = SMF_EXIT_OK; 3182 char *protocol = NULL; 3183 char *state; 3184 struct list *worklist = NULL; 3185 #ifdef lint 3186 flags = flags; 3187 #endif 3188 3189 while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3190 switch (c) { 3191 case 'a': 3192 all = 1; 3193 break; 3194 case 'P': 3195 protocol = optarg; 3196 if (!sa_valid_protocol(protocol)) { 3197 (void) printf(gettext("Invalid protocol specified: %s\n"), 3198 protocol); 3199 return (SA_INVALID_PROTOCOL); 3200 } 3201 break; 3202 case 'v': 3203 verbose++; 3204 break; 3205 default: 3206 case 'h': 3207 case '?': 3208 (void) printf(gettext("usage: %s\n"), 3209 sa_get_usage(USAGE_START)); 3210 return (SA_OK); 3211 } 3212 } 3213 3214 if (optind == argc && !all) { 3215 (void) printf(gettext("usage: %s\n"), 3216 sa_get_usage(USAGE_START)); 3217 ret = SMF_EXIT_ERR_FATAL; 3218 } else { 3219 sa_group_t group; 3220 3221 if (!all) { 3222 while (optind < argc) { 3223 group = sa_get_group(handle, argv[optind]); 3224 if (group != NULL) { 3225 state = sa_get_group_attr(group, "state"); 3226 if (state == NULL || 3227 strcmp(state, "enabled") == 0) { 3228 worklist = add_list(worklist, group, 0); 3229 if (verbose) 3230 (void) printf(gettext("Starting group " 3231 "\"%s\"\n"), 3232 argv[optind]); 3233 } else { 3234 /* 3235 * determine if there are any 3236 * protocols. if there aren't any, 3237 * then there isn't anything to do in 3238 * any case so no error. 3239 */ 3240 if (sa_get_optionset(group, protocol) != NULL) { 3241 ret = SMF_EXIT_OK; 3242 } 3243 } 3244 if (state != NULL) 3245 sa_free_attr_string(state); 3246 } 3247 optind++; 3248 } 3249 } else { 3250 for (group = sa_get_group(handle, NULL); group != NULL; 3251 group = sa_get_next_group(group)) { 3252 state = sa_get_group_attr(group, "state"); 3253 if (state == NULL || strcmp(state, "enabled") == 0) 3254 worklist = add_list(worklist, group, 0); 3255 if (state != NULL) 3256 sa_free_attr_string(state); 3257 } 3258 } 3259 (void) enable_all_groups(handle, worklist, 0, 1, NULL); 3260 } 3261 if (worklist != NULL) 3262 free_list(worklist); 3263 return (ret); 3264 } 3265 3266 /* 3267 * sa_stop_group(flags, argc, argv) 3268 * 3269 * Implements the stop command. 3270 * This is similar to disable except it doesn't change the state 3271 * of the group(s) and only disables shares if the group is already 3272 * enabled. 3273 */ 3274 3275 int 3276 sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 3277 { 3278 int verbose = 0; 3279 int all = 0; 3280 int c; 3281 int ret = SMF_EXIT_OK; 3282 char *protocol = NULL; 3283 char *state; 3284 struct list *worklist = NULL; 3285 #ifdef lint 3286 flags = flags; 3287 #endif 3288 3289 while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3290 switch (c) { 3291 case 'a': 3292 all = 1; 3293 break; 3294 case 'P': 3295 protocol = optarg; 3296 if (!sa_valid_protocol(protocol)) { 3297 (void) printf(gettext("Invalid protocol specified: %s\n"), 3298 protocol); 3299 return (SA_INVALID_PROTOCOL); 3300 } 3301 break; 3302 case 'v': 3303 verbose++; 3304 break; 3305 default: 3306 case 'h': 3307 case '?': 3308 (void) printf(gettext("usage: %s\n"), 3309 sa_get_usage(USAGE_STOP)); 3310 return (0); 3311 } 3312 } 3313 3314 if (optind == argc && !all) { 3315 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP)); 3316 ret = SMF_EXIT_ERR_FATAL; 3317 } else { 3318 sa_group_t group; 3319 if (!all) { 3320 while (optind < argc) { 3321 group = sa_get_group(handle, argv[optind]); 3322 if (group != NULL) { 3323 state = sa_get_group_attr(group, "state"); 3324 if (state == NULL || 3325 strcmp(state, "enabled") == 0) { 3326 worklist = add_list(worklist, group, 0); 3327 if (verbose) 3328 (void) printf(gettext("Stopping group " 3329 "\"%s\"\n"), 3330 argv[optind]); 3331 } else { 3332 ret = SMF_EXIT_OK; 3333 } 3334 if (state != NULL) 3335 sa_free_attr_string(state); 3336 } 3337 optind++; 3338 } 3339 } else { 3340 for (group = sa_get_group(handle, NULL); group != NULL; 3341 group = sa_get_next_group(group)) { 3342 state = sa_get_group_attr(group, "state"); 3343 if (state == NULL || strcmp(state, "enabled") == 0) 3344 worklist = add_list(worklist, group, 0); 3345 if (state != NULL) 3346 sa_free_attr_string(state); 3347 } 3348 } 3349 (void) disable_all_groups(handle, worklist, 0); 3350 ret = sa_update_config(handle); 3351 } 3352 if (worklist != NULL) 3353 free_list(worklist); 3354 return (ret); 3355 } 3356 3357 /* 3358 * remove_all_options(share, proto) 3359 * 3360 * Removes all options on a share. 3361 */ 3362 3363 static void 3364 remove_all_options(sa_share_t share, char *proto) 3365 { 3366 sa_optionset_t optionset; 3367 sa_security_t security; 3368 sa_security_t prevsec = NULL; 3369 3370 optionset = sa_get_optionset(share, proto); 3371 if (optionset != NULL) 3372 (void) sa_destroy_optionset(optionset); 3373 for (security = sa_get_security(share, NULL, NULL); 3374 security != NULL; 3375 security = sa_get_next_security(security)) { 3376 char *type; 3377 /* 3378 * we walk through the list. prevsec keeps the 3379 * previous security so we can delete it without 3380 * destroying the list. 3381 */ 3382 if (prevsec != NULL) { 3383 /* remove the previously seen security */ 3384 (void) sa_destroy_security(prevsec); 3385 /* set to NULL so we don't try multiple times */ 3386 prevsec = NULL; 3387 } 3388 type = sa_get_security_attr(security, "type"); 3389 if (type != NULL) { 3390 /* 3391 * if the security matches the specified protocol, we 3392 * want to remove it. prevsec holds it until either 3393 * the next pass or we fall out of the loop. 3394 */ 3395 if (strcmp(type, proto) == 0) 3396 prevsec = security; 3397 sa_free_attr_string(type); 3398 } 3399 } 3400 /* in case there is one left */ 3401 if (prevsec != NULL) 3402 (void) sa_destroy_security(prevsec); 3403 } 3404 3405 3406 /* 3407 * for legacy support, we need to handle the old syntax. This is what 3408 * we get if sharemgr is called with the name "share" rather than 3409 * sharemgr. 3410 */ 3411 3412 static int 3413 format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 3414 { 3415 int err; 3416 3417 err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 3418 if (err > buffsize) 3419 return (-1); 3420 return (0); 3421 } 3422 3423 3424 /* 3425 * check_legacy_cmd(proto, cmd) 3426 * 3427 * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 3428 * executable. 3429 */ 3430 3431 static int 3432 check_legacy_cmd(char *path) 3433 { 3434 struct stat st; 3435 int ret = 0; 3436 3437 if (stat(path, &st) == 0) { 3438 if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 3439 ret = 1; 3440 } 3441 return (ret); 3442 } 3443 3444 /* 3445 * run_legacy_command(proto, cmd, argv) 3446 * 3447 * we know the command exists, so attempt to execute it with all the 3448 * arguments. This implements full legacy share support for those 3449 * protocols that don't have plugin providers. 3450 */ 3451 3452 static int 3453 run_legacy_command(char *path, char *argv[]) 3454 { 3455 int ret; 3456 3457 ret = execv(path, argv); 3458 if (ret < 0) { 3459 switch (errno) { 3460 case EACCES: 3461 ret = SA_NO_PERMISSION; 3462 break; 3463 default: 3464 ret = SA_SYSTEM_ERR; 3465 break; 3466 } 3467 } 3468 return (ret); 3469 } 3470 3471 /* 3472 * out_share(out, group, proto) 3473 * 3474 * Display the share information in the format that the "share" 3475 * command has traditionally used. 3476 */ 3477 3478 static void 3479 out_share(FILE *out, sa_group_t group, char *proto) 3480 { 3481 sa_share_t share; 3482 char resfmt[128]; 3483 3484 for (share = sa_get_share(group, NULL); share != NULL; 3485 share = sa_get_next_share(share)) { 3486 char *path; 3487 char *type; 3488 char *resource; 3489 char *description; 3490 char *groupname; 3491 char *sharedstate; 3492 int shared = 1; 3493 char *soptions; 3494 3495 sharedstate = sa_get_share_attr(share, "shared"); 3496 path = sa_get_share_attr(share, "path"); 3497 type = sa_get_share_attr(share, "type"); 3498 resource = sa_get_share_attr(share, "resource"); 3499 groupname = sa_get_group_attr(group, "name"); 3500 3501 if (groupname != NULL && strcmp(groupname, "default") == 0) { 3502 sa_free_attr_string(groupname); 3503 groupname = NULL; 3504 } 3505 description = sa_get_share_description(share); 3506 3507 /* want the sharetab version if it exists */ 3508 soptions = sa_get_share_attr(share, "shareopts"); 3509 3510 if (sharedstate == NULL) 3511 shared = 0; 3512 3513 if (soptions == NULL) 3514 soptions = sa_proto_legacy_format(proto, share, 1); 3515 3516 if (shared) { 3517 /* only active shares go here */ 3518 (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 3519 resource != NULL ? resource : "-", 3520 groupname != NULL ? "@" : "", 3521 groupname != NULL ? groupname : ""); 3522 (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 3523 resfmt, 3524 path, 3525 (soptions != NULL && strlen(soptions) > 0) ? 3526 soptions : "rw", 3527 (description != NULL) ? description : ""); 3528 } 3529 3530 if (path != NULL) 3531 sa_free_attr_string(path); 3532 if (type != NULL) 3533 sa_free_attr_string(type); 3534 if (resource != NULL) 3535 sa_free_attr_string(resource); 3536 if (groupname != NULL) 3537 sa_free_attr_string(groupname); 3538 if (description != NULL) 3539 sa_free_share_description(description); 3540 if (sharedstate != NULL) 3541 sa_free_attr_string(sharedstate); 3542 if (soptions != NULL) 3543 sa_format_free(soptions); 3544 } 3545 } 3546 3547 /* 3548 * output_legacy_file(out, proto) 3549 * 3550 * Walk all of the groups for the specified protocol and call 3551 * out_share() to format and write in the format displayed by the 3552 * "share" command with no arguments. 3553 */ 3554 3555 static void 3556 output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 3557 { 3558 sa_group_t group; 3559 3560 for (group = sa_get_group(handle, NULL); group != NULL; 3561 group = sa_get_next_group(group)) { 3562 char *options; 3563 char *zfs; 3564 3565 /* 3566 * get default options preformated, being careful to 3567 * handle legacy shares differently from new style 3568 * shares. Legacy share have options on the share. 3569 */ 3570 3571 zfs = sa_get_group_attr(group, "zfs"); 3572 if (zfs != NULL) { 3573 sa_group_t zgroup; 3574 sa_free_attr_string(zfs); 3575 options = sa_proto_legacy_format(proto, group, 1); 3576 for (zgroup = sa_get_sub_group(group); zgroup != NULL; 3577 zgroup = sa_get_next_group(zgroup)) { 3578 3579 /* got a group, so display it */ 3580 out_share(out, zgroup, proto); 3581 } 3582 } else { 3583 options = sa_proto_legacy_format(proto, group, 1); 3584 out_share(out, group, proto); 3585 } 3586 if (options != NULL) 3587 free(options); 3588 } 3589 } 3590 3591 int 3592 sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 3593 { 3594 char *protocol = "nfs"; 3595 char *options = NULL; 3596 char *description = NULL; 3597 char *groupname = NULL; 3598 char *sharepath = NULL; 3599 char *resource = NULL; 3600 char *groupstatus = NULL; 3601 int persist = SA_SHARE_TRANSIENT; 3602 int argsused = 0; 3603 int c; 3604 int ret = SA_OK; 3605 int zfs = 0; 3606 int true_legacy = 0; 3607 int curtype = SA_SHARE_TRANSIENT; 3608 char cmd[MAXPATHLEN]; 3609 #ifdef lint 3610 flags = flags; 3611 #endif 3612 3613 while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 3614 switch (c) { 3615 case 'd': 3616 description = optarg; 3617 argsused++; 3618 break; 3619 case 'F': 3620 protocol = optarg; 3621 if (!sa_valid_protocol(protocol)) { 3622 if (format_legacy_path(cmd, MAXPATHLEN, 3623 protocol, "share") == 0 && check_legacy_cmd(cmd)) { 3624 true_legacy++; 3625 } else { 3626 (void) fprintf(stderr, 3627 gettext("Invalid protocol specified:" 3628 "%s\n"), 3629 protocol); 3630 return (SA_INVALID_PROTOCOL); 3631 } 3632 } 3633 break; 3634 case 'o': 3635 options = optarg; 3636 argsused++; 3637 break; 3638 case 'p': 3639 persist = SA_SHARE_PERMANENT; 3640 argsused++; 3641 break; 3642 case 'h': 3643 case '?': 3644 default: 3645 (void) fprintf(stderr, gettext("usage: %s\n"), 3646 sa_get_usage(USAGE_SHARE)); 3647 return (SA_OK); 3648 } 3649 } 3650 3651 /* have the info so construct what is needed */ 3652 if (!argsused && optind == argc) { 3653 /* display current info in share format */ 3654 (void) output_legacy_file(stdout, "nfs", handle); 3655 } else { 3656 sa_group_t group = NULL; 3657 sa_share_t share; 3658 char dir[MAXPATHLEN]; 3659 3660 /* we are modifying the configuration */ 3661 if (optind == argc) { 3662 (void) fprintf(stderr, gettext("usage: %s\n"), 3663 sa_get_usage(USAGE_SHARE)); 3664 return (SA_LEGACY_ERR); 3665 } 3666 3667 if (true_legacy) { 3668 /* if still using legacy share/unshare, exec it */ 3669 ret = run_legacy_command(cmd, argv); 3670 return (ret); 3671 } 3672 3673 sharepath = argv[optind++]; 3674 if (optind < argc) { 3675 resource = argv[optind]; 3676 groupname = strchr(resource, '@'); 3677 if (groupname != NULL) 3678 *groupname++ = '\0'; 3679 } 3680 if (realpath(sharepath, dir) == NULL) 3681 ret = SA_BAD_PATH; 3682 else 3683 sharepath = dir; 3684 if (ret == SA_OK) { 3685 share = sa_find_share(handle, sharepath); 3686 } else { 3687 share = NULL; 3688 } 3689 if (groupname != NULL) { 3690 ret = SA_NOT_ALLOWED; 3691 } else if (ret == SA_OK) { 3692 char *legacygroup = "default"; 3693 /* 3694 * the legacy group is always present and zfs groups 3695 * come and go. zfs shares may be in sub-groups and 3696 * the zfs share will already be in that group so it 3697 * isn't an error. 3698 */ 3699 if (share != NULL) { 3700 /* 3701 * if the share exists, then make sure it is one we 3702 * want to handle. 3703 */ 3704 group = sa_get_parent_group(share); 3705 } else { 3706 group = sa_get_group(handle, legacygroup); 3707 } 3708 if (group != NULL) { 3709 groupstatus = group_status(group); 3710 if (share == NULL) { 3711 share = sa_add_share(group, sharepath, persist, &ret); 3712 if (share == NULL && ret == SA_DUPLICATE_NAME) { 3713 /* could be a ZFS path being started */ 3714 if (sa_zfs_is_shared(handle, sharepath)) { 3715 ret = SA_OK; 3716 group = sa_get_group(handle, "zfs"); 3717 if (group == NULL) { 3718 /* this shouldn't happen */ 3719 ret = SA_CONFIG_ERR; 3720 } 3721 if (group != NULL) { 3722 share = sa_add_share(group, sharepath, 3723 persist, &ret); 3724 } 3725 } 3726 } 3727 } else { 3728 char *type; 3729 /* 3730 * may want to change persist state, but the 3731 * important thing is to change options. We 3732 * need to change them regardless of the 3733 * source. 3734 */ 3735 if (sa_zfs_is_shared(handle, sharepath)) { 3736 zfs = 1; 3737 } 3738 remove_all_options(share, protocol); 3739 type = sa_get_share_attr(share, "type"); 3740 if (type != NULL && 3741 strcmp(type, "transient") != 0) { 3742 curtype = SA_SHARE_PERMANENT; 3743 } 3744 if (type != NULL) 3745 sa_free_attr_string(type); 3746 if (curtype != persist) { 3747 (void) sa_set_share_attr(share, "type", 3748 persist == SA_SHARE_PERMANENT ? 3749 "persist" : "transient"); 3750 } 3751 } 3752 /* have a group to hold this share path */ 3753 if (ret == SA_OK && options != NULL && 3754 strlen(options) > 0) { 3755 ret = sa_parse_legacy_options(share, 3756 options, 3757 protocol); 3758 } 3759 if (!zfs) { 3760 /* 3761 * zfs shares never have resource or 3762 * description and we can't store the values 3763 * so don't try. 3764 */ 3765 if (ret == SA_OK && description != NULL) 3766 ret = sa_set_share_description(share, description); 3767 if (ret == SA_OK && resource != NULL) 3768 ret = sa_set_share_attr(share, "resource", 3769 resource); 3770 } 3771 if (ret == SA_OK) { 3772 if (strcmp(groupstatus, "enabled") == 0) 3773 ret = sa_enable_share(share, protocol); 3774 if (ret == SA_OK && persist == SA_SHARE_PERMANENT) { 3775 (void) sa_update_legacy(share, protocol); 3776 } 3777 if (ret == SA_OK) 3778 ret = sa_update_config(handle); 3779 } 3780 } else { 3781 ret = SA_SYSTEM_ERR; 3782 } 3783 } 3784 } 3785 if (ret != SA_OK) { 3786 (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 3787 sharepath, sa_errorstr(ret)); 3788 ret = SA_LEGACY_ERR; 3789 3790 } 3791 return (ret); 3792 } 3793 3794 /* 3795 * sa_legacy_unshare(flags, argc, argv) 3796 * 3797 * Implements the original unshare command. 3798 */ 3799 3800 int 3801 sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 3802 { 3803 char *protocol = "nfs"; /* for now */ 3804 char *options = NULL; 3805 char *sharepath = NULL; 3806 int persist = SA_SHARE_TRANSIENT; 3807 int argsused = 0; 3808 int c; 3809 int ret = SA_OK; 3810 int true_legacy = 0; 3811 char cmd[MAXPATHLEN]; 3812 #ifdef lint 3813 flags = flags; 3814 options = options; 3815 #endif 3816 3817 while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 3818 switch (c) { 3819 case 'h': 3820 case '?': 3821 break; 3822 case 'F': 3823 protocol = optarg; 3824 if (!sa_valid_protocol(protocol)) { 3825 if (format_legacy_path(cmd, MAXPATHLEN, 3826 protocol, "unshare") == 0 && 3827 check_legacy_cmd(cmd)) { 3828 true_legacy++; 3829 } else { 3830 (void) printf(gettext("Invalid file system name\n")); 3831 return (SA_INVALID_PROTOCOL); 3832 } 3833 } 3834 break; 3835 case 'o': 3836 options = optarg; 3837 argsused++; 3838 break; 3839 case 'p': 3840 persist = SA_SHARE_PERMANENT; 3841 argsused++; 3842 break; 3843 default: 3844 (void) printf(gettext("usage: %s\n"), 3845 sa_get_usage(USAGE_UNSHARE)); 3846 return (SA_OK); 3847 } 3848 } 3849 3850 /* have the info so construct what is needed */ 3851 if (optind == argc || (optind + 1) < argc) { 3852 ret = SA_SYNTAX_ERR; 3853 } else { 3854 sa_share_t share; 3855 char dir[MAXPATHLEN]; 3856 if (true_legacy) { 3857 /* if still using legacy share/unshare, exec it */ 3858 ret = run_legacy_command(cmd, argv); 3859 return (ret); 3860 } 3861 /* 3862 * Find the path in the internal configuration. If it 3863 * isn't found, attempt to resolve the path via 3864 * realpath() and try again. 3865 */ 3866 sharepath = argv[optind++]; 3867 share = sa_find_share(handle, sharepath); 3868 if (share == NULL) { 3869 if (realpath(sharepath, dir) == NULL) { 3870 ret = SA_NO_SUCH_PATH; 3871 } else { 3872 share = sa_find_share(handle, dir); 3873 } 3874 } 3875 if (share != NULL) { 3876 ret = sa_disable_share(share, protocol); 3877 /* 3878 * Errors are ok and removal should still occur. The 3879 * legacy unshare is more forgiving of errors than the 3880 * remove-share subcommand which may need the force 3881 * flag set for some error conditions. That is, the 3882 * "unshare" command will always unshare if it can 3883 * while "remove-share" might require the force option. 3884 */ 3885 if (persist == SA_SHARE_PERMANENT) { 3886 ret = sa_remove_share(share); 3887 if (ret == SA_OK) 3888 ret = sa_update_config(handle); 3889 } 3890 } else { 3891 ret = SA_NOT_SHARED; 3892 } 3893 } 3894 switch (ret) { 3895 default: 3896 (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 3897 ret = SA_LEGACY_ERR; 3898 break; 3899 case SA_SYNTAX_ERR: 3900 (void) printf(gettext("usage: %s\n"), 3901 sa_get_usage(USAGE_UNSHARE)); 3902 break; 3903 case SA_OK: 3904 break; 3905 } 3906 return (ret); 3907 } 3908 3909 /* 3910 * common commands that implement the sub-commands used by all 3911 * protcols. The entries are found via the lookup command 3912 */ 3913 3914 static sa_command_t commands[] = { 3915 {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 3916 {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 3917 {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 3918 {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 3919 {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 3920 {"list", 0, sa_list, USAGE_LIST}, 3921 {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 3922 {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 3923 {"set", 0, sa_set, USAGE_SET, SVC_SET}, 3924 {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 3925 {"show", 0, sa_show, USAGE_SHOW}, 3926 {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 3927 {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 3928 SVC_SET|SVC_ACTION}, 3929 {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 3930 {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 3931 {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 3932 {NULL, 0, NULL, NULL} 3933 }; 3934 3935 static char * 3936 sa_get_usage(sa_usage_t index) 3937 { 3938 char *ret = NULL; 3939 switch (index) { 3940 case USAGE_ADD_SHARE: 3941 ret = gettext("add-share [-nth] [-r resource-name] " 3942 "[-d \"description text\"] -s sharepath group"); 3943 break; 3944 case USAGE_CREATE: 3945 ret = gettext("create [-nvh] [-P proto [-p property=value]] group"); 3946 break; 3947 case USAGE_DELETE: 3948 ret = gettext("delete [-nvh] [-P proto] [-f] group"); 3949 break; 3950 case USAGE_DISABLE: 3951 ret = gettext("disable [-nvh] {-a | group ...}"); 3952 break; 3953 case USAGE_ENABLE: 3954 ret = gettext("enable [-nvh] {-a | group ...}"); 3955 break; 3956 case USAGE_LIST: 3957 ret = gettext("list [-vh] [-P proto]"); 3958 break; 3959 case USAGE_MOVE_SHARE: 3960 ret = gettext("move-share [-nvh] -s sharepath destination-group"); 3961 break; 3962 case USAGE_REMOVE_SHARE: 3963 ret = gettext("remove-share [-fnvh] -s sharepath group"); 3964 break; 3965 case USAGE_SET: 3966 ret = gettext("set [-nvh] -P proto [-S optspace] " 3967 "[-p property=value]* [-s sharepath] group"); 3968 break; 3969 case USAGE_SET_SECURITY: 3970 ret = gettext("set-security [-nvh] -P proto -S security-type " 3971 "[-p property=value]* group"); 3972 break; 3973 case USAGE_SET_SHARE: 3974 ret = gettext("set-share [-nh] [-r resource] " 3975 "[-d \"description text\"] -s sharepath group"); 3976 break; 3977 case USAGE_SHOW: 3978 ret = gettext("show [-pvxh] [-P proto] [group ...]"); 3979 break; 3980 case USAGE_SHARE: 3981 ret = gettext("share [-F fstype] [-p] [-o optionlist]" 3982 "[-d description] [pathname [resourcename]]"); 3983 break; 3984 case USAGE_START: 3985 ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 3986 break; 3987 case USAGE_STOP: 3988 ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 3989 break; 3990 case USAGE_UNSET: 3991 ret = gettext("unset [-nvh] -P proto [-S optspace] " 3992 "[-p property]* group"); 3993 break; 3994 case USAGE_UNSET_SECURITY: 3995 ret = gettext("unset-security [-nvh] -P proto -S security-type " 3996 "[-p property]* group"); 3997 break; 3998 case USAGE_UNSHARE: 3999 ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath"); 4000 break; 4001 } 4002 return (ret); 4003 } 4004 4005 /* 4006 * sa_lookup(cmd, proto) 4007 * 4008 * Lookup the sub-command. proto isn't currently used, but it may 4009 * eventually provide a way to provide protocol specific sub-commands. 4010 */ 4011 4012 sa_command_t * 4013 sa_lookup(char *cmd, char *proto) 4014 { 4015 int i; 4016 size_t len; 4017 #ifdef lint 4018 proto = proto; 4019 #endif 4020 4021 len = strlen(cmd); 4022 for (i = 0; commands[i].cmdname != NULL; i++) { 4023 if (strncmp(cmd, commands[i].cmdname, len) == 0) 4024 return (&commands[i]); 4025 } 4026 return (NULL); 4027 } 4028 4029 void 4030 sub_command_help(char *proto) 4031 { 4032 int i; 4033 #ifdef lint 4034 proto = proto; 4035 #endif 4036 4037 (void) printf(gettext("\tsub-commands:\n")); 4038 for (i = 0; commands[i].cmdname != NULL; i++) { 4039 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 4040 (void) printf("\t%s\n", 4041 sa_get_usage((sa_usage_t)commands[i].cmdidx)); 4042 } 4043 } 4044