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