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