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