13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 233348Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm #include <sys/types.h> 303034Sdougm #include <sys/stat.h> 313034Sdougm #include <fcntl.h> 323034Sdougm #include <stdlib.h> 333034Sdougm #include <stdio.h> 343034Sdougm #include <string.h> 353034Sdougm #include <ctype.h> 363034Sdougm #include <unistd.h> 373034Sdougm #include <getopt.h> 383034Sdougm #include <utmpx.h> 393034Sdougm #include <pwd.h> 403034Sdougm #include <auth_attr.h> 413034Sdougm #include <secdb.h> 423034Sdougm #include <sys/param.h> 433034Sdougm #include <sys/stat.h> 443034Sdougm #include <errno.h> 453034Sdougm 463034Sdougm #include <libshare.h> 473034Sdougm #include "sharemgr.h" 483034Sdougm #include <libscf.h> 493034Sdougm #include <libxml/tree.h> 503034Sdougm #include <libintl.h> 513034Sdougm 523034Sdougm static char *sa_get_usage(sa_usage_t); 533034Sdougm 543034Sdougm /* 553034Sdougm * Implementation of the common sub-commands supported by sharemgr. 563034Sdougm * A number of helper functions are also included. 573034Sdougm */ 583034Sdougm 593034Sdougm /* 603034Sdougm * has_protocol(group, proto) 613034Sdougm * If the group has an optionset with the specified protocol, 623034Sdougm * return true (1) otherwise false (0). 633034Sdougm */ 643034Sdougm static int 653034Sdougm has_protocol(sa_group_t group, char *protocol) 663034Sdougm { 673034Sdougm sa_optionset_t optionset; 683034Sdougm int result = 0; 693034Sdougm 703034Sdougm optionset = sa_get_optionset(group, protocol); 713034Sdougm if (optionset != NULL) { 72*4653Sdougm result++; 733034Sdougm } 743034Sdougm return (result); 753034Sdougm } 763034Sdougm 773034Sdougm /* 783034Sdougm * add_list(list, item) 793034Sdougm * Adds a new list member that points to item to the list. 803034Sdougm * If list is NULL, it starts a new list. The function returns 813034Sdougm * the first member of the list. 823034Sdougm */ 833034Sdougm struct list * 843034Sdougm add_list(struct list *listp, void *item, void *data) 853034Sdougm { 863034Sdougm struct list *new, *tmp; 873034Sdougm 883034Sdougm new = malloc(sizeof (struct list)); 893034Sdougm if (new != NULL) { 90*4653Sdougm new->next = NULL; 91*4653Sdougm new->item = item; 92*4653Sdougm new->itemdata = data; 933034Sdougm } else { 94*4653Sdougm return (listp); 953034Sdougm } 963034Sdougm 973034Sdougm if (listp == NULL) 98*4653Sdougm return (new); 993034Sdougm 1003034Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 1013034Sdougm /* get to end of list */ 1023034Sdougm } 1033034Sdougm tmp->next = new; 1043034Sdougm return (listp); 1053034Sdougm } 1063034Sdougm 1073034Sdougm /* 1083034Sdougm * free_list(list) 1093034Sdougm * Given a list, free all the members of the list; 1103034Sdougm */ 1113034Sdougm static void 1123034Sdougm free_list(struct list *listp) 1133034Sdougm { 1143034Sdougm struct list *tmp; 1153034Sdougm while (listp != NULL) { 116*4653Sdougm tmp = listp; 117*4653Sdougm listp = listp->next; 118*4653Sdougm free(tmp); 1193034Sdougm } 1203034Sdougm } 1213034Sdougm 1223034Sdougm /* 1233034Sdougm * check_authorization(instname, which) 1243034Sdougm * 1253034Sdougm * Checks to see if the specific type of authorization in which is 1263034Sdougm * enabled for the user in this SMF service instance. 1273034Sdougm */ 1283034Sdougm 1293034Sdougm static int 1303034Sdougm check_authorization(char *instname, int which) 1313034Sdougm { 1323034Sdougm scf_handle_t *handle = NULL; 1333034Sdougm scf_simple_prop_t *prop = NULL; 1343034Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 1353034Sdougm char *authstr = NULL; 1363034Sdougm ssize_t numauths; 137*4653Sdougm int ret = B_TRUE; 1383034Sdougm uid_t uid; 1393034Sdougm struct passwd *pw = NULL; 1403034Sdougm 1413034Sdougm uid = getuid(); 1423034Sdougm pw = getpwuid(uid); 143*4653Sdougm if (pw == NULL) { 144*4653Sdougm ret = B_FALSE; 145*4653Sdougm } else { 146*4653Sdougm /* 147*4653Sdougm * Since names are restricted to SA_MAX_NAME_LEN won't 148*4653Sdougm * overflow. 149*4653Sdougm */ 150*4653Sdougm (void) snprintf(svcstring, sizeof (svcstring), "%s:%s", 151*4653Sdougm SA_SVC_FMRI_BASE, instname); 152*4653Sdougm handle = scf_handle_create(SCF_VERSION); 153*4653Sdougm if (handle != NULL) { 154*4653Sdougm if (scf_handle_bind(handle) == 0) { 155*4653Sdougm switch (which) { 156*4653Sdougm case SVC_SET: 157*4653Sdougm prop = scf_simple_prop_get(handle, 158*4653Sdougm svcstring, "general", 159*4653Sdougm SVC_AUTH_VALUE); 160*4653Sdougm break; 161*4653Sdougm case SVC_ACTION: 162*4653Sdougm prop = scf_simple_prop_get(handle, 163*4653Sdougm svcstring, "general", 164*4653Sdougm SVC_AUTH_ACTION); 165*4653Sdougm break; 166*4653Sdougm } 167*4653Sdougm } 1683034Sdougm } 1693034Sdougm } 1703034Sdougm /* make sure we have an authorization string property */ 1713034Sdougm if (prop != NULL) { 172*4653Sdougm int i; 173*4653Sdougm numauths = scf_simple_prop_numvalues(prop); 174*4653Sdougm for (ret = 0, i = 0; i < numauths; i++) { 175*4653Sdougm authstr = scf_simple_prop_next_astring(prop); 176*4653Sdougm if (authstr != NULL) { 177*4653Sdougm /* check if this user has one of the strings */ 178*4653Sdougm if (chkauthattr(authstr, pw->pw_name)) { 179*4653Sdougm ret = 1; 180*4653Sdougm break; 181*4653Sdougm } 182*4653Sdougm } 1833034Sdougm } 184*4653Sdougm endauthattr(); 185*4653Sdougm scf_simple_prop_free(prop); 1863034Sdougm } else { 187*4653Sdougm /* no authorization string defined */ 188*4653Sdougm ret = 0; 1893034Sdougm } 1903034Sdougm if (handle != NULL) 191*4653Sdougm scf_handle_destroy(handle); 1923034Sdougm return (ret); 1933034Sdougm } 1943034Sdougm 1953034Sdougm /* 1963034Sdougm * check_authorizations(instname, flags) 1973034Sdougm * 1983034Sdougm * check all the needed authorizations for the user in this service 1993034Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 2003034Sdougm * there are authorizations for the user or not. 2013034Sdougm */ 2023034Sdougm 2033034Sdougm static int 2043034Sdougm check_authorizations(char *instname, int flags) 2053034Sdougm { 2063034Sdougm int ret1 = 0; 2073034Sdougm int ret2 = 0; 2083034Sdougm int ret; 2093034Sdougm 2103034Sdougm if (flags & SVC_SET) 211*4653Sdougm ret1 = check_authorization(instname, SVC_SET); 2123034Sdougm if (flags & SVC_ACTION) 213*4653Sdougm ret2 = check_authorization(instname, SVC_ACTION); 2143034Sdougm switch (flags) { 2153034Sdougm case SVC_ACTION: 216*4653Sdougm ret = ret2; 217*4653Sdougm break; 2183034Sdougm case SVC_SET: 219*4653Sdougm ret = ret1; 220*4653Sdougm break; 2213034Sdougm case SVC_ACTION|SVC_SET: 222*4653Sdougm ret = ret1 & ret2; 223*4653Sdougm break; 2243034Sdougm default: 225*4653Sdougm /* if not flags set, we assume we don't need authorizations */ 226*4653Sdougm ret = 1; 2273034Sdougm } 2283034Sdougm return (ret); 2293034Sdougm } 2303034Sdougm 2313034Sdougm /* 2323082Sdougm * enable_group(group, updateproto) 2333082Sdougm * 2343082Sdougm * enable all the shares in the specified group. This is a helper for 2353082Sdougm * enable_all_groups in order to simplify regular and subgroup (zfs) 2363082Sdougm * disabling. Group has already been checked for non-NULL. 2373082Sdougm */ 2383082Sdougm 2393082Sdougm static void 2403082Sdougm enable_group(sa_group_t group, char *updateproto) 2413082Sdougm { 2423082Sdougm sa_share_t share; 2433082Sdougm 2443082Sdougm for (share = sa_get_share(group, NULL); 2453082Sdougm share != NULL; 2463082Sdougm share = sa_get_next_share(share)) { 247*4653Sdougm if (updateproto != NULL) 248*4653Sdougm (void) sa_update_legacy(share, updateproto); 249*4653Sdougm (void) sa_enable_share(share, NULL); 2503082Sdougm } 2513082Sdougm } 2523082Sdougm 2533082Sdougm /* 2544241Sdougm * isenabled(group) 2554241Sdougm * 2564241Sdougm * Returns B_TRUE if the group is enabled or B_FALSE if it isn't. 2574241Sdougm * Moved to separate function to reduce clutter in the code. 2584241Sdougm */ 2594241Sdougm 2604241Sdougm static int 2614241Sdougm isenabled(sa_group_t group) 2624241Sdougm { 2634241Sdougm char *state; 2644241Sdougm int ret = B_FALSE; 2654241Sdougm 2664241Sdougm if (group != NULL) { 267*4653Sdougm state = sa_get_group_attr(group, "state"); 268*4653Sdougm if (state != NULL) { 269*4653Sdougm if (strcmp(state, "enabled") == 0) 270*4653Sdougm ret = B_TRUE; 271*4653Sdougm sa_free_attr_string(state); 272*4653Sdougm } 2734241Sdougm } 2744241Sdougm return (ret); 2754241Sdougm } 2764241Sdougm 2774241Sdougm /* 2783082Sdougm * enable_all_groups(list, setstate, online, updateproto) 2793082Sdougm * Given a list of groups, enable each one found. If updateproto 2803082Sdougm * is not NULL, then update all the shares for the protocol that 2813082Sdougm * was passed in. 2823034Sdougm */ 2833034Sdougm static int 2843910Sdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate, 2853910Sdougm int online, char *updateproto) 2863034Sdougm { 2874241Sdougm int ret; 2883034Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 2893034Sdougm char *state; 2903034Sdougm char *name; 2913034Sdougm char *zfs = NULL; 2923034Sdougm sa_group_t group; 2933082Sdougm sa_group_t subgroup; 2943034Sdougm 2954241Sdougm for (ret = SA_OK; work != NULL; work = work->next) { 296*4653Sdougm group = (sa_group_t)work->item; 2974241Sdougm 2984241Sdougm /* 2994241Sdougm * If setstate == TRUE, then make sure to set 3004241Sdougm * enabled. This needs to be done here in order for 3014241Sdougm * the isenabled check to succeed on a newly enabled 3024241Sdougm * group. 3034241Sdougm */ 304*4653Sdougm if (setstate == B_TRUE) { 305*4653Sdougm ret = sa_set_group_attr(group, "state", "enabled"); 306*4653Sdougm if (ret != SA_OK) 307*4653Sdougm break; 308*4653Sdougm } 3094241Sdougm 3104241Sdougm /* 3114241Sdougm * Check to see if group is enabled. If it isn't, skip 3124241Sdougm * the rest. We don't want shares starting if the 3134241Sdougm * group is disabled. The properties may have been 3144241Sdougm * updated, but there won't be a change until the 3154241Sdougm * group is enabled. 3164241Sdougm */ 317*4653Sdougm if (!isenabled(group)) 318*4653Sdougm continue; 319*4653Sdougm 320*4653Sdougm /* if itemdata != NULL then a single share */ 321*4653Sdougm if (work->itemdata != NULL) { 322*4653Sdougm ret = sa_enable_share((sa_share_t)work->itemdata, NULL); 3233034Sdougm } 324*4653Sdougm if (ret != SA_OK) 325*4653Sdougm break; 326*4653Sdougm 327*4653Sdougm /* if itemdata == NULL then the whole group */ 328*4653Sdougm if (work->itemdata == NULL) { 329*4653Sdougm zfs = sa_get_group_attr(group, "zfs"); 330*4653Sdougm /* 331*4653Sdougm * if the share is managed by ZFS, don't 332*4653Sdougm * update any of the protocols since ZFS is 333*4653Sdougm * handling this. updateproto will contain 334*4653Sdougm * the name of the protocol that we want to 335*4653Sdougm * update legacy files for. 336*4653Sdougm */ 337*4653Sdougm enable_group(group, zfs == NULL ? updateproto : NULL); 338*4653Sdougm for (subgroup = sa_get_sub_group(group); 339*4653Sdougm subgroup != NULL; 340*4653Sdougm subgroup = sa_get_next_group(subgroup)) { 341*4653Sdougm /* never update legacy for ZFS subgroups */ 342*4653Sdougm enable_group(subgroup, NULL); 3433034Sdougm } 3443034Sdougm } 345*4653Sdougm if (online) { 346*4653Sdougm zfs = sa_get_group_attr(group, "zfs"); 347*4653Sdougm name = sa_get_group_attr(group, "name"); 348*4653Sdougm if (name != NULL) { 349*4653Sdougm if (zfs == NULL) { 350*4653Sdougm (void) snprintf(instance, 351*4653Sdougm sizeof (instance), "%s:%s", 352*4653Sdougm SA_SVC_FMRI_BASE, name); 353*4653Sdougm state = smf_get_state(instance); 354*4653Sdougm if (state == NULL || 355*4653Sdougm strcmp(state, "online") != 0) { 356*4653Sdougm (void) smf_enable_instance( 357*4653Sdougm instance, 0); 358*4653Sdougm free(state); 359*4653Sdougm } 360*4653Sdougm } else { 361*4653Sdougm sa_free_attr_string(zfs); 362*4653Sdougm zfs = NULL; 363*4653Sdougm } 364*4653Sdougm if (name != NULL) 365*4653Sdougm sa_free_attr_string(name); 366*4653Sdougm } 367*4653Sdougm } 3683034Sdougm } 3693034Sdougm if (ret == SA_OK) { 370*4653Sdougm ret = sa_update_config(handle); 3713034Sdougm } 3723034Sdougm return (ret); 3733034Sdougm } 3743034Sdougm 3753034Sdougm /* 3763034Sdougm * chk_opt(optlistp, security, proto) 3773034Sdougm * 3783034Sdougm * Do a sanity check on the optlist provided for the protocol. This 3793034Sdougm * is a syntax check and verification that the property is either a 3803034Sdougm * general or specific to a names optionset. 3813034Sdougm */ 3823034Sdougm 3833034Sdougm static int 3843034Sdougm chk_opt(struct options *optlistp, int security, char *proto) 3853034Sdougm { 3863034Sdougm struct options *optlist; 3873034Sdougm char *sep = ""; 3883034Sdougm int notfirst = 0; 3893034Sdougm int ret; 3903034Sdougm 3913034Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 392*4653Sdougm char *optname; 393*4653Sdougm 394*4653Sdougm optname = optlist->optname; 395*4653Sdougm ret = OPT_ADD_OK; 396*4653Sdougm /* extract property/value pair */ 397*4653Sdougm if (sa_is_security(optname, proto)) { 398*4653Sdougm if (!security) 399*4653Sdougm ret = OPT_ADD_SECURITY; 400*4653Sdougm } else { 401*4653Sdougm if (security) 402*4653Sdougm ret = OPT_ADD_PROPERTY; 403*4653Sdougm } 404*4653Sdougm if (ret != OPT_ADD_OK) { 405*4653Sdougm if (notfirst == 0) 406*4653Sdougm (void) printf( 407*4653Sdougm gettext("Property syntax error: ")); 408*4653Sdougm switch (ret) { 409*4653Sdougm case OPT_ADD_SYNTAX: 410*4653Sdougm (void) printf(gettext("%ssyntax error: %s"), 4113034Sdougm sep, optname); 412*4653Sdougm sep = ", "; 413*4653Sdougm break; 414*4653Sdougm case OPT_ADD_SECURITY: 415*4653Sdougm (void) printf(gettext("%s%s requires -S"), 4163034Sdougm optname, sep); 417*4653Sdougm sep = ", "; 418*4653Sdougm break; 419*4653Sdougm case OPT_ADD_PROPERTY: 420*4653Sdougm (void) printf( 421*4653Sdougm gettext("%s%s not supported with -S"), 4223034Sdougm optname, sep); 423*4653Sdougm sep = ", "; 424*4653Sdougm break; 425*4653Sdougm } 426*4653Sdougm notfirst++; 4273034Sdougm } 4283034Sdougm } 4293034Sdougm if (notfirst) { 430*4653Sdougm (void) printf("\n"); 431*4653Sdougm ret = SA_SYNTAX_ERR; 4323034Sdougm } 4333034Sdougm return (ret); 4343034Sdougm } 4353034Sdougm 4363034Sdougm /* 4373034Sdougm * free_opt(optlist) 4383034Sdougm * Free the specified option list. 4393034Sdougm */ 4403034Sdougm static void 4413034Sdougm free_opt(struct options *optlist) 4423034Sdougm { 4433034Sdougm struct options *nextopt; 4443034Sdougm while (optlist != NULL) { 4453034Sdougm nextopt = optlist->next; 4463034Sdougm free(optlist); 4473034Sdougm optlist = nextopt; 4483034Sdougm } 4493034Sdougm } 4503034Sdougm 4513034Sdougm /* 4523034Sdougm * check property list for valid properties 4533034Sdougm * A null value is a remove which is always valid. 4543034Sdougm */ 4553034Sdougm static int 4563034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec) 4573034Sdougm { 4583034Sdougm int ret = SA_OK; 4593034Sdougm struct options *cur; 4603034Sdougm sa_property_t prop; 4613034Sdougm sa_optionset_t parent = NULL; 4623034Sdougm 4633034Sdougm if (object != NULL) { 464*4653Sdougm if (sec == NULL) 465*4653Sdougm parent = sa_get_optionset(object, proto); 466*4653Sdougm else 467*4653Sdougm parent = sa_get_security(object, sec, proto); 4683034Sdougm } 4693034Sdougm 4703034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 471*4653Sdougm if (cur->optvalue == NULL) 472*4653Sdougm continue; 4733034Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 4743034Sdougm if (prop == NULL) 475*4653Sdougm ret = SA_NO_MEMORY; 4763034Sdougm if (ret != SA_OK || 4773034Sdougm (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 478*4653Sdougm (void) printf( 479*4653Sdougm gettext("Could not add property %s: %s\n"), 480*4653Sdougm cur->optname, sa_errorstr(ret)); 4813034Sdougm } 4823034Sdougm (void) sa_remove_property(prop); 4833034Sdougm } 4843034Sdougm return (ret); 4853034Sdougm } 4863034Sdougm 4873034Sdougm /* 4883034Sdougm * add_optionset(group, optlist, protocol, *err) 4893034Sdougm * Add the options in optlist to an optionset and then add the optionset 4903034Sdougm * to the group. 4913034Sdougm * 4923034Sdougm * The return value indicates if there was a "change" while errors are 4933034Sdougm * returned via the *err parameters. 4943034Sdougm */ 4953034Sdougm static int 4963034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 4973034Sdougm { 4983034Sdougm sa_optionset_t optionset; 4993034Sdougm int ret = SA_OK; 5003034Sdougm int result = 0; 5013034Sdougm 5023034Sdougm optionset = sa_get_optionset(group, proto); 5033034Sdougm if (optionset == NULL) { 504*4653Sdougm optionset = sa_create_optionset(group, proto); 505*4653Sdougm result = 1; /* adding a protocol is a change */ 5063034Sdougm } 507*4653Sdougm if (optionset == NULL) { 508*4653Sdougm ret = SA_NO_MEMORY; 509*4653Sdougm goto out; 510*4653Sdougm } 511*4653Sdougm while (optlist != NULL) { 5123034Sdougm sa_property_t prop; 5133034Sdougm prop = sa_get_property(optionset, optlist->optname); 5143034Sdougm if (prop == NULL) { 5153034Sdougm /* 5163034Sdougm * add the property, but only if it is 5173034Sdougm * a non-NULL or non-zero length value 5183034Sdougm */ 519*4653Sdougm if (optlist->optvalue != NULL) { 520*4653Sdougm prop = sa_create_property(optlist->optname, 521*4653Sdougm optlist->optvalue); 522*4653Sdougm if (prop != NULL) { 523*4653Sdougm ret = sa_valid_property(optionset, 524*4653Sdougm proto, prop); 525*4653Sdougm if (ret != SA_OK) { 526*4653Sdougm (void) sa_remove_property(prop); 527*4653Sdougm (void) printf(gettext("Could " 528*4653Sdougm "not add property " 529*4653Sdougm "%s: %s\n"), 530*4653Sdougm optlist->optname, 531*4653Sdougm sa_errorstr(ret)); 532*4653Sdougm } 533*4653Sdougm } 534*4653Sdougm if (ret == SA_OK) { 535*4653Sdougm ret = sa_add_property(optionset, prop); 536*4653Sdougm if (ret != SA_OK) { 537*4653Sdougm (void) printf(gettext( 538*4653Sdougm "Could not add property " 539*4653Sdougm "%s: %s\n"), 540*4653Sdougm optlist->optname, 541*4653Sdougm sa_errorstr(ret)); 542*4653Sdougm } else { 543*4653Sdougm /* there was a change */ 544*4653Sdougm result = 1; 545*4653Sdougm } 546*4653Sdougm } 5473034Sdougm } 548*4653Sdougm } else { 549*4653Sdougm ret = sa_update_property(prop, optlist->optvalue); 550*4653Sdougm /* should check to see if value changed */ 551*4653Sdougm if (ret != SA_OK) { 552*4653Sdougm (void) printf(gettext("Could not update " 553*4653Sdougm "property %s: %s\n"), optlist->optname, 554*4653Sdougm sa_errorstr(ret)); 555*4653Sdougm } else { 5563034Sdougm result = 1; 5573034Sdougm } 5583034Sdougm } 5593034Sdougm optlist = optlist->next; 5603034Sdougm } 561*4653Sdougm ret = sa_commit_properties(optionset, 0); 562*4653Sdougm 563*4653Sdougm out: 5643034Sdougm if (err != NULL) 565*4653Sdougm *err = ret; 5663034Sdougm return (result); 5673034Sdougm } 5683034Sdougm 5693034Sdougm /* 5703034Sdougm * sa_create(flags, argc, argv) 5713034Sdougm * create a new group 5723034Sdougm * this may or may not have a protocol associated with it. 5733034Sdougm * No protocol means "all" protocols in this case. 5743034Sdougm */ 5753034Sdougm static int 5763910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[]) 5773034Sdougm { 5783034Sdougm char *groupname; 5793034Sdougm 5803034Sdougm sa_group_t group; 5813034Sdougm int verbose = 0; 5823034Sdougm int dryrun = 0; 5833034Sdougm int c; 5843034Sdougm char *protocol = NULL; 5853034Sdougm int ret = SA_OK; 5863034Sdougm struct options *optlist = NULL; 5873034Sdougm int err = 0; 5883034Sdougm int auth; 5893034Sdougm 5903034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) { 591*4653Sdougm switch (c) { 592*4653Sdougm case 'v': 593*4653Sdougm verbose++; 594*4653Sdougm break; 595*4653Sdougm case 'n': 596*4653Sdougm dryrun++; 597*4653Sdougm break; 598*4653Sdougm case 'P': 599*4653Sdougm protocol = optarg; 600*4653Sdougm if (sa_valid_protocol(protocol)) 601*4653Sdougm break; 602*4653Sdougm (void) printf(gettext( 603*4653Sdougm "Invalid protocol specified: %s\n"), protocol); 604*4653Sdougm return (SA_INVALID_PROTOCOL); 605*4653Sdougm break; 606*4653Sdougm case 'p': 607*4653Sdougm ret = add_opt(&optlist, optarg, 0); 608*4653Sdougm switch (ret) { 609*4653Sdougm case OPT_ADD_SYNTAX: 610*4653Sdougm (void) printf(gettext( 611*4653Sdougm "Property syntax error for property: %s\n"), 612*4653Sdougm optarg); 613*4653Sdougm return (SA_SYNTAX_ERR); 614*4653Sdougm case OPT_ADD_SECURITY: 615*4653Sdougm (void) printf(gettext( 616*4653Sdougm "Security properties need " 617*4653Sdougm "to be set with set-security: %s\n"), 618*4653Sdougm optarg); 619*4653Sdougm return (SA_SYNTAX_ERR); 620*4653Sdougm default: 621*4653Sdougm break; 622*4653Sdougm } 623*4653Sdougm break; 624*4653Sdougm default: 625*4653Sdougm case 'h': 626*4653Sdougm case '?': 627*4653Sdougm (void) printf(gettext("usage: %s\n"), 628*4653Sdougm sa_get_usage(USAGE_CREATE)); 629*4653Sdougm return (0); 6303034Sdougm } 6313034Sdougm } 6323034Sdougm 6333034Sdougm if (optind >= argc) { 634*4653Sdougm (void) printf(gettext("usage: %s\n"), 635*4653Sdougm sa_get_usage(USAGE_CREATE)); 636*4653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 637*4653Sdougm return (SA_BAD_PATH); 6383034Sdougm } 6393034Sdougm 6403034Sdougm if ((optind + 1) < argc) { 641*4653Sdougm (void) printf(gettext("usage: %s\n"), 642*4653Sdougm sa_get_usage(USAGE_CREATE)); 643*4653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 644*4653Sdougm return (SA_SYNTAX_ERR); 6453034Sdougm } 6463034Sdougm 6473034Sdougm if (protocol == NULL && optlist != NULL) { 648*4653Sdougm /* lookup default protocol */ 649*4653Sdougm (void) printf(gettext("usage: %s\n"), 650*4653Sdougm sa_get_usage(USAGE_CREATE)); 651*4653Sdougm (void) printf(gettext("\tprotocol must be specified " 652*4653Sdougm "with properties\n")); 653*4653Sdougm return (SA_INVALID_PROTOCOL); 6543034Sdougm } 6553034Sdougm 6563034Sdougm if (optlist != NULL) 657*4653Sdougm ret = chk_opt(optlist, 0, protocol); 6583034Sdougm if (ret == OPT_ADD_SECURITY) { 659*4653Sdougm (void) printf(gettext("Security properties not " 660*4653Sdougm "supported with create\n")); 661*4653Sdougm return (SA_SYNTAX_ERR); 6623034Sdougm } 6633034Sdougm 6643034Sdougm /* 665*4653Sdougm * If a group already exists, we can only add a new protocol 6663034Sdougm * to it and not create a new one or add the same protocol 6673034Sdougm * again. 6683034Sdougm */ 6693034Sdougm 6703034Sdougm groupname = argv[optind]; 6713034Sdougm 6723034Sdougm auth = check_authorizations(groupname, flags); 6733034Sdougm 6743910Sdougm group = sa_get_group(handle, groupname); 6753034Sdougm if (group != NULL) { 676*4653Sdougm /* group exists so must be a protocol add */ 677*4653Sdougm if (protocol != NULL) { 678*4653Sdougm if (has_protocol(group, protocol)) { 679*4653Sdougm (void) printf(gettext( 680*4653Sdougm "Group \"%s\" already exists" 681*4653Sdougm " with protocol %s\n"), groupname, 682*4653Sdougm protocol); 683*4653Sdougm ret = SA_DUPLICATE_NAME; 684*4653Sdougm } 685*4653Sdougm } else { 686*4653Sdougm /* must add new protocol */ 687*4653Sdougm (void) printf(gettext( 688*4653Sdougm "Group already exists and no protocol " 689*4653Sdougm "specified.\n")); 690*4653Sdougm ret = SA_DUPLICATE_NAME; 6913034Sdougm } 6923034Sdougm } else { 6933034Sdougm /* 6943034Sdougm * is it a valid name? Must comply with SMF instance 6953034Sdougm * name restrictions. 6963034Sdougm */ 697*4653Sdougm if (!sa_valid_group_name(groupname)) { 698*4653Sdougm ret = SA_INVALID_NAME; 699*4653Sdougm (void) printf(gettext("Invalid group name: %s\n"), 700*4653Sdougm groupname); 701*4653Sdougm } 7023034Sdougm } 7033034Sdougm if (ret == SA_OK) { 704*4653Sdougm /* check protocol vs optlist */ 705*4653Sdougm if (optlist != NULL) { 706*4653Sdougm /* check options, if any, for validity */ 707*4653Sdougm ret = valid_options(optlist, protocol, group, NULL); 708*4653Sdougm } 7093034Sdougm } 7103034Sdougm if (ret == SA_OK && !dryrun) { 711*4653Sdougm if (group == NULL) { 712*4653Sdougm group = sa_create_group(handle, (char *)groupname, 713*4653Sdougm &err); 7143034Sdougm } 715*4653Sdougm if (group != NULL) { 716*4653Sdougm sa_optionset_t optionset; 717*4653Sdougm if (optlist != NULL) { 718*4653Sdougm (void) add_optionset(group, optlist, protocol, 719*4653Sdougm &ret); 720*4653Sdougm } else if (protocol != NULL) { 721*4653Sdougm optionset = sa_create_optionset(group, 722*4653Sdougm protocol); 723*4653Sdougm if (optionset == NULL) 724*4653Sdougm ret = SA_NO_MEMORY; 725*4653Sdougm } else if (protocol == NULL) { 726*4653Sdougm char **protolist; 727*4653Sdougm int numprotos, i; 728*4653Sdougm numprotos = sa_get_protocols(&protolist); 729*4653Sdougm for (i = 0; i < numprotos; i++) { 730*4653Sdougm optionset = sa_create_optionset(group, 731*4653Sdougm protolist[i]); 732*4653Sdougm } 733*4653Sdougm if (protolist != NULL) 734*4653Sdougm free(protolist); 735*4653Sdougm } 7363034Sdougm /* 737*4653Sdougm * We have a group and legal additions 7383034Sdougm */ 739*4653Sdougm if (ret == SA_OK) { 740*4653Sdougm /* 741*4653Sdougm * Commit to configuration for protocols that 742*4653Sdougm * need to do block updates. For NFS, this 743*4653Sdougm * doesn't do anything but it will be run for 744*4653Sdougm * all protocols that implement the 745*4653Sdougm * appropriate plugin. 746*4653Sdougm */ 747*4653Sdougm ret = sa_update_config(handle); 748*4653Sdougm } else { 749*4653Sdougm if (group != NULL) 750*4653Sdougm (void) sa_remove_group(group); 751*4653Sdougm } 7523034Sdougm } else { 753*4653Sdougm ret = err; 754*4653Sdougm (void) printf(gettext("Could not create group: %s\n"), 755*4653Sdougm sa_errorstr(ret)); 7563034Sdougm } 7573034Sdougm } 7583034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 759*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 760*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 761*4653Sdougm ret = SA_NO_PERMISSION; 7623034Sdougm } 7633034Sdougm free_opt(optlist); 7643034Sdougm return (ret); 7653034Sdougm } 7663034Sdougm 7673034Sdougm /* 7683034Sdougm * group_status(group) 7693034Sdougm * 7703034Sdougm * return the current status (enabled/disabled) of the group. 7713034Sdougm */ 7723034Sdougm 7733034Sdougm static char * 7743034Sdougm group_status(sa_group_t group) 7753034Sdougm { 7763034Sdougm char *state; 7773034Sdougm int enabled = 0; 7783034Sdougm 7793034Sdougm state = sa_get_group_attr(group, "state"); 7803034Sdougm if (state != NULL) { 781*4653Sdougm if (strcmp(state, "enabled") == 0) { 782*4653Sdougm enabled = 1; 783*4653Sdougm } 784*4653Sdougm sa_free_attr_string(state); 7853034Sdougm } 7864255Sdougm return (enabled ? "enabled" : "disabled"); 7873034Sdougm } 7883034Sdougm 7893034Sdougm /* 7903034Sdougm * sa_delete(flags, argc, argv) 7913034Sdougm * 7923034Sdougm * Delete a group. 7933034Sdougm */ 7943034Sdougm 7953034Sdougm static int 7963910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[]) 7973034Sdougm { 7983034Sdougm char *groupname; 7993034Sdougm sa_group_t group; 8003034Sdougm sa_share_t share; 8013034Sdougm int verbose = 0; 8023034Sdougm int dryrun = 0; 8033034Sdougm int force = 0; 8043034Sdougm int c; 8053034Sdougm char *protocol = NULL; 8063034Sdougm char *sectype = NULL; 8073034Sdougm int ret = SA_OK; 8083034Sdougm int auth; 8093034Sdougm 8103034Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 811*4653Sdougm switch (c) { 812*4653Sdougm case 'v': 813*4653Sdougm verbose++; 814*4653Sdougm break; 815*4653Sdougm case 'n': 816*4653Sdougm dryrun++; 817*4653Sdougm break; 818*4653Sdougm case 'P': 819*4653Sdougm protocol = optarg; 820*4653Sdougm if (!sa_valid_protocol(protocol)) { 821*4653Sdougm (void) printf(gettext("Invalid protocol " 822*4653Sdougm "specified: %s\n"), protocol); 823*4653Sdougm return (SA_INVALID_PROTOCOL); 824*4653Sdougm } 825*4653Sdougm break; 826*4653Sdougm case 'S': 827*4653Sdougm sectype = optarg; 828*4653Sdougm break; 829*4653Sdougm case 'f': 830*4653Sdougm force++; 831*4653Sdougm break; 832*4653Sdougm default: 833*4653Sdougm case 'h': 834*4653Sdougm case '?': 835*4653Sdougm (void) printf(gettext("usage: %s\n"), 836*4653Sdougm sa_get_usage(USAGE_DELETE)); 837*4653Sdougm return (0); 8383034Sdougm } 8393034Sdougm } 8403034Sdougm 8413034Sdougm if (optind >= argc) { 842*4653Sdougm (void) printf(gettext("usage: %s\n"), 843*4653Sdougm sa_get_usage(USAGE_DELETE)); 844*4653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 845*4653Sdougm return (SA_SYNTAX_ERR); 8463034Sdougm } 8473034Sdougm 8483034Sdougm if ((optind + 1) < argc) { 849*4653Sdougm (void) printf(gettext("usage: %s\n"), 850*4653Sdougm sa_get_usage(USAGE_DELETE)); 851*4653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 852*4653Sdougm return (SA_SYNTAX_ERR); 8533034Sdougm } 8543034Sdougm 8553034Sdougm if (sectype != NULL && protocol == NULL) { 856*4653Sdougm (void) printf(gettext("usage: %s\n"), 857*4653Sdougm sa_get_usage(USAGE_DELETE)); 858*4653Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 859*4653Sdougm "specified.\n")); 860*4653Sdougm return (SA_SYNTAX_ERR); 8613034Sdougm } 8623034Sdougm 8633034Sdougm /* 8643034Sdougm * Determine if the group already exists since it must in 8653034Sdougm * order to be removed. 8663034Sdougm * 8673034Sdougm * We can delete when: 8683034Sdougm * 8693034Sdougm * - group is empty 8703034Sdougm * - force flag is set 8713034Sdougm * - if protocol specified, only delete the protocol 8723034Sdougm */ 8733034Sdougm 8743034Sdougm groupname = argv[optind]; 8753910Sdougm group = sa_get_group(handle, groupname); 8763034Sdougm if (group == NULL) { 8773034Sdougm ret = SA_NO_SUCH_GROUP; 878*4653Sdougm goto done; 879*4653Sdougm } 880*4653Sdougm auth = check_authorizations(groupname, flags); 881*4653Sdougm if (protocol == NULL) { 8823034Sdougm share = sa_get_share(group, NULL); 8833034Sdougm if (share != NULL) 884*4653Sdougm ret = SA_BUSY; 8853034Sdougm if (share == NULL || (share != NULL && force == 1)) { 886*4653Sdougm ret = SA_OK; 887*4653Sdougm if (!dryrun) { 888*4653Sdougm while (share != NULL) { 889*4653Sdougm sa_share_t next_share; 890*4653Sdougm next_share = sa_get_next_share(share); 891*4653Sdougm /* 892*4653Sdougm * need to do the disable of 893*4653Sdougm * each share, but don't 894*4653Sdougm * actually do anything on a 895*4653Sdougm * dryrun. 896*4653Sdougm */ 897*4653Sdougm ret = sa_disable_share(share, NULL); 898*4653Sdougm ret = sa_remove_share(share); 899*4653Sdougm share = next_share; 900*4653Sdougm } 901*4653Sdougm ret = sa_remove_group(group); 9023034Sdougm } 9033034Sdougm } 904*4653Sdougm /* Commit to configuration if not a dryrun */ 9053034Sdougm if (!dryrun && ret == SA_OK) { 906*4653Sdougm ret = sa_update_config(handle); 9073034Sdougm } 908*4653Sdougm } else { 9093034Sdougm /* a protocol delete */ 9103034Sdougm sa_optionset_t optionset; 9113034Sdougm sa_security_t security; 912*4653Sdougm if (sectype != NULL) { 913*4653Sdougm /* only delete specified security */ 914*4653Sdougm security = sa_get_security(group, sectype, protocol); 915*4653Sdougm if (security != NULL && !dryrun) 916*4653Sdougm ret = sa_destroy_security(security); 917*4653Sdougm else 918*4653Sdougm ret = SA_INVALID_PROTOCOL; 9193034Sdougm } else { 920*4653Sdougm optionset = sa_get_optionset(group, protocol); 921*4653Sdougm if (optionset != NULL && !dryrun) { 922*4653Sdougm /* 923*4653Sdougm * have an optionset with 924*4653Sdougm * protocol to delete 925*4653Sdougm */ 926*4653Sdougm ret = sa_destroy_optionset(optionset); 927*4653Sdougm /* 928*4653Sdougm * Now find all security sets 929*4653Sdougm * for the protocol and remove 930*4653Sdougm * them. Don't remove other 931*4653Sdougm * protocols. 932*4653Sdougm */ 933*4653Sdougm for (security = 934*4653Sdougm sa_get_security(group, NULL, NULL); 935*4653Sdougm ret == SA_OK && security != NULL; 936*4653Sdougm security = sa_get_next_security(security)) { 937*4653Sdougm char *secprot; 938*4653Sdougm secprot = sa_get_security_attr(security, 939*4653Sdougm "type"); 940*4653Sdougm if (secprot != NULL && 941*4653Sdougm strcmp(secprot, protocol) == 0) 942*4653Sdougm ret = sa_destroy_security( 943*4653Sdougm security); 944*4653Sdougm if (secprot != NULL) 945*4653Sdougm sa_free_attr_string(secprot); 946*4653Sdougm } 947*4653Sdougm } else { 948*4653Sdougm if (!dryrun) 949*4653Sdougm ret = SA_INVALID_PROTOCOL; 9503034Sdougm } 9513034Sdougm } 9523034Sdougm } 953*4653Sdougm 954*4653Sdougm done: 9553034Sdougm if (ret != SA_OK) { 956*4653Sdougm (void) printf(gettext("Could not delete group: %s\n"), 957*4653Sdougm sa_errorstr(ret)); 9583034Sdougm } else if (dryrun && !auth && verbose) { 959*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 960*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 9613034Sdougm } 9623034Sdougm return (ret); 9633034Sdougm } 9643034Sdougm 9653034Sdougm /* 9663034Sdougm * strndupr(*buff, str, buffsize) 9673034Sdougm * 9683034Sdougm * used with small strings to duplicate and possibly increase the 9693034Sdougm * buffer size of a string. 9703034Sdougm */ 9713034Sdougm static char * 9723034Sdougm strndupr(char *buff, char *str, int *buffsize) 9733034Sdougm { 9743034Sdougm int limit; 9753034Sdougm char *orig_buff = buff; 9763034Sdougm 9773034Sdougm if (buff == NULL) { 978*4653Sdougm buff = (char *)malloc(64); 979*4653Sdougm if (buff == NULL) 980*4653Sdougm return (NULL); 981*4653Sdougm *buffsize = 64; 982*4653Sdougm buff[0] = '\0'; 9833034Sdougm } 9843034Sdougm limit = strlen(buff) + strlen(str) + 1; 9853034Sdougm if (limit > *buffsize) { 986*4653Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 987*4653Sdougm buff = realloc(buff, limit); 9883034Sdougm } 9893034Sdougm if (buff != NULL) { 990*4653Sdougm (void) strcat(buff, str); 9913034Sdougm } else { 992*4653Sdougm /* if it fails, fail it hard */ 993*4653Sdougm if (orig_buff != NULL) 994*4653Sdougm free(orig_buff); 9953034Sdougm } 9963034Sdougm return (buff); 9973034Sdougm } 9983034Sdougm 9993034Sdougm /* 10003034Sdougm * group_proto(group) 10013034Sdougm * 10023034Sdougm * return a string of all the protocols (space separated) associated 10033034Sdougm * with this group. 10043034Sdougm */ 10053034Sdougm 10063034Sdougm static char * 10073034Sdougm group_proto(sa_group_t group) 10083034Sdougm { 10093034Sdougm sa_optionset_t optionset; 10103034Sdougm char *proto; 10113034Sdougm char *buff = NULL; 10123034Sdougm int buffsize = 0; 10133034Sdougm int addspace = 0; 10143034Sdougm /* 10153034Sdougm * get the protocol list by finding the optionsets on this 10163034Sdougm * group and extracting the type value. The initial call to 10173034Sdougm * strndupr() initailizes buff. 10183034Sdougm */ 10193034Sdougm buff = strndupr(buff, "", &buffsize); 10203034Sdougm if (buff != NULL) { 1021*4653Sdougm for (optionset = sa_get_optionset(group, NULL); 1022*4653Sdougm optionset != NULL && buff != NULL; 1023*4653Sdougm optionset = sa_get_next_optionset(optionset)) { 1024*4653Sdougm /* 1025*4653Sdougm * extract out the protocol type from this optionset 1026*4653Sdougm * and append it to the buffer "buff". strndupr() will 1027*4653Sdougm * reallocate space as necessay. 1028*4653Sdougm */ 1029*4653Sdougm proto = sa_get_optionset_attr(optionset, "type"); 1030*4653Sdougm if (proto != NULL) { 1031*4653Sdougm if (addspace++) 1032*4653Sdougm buff = strndupr(buff, " ", &buffsize); 1033*4653Sdougm buff = strndupr(buff, proto, &buffsize); 1034*4653Sdougm sa_free_attr_string(proto); 1035*4653Sdougm } 10363034Sdougm } 10373034Sdougm } 10383034Sdougm return (buff); 10393034Sdougm } 10403034Sdougm 10413034Sdougm /* 10423034Sdougm * sa_list(flags, argc, argv) 10433034Sdougm * 10443034Sdougm * implements the "list" subcommand to list groups and optionally 10453034Sdougm * their state and protocols. 10463034Sdougm */ 10473034Sdougm 1048*4653Sdougm /*ARGSUSED*/ 10493034Sdougm static int 10503910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[]) 10513034Sdougm { 10523034Sdougm sa_group_t group; 10533034Sdougm int verbose = 0; 10543034Sdougm int c; 10553034Sdougm char *protocol = NULL; 10563034Sdougm 10573034Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 1058*4653Sdougm switch (c) { 1059*4653Sdougm case 'v': 1060*4653Sdougm verbose++; 1061*4653Sdougm break; 1062*4653Sdougm case 'P': 1063*4653Sdougm protocol = optarg; 1064*4653Sdougm if (!sa_valid_protocol(protocol)) { 1065*4653Sdougm (void) printf(gettext( 1066*4653Sdougm "Invalid protocol specified: %s\n"), 1067*4653Sdougm protocol); 1068*4653Sdougm return (SA_INVALID_PROTOCOL); 1069*4653Sdougm } 1070*4653Sdougm break; 1071*4653Sdougm default: 1072*4653Sdougm case 'h': 1073*4653Sdougm case '?': 1074*4653Sdougm (void) printf(gettext("usage: %s\n"), 1075*4653Sdougm sa_get_usage(USAGE_LIST)); 1076*4653Sdougm return (0); 10773034Sdougm } 10783034Sdougm } 10793034Sdougm 1080*4653Sdougm for (group = sa_get_group(handle, NULL); 1081*4653Sdougm group != NULL; 10823034Sdougm group = sa_get_next_group(group)) { 1083*4653Sdougm char *name; 1084*4653Sdougm char *proto; 1085*4653Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 1086*4653Sdougm name = sa_get_group_attr(group, "name"); 1087*4653Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 1088*4653Sdougm (void) printf("%s", (char *)name); 1089*4653Sdougm if (verbose) { 1090*4653Sdougm /* 1091*4653Sdougm * Need the list of protocols 1092*4653Sdougm * and current status once 1093*4653Sdougm * available. We do want to 1094*4653Sdougm * translate the 1095*4653Sdougm * enabled/disabled text here. 1096*4653Sdougm */ 1097*4653Sdougm (void) printf("\t%s", isenabled(group) ? 1098*4653Sdougm gettext("enabled") : 1099*4653Sdougm gettext("disabled")); 1100*4653Sdougm proto = group_proto(group); 1101*4653Sdougm if (proto != NULL) { 1102*4653Sdougm (void) printf("\t%s", 1103*4653Sdougm (char *)proto); 1104*4653Sdougm free(proto); 1105*4653Sdougm } 1106*4653Sdougm } 1107*4653Sdougm (void) printf("\n"); 11083034Sdougm } 1109*4653Sdougm if (name != NULL) 1110*4653Sdougm sa_free_attr_string(name); 11113034Sdougm } 11123034Sdougm } 11133034Sdougm return (0); 11143034Sdougm } 11153034Sdougm 11163034Sdougm /* 11173034Sdougm * out_properties(optionset, proto, sec) 11183034Sdougm * 11193034Sdougm * Format the properties and encode the protocol and optional named 11203034Sdougm * optionset into the string. 11213034Sdougm * 11223034Sdougm * format is protocol[:name]=(property-list) 11233034Sdougm */ 11243034Sdougm 11253034Sdougm static void 11263034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 11273034Sdougm { 11283034Sdougm char *type; 11293034Sdougm char *value; 11303034Sdougm int spacer; 11313034Sdougm sa_property_t prop; 11323034Sdougm 1133*4653Sdougm if (sec == NULL) 1134*4653Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 1135*4653Sdougm else 1136*4653Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 11373034Sdougm 11383034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 1139*4653Sdougm prop != NULL; 1140*4653Sdougm prop = sa_get_next_property(prop)) { 11413034Sdougm 11423034Sdougm /* 11433034Sdougm * extract the property name/value and output with 11443034Sdougm * appropriate spacing. I.e. no prefixed space the 11453034Sdougm * first time through but a space on subsequent 11463034Sdougm * properties. 11473034Sdougm */ 1148*4653Sdougm type = sa_get_property_attr(prop, "type"); 1149*4653Sdougm value = sa_get_property_attr(prop, "value"); 1150*4653Sdougm if (type != NULL) { 1151*4653Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 1152*4653Sdougm spacer = 1; 1153*4653Sdougm if (value != NULL) 1154*4653Sdougm (void) printf("\"%s\"", value); 1155*4653Sdougm else 1156*4653Sdougm (void) printf("\"\""); 1157*4653Sdougm } 1158*4653Sdougm if (type != NULL) 1159*4653Sdougm sa_free_attr_string(type); 11603034Sdougm if (value != NULL) 1161*4653Sdougm sa_free_attr_string(value); 11623034Sdougm } 11633034Sdougm (void) printf(")"); 11643034Sdougm } 11653034Sdougm 11663034Sdougm /* 11673034Sdougm * show_properties(group, protocol, prefix) 11683034Sdougm * 11693034Sdougm * print the properties for a group. If protocol is NULL, do all 11703034Sdougm * protocols otherwise only the specified protocol. All security 11713034Sdougm * (named groups specific to the protocol) are included. 11723034Sdougm * 11733034Sdougm * The "prefix" is always applied. The caller knows whether it wants 11743034Sdougm * some type of prefix string (white space) or not. Once the prefix 11753034Sdougm * has been output, it is reduced to the zero length string for the 11763034Sdougm * remainder of the property output. 11773034Sdougm */ 11783034Sdougm 11793034Sdougm static void 11803034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 11813034Sdougm { 11823034Sdougm sa_optionset_t optionset; 11833034Sdougm sa_security_t security; 11843034Sdougm char *value; 11853034Sdougm char *secvalue; 11863034Sdougm 11873034Sdougm if (protocol != NULL) { 1188*4653Sdougm optionset = sa_get_optionset(group, protocol); 1189*4653Sdougm if (optionset != NULL) { 1190*4653Sdougm (void) printf("%s", prefix); 1191*4653Sdougm prefix = ""; 1192*4653Sdougm out_properties(optionset, protocol, NULL); 1193*4653Sdougm } 1194*4653Sdougm security = sa_get_security(group, protocol, NULL); 1195*4653Sdougm if (security != NULL) { 1196*4653Sdougm (void) printf("%s", prefix); 1197*4653Sdougm prefix = ""; 1198*4653Sdougm out_properties(security, protocol, NULL); 1199*4653Sdougm } 12003034Sdougm } else { 1201*4653Sdougm for (optionset = sa_get_optionset(group, protocol); 1202*4653Sdougm optionset != NULL; 1203*4653Sdougm optionset = sa_get_next_optionset(optionset)) { 1204*4653Sdougm 1205*4653Sdougm value = sa_get_optionset_attr(optionset, "type"); 1206*4653Sdougm (void) printf("%s", prefix); 1207*4653Sdougm prefix = ""; 1208*4653Sdougm out_properties(optionset, value, 0); 1209*4653Sdougm if (value != NULL) 1210*4653Sdougm sa_free_attr_string(value); 1211*4653Sdougm } 1212*4653Sdougm for (security = sa_get_security(group, NULL, protocol); 1213*4653Sdougm security != NULL; 1214*4653Sdougm security = sa_get_next_security(security)) { 1215*4653Sdougm 1216*4653Sdougm value = sa_get_security_attr(security, "type"); 1217*4653Sdougm secvalue = sa_get_security_attr(security, "sectype"); 1218*4653Sdougm (void) printf("%s", prefix); 1219*4653Sdougm prefix = ""; 1220*4653Sdougm out_properties(security, value, secvalue); 1221*4653Sdougm if (value != NULL) 1222*4653Sdougm sa_free_attr_string(value); 1223*4653Sdougm if (secvalue != NULL) 1224*4653Sdougm sa_free_attr_string(secvalue); 1225*4653Sdougm } 12263034Sdougm } 12273034Sdougm } 12283034Sdougm 12293034Sdougm /* 12303034Sdougm * show_group(group, verbose, properties, proto, subgroup) 12313034Sdougm * 12323034Sdougm * helper function to show the contents of a group. 12333034Sdougm */ 12343034Sdougm 12353034Sdougm static void 12363034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 12373034Sdougm char *subgroup) 12383034Sdougm { 12393034Sdougm sa_share_t share; 12403034Sdougm char *groupname; 12413034Sdougm char *sharepath; 12423034Sdougm char *resource; 12433034Sdougm char *description; 12443034Sdougm char *type; 12453034Sdougm char *zfs = NULL; 12463034Sdougm int iszfs = 0; 12473034Sdougm 12483034Sdougm groupname = sa_get_group_attr(group, "name"); 12493034Sdougm if (groupname != NULL) { 1250*4653Sdougm if (proto != NULL && !has_protocol(group, proto)) { 1251*4653Sdougm sa_free_attr_string(groupname); 1252*4653Sdougm return; 1253*4653Sdougm } 12543034Sdougm /* 12553034Sdougm * check to see if the group is managed by ZFS. If 12563034Sdougm * there is an attribute, then it is. A non-NULL zfs 12573034Sdougm * variable will trigger the different way to display 12583034Sdougm * and will remove the transient property indicator 12593034Sdougm * from the output. 12603034Sdougm */ 1261*4653Sdougm zfs = sa_get_group_attr(group, "zfs"); 1262*4653Sdougm if (zfs != NULL) { 1263*4653Sdougm iszfs = 1; 1264*4653Sdougm sa_free_attr_string(zfs); 12653034Sdougm } 1266*4653Sdougm share = sa_get_share(group, NULL); 1267*4653Sdougm if (subgroup == NULL) 1268*4653Sdougm (void) printf("%s", groupname); 1269*4653Sdougm else 1270*4653Sdougm (void) printf(" %s/%s", subgroup, groupname); 1271*4653Sdougm if (properties) 1272*4653Sdougm show_properties(group, proto, ""); 1273*4653Sdougm (void) printf("\n"); 1274*4653Sdougm if (strcmp(groupname, "zfs") == 0) { 1275*4653Sdougm sa_group_t zgroup; 1276*4653Sdougm 1277*4653Sdougm for (zgroup = sa_get_sub_group(group); 1278*4653Sdougm zgroup != NULL; 1279*4653Sdougm zgroup = sa_get_next_group(zgroup)) { 1280*4653Sdougm show_group(zgroup, verbose, properties, proto, 1281*4653Sdougm "zfs"); 1282*4653Sdougm } 1283*4653Sdougm sa_free_attr_string(groupname); 1284*4653Sdougm return; 1285*4653Sdougm } 12863034Sdougm /* 1287*4653Sdougm * Have a group, so list the contents. Resource and 12883034Sdougm * description are only listed if verbose is set. 12893034Sdougm */ 1290*4653Sdougm for (share = sa_get_share(group, NULL); 1291*4653Sdougm share != NULL; 1292*4653Sdougm share = sa_get_next_share(share)) { 1293*4653Sdougm sharepath = sa_get_share_attr(share, "path"); 1294*4653Sdougm if (sharepath != NULL) { 1295*4653Sdougm if (verbose) { 1296*4653Sdougm resource = sa_get_share_attr(share, 1297*4653Sdougm "resource"); 1298*4653Sdougm description = 1299*4653Sdougm sa_get_share_description(share); 1300*4653Sdougm type = sa_get_share_attr(share, 1301*4653Sdougm "type"); 1302*4653Sdougm if (type != NULL && !iszfs && 1303*4653Sdougm strcmp(type, "transient") == 0) 1304*4653Sdougm (void) printf("\t* "); 1305*4653Sdougm else 1306*4653Sdougm (void) printf("\t "); 1307*4653Sdougm if (resource != NULL && 1308*4653Sdougm strlen(resource) > 0) { 1309*4653Sdougm (void) printf("%s=%s", 1310*4653Sdougm resource, sharepath); 1311*4653Sdougm } else { 1312*4653Sdougm (void) printf("%s", sharepath); 1313*4653Sdougm } 1314*4653Sdougm if (resource != NULL) 1315*4653Sdougm sa_free_attr_string(resource); 1316*4653Sdougm if (properties) 1317*4653Sdougm show_properties(share, NULL, 1318*4653Sdougm "\t"); 1319*4653Sdougm if (description != NULL) { 1320*4653Sdougm if (strlen(description) > 0) { 1321*4653Sdougm (void) printf( 1322*4653Sdougm "\t\"%s\"", 1323*4653Sdougm description); 1324*4653Sdougm } 1325*4653Sdougm sa_free_share_description( 1326*4653Sdougm description); 1327*4653Sdougm } 1328*4653Sdougm if (type != NULL) 1329*4653Sdougm sa_free_attr_string(type); 1330*4653Sdougm } else { 1331*4653Sdougm (void) printf("\t%s", sharepath); 1332*4653Sdougm if (properties) 1333*4653Sdougm show_properties(share, NULL, 1334*4653Sdougm "\t"); 1335*4653Sdougm } 1336*4653Sdougm (void) printf("\n"); 1337*4653Sdougm sa_free_attr_string(sharepath); 13383034Sdougm } 13393034Sdougm } 13403034Sdougm } 13413034Sdougm if (groupname != NULL) { 13423034Sdougm sa_free_attr_string(groupname); 13433034Sdougm } 13443034Sdougm } 13453034Sdougm 13463034Sdougm /* 13473034Sdougm * show_group_xml_init() 13483034Sdougm * 13493034Sdougm * Create an XML document that will be used to display config info via 13503034Sdougm * XML format. 13513034Sdougm */ 13523034Sdougm 13533034Sdougm xmlDocPtr 13543034Sdougm show_group_xml_init() 13553034Sdougm { 13563034Sdougm xmlDocPtr doc; 13573034Sdougm xmlNodePtr root; 13583034Sdougm 13593034Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 13603034Sdougm if (doc != NULL) { 1361*4653Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 1362*4653Sdougm if (root != NULL) 1363*4653Sdougm xmlDocSetRootElement(doc, root); 13643034Sdougm } 13653034Sdougm return (doc); 13663034Sdougm } 13673034Sdougm 13683034Sdougm /* 13693034Sdougm * show_group_xml(doc, group) 13703034Sdougm * 13713034Sdougm * Copy the group info into the XML doc. 13723034Sdougm */ 13733034Sdougm 13743034Sdougm static void 13753034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 13763034Sdougm { 13773034Sdougm xmlNodePtr node; 13783034Sdougm xmlNodePtr root; 13793034Sdougm 13803034Sdougm root = xmlDocGetRootElement(doc); 13813034Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 13823034Sdougm if (node != NULL && root != NULL) { 1383*4653Sdougm xmlAddChild(root, node); 13843034Sdougm /* 13853034Sdougm * In the future, we may have interally used tags that 13863034Sdougm * should not appear in the XML output. Remove 13873034Sdougm * anything we don't want to show here. 13883034Sdougm */ 13893034Sdougm } 13903034Sdougm } 13913034Sdougm 13923034Sdougm /* 13933034Sdougm * sa_show(flags, argc, argv) 13943034Sdougm * 13953034Sdougm * Implements the show subcommand. 13963034Sdougm */ 13973034Sdougm 1398*4653Sdougm /*ARGSUSED*/ 13993034Sdougm int 14003910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[]) 14013034Sdougm { 14023034Sdougm sa_group_t group; 14033034Sdougm int verbose = 0; 14043034Sdougm int properties = 0; 14053034Sdougm int c; 14063034Sdougm int ret = SA_OK; 14073034Sdougm char *protocol = NULL; 14083034Sdougm int xml = 0; 14093034Sdougm xmlDocPtr doc; 14103034Sdougm 14113034Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 1412*4653Sdougm switch (c) { 1413*4653Sdougm case 'v': 1414*4653Sdougm verbose++; 1415*4653Sdougm break; 1416*4653Sdougm case 'p': 1417*4653Sdougm properties++; 1418*4653Sdougm break; 1419*4653Sdougm case 'P': 1420*4653Sdougm protocol = optarg; 1421*4653Sdougm if (!sa_valid_protocol(protocol)) { 1422*4653Sdougm (void) printf(gettext( 1423*4653Sdougm "Invalid protocol specified: %s\n"), 1424*4653Sdougm protocol); 1425*4653Sdougm return (SA_INVALID_PROTOCOL); 1426*4653Sdougm } 1427*4653Sdougm break; 1428*4653Sdougm case 'x': 1429*4653Sdougm xml++; 1430*4653Sdougm break; 1431*4653Sdougm default: 1432*4653Sdougm case 'h': 1433*4653Sdougm case '?': 1434*4653Sdougm (void) printf(gettext("usage: %s\n"), 1435*4653Sdougm sa_get_usage(USAGE_SHOW)); 1436*4653Sdougm return (0); 14373034Sdougm } 14383034Sdougm } 14393034Sdougm 14403034Sdougm if (xml) { 1441*4653Sdougm doc = show_group_xml_init(); 1442*4653Sdougm if (doc == NULL) 1443*4653Sdougm ret = SA_NO_MEMORY; 14443034Sdougm } 14453034Sdougm 14463034Sdougm if (optind == argc) { 1447*4653Sdougm /* No group specified so go through them all */ 1448*4653Sdougm for (group = sa_get_group(handle, NULL); 1449*4653Sdougm group != NULL; 1450*4653Sdougm group = sa_get_next_group(group)) { 1451*4653Sdougm /* 1452*4653Sdougm * Have a group so check if one we want and then list 1453*4653Sdougm * contents with appropriate options. 1454*4653Sdougm */ 1455*4653Sdougm if (xml) 1456*4653Sdougm show_group_xml(doc, group); 1457*4653Sdougm else 1458*4653Sdougm show_group(group, verbose, properties, protocol, 1459*4653Sdougm NULL); 1460*4653Sdougm } 14613034Sdougm } else { 1462*4653Sdougm /* Have a specified list of groups */ 1463*4653Sdougm for (; optind < argc; optind++) { 1464*4653Sdougm group = sa_get_group(handle, argv[optind]); 1465*4653Sdougm if (group != NULL) { 1466*4653Sdougm if (xml) 1467*4653Sdougm show_group_xml(doc, group); 1468*4653Sdougm else 1469*4653Sdougm show_group(group, verbose, properties, 1470*4653Sdougm protocol, NULL); 1471*4653Sdougm } else { 1472*4653Sdougm (void) printf(gettext("%s: not found\n"), 1473*4653Sdougm argv[optind]); 1474*4653Sdougm ret = SA_NO_SUCH_GROUP; 1475*4653Sdougm } 14763034Sdougm } 14773034Sdougm } 14783034Sdougm if (xml && ret == SA_OK) { 1479*4653Sdougm xmlDocFormatDump(stdout, doc, 1); 1480*4653Sdougm xmlFreeDoc(doc); 14813034Sdougm } 14823034Sdougm return (ret); 14833034Sdougm 14843034Sdougm } 14853034Sdougm 14863034Sdougm /* 14873034Sdougm * enable_share(group, share, update_legacy) 14883034Sdougm * 14893034Sdougm * helper function to enable a share if the group is enabled. 14903034Sdougm */ 14913034Sdougm 14923034Sdougm static int 14933910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 14943910Sdougm int update_legacy) 14953034Sdougm { 14963034Sdougm char *value; 14973034Sdougm int enabled; 14983034Sdougm sa_optionset_t optionset; 14993034Sdougm int ret = SA_OK; 15003034Sdougm char *zfs = NULL; 15013034Sdougm int iszfs = 0; 15023034Sdougm 15033034Sdougm /* 15043034Sdougm * need to enable this share if the group is enabled but not 15053034Sdougm * otherwise. The enable is also done on each protocol 15063034Sdougm * represented in the group. 15073034Sdougm */ 15083034Sdougm value = sa_get_group_attr(group, "state"); 15093034Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 15103034Sdougm if (value != NULL) 1511*4653Sdougm sa_free_attr_string(value); 15123034Sdougm /* remove legacy config if necessary */ 15133034Sdougm if (update_legacy) 1514*4653Sdougm ret = sa_delete_legacy(share); 15153034Sdougm zfs = sa_get_group_attr(group, "zfs"); 15163034Sdougm if (zfs != NULL) { 1517*4653Sdougm iszfs++; 1518*4653Sdougm sa_free_attr_string(zfs); 15193034Sdougm } 15203034Sdougm 15213034Sdougm /* 15223034Sdougm * Step through each optionset at the group level and 15233034Sdougm * enable the share based on the protocol type. This 15243034Sdougm * works because protocols must be set on the group 15253034Sdougm * for the protocol to be enabled. 15263034Sdougm */ 15273034Sdougm for (optionset = sa_get_optionset(group, NULL); 15283034Sdougm optionset != NULL && ret == SA_OK; 15293034Sdougm optionset = sa_get_next_optionset(optionset)) { 1530*4653Sdougm value = sa_get_optionset_attr(optionset, "type"); 1531*4653Sdougm if (value != NULL) { 1532*4653Sdougm if (enabled) 1533*4653Sdougm ret = sa_enable_share(share, value); 1534*4653Sdougm if (update_legacy && !iszfs) 1535*4653Sdougm (void) sa_update_legacy(share, value); 1536*4653Sdougm sa_free_attr_string(value); 1537*4653Sdougm } 15383034Sdougm } 15393034Sdougm if (ret == SA_OK) 1540*4653Sdougm (void) sa_update_config(handle); 15413034Sdougm return (ret); 15423034Sdougm } 15433034Sdougm 15443034Sdougm /* 15453034Sdougm * sa_addshare(flags, argc, argv) 15463034Sdougm * 15473034Sdougm * implements add-share subcommand. 15483034Sdougm */ 15493034Sdougm 15503034Sdougm int 15513910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 15523034Sdougm { 15533034Sdougm int verbose = 0; 15543034Sdougm int dryrun = 0; 15553034Sdougm int c; 15563034Sdougm int ret = SA_OK; 15573034Sdougm sa_group_t group; 15583034Sdougm sa_share_t share; 15593034Sdougm char *sharepath = NULL; 15603034Sdougm char *description = NULL; 15613034Sdougm char *resource = NULL; 15623034Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 15633034Sdougm int auth; 15643034Sdougm char dir[MAXPATHLEN]; 15653034Sdougm 15663034Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 1567*4653Sdougm switch (c) { 1568*4653Sdougm case 'n': 1569*4653Sdougm dryrun++; 1570*4653Sdougm break; 1571*4653Sdougm case 'v': 1572*4653Sdougm verbose++; 1573*4653Sdougm break; 1574*4653Sdougm case 'd': 1575*4653Sdougm description = optarg; 1576*4653Sdougm break; 1577*4653Sdougm case 'r': 1578*4653Sdougm resource = optarg; 1579*4653Sdougm break; 1580*4653Sdougm case 's': 1581*4653Sdougm /* 1582*4653Sdougm * Save share path into group. Currently limit 1583*4653Sdougm * to one share per command. 1584*4653Sdougm */ 1585*4653Sdougm if (sharepath != NULL) { 1586*4653Sdougm (void) printf(gettext( 1587*4653Sdougm "Adding multiple shares not supported\n")); 1588*4653Sdougm return (1); 1589*4653Sdougm } 1590*4653Sdougm sharepath = optarg; 1591*4653Sdougm break; 1592*4653Sdougm case 't': 1593*4653Sdougm persist = SA_SHARE_TRANSIENT; 1594*4653Sdougm break; 1595*4653Sdougm default: 1596*4653Sdougm case 'h': 1597*4653Sdougm case '?': 1598*4653Sdougm (void) printf(gettext("usage: %s\n"), 1599*4653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1600*4653Sdougm return (0); 16013034Sdougm } 16023034Sdougm } 16033034Sdougm 16043034Sdougm if (optind >= argc) { 1605*4653Sdougm (void) printf(gettext("usage: %s\n"), 1606*4653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1607*4653Sdougm if (dryrun || sharepath != NULL || description != NULL || 1608*4653Sdougm resource != NULL || verbose || persist) { 1609*4653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 1610*4653Sdougm ret = SA_NO_SUCH_GROUP; 1611*4653Sdougm } else { 1612*4653Sdougm ret = SA_OK; 1613*4653Sdougm } 16143034Sdougm } else { 1615*4653Sdougm if (sharepath == NULL) { 1616*4653Sdougm (void) printf(gettext("usage: %s\n"), 1617*4653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1618*4653Sdougm (void) printf(gettext( 1619*4653Sdougm "\t-s sharepath must be specified\n")); 1620*4653Sdougm return (SA_BAD_PATH); 1621*4653Sdougm } 16223034Sdougm if (realpath(sharepath, dir) == NULL) { 1623*4653Sdougm (void) printf(gettext( 1624*4653Sdougm "Path is not valid: %s\n"), sharepath); 1625*4653Sdougm return (SA_BAD_PATH); 16263034Sdougm } else { 1627*4653Sdougm sharepath = dir; 16283034Sdougm } 1629*4653Sdougm 1630*4653Sdougm /* Check for valid syntax */ 1631*4653Sdougm if (resource != NULL && strpbrk(resource, " \t/") != NULL) { 1632*4653Sdougm (void) printf(gettext("usage: %s\n"), 1633*4653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1634*4653Sdougm (void) printf(gettext( 1635*4653Sdougm "\tresource must not contain white" 1636*4653Sdougm "space or '/' characters\n")); 1637*4653Sdougm return (SA_BAD_PATH); 16383034Sdougm } 16393910Sdougm group = sa_get_group(handle, argv[optind]); 1640*4653Sdougm if (group == NULL) { 1641*4653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 1642*4653Sdougm argv[optind]); 1643*4653Sdougm return (SA_NO_SUCH_GROUP); 1644*4653Sdougm } 1645*4653Sdougm auth = check_authorizations(argv[optind], flags); 1646*4653Sdougm share = sa_find_share(handle, sharepath); 1647*4653Sdougm if (share != NULL) { 16483034Sdougm group = sa_get_parent_group(share); 16493034Sdougm if (group != NULL) { 1650*4653Sdougm char *groupname; 1651*4653Sdougm groupname = sa_get_group_attr( 1652*4653Sdougm group, "name"); 1653*4653Sdougm if (groupname != NULL) { 1654*4653Sdougm (void) printf(gettext( 1655*4653Sdougm "Share path already " 1656*4653Sdougm "shared in group " 1657*4653Sdougm "\"%s\": %s\n"), 1658*4653Sdougm groupname, sharepath); 1659*4653Sdougm sa_free_attr_string(groupname); 1660*4653Sdougm } else { 1661*4653Sdougm (void) printf(gettext( 1662*4653Sdougm "Share path already" 1663*4653Sdougm "shared: %s\n"), 1664*4653Sdougm groupname, sharepath); 1665*4653Sdougm } 16663034Sdougm } else { 1667*4653Sdougm (void) printf(gettext( 1668*4653Sdougm "Share path %s already shared\n"), 16693034Sdougm sharepath); 16703034Sdougm } 1671*4653Sdougm return (SA_DUPLICATE_NAME); 1672*4653Sdougm } else { 16733034Sdougm /* 1674*4653Sdougm * Need to check that resource name is 1675*4653Sdougm * unique at some point. Path checking 1676*4653Sdougm * should use the "normal" rules which 1677*4653Sdougm * don't check the repository. 16783034Sdougm */ 16793034Sdougm if (dryrun) 1680*4653Sdougm ret = sa_check_path(group, sharepath, 1681*4653Sdougm SA_CHECK_NORMAL); 16823034Sdougm else 1683*4653Sdougm share = sa_add_share(group, sharepath, 1684*4653Sdougm persist, &ret); 16853034Sdougm if (!dryrun && share == NULL) { 1686*4653Sdougm (void) printf(gettext( 1687*4653Sdougm "Could not add share: %s\n"), 1688*4653Sdougm sa_errorstr(ret)); 16893034Sdougm } else { 1690*4653Sdougm if (!dryrun && ret == SA_OK) { 1691*4653Sdougm if (resource != NULL && 1692*4653Sdougm strpbrk(resource, " \t/") == NULL) { 1693*4653Sdougm ret = sa_set_share_attr(share, 1694*4653Sdougm "resource", resource); 1695*4653Sdougm } 1696*4653Sdougm if (ret == SA_OK && 1697*4653Sdougm description != NULL) { 1698*4653Sdougm ret = sa_set_share_description( 1699*4653Sdougm share, description); 1700*4653Sdougm } 1701*4653Sdougm if (ret == SA_OK) { 1702*4653Sdougm /* Now enable the share(s) */ 1703*4653Sdougm ret = enable_share(handle, 1704*4653Sdougm group, share, 1); 1705*4653Sdougm ret = sa_update_config(handle); 1706*4653Sdougm } 1707*4653Sdougm switch (ret) { 1708*4653Sdougm case SA_DUPLICATE_NAME: 1709*4653Sdougm (void) printf(gettext( 1710*4653Sdougm "Resource name in" 1711*4653Sdougm "use: %s\n"), resource); 1712*4653Sdougm break; 1713*4653Sdougm default: 1714*4653Sdougm (void) printf( 1715*4653Sdougm gettext("Could not set " 1716*4653Sdougm "attribute: %s\n"), 1717*4653Sdougm sa_errorstr(ret)); 1718*4653Sdougm break; 1719*4653Sdougm case SA_OK: 1720*4653Sdougm break; 1721*4653Sdougm } 1722*4653Sdougm } else if (dryrun && ret == SA_OK && !auth && 1723*4653Sdougm verbose) { 1724*4653Sdougm (void) printf(gettext( 1725*4653Sdougm "Command would fail: %s\n"), 1726*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 1727*4653Sdougm ret = SA_NO_PERMISSION; 17283034Sdougm } 17293034Sdougm } 17303034Sdougm } 17313034Sdougm } 17323034Sdougm return (ret); 17333034Sdougm } 17343034Sdougm 17353034Sdougm /* 17363034Sdougm * sa_moveshare(flags, argc, argv) 17373034Sdougm * 17383034Sdougm * implements move-share subcommand. 17393034Sdougm */ 17403034Sdougm 17413034Sdougm int 17423910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 17433034Sdougm { 17443034Sdougm int verbose = 0; 17453034Sdougm int dryrun = 0; 17463034Sdougm int c; 17473034Sdougm int ret = SA_OK; 17483034Sdougm sa_group_t group; 17493034Sdougm sa_share_t share; 17503034Sdougm char *sharepath = NULL; 17513034Sdougm int authsrc = 0, authdst = 0; 17523034Sdougm 17533034Sdougm while ((c = getopt(argc, argv, "?hvns:")) != EOF) { 1754*4653Sdougm switch (c) { 1755*4653Sdougm case 'n': 1756*4653Sdougm dryrun++; 1757*4653Sdougm break; 1758*4653Sdougm case 'v': 1759*4653Sdougm verbose++; 1760*4653Sdougm break; 1761*4653Sdougm case 's': 1762*4653Sdougm /* 1763*4653Sdougm * Remove share path from group. Currently limit 1764*4653Sdougm * to one share per command. 1765*4653Sdougm */ 1766*4653Sdougm if (sharepath != NULL) { 1767*4653Sdougm (void) printf(gettext("Moving multiple shares" 1768*4653Sdougm "not supported\n")); 1769*4653Sdougm return (SA_BAD_PATH); 1770*4653Sdougm } 1771*4653Sdougm sharepath = optarg; 1772*4653Sdougm break; 1773*4653Sdougm default: 1774*4653Sdougm case 'h': 1775*4653Sdougm case '?': 1776*4653Sdougm (void) printf(gettext("usage: %s\n"), 1777*4653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 1778*4653Sdougm return (0); 17793034Sdougm } 17803034Sdougm } 17813034Sdougm 17823034Sdougm if (optind >= argc || sharepath == NULL) { 17833034Sdougm (void) printf(gettext("usage: %s\n"), 1784*4653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 1785*4653Sdougm if (dryrun || verbose || sharepath != NULL) { 1786*4653Sdougm (void) printf(gettext( 1787*4653Sdougm "\tgroup must be specified\n")); 1788*4653Sdougm ret = SA_NO_SUCH_GROUP; 1789*4653Sdougm } else { 1790*4653Sdougm if (sharepath == NULL) { 1791*4653Sdougm ret = SA_SYNTAX_ERR; 1792*4653Sdougm (void) printf(gettext( 1793*4653Sdougm "\tsharepath must be specified\n")); 1794*4653Sdougm } else { 1795*4653Sdougm ret = SA_OK; 1796*4653Sdougm } 1797*4653Sdougm } 1798*4653Sdougm } else { 1799*4653Sdougm sa_group_t parent; 1800*4653Sdougm char *zfsold; 1801*4653Sdougm char *zfsnew; 1802*4653Sdougm 18033034Sdougm if (sharepath == NULL) { 1804*4653Sdougm (void) printf(gettext( 1805*4653Sdougm "sharepath must be specified with the -s " 1806*4653Sdougm "option\n")); 1807*4653Sdougm return (SA_BAD_PATH); 1808*4653Sdougm } 18093910Sdougm group = sa_get_group(handle, argv[optind]); 1810*4653Sdougm if (group == NULL) { 1811*4653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 1812*4653Sdougm argv[optind]); 1813*4653Sdougm return (SA_NO_SUCH_GROUP); 1814*4653Sdougm } 1815*4653Sdougm share = sa_find_share(handle, sharepath); 1816*4653Sdougm authdst = check_authorizations(argv[optind], flags); 1817*4653Sdougm if (share == NULL) { 18183034Sdougm (void) printf(gettext("Share not found: %s\n"), 1819*4653Sdougm sharepath); 1820*4653Sdougm return (SA_NO_SUCH_PATH); 1821*4653Sdougm } 1822*4653Sdougm 1823*4653Sdougm parent = sa_get_parent_group(share); 1824*4653Sdougm if (parent != NULL) { 1825*4653Sdougm char *pname; 1826*4653Sdougm pname = sa_get_group_attr(parent, "name"); 1827*4653Sdougm if (pname != NULL) { 18283034Sdougm authsrc = check_authorizations(pname, flags); 18293034Sdougm sa_free_attr_string(pname); 1830*4653Sdougm } 1831*4653Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 1832*4653Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 1833*4653Sdougm if ((zfsold != NULL && zfsnew == NULL) || 1834*4653Sdougm (zfsold == NULL && zfsnew != NULL)) { 18353034Sdougm ret = SA_NOT_ALLOWED; 18363034Sdougm } 1837*4653Sdougm if (zfsold != NULL) 1838*4653Sdougm sa_free_attr_string(zfsold); 1839*4653Sdougm if (zfsnew != NULL) 1840*4653Sdougm sa_free_attr_string(zfsnew); 1841*4653Sdougm } 1842*4653Sdougm if (!dryrun && ret == SA_OK) 1843*4653Sdougm ret = sa_move_share(group, share); 1844*4653Sdougm 1845*4653Sdougm if (ret == SA_OK && parent != group && !dryrun) { 1846*4653Sdougm char *oldstate; 1847*4653Sdougm ret = sa_update_config(handle); 1848*4653Sdougm /* 1849*4653Sdougm * Note that the share may need to be 1850*4653Sdougm * "unshared" if the new group is 1851*4653Sdougm * disabled and the old was enabled or 1852*4653Sdougm * it may need to be share to update 1853*4653Sdougm * if the new group is enabled. 1854*4653Sdougm */ 1855*4653Sdougm oldstate = sa_get_group_attr(parent, "state"); 1856*4653Sdougm 1857*4653Sdougm /* enable_share determines what to do */ 1858*4653Sdougm if (strcmp(oldstate, "enabled") == 0) { 18593034Sdougm (void) sa_disable_share(share, NULL); 1860*4653Sdougm } 1861*4653Sdougm (void) enable_share(handle, group, share, 1); 1862*4653Sdougm if (oldstate != NULL) 18633034Sdougm sa_free_attr_string(oldstate); 18643034Sdougm } 1865*4653Sdougm 1866*4653Sdougm if (ret != SA_OK) 1867*4653Sdougm (void) printf(gettext("Could not move share: %s\n"), 1868*4653Sdougm sa_errorstr(ret)); 1869*4653Sdougm 1870*4653Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 1871*4653Sdougm verbose) { 1872*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 1873*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 1874*4653Sdougm } 18753034Sdougm } 18763034Sdougm return (ret); 18773034Sdougm } 18783034Sdougm 18793034Sdougm /* 18803034Sdougm * sa_removeshare(flags, argc, argv) 18813034Sdougm * 18823034Sdougm * implements remove-share subcommand. 18833034Sdougm */ 18843034Sdougm 18853034Sdougm int 18863910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 18873034Sdougm { 18883034Sdougm int verbose = 0; 18893034Sdougm int dryrun = 0; 18903034Sdougm int force = 0; 18913034Sdougm int c; 18923034Sdougm int ret = SA_OK; 18933034Sdougm sa_group_t group; 18943034Sdougm sa_share_t share; 18953034Sdougm char *sharepath = NULL; 18963034Sdougm char dir[MAXPATHLEN]; 18973034Sdougm int auth; 18983034Sdougm 18993034Sdougm while ((c = getopt(argc, argv, "?hfns:v")) != EOF) { 1900*4653Sdougm switch (c) { 1901*4653Sdougm case 'n': 1902*4653Sdougm dryrun++; 1903*4653Sdougm break; 1904*4653Sdougm case 'v': 1905*4653Sdougm verbose++; 1906*4653Sdougm break; 1907*4653Sdougm case 'f': 1908*4653Sdougm force++; 1909*4653Sdougm break; 1910*4653Sdougm case 's': 1911*4653Sdougm /* 1912*4653Sdougm * Remove share path from group. Currently limit 1913*4653Sdougm * to one share per command. 1914*4653Sdougm */ 1915*4653Sdougm if (sharepath != NULL) { 1916*4653Sdougm (void) printf(gettext( 1917*4653Sdougm "Removing multiple shares not " 19183034Sdougm "supported\n")); 1919*4653Sdougm return (SA_SYNTAX_ERR); 1920*4653Sdougm } 1921*4653Sdougm sharepath = optarg; 1922*4653Sdougm break; 1923*4653Sdougm default: 1924*4653Sdougm case 'h': 1925*4653Sdougm case '?': 1926*4653Sdougm (void) printf(gettext("usage: %s\n"), 1927*4653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 1928*4653Sdougm return (0); 19293034Sdougm } 19303034Sdougm } 19313034Sdougm 19323034Sdougm if (optind >= argc || sharepath == NULL) { 1933*4653Sdougm if (sharepath == NULL) { 19343034Sdougm (void) printf(gettext("usage: %s\n"), 1935*4653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 1936*4653Sdougm (void) printf(gettext( 1937*4653Sdougm "\t-s sharepath must be specified\n")); 1938*4653Sdougm ret = SA_BAD_PATH; 1939*4653Sdougm } else { 1940*4653Sdougm ret = SA_OK; 1941*4653Sdougm } 19423034Sdougm } 1943*4653Sdougm if (ret != SA_OK) { 1944*4653Sdougm return (ret); 1945*4653Sdougm } 1946*4653Sdougm 1947*4653Sdougm if (optind < argc) { 19483034Sdougm if ((optind + 1) < argc) { 1949*4653Sdougm (void) printf(gettext("Extraneous group(s) at end of " 1950*4653Sdougm "command\n")); 1951*4653Sdougm ret = SA_SYNTAX_ERR; 19523034Sdougm } else { 1953*4653Sdougm group = sa_get_group(handle, argv[optind]); 1954*4653Sdougm if (group == NULL) { 1955*4653Sdougm (void) printf(gettext( 1956*4653Sdougm "Group \"%s\" not found\n"), argv[optind]); 1957*4653Sdougm ret = SA_NO_SUCH_GROUP; 1958*4653Sdougm } 19593034Sdougm } 1960*4653Sdougm } else { 19613034Sdougm group = NULL; 1962*4653Sdougm } 1963*4653Sdougm 1964*4653Sdougm /* 1965*4653Sdougm * Lookup the path in the internal configuration. Care 1966*4653Sdougm * must be taken to handle the case where the 1967*4653Sdougm * underlying path has been removed since we need to 1968*4653Sdougm * be able to deal with that as well. 1969*4653Sdougm */ 1970*4653Sdougm if (ret == SA_OK) { 19713034Sdougm if (group != NULL) 1972*4653Sdougm share = sa_get_share(group, sharepath); 19733034Sdougm else 1974*4653Sdougm share = sa_find_share(handle, sharepath); 19753663Sdougm /* 19763663Sdougm * If we didn't find the share with the provided path, 19773663Sdougm * it may be a symlink so attempt to resolve it using 19783663Sdougm * realpath and try again. Realpath will resolve any 19793663Sdougm * symlinks and place them in "dir". Note that 19803663Sdougm * sharepath is only used for the lookup the first 19813663Sdougm * time and later for error messages. dir will be used 19823663Sdougm * on the second attempt. Once a share is found, all 19833663Sdougm * operations are based off of the share variable. 19843663Sdougm */ 19853663Sdougm if (share == NULL) { 1986*4653Sdougm if (realpath(sharepath, dir) == NULL) { 1987*4653Sdougm ret = SA_BAD_PATH; 1988*4653Sdougm (void) printf(gettext( 1989*4653Sdougm "Path is not valid: %s\n"), sharepath); 1990*4653Sdougm } else { 1991*4653Sdougm if (group != NULL) 1992*4653Sdougm share = sa_get_share(group, dir); 1993*4653Sdougm else 1994*4653Sdougm share = sa_find_share(handle, dir); 1995*4653Sdougm } 19963663Sdougm } 1997*4653Sdougm } 1998*4653Sdougm 1999*4653Sdougm /* 2000*4653Sdougm * If there hasn't been an error, there was likely a 2001*4653Sdougm * path found. If not, give the appropriate error 2002*4653Sdougm * message and set the return error. If it was found, 2003*4653Sdougm * then disable the share and then remove it from the 2004*4653Sdougm * configuration. 2005*4653Sdougm */ 2006*4653Sdougm if (ret != SA_OK) { 2007*4653Sdougm return (ret); 2008*4653Sdougm } 2009*4653Sdougm if (share == NULL) { 2010*4653Sdougm if (group != NULL) 20113034Sdougm (void) printf(gettext("Share not found in group %s:" 2012*4653Sdougm " %s\n"), argv[optind], sharepath); 2013*4653Sdougm else 20143034Sdougm (void) printf(gettext("Share not found: %s\n"), 2015*4653Sdougm sharepath); 2016*4653Sdougm ret = SA_NO_SUCH_PATH; 2017*4653Sdougm } else { 2018*4653Sdougm if (group == NULL) 20193034Sdougm group = sa_get_parent_group(share); 2020*4653Sdougm if (!dryrun) { 20213034Sdougm if (ret == SA_OK) { 2022*4653Sdougm ret = sa_disable_share(share, NULL); 20233034Sdougm /* 2024*4653Sdougm * We don't care if it fails since it 20253663Sdougm * could be disabled already. Some 20263663Sdougm * unexpected errors could occur that 20273663Sdougm * prevent removal, so also check for 20283663Sdougm * force being set. 20293034Sdougm */ 2030*4653Sdougm if (ret == SA_OK || ret == SA_NO_SUCH_PATH || 2031*4653Sdougm ret == SA_NOT_SUPPORTED || 2032*4653Sdougm ret == SA_SYSTEM_ERR || force) { 2033*4653Sdougm ret = sa_remove_share(share); 2034*4653Sdougm } 2035*4653Sdougm if (ret == SA_OK) 2036*4653Sdougm ret = sa_update_config(handle); 20373034Sdougm } 2038*4653Sdougm if (ret != SA_OK) 2039*4653Sdougm (void) printf(gettext( 2040*4653Sdougm "Could not remove share: %s\n"), 2041*4653Sdougm sa_errorstr(ret)); 2042*4653Sdougm 2043*4653Sdougm } else if (ret == SA_OK) { 20443034Sdougm char *pname; 20453034Sdougm pname = sa_get_group_attr(group, "name"); 20463034Sdougm if (pname != NULL) { 2047*4653Sdougm auth = check_authorizations(pname, flags); 2048*4653Sdougm sa_free_attr_string(pname); 20493034Sdougm } 20503034Sdougm if (!auth && verbose) { 2051*4653Sdougm (void) printf(gettext( 2052*4653Sdougm "Command would fail: %s\n"), 2053*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 20543034Sdougm } 20553034Sdougm } 20563034Sdougm } 20573034Sdougm return (ret); 20583034Sdougm } 20593034Sdougm 20603034Sdougm /* 20613034Sdougm * sa_set_share(flags, argc, argv) 20623034Sdougm * 20633034Sdougm * implements set-share subcommand. 20643034Sdougm */ 20653034Sdougm 20663034Sdougm int 20673910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 20683034Sdougm { 20693034Sdougm int dryrun = 0; 20703034Sdougm int c; 20713034Sdougm int ret = SA_OK; 20723034Sdougm sa_group_t group, sharegroup; 20733034Sdougm sa_share_t share; 20743034Sdougm char *sharepath = NULL; 20753034Sdougm char *description = NULL; 20763034Sdougm char *resource = NULL; 20773034Sdougm int auth; 20783034Sdougm int verbose = 0; 2079*4653Sdougm char *groupname; 20803034Sdougm 20813034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 2082*4653Sdougm switch (c) { 2083*4653Sdougm case 'n': 2084*4653Sdougm dryrun++; 2085*4653Sdougm break; 2086*4653Sdougm case 'd': 2087*4653Sdougm description = optarg; 2088*4653Sdougm break; 2089*4653Sdougm case 'r': 2090*4653Sdougm resource = optarg; 2091*4653Sdougm break; 2092*4653Sdougm case 'v': 2093*4653Sdougm verbose++; 2094*4653Sdougm break; 2095*4653Sdougm case 's': 2096*4653Sdougm /* 2097*4653Sdougm * Save share path into group. Currently limit 2098*4653Sdougm * to one share per command. 2099*4653Sdougm */ 2100*4653Sdougm if (sharepath != NULL) { 2101*4653Sdougm (void) printf(gettext( 2102*4653Sdougm "Updating multiple shares not " 21033034Sdougm "supported\n")); 2104*4653Sdougm return (SA_BAD_PATH); 2105*4653Sdougm } 2106*4653Sdougm sharepath = optarg; 2107*4653Sdougm break; 2108*4653Sdougm default: 2109*4653Sdougm case 'h': 2110*4653Sdougm case '?': 2111*4653Sdougm (void) printf(gettext("usage: %s\n"), 2112*4653Sdougm sa_get_usage(USAGE_SET_SHARE)); 2113*4653Sdougm return (SA_OK); 21143034Sdougm } 21153034Sdougm } 2116*4653Sdougm 21173034Sdougm if (optind >= argc || sharepath == NULL) { 2118*4653Sdougm if (sharepath == NULL) { 2119*4653Sdougm (void) printf(gettext("usage: %s\n"), 2120*4653Sdougm sa_get_usage(USAGE_SET_SHARE)); 2121*4653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 2122*4653Sdougm ret = SA_BAD_PATH; 2123*4653Sdougm } else { 2124*4653Sdougm ret = SA_OK; 2125*4653Sdougm } 21263034Sdougm } 21273034Sdougm if ((optind + 1) < argc) { 2128*4653Sdougm (void) printf(gettext("usage: %s\n"), 2129*4653Sdougm sa_get_usage(USAGE_SET_SHARE)); 2130*4653Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 2131*4653Sdougm ret = SA_SYNTAX_ERR; 21323034Sdougm } 2133*4653Sdougm 2134*4653Sdougm if (ret != SA_OK) 2135*4653Sdougm return (ret); 2136*4653Sdougm 2137*4653Sdougm if (optind < argc) { 21383034Sdougm groupname = argv[optind]; 21393910Sdougm group = sa_get_group(handle, groupname); 2140*4653Sdougm } else { 21413034Sdougm group = NULL; 21423034Sdougm groupname = NULL; 2143*4653Sdougm } 2144*4653Sdougm share = sa_find_share(handle, sharepath); 2145*4653Sdougm if (share == NULL) { 2146*4653Sdougm (void) printf(gettext("Share path \"%s\" not found\n"), 2147*4653Sdougm sharepath); 2148*4653Sdougm return (SA_NO_SUCH_PATH); 2149*4653Sdougm } 2150*4653Sdougm sharegroup = sa_get_parent_group(share); 2151*4653Sdougm if (group != NULL && group != sharegroup) { 2152*4653Sdougm (void) printf(gettext("Group \"%s\" does not contain " 2153*4653Sdougm "share %s\n"), argv[optind], sharepath); 2154*4653Sdougm ret = SA_BAD_PATH; 2155*4653Sdougm } else { 2156*4653Sdougm int delgroupname = 0; 2157*4653Sdougm if (groupname == NULL) { 21583034Sdougm groupname = sa_get_group_attr(sharegroup, "name"); 21593034Sdougm delgroupname = 1; 2160*4653Sdougm } 2161*4653Sdougm if (groupname != NULL) { 21623034Sdougm auth = check_authorizations(groupname, flags); 21633034Sdougm if (delgroupname) { 2164*4653Sdougm sa_free_attr_string(groupname); 2165*4653Sdougm groupname = NULL; 21663034Sdougm } 2167*4653Sdougm } else { 21683034Sdougm ret = SA_NO_MEMORY; 2169*4653Sdougm } 2170*4653Sdougm if (resource != NULL) { 21713034Sdougm if (strpbrk(resource, " \t/") == NULL) { 2172*4653Sdougm if (!dryrun) { 2173*4653Sdougm ret = sa_set_share_attr(share, 2174*4653Sdougm "resource", resource); 2175*4653Sdougm } else { 2176*4653Sdougm sa_share_t resshare; 2177*4653Sdougm resshare = sa_get_resource(sharegroup, 2178*4653Sdougm resource); 2179*4653Sdougm if (resshare != NULL && 2180*4653Sdougm resshare != share) 2181*4653Sdougm ret = SA_DUPLICATE_NAME; 2182*4653Sdougm } 21833034Sdougm } else { 2184*4653Sdougm ret = SA_BAD_PATH; 2185*4653Sdougm (void) printf(gettext("Resource must not " 2186*4653Sdougm "contain white space or '/'\n")); 21873034Sdougm } 2188*4653Sdougm } 2189*4653Sdougm if (ret == SA_OK && description != NULL) 21903034Sdougm ret = sa_set_share_description(share, description); 2191*4653Sdougm } 2192*4653Sdougm if (!dryrun && ret == SA_OK) 2193*4653Sdougm ret = sa_update_config(handle); 2194*4653Sdougm 2195*4653Sdougm switch (ret) { 2196*4653Sdougm case SA_DUPLICATE_NAME: 2197*4653Sdougm (void) printf(gettext("Resource name in use: %s\n"), resource); 2198*4653Sdougm break; 2199*4653Sdougm default: 2200*4653Sdougm (void) printf(gettext("Could not set attribute: %s\n"), 2201*4653Sdougm sa_errorstr(ret)); 2202*4653Sdougm break; 2203*4653Sdougm case SA_OK: 2204*4653Sdougm if (dryrun && !auth && verbose) 22053034Sdougm (void) printf(gettext("Command would fail: %s\n"), 2206*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 2207*4653Sdougm break; 22083034Sdougm } 2209*4653Sdougm 22103034Sdougm return (ret); 22113034Sdougm } 22123034Sdougm 22133034Sdougm /* 22143034Sdougm * add_security(group, sectype, optlist, proto, *err) 22153034Sdougm * 22163034Sdougm * Helper function to add a security option (named optionset) to the 22173034Sdougm * group. 22183034Sdougm */ 22193034Sdougm 22203034Sdougm static int 22213034Sdougm add_security(sa_group_t group, char *sectype, 22223034Sdougm struct options *optlist, char *proto, int *err) 22233034Sdougm { 22243034Sdougm sa_security_t security; 22253034Sdougm int ret = SA_OK; 22263034Sdougm int result = 0; 22273034Sdougm 22283034Sdougm sectype = sa_proto_space_alias(proto, sectype); 22293034Sdougm security = sa_get_security(group, sectype, proto); 2230*4653Sdougm if (security == NULL) 2231*4653Sdougm security = sa_create_security(group, sectype, proto); 2232*4653Sdougm 22333034Sdougm if (sectype != NULL) 2234*4653Sdougm sa_free_attr_string(sectype); 2235*4653Sdougm 2236*4653Sdougm if (security == NULL) 2237*4653Sdougm return (ret); 2238*4653Sdougm 2239*4653Sdougm while (optlist != NULL) { 22403034Sdougm sa_property_t prop; 22413034Sdougm prop = sa_get_property(security, optlist->optname); 22423034Sdougm if (prop == NULL) { 22433034Sdougm /* 2244*4653Sdougm * Add the property, but only if it is 22453034Sdougm * a non-NULL or non-zero length value 22463034Sdougm */ 2247*4653Sdougm if (optlist->optvalue != NULL) { 2248*4653Sdougm prop = sa_create_property(optlist->optname, 2249*4653Sdougm optlist->optvalue); 2250*4653Sdougm if (prop != NULL) { 2251*4653Sdougm ret = sa_valid_property(security, proto, 2252*4653Sdougm prop); 2253*4653Sdougm if (ret != SA_OK) { 2254*4653Sdougm (void) sa_remove_property(prop); 2255*4653Sdougm (void) printf(gettext( 2256*4653Sdougm "Could not add " 2257*4653Sdougm "property %s: %s\n"), 2258*4653Sdougm optlist->optname, 2259*4653Sdougm sa_errorstr(ret)); 2260*4653Sdougm } 2261*4653Sdougm if (ret == SA_OK) { 2262*4653Sdougm ret = sa_add_property(security, 2263*4653Sdougm prop); 2264*4653Sdougm if (ret != SA_OK) { 2265*4653Sdougm (void) printf(gettext( 2266*4653Sdougm "Could not add " 2267*4653Sdougm "property (%s=%s): " 2268*4653Sdougm "%s\n"), 2269*4653Sdougm optlist->optname, 2270*4653Sdougm optlist->optvalue, 2271*4653Sdougm sa_errorstr(ret)); 2272*4653Sdougm } else { 2273*4653Sdougm result = 1; 2274*4653Sdougm } 2275*4653Sdougm } 22763034Sdougm } 22773034Sdougm } 22783034Sdougm } else { 2279*4653Sdougm ret = sa_update_property(prop, optlist->optvalue); 2280*4653Sdougm result = 1; /* should check if really changed */ 22813034Sdougm } 22823034Sdougm optlist = optlist->next; 2283*4653Sdougm } 2284*4653Sdougm /* 2285*4653Sdougm * When done, properties may have all been removed but 2286*4653Sdougm * we need to keep the security type itself until 2287*4653Sdougm * explicitly removed. 2288*4653Sdougm */ 2289*4653Sdougm if (result) 22903034Sdougm ret = sa_commit_properties(security, 0); 22913034Sdougm *err = ret; 22923034Sdougm return (result); 22933034Sdougm } 22943034Sdougm 22953034Sdougm /* 22963034Sdougm * basic_set(groupname, optlist, protocol, sharepath, dryrun) 22973034Sdougm * 22983034Sdougm * This function implements "set" when a name space (-S) is not 22993034Sdougm * specified. It is a basic set. Options and other CLI parsing has 23003034Sdougm * already been done. 23013034Sdougm */ 23023034Sdougm 23033034Sdougm static int 23043910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 23053910Sdougm char *protocol, char *sharepath, int dryrun) 23063034Sdougm { 23073034Sdougm sa_group_t group; 23083034Sdougm int ret = SA_OK; 23093034Sdougm int change = 0; 23103034Sdougm struct list *worklist = NULL; 23113034Sdougm 23123910Sdougm group = sa_get_group(handle, groupname); 23133034Sdougm if (group != NULL) { 2314*4653Sdougm sa_share_t share = NULL; 2315*4653Sdougm if (sharepath != NULL) { 2316*4653Sdougm share = sa_get_share(group, sharepath); 2317*4653Sdougm if (share == NULL) { 2318*4653Sdougm (void) printf(gettext( 2319*4653Sdougm "Share does not exist in group %s\n"), 2320*4653Sdougm groupname, sharepath); 2321*4653Sdougm ret = SA_NO_SUCH_PATH; 2322*4653Sdougm } 23233034Sdougm } 2324*4653Sdougm if (ret == SA_OK) { 2325*4653Sdougm /* group must exist */ 2326*4653Sdougm ret = valid_options(optlist, protocol, 2327*4653Sdougm share == NULL ? group : share, NULL); 2328*4653Sdougm if (ret == SA_OK && !dryrun) { 2329*4653Sdougm if (share != NULL) 2330*4653Sdougm change |= add_optionset(share, optlist, 2331*4653Sdougm protocol, &ret); 2332*4653Sdougm else 2333*4653Sdougm change |= add_optionset(group, optlist, 2334*4653Sdougm protocol, &ret); 2335*4653Sdougm if (ret == SA_OK && change) 2336*4653Sdougm worklist = add_list(worklist, group, 2337*4653Sdougm share); 2338*4653Sdougm } 23393034Sdougm } 2340*4653Sdougm free_opt(optlist); 23413034Sdougm } else { 23423034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 23433034Sdougm ret = SA_NO_SUCH_GROUP; 23443034Sdougm } 23453034Sdougm /* 23463034Sdougm * we have a group and potentially legal additions 23473034Sdougm */ 23483034Sdougm 2349*4653Sdougm /* 2350*4653Sdougm * Commit to configuration if not a dryrunp and properties 2351*4653Sdougm * have changed. 2352*4653Sdougm */ 2353*4653Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 23543034Sdougm /* properties changed, so update all shares */ 23553910Sdougm (void) enable_all_groups(handle, worklist, 0, 0, protocol); 2356*4653Sdougm 23573034Sdougm if (worklist != NULL) 2358*4653Sdougm free_list(worklist); 23593034Sdougm return (ret); 23603034Sdougm } 23613034Sdougm 23623034Sdougm /* 23633034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 23643034Sdougm * 23653034Sdougm * This function implements "set" when a name space (-S) is 23663034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 23673034Sdougm * already been done. 23683034Sdougm */ 23693034Sdougm 23703034Sdougm static int 23713910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 23723910Sdougm char *protocol, char *sharepath, int dryrun, char *sectype) 23733034Sdougm { 23743034Sdougm sa_group_t group; 23753034Sdougm int ret = SA_OK; 23763034Sdougm int change = 0; 23773034Sdougm struct list *worklist = NULL; 23783034Sdougm 23793034Sdougm /* 23803034Sdougm * make sure protcol and sectype are valid 23813034Sdougm */ 23823034Sdougm 23833034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 2384*4653Sdougm (void) printf(gettext("Option space \"%s\" not valid " 2385*4653Sdougm "for protocol.\n"), sectype); 2386*4653Sdougm return (SA_INVALID_SECURITY); 23873034Sdougm } 23883034Sdougm 23893910Sdougm group = sa_get_group(handle, groupname); 23903034Sdougm if (group != NULL) { 2391*4653Sdougm sa_share_t share = NULL; 2392*4653Sdougm if (sharepath != NULL) { 2393*4653Sdougm share = sa_get_share(group, sharepath); 2394*4653Sdougm if (share == NULL) { 2395*4653Sdougm (void) printf(gettext( 2396*4653Sdougm "Share does not exist in group %s\n"), 2397*4653Sdougm groupname, sharepath); 2398*4653Sdougm ret = SA_NO_SUCH_PATH; 2399*4653Sdougm } 24003034Sdougm } 2401*4653Sdougm if (ret == SA_OK) { 2402*4653Sdougm /* group must exist */ 2403*4653Sdougm ret = valid_options(optlist, protocol, 2404*4653Sdougm share == NULL ? group : share, sectype); 2405*4653Sdougm if (ret == SA_OK && !dryrun) { 2406*4653Sdougm if (share != NULL) 2407*4653Sdougm change = add_security(share, sectype, 2408*4653Sdougm optlist, protocol, &ret); 2409*4653Sdougm else 2410*4653Sdougm change = add_security(group, sectype, 2411*4653Sdougm optlist, protocol, &ret); 2412*4653Sdougm if (ret != SA_OK) 2413*4653Sdougm (void) printf(gettext( 2414*4653Sdougm "Could not set property: %s\n"), 2415*4653Sdougm sa_errorstr(ret)); 2416*4653Sdougm } 2417*4653Sdougm if (ret == SA_OK && change) 2418*4653Sdougm worklist = add_list(worklist, group, share); 24193034Sdougm } 2420*4653Sdougm free_opt(optlist); 24213034Sdougm } else { 24223034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 24233034Sdougm ret = SA_NO_SUCH_GROUP; 24243034Sdougm } 24253034Sdougm /* 24263034Sdougm * we have a group and potentially legal additions 24273034Sdougm */ 24283034Sdougm 2429*4653Sdougm /* Commit to configuration if not a dryrun */ 24303034Sdougm if (!dryrun && ret == 0) { 2431*4653Sdougm if (change && worklist != NULL) { 2432*4653Sdougm /* properties changed, so update all shares */ 2433*4653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 2434*4653Sdougm protocol); 2435*4653Sdougm } 2436*4653Sdougm ret = sa_update_config(handle); 24373034Sdougm } 24383034Sdougm if (worklist != NULL) 2439*4653Sdougm free_list(worklist); 24403034Sdougm return (ret); 24413034Sdougm } 24423034Sdougm 24433034Sdougm /* 24443034Sdougm * sa_set(flags, argc, argv) 24453034Sdougm * 24463034Sdougm * Implements the set subcommand. It keys off of -S to determine which 24473034Sdougm * set of operations to actually do. 24483034Sdougm */ 24493034Sdougm 24503034Sdougm int 24513910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 24523034Sdougm { 24533034Sdougm char *groupname; 24543034Sdougm int verbose = 0; 24553034Sdougm int dryrun = 0; 24563034Sdougm int c; 24573034Sdougm char *protocol = NULL; 24583034Sdougm int ret = SA_OK; 24593034Sdougm struct options *optlist = NULL; 24603034Sdougm char *sharepath = NULL; 24613034Sdougm char *optset = NULL; 24623034Sdougm int auth; 24633034Sdougm 24643034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2465*4653Sdougm switch (c) { 2466*4653Sdougm case 'v': 2467*4653Sdougm verbose++; 2468*4653Sdougm break; 2469*4653Sdougm case 'n': 2470*4653Sdougm dryrun++; 2471*4653Sdougm break; 2472*4653Sdougm case 'P': 2473*4653Sdougm protocol = optarg; 2474*4653Sdougm if (!sa_valid_protocol(protocol)) { 2475*4653Sdougm (void) printf(gettext( 2476*4653Sdougm "Invalid protocol specified: %s\n"), 2477*4653Sdougm protocol); 2478*4653Sdougm return (SA_INVALID_PROTOCOL); 2479*4653Sdougm } 2480*4653Sdougm break; 2481*4653Sdougm case 'p': 2482*4653Sdougm ret = add_opt(&optlist, optarg, 0); 2483*4653Sdougm switch (ret) { 2484*4653Sdougm case OPT_ADD_SYNTAX: 2485*4653Sdougm (void) printf(gettext("Property syntax error:" 2486*4653Sdougm " %s\n"), optarg); 2487*4653Sdougm return (SA_SYNTAX_ERR); 2488*4653Sdougm case OPT_ADD_MEMORY: 2489*4653Sdougm (void) printf(gettext("No memory to set " 2490*4653Sdougm "property: %s\n"), optarg); 2491*4653Sdougm return (SA_NO_MEMORY); 2492*4653Sdougm default: 2493*4653Sdougm break; 2494*4653Sdougm } 2495*4653Sdougm break; 2496*4653Sdougm case 's': 2497*4653Sdougm sharepath = optarg; 2498*4653Sdougm break; 2499*4653Sdougm case 'S': 2500*4653Sdougm optset = optarg; 2501*4653Sdougm break; 2502*4653Sdougm default: 2503*4653Sdougm case 'h': 2504*4653Sdougm case '?': 2505*4653Sdougm (void) printf(gettext("usage: %s\n"), 2506*4653Sdougm sa_get_usage(USAGE_SET)); 2507*4653Sdougm return (SA_OK); 25083034Sdougm } 25093034Sdougm } 25103034Sdougm 25113034Sdougm if (optlist != NULL) 2512*4653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 25133034Sdougm 25143034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 2515*4653Sdougm protocol == NULL || ret != OPT_ADD_OK) { 2516*4653Sdougm char *sep = "\t"; 2517*4653Sdougm 2518*4653Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 2519*4653Sdougm if (optind >= argc) { 2520*4653Sdougm (void) printf(gettext("%sgroup must be specified"), 2521*4653Sdougm sep); 2522*4653Sdougm sep = ", "; 2523*4653Sdougm } 2524*4653Sdougm if (optlist == NULL) { 2525*4653Sdougm (void) printf(gettext("%sat least one property must be" 2526*4653Sdougm " specified"), sep); 2527*4653Sdougm sep = ", "; 2528*4653Sdougm } 2529*4653Sdougm if (protocol == NULL) { 2530*4653Sdougm (void) printf(gettext("%sprotocol must be specified"), 2531*4653Sdougm sep); 2532*4653Sdougm sep = ", "; 2533*4653Sdougm } 2534*4653Sdougm (void) printf("\n"); 2535*4653Sdougm ret = SA_SYNTAX_ERR; 25363034Sdougm } else { 25373034Sdougm /* 2538*4653Sdougm * If a group already exists, we can only add a new 25393034Sdougm * protocol to it and not create a new one or add the 25403034Sdougm * same protocol again. 25413034Sdougm */ 25423034Sdougm 2543*4653Sdougm groupname = argv[optind]; 2544*4653Sdougm auth = check_authorizations(groupname, flags); 2545*4653Sdougm if (optset == NULL) 2546*4653Sdougm ret = basic_set(handle, groupname, optlist, protocol, 2547*4653Sdougm sharepath, dryrun); 2548*4653Sdougm else 2549*4653Sdougm ret = space_set(handle, groupname, optlist, protocol, 2550*4653Sdougm sharepath, dryrun, optset); 2551*4653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 2552*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 2553*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 2554*4653Sdougm } 25553034Sdougm } 25563034Sdougm return (ret); 25573034Sdougm } 25583034Sdougm 25593034Sdougm /* 25603034Sdougm * remove_options(group, optlist, proto, *err) 25613034Sdougm * 2562*4653Sdougm * Helper function to actually remove options from a group after all 25633034Sdougm * preprocessing is done. 25643034Sdougm */ 25653034Sdougm 25663034Sdougm static int 25673034Sdougm remove_options(sa_group_t group, struct options *optlist, 25683034Sdougm char *proto, int *err) 25693034Sdougm { 25703034Sdougm struct options *cur; 25713034Sdougm sa_optionset_t optionset; 25723034Sdougm sa_property_t prop; 25733034Sdougm int change = 0; 25743034Sdougm int ret = SA_OK; 25753034Sdougm 25763034Sdougm optionset = sa_get_optionset(group, proto); 25773034Sdougm if (optionset != NULL) { 2578*4653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 2579*4653Sdougm prop = sa_get_property(optionset, cur->optname); 2580*4653Sdougm if (prop != NULL) { 2581*4653Sdougm ret = sa_remove_property(prop); 2582*4653Sdougm if (ret != SA_OK) 2583*4653Sdougm break; 2584*4653Sdougm change = 1; 2585*4653Sdougm } 25863034Sdougm } 25873034Sdougm } 25883034Sdougm if (ret == SA_OK && change) 2589*4653Sdougm ret = sa_commit_properties(optionset, 0); 25903034Sdougm 25913034Sdougm if (err != NULL) 2592*4653Sdougm *err = ret; 25933034Sdougm return (change); 25943034Sdougm } 25953034Sdougm 25963034Sdougm /* 25973034Sdougm * valid_unset(group, optlist, proto) 25983034Sdougm * 25993034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 26003034Sdougm * error if a property doesn't exist. 26013034Sdougm */ 26023034Sdougm 26033034Sdougm static int 26043034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 26053034Sdougm { 26063034Sdougm struct options *cur; 26073034Sdougm sa_optionset_t optionset; 26083034Sdougm sa_property_t prop; 26093034Sdougm int ret = SA_OK; 26103034Sdougm 26113034Sdougm optionset = sa_get_optionset(group, proto); 26123034Sdougm if (optionset != NULL) { 2613*4653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 2614*4653Sdougm prop = sa_get_property(optionset, cur->optname); 2615*4653Sdougm if (prop == NULL) { 2616*4653Sdougm (void) printf(gettext( 2617*4653Sdougm "Could not unset property %s: not set\n"), 2618*4653Sdougm cur->optname); 2619*4653Sdougm ret = SA_NO_SUCH_PROP; 2620*4653Sdougm } 26213034Sdougm } 26223034Sdougm } 26233034Sdougm return (ret); 26243034Sdougm } 26253034Sdougm 26263034Sdougm /* 26273034Sdougm * valid_unset_security(group, optlist, proto) 26283034Sdougm * 26293034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 26303034Sdougm * error if a property doesn't exist. 26313034Sdougm */ 26323034Sdougm 26333034Sdougm static int 26343034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 26353034Sdougm char *sectype) 26363034Sdougm { 26373034Sdougm struct options *cur; 26383034Sdougm sa_security_t security; 26393034Sdougm sa_property_t prop; 26403034Sdougm int ret = SA_OK; 26413034Sdougm char *sec; 26423034Sdougm 26433034Sdougm sec = sa_proto_space_alias(proto, sectype); 26443034Sdougm security = sa_get_security(group, sec, proto); 26453034Sdougm if (security != NULL) { 2646*4653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 2647*4653Sdougm prop = sa_get_property(security, cur->optname); 2648*4653Sdougm if (prop == NULL) { 2649*4653Sdougm (void) printf(gettext( 2650*4653Sdougm "Could not unset property %s: not set\n"), 2651*4653Sdougm cur->optname); 2652*4653Sdougm ret = SA_NO_SUCH_PROP; 2653*4653Sdougm } 26543034Sdougm } 26553034Sdougm } else { 2656*4653Sdougm (void) printf(gettext( 2657*4653Sdougm "Could not unset %s: space not defined\n"), sectype); 2658*4653Sdougm ret = SA_NO_SUCH_SECURITY; 26593034Sdougm } 26603034Sdougm if (sec != NULL) 2661*4653Sdougm sa_free_attr_string(sec); 26623034Sdougm return (ret); 26633034Sdougm } 26643034Sdougm 26653034Sdougm /* 26663034Sdougm * remove_security(group, optlist, proto) 26673034Sdougm * 26683034Sdougm * Remove the properties since they were checked as valid. 26693034Sdougm */ 26703034Sdougm 26713034Sdougm static int 26723034Sdougm remove_security(sa_group_t group, char *sectype, 26733034Sdougm struct options *optlist, char *proto, int *err) 26743034Sdougm { 26753034Sdougm sa_security_t security; 26763034Sdougm int ret = SA_OK; 26773034Sdougm int change = 0; 26783034Sdougm 26793034Sdougm sectype = sa_proto_space_alias(proto, sectype); 26803034Sdougm security = sa_get_security(group, sectype, proto); 26813034Sdougm if (sectype != NULL) 2682*4653Sdougm sa_free_attr_string(sectype); 26833034Sdougm 26843034Sdougm if (security != NULL) { 2685*4653Sdougm while (optlist != NULL) { 2686*4653Sdougm sa_property_t prop; 2687*4653Sdougm prop = sa_get_property(security, optlist->optname); 2688*4653Sdougm if (prop != NULL) { 2689*4653Sdougm ret = sa_remove_property(prop); 2690*4653Sdougm if (ret != SA_OK) 2691*4653Sdougm break; 2692*4653Sdougm change = 1; 2693*4653Sdougm } 2694*4653Sdougm optlist = optlist->next; 26953034Sdougm } 26963034Sdougm /* 26973034Sdougm * when done, properties may have all been removed but 26983034Sdougm * we need to keep the security type itself until 26993034Sdougm * explicitly removed. 27003034Sdougm */ 2701*4653Sdougm if (ret == SA_OK && change) 2702*4653Sdougm ret = sa_commit_properties(security, 0); 27033034Sdougm } else { 2704*4653Sdougm ret = SA_NO_SUCH_PROP; 27053034Sdougm } 27063034Sdougm if (err != NULL) 2707*4653Sdougm *err = ret; 27083034Sdougm return (change); 27093034Sdougm } 27103034Sdougm 27113034Sdougm /* 27123034Sdougm * basic_unset(groupname, optlist, protocol, sharepath, dryrun) 27133034Sdougm * 2714*4653Sdougm * Unset non-named optionset properties. 27153034Sdougm */ 27163034Sdougm 27173034Sdougm static int 27183910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 27193910Sdougm char *protocol, char *sharepath, int dryrun) 27203034Sdougm { 27213034Sdougm sa_group_t group; 27223034Sdougm int ret = SA_OK; 27233034Sdougm int change = 0; 27243034Sdougm struct list *worklist = NULL; 2725*4653Sdougm sa_share_t share = NULL; 27263034Sdougm 27273910Sdougm group = sa_get_group(handle, groupname); 2728*4653Sdougm if (group == NULL) 2729*4653Sdougm return (ret); 2730*4653Sdougm 2731*4653Sdougm if (sharepath != NULL) { 27323034Sdougm share = sa_get_share(group, sharepath); 27333034Sdougm if (share == NULL) { 2734*4653Sdougm (void) printf(gettext( 2735*4653Sdougm "Share does not exist in group %s\n"), 2736*4653Sdougm groupname, sharepath); 2737*4653Sdougm ret = SA_NO_SUCH_PATH; 27383034Sdougm } 2739*4653Sdougm } 2740*4653Sdougm if (ret == SA_OK) { 27413034Sdougm /* group must exist */ 27423034Sdougm ret = valid_unset(share != NULL ? share : group, 2743*4653Sdougm optlist, protocol); 27443034Sdougm if (ret == SA_OK && !dryrun) { 2745*4653Sdougm if (share != NULL) { 2746*4653Sdougm sa_optionset_t optionset; 2747*4653Sdougm sa_property_t prop; 2748*4653Sdougm change |= remove_options(share, optlist, 2749*4653Sdougm protocol, &ret); 2750*4653Sdougm /* 2751*4653Sdougm * If a share optionset is 2752*4653Sdougm * empty, remove it. 2753*4653Sdougm */ 2754*4653Sdougm optionset = sa_get_optionset((sa_share_t)share, 2755*4653Sdougm protocol); 2756*4653Sdougm if (optionset != NULL) { 2757*4653Sdougm prop = sa_get_property(optionset, NULL); 2758*4653Sdougm if (prop == NULL) 2759*4653Sdougm (void) sa_destroy_optionset( 2760*4653Sdougm optionset); 2761*4653Sdougm } 2762*4653Sdougm } else { 2763*4653Sdougm change |= remove_options(group, 2764*4653Sdougm optlist, protocol, &ret); 27653034Sdougm } 2766*4653Sdougm if (ret == SA_OK && change) 2767*4653Sdougm worklist = add_list(worklist, group, 2768*4653Sdougm share); 2769*4653Sdougm if (ret != SA_OK) 2770*4653Sdougm (void) printf(gettext( 2771*4653Sdougm "Could not remove properties: " 2772*4653Sdougm "%s\n"), sa_errorstr(ret)); 27733034Sdougm } 2774*4653Sdougm } else { 2775*4653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 2776*4653Sdougm groupname); 27773034Sdougm ret = SA_NO_SUCH_GROUP; 27783034Sdougm } 2779*4653Sdougm free_opt(optlist); 27803034Sdougm 27813034Sdougm /* 2782*4653Sdougm * We have a group and potentially legal additions 2783*4653Sdougm * 2784*4653Sdougm * Commit to configuration if not a dryrun 27853034Sdougm */ 27863034Sdougm if (!dryrun && ret == SA_OK) { 2787*4653Sdougm if (change && worklist != NULL) { 2788*4653Sdougm /* properties changed, so update all shares */ 2789*4653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 2790*4653Sdougm protocol); 2791*4653Sdougm } 27923034Sdougm } 27933034Sdougm if (worklist != NULL) 2794*4653Sdougm free_list(worklist); 27953034Sdougm return (ret); 27963034Sdougm } 27973034Sdougm 27983034Sdougm /* 27993034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 28003034Sdougm * 2801*4653Sdougm * Unset named optionset properties. 28023034Sdougm */ 28033034Sdougm static int 28043910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 28053910Sdougm char *protocol, char *sharepath, int dryrun, char *sectype) 28063034Sdougm { 28073034Sdougm sa_group_t group; 28083034Sdougm int ret = SA_OK; 28093034Sdougm int change = 0; 28103034Sdougm struct list *worklist = NULL; 2811*4653Sdougm sa_share_t share = NULL; 28123034Sdougm 28133910Sdougm group = sa_get_group(handle, groupname); 2814*4653Sdougm if (group == NULL) { 2815*4653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2816*4653Sdougm return (SA_NO_SUCH_GROUP); 2817*4653Sdougm } 2818*4653Sdougm if (sharepath != NULL) { 28193034Sdougm share = sa_get_share(group, sharepath); 28203034Sdougm if (share == NULL) { 2821*4653Sdougm (void) printf(gettext( 2822*4653Sdougm "Share does not exist in group %s\n"), 2823*4653Sdougm groupname, sharepath); 2824*4653Sdougm return (SA_NO_SUCH_PATH); 28253034Sdougm } 2826*4653Sdougm } 2827*4653Sdougm ret = valid_unset_security(share != NULL ? share : group, optlist, 2828*4653Sdougm protocol, sectype); 2829*4653Sdougm 2830*4653Sdougm if (ret == SA_OK && !dryrun) { 2831*4653Sdougm if (optlist != NULL) { 28323034Sdougm if (share != NULL) { 2833*4653Sdougm sa_security_t optionset; 2834*4653Sdougm sa_property_t prop; 2835*4653Sdougm change = remove_security(share, 2836*4653Sdougm sectype, optlist, protocol, &ret); 2837*4653Sdougm 2838*4653Sdougm /* If a share security is empty, remove it */ 2839*4653Sdougm optionset = sa_get_security((sa_group_t)share, 2840*4653Sdougm sectype, protocol); 2841*4653Sdougm if (optionset != NULL) { 2842*4653Sdougm prop = sa_get_property(optionset, 2843*4653Sdougm NULL); 2844*4653Sdougm if (prop == NULL) 2845*4653Sdougm ret = sa_destroy_security( 2846*4653Sdougm optionset); 2847*4653Sdougm } 28483034Sdougm } else { 2849*4653Sdougm change = remove_security(group, sectype, 2850*4653Sdougm optlist, protocol, &ret); 28513034Sdougm } 2852*4653Sdougm } else { 28533034Sdougm sa_security_t security; 28543034Sdougm char *sec; 28553034Sdougm sec = sa_proto_space_alias(protocol, sectype); 28563034Sdougm security = sa_get_security(group, sec, protocol); 28573034Sdougm if (sec != NULL) 2858*4653Sdougm sa_free_attr_string(sec); 28593034Sdougm if (security != NULL) { 2860*4653Sdougm ret = sa_destroy_security(security); 2861*4653Sdougm if (ret == SA_OK) 2862*4653Sdougm change = 1; 28633034Sdougm } else { 2864*4653Sdougm ret = SA_NO_SUCH_PROP; 28653034Sdougm } 2866*4653Sdougm } 2867*4653Sdougm if (ret != SA_OK) 28683034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 2869*4653Sdougm sa_errorstr(ret)); 28703034Sdougm } 2871*4653Sdougm 2872*4653Sdougm if (ret == SA_OK && change) 2873*4653Sdougm worklist = add_list(worklist, group, 0); 2874*4653Sdougm 28753034Sdougm free_opt(optlist); 28763034Sdougm /* 2877*4653Sdougm * We have a group and potentially legal additions 28783034Sdougm */ 28793034Sdougm 2880*4653Sdougm /* Commit to configuration if not a dryrun */ 28813034Sdougm if (!dryrun && ret == 0) { 28823034Sdougm /* properties changed, so update all shares */ 2883*4653Sdougm if (change && worklist != NULL) 2884*4653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 2885*4653Sdougm protocol); 2886*4653Sdougm ret = sa_update_config(handle); 28873034Sdougm } 28883034Sdougm if (worklist != NULL) 2889*4653Sdougm free_list(worklist); 28903034Sdougm return (ret); 28913034Sdougm } 28923034Sdougm 28933034Sdougm /* 28943034Sdougm * sa_unset(flags, argc, argv) 28953034Sdougm * 2896*4653Sdougm * Implements the unset subcommand. Parsing done here and then basic 28973034Sdougm * or space versions of the real code are called. 28983034Sdougm */ 28993034Sdougm 29003034Sdougm int 29013910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 29023034Sdougm { 29033034Sdougm char *groupname; 29043034Sdougm int verbose = 0; 29053034Sdougm int dryrun = 0; 29063034Sdougm int c; 29073034Sdougm char *protocol = NULL; 29083034Sdougm int ret = SA_OK; 29093034Sdougm struct options *optlist = NULL; 29103034Sdougm char *sharepath = NULL; 29113034Sdougm char *optset = NULL; 29123034Sdougm int auth; 29133034Sdougm 29143034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2915*4653Sdougm switch (c) { 2916*4653Sdougm case 'v': 2917*4653Sdougm verbose++; 2918*4653Sdougm break; 2919*4653Sdougm case 'n': 2920*4653Sdougm dryrun++; 2921*4653Sdougm break; 2922*4653Sdougm case 'P': 2923*4653Sdougm protocol = optarg; 2924*4653Sdougm if (!sa_valid_protocol(protocol)) { 2925*4653Sdougm (void) printf(gettext( 2926*4653Sdougm "Invalid protocol specified: %s\n"), 2927*4653Sdougm protocol); 2928*4653Sdougm return (SA_INVALID_PROTOCOL); 2929*4653Sdougm } 2930*4653Sdougm break; 2931*4653Sdougm case 'p': 2932*4653Sdougm ret = add_opt(&optlist, optarg, 1); 2933*4653Sdougm switch (ret) { 2934*4653Sdougm case OPT_ADD_SYNTAX: 2935*4653Sdougm (void) printf(gettext("Property syntax error " 2936*4653Sdougm "for property %s\n"), optarg); 2937*4653Sdougm return (SA_SYNTAX_ERR); 2938*4653Sdougm 2939*4653Sdougm case OPT_ADD_PROPERTY: 2940*4653Sdougm (void) printf(gettext("Properties need to be " 2941*4653Sdougm "set with set command: %s\n"), optarg); 2942*4653Sdougm return (SA_SYNTAX_ERR); 2943*4653Sdougm 2944*4653Sdougm default: 2945*4653Sdougm break; 2946*4653Sdougm } 2947*4653Sdougm break; 2948*4653Sdougm case 's': 2949*4653Sdougm sharepath = optarg; 2950*4653Sdougm break; 2951*4653Sdougm case 'S': 2952*4653Sdougm optset = optarg; 2953*4653Sdougm break; 2954*4653Sdougm default: 2955*4653Sdougm case 'h': 2956*4653Sdougm case '?': 2957*4653Sdougm (void) printf(gettext("usage: %s\n"), 2958*4653Sdougm sa_get_usage(USAGE_UNSET)); 2959*4653Sdougm return (SA_OK); 29603034Sdougm } 29613034Sdougm } 29623034Sdougm 29633034Sdougm if (optlist != NULL) 2964*4653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 29653034Sdougm 29663034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 29673034Sdougm protocol == NULL) { 2968*4653Sdougm char *sep = "\t"; 2969*4653Sdougm (void) printf(gettext("usage: %s\n"), 2970*4653Sdougm sa_get_usage(USAGE_UNSET)); 2971*4653Sdougm if (optind >= argc) { 2972*4653Sdougm (void) printf(gettext("%sgroup must be specified"), 2973*4653Sdougm sep); 2974*4653Sdougm sep = ", "; 2975*4653Sdougm } 2976*4653Sdougm if (optlist == NULL) { 2977*4653Sdougm (void) printf(gettext("%sat least one property must " 2978*4653Sdougm "be specified"), sep); 2979*4653Sdougm sep = ", "; 2980*4653Sdougm } 2981*4653Sdougm if (protocol == NULL) { 2982*4653Sdougm (void) printf(gettext("%sprotocol must be specified"), 2983*4653Sdougm sep); 2984*4653Sdougm sep = ", "; 2985*4653Sdougm } 2986*4653Sdougm (void) printf("\n"); 2987*4653Sdougm ret = SA_SYNTAX_ERR; 29883034Sdougm } else { 29893034Sdougm 29903034Sdougm /* 2991*4653Sdougm * If a group already exists, we can only add a new 29923034Sdougm * protocol to it and not create a new one or add the 29933034Sdougm * same protocol again. 29943034Sdougm */ 29953034Sdougm 2996*4653Sdougm groupname = argv[optind]; 2997*4653Sdougm auth = check_authorizations(groupname, flags); 2998*4653Sdougm if (optset == NULL) 2999*4653Sdougm ret = basic_unset(handle, groupname, optlist, protocol, 3000*4653Sdougm sharepath, dryrun); 3001*4653Sdougm else 3002*4653Sdougm ret = space_unset(handle, groupname, optlist, protocol, 3003*4653Sdougm sharepath, dryrun, optset); 3004*4653Sdougm 3005*4653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 3006*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 3007*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 30083034Sdougm } 30093034Sdougm return (ret); 30103034Sdougm } 30113034Sdougm 30123034Sdougm /* 30133034Sdougm * sa_enable_group(flags, argc, argv) 30143034Sdougm * 30153034Sdougm * Implements the enable subcommand 30163034Sdougm */ 30173034Sdougm 30183034Sdougm int 30193910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 30203034Sdougm { 30213034Sdougm int verbose = 0; 30223034Sdougm int dryrun = 0; 30233034Sdougm int all = 0; 30243034Sdougm int c; 30253034Sdougm int ret = SA_OK; 30263034Sdougm char *protocol = NULL; 30273034Sdougm char *state; 30283034Sdougm struct list *worklist = NULL; 30293034Sdougm int auth = 1; 3030*4653Sdougm sa_group_t group; 30313034Sdougm 30323034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 3033*4653Sdougm switch (c) { 3034*4653Sdougm case 'a': 3035*4653Sdougm all = 1; 3036*4653Sdougm break; 3037*4653Sdougm case 'n': 3038*4653Sdougm dryrun++; 3039*4653Sdougm break; 3040*4653Sdougm case 'P': 3041*4653Sdougm protocol = optarg; 3042*4653Sdougm if (!sa_valid_protocol(protocol)) { 3043*4653Sdougm (void) printf(gettext( 3044*4653Sdougm "Invalid protocol specified: %s\n"), 30453034Sdougm protocol); 3046*4653Sdougm return (SA_INVALID_PROTOCOL); 3047*4653Sdougm } 3048*4653Sdougm break; 3049*4653Sdougm case 'v': 3050*4653Sdougm verbose++; 3051*4653Sdougm break; 3052*4653Sdougm default: 3053*4653Sdougm case 'h': 3054*4653Sdougm case '?': 3055*4653Sdougm (void) printf(gettext("usage: %s\n"), 3056*4653Sdougm sa_get_usage(USAGE_ENABLE)); 3057*4653Sdougm return (0); 30583034Sdougm } 30593034Sdougm } 30603034Sdougm 30613034Sdougm if (optind == argc && !all) { 3062*4653Sdougm (void) printf(gettext("usage: %s\n"), 3063*4653Sdougm sa_get_usage(USAGE_ENABLE)); 3064*4653Sdougm (void) printf(gettext("\tmust specify group\n")); 3065*4653Sdougm return (SA_NO_SUCH_PATH); 3066*4653Sdougm } 3067*4653Sdougm if (!all) { 30683034Sdougm while (optind < argc) { 3069*4653Sdougm group = sa_get_group(handle, argv[optind]); 3070*4653Sdougm if (group != NULL) { 3071*4653Sdougm auth &= check_authorizations(argv[optind], 3072*4653Sdougm flags); 3073*4653Sdougm state = sa_get_group_attr(group, "state"); 3074*4653Sdougm if (state != NULL && 3075*4653Sdougm strcmp(state, "enabled") == 0) { 3076*4653Sdougm /* already enabled */ 3077*4653Sdougm if (verbose) 3078*4653Sdougm (void) printf(gettext( 3079*4653Sdougm "Group \"%s\" is already " 3080*4653Sdougm "enabled\n"), 3081*4653Sdougm argv[optind]); 3082*4653Sdougm ret = SA_BUSY; /* already enabled */ 3083*4653Sdougm } else { 3084*4653Sdougm worklist = add_list(worklist, group, 3085*4653Sdougm 0); 3086*4653Sdougm if (verbose) 3087*4653Sdougm (void) printf(gettext( 3088*4653Sdougm "Enabling group \"%s\"\n"), 3089*4653Sdougm argv[optind]); 3090*4653Sdougm } 3091*4653Sdougm if (state != NULL) 3092*4653Sdougm sa_free_attr_string(state); 30933034Sdougm } else { 3094*4653Sdougm ret = SA_NO_SUCH_GROUP; 30953034Sdougm } 3096*4653Sdougm optind++; 30973034Sdougm } 3098*4653Sdougm } else { 3099*4653Sdougm for (group = sa_get_group(handle, NULL); 3100*4653Sdougm group != NULL; 31013034Sdougm group = sa_get_next_group(group)) { 3102*4653Sdougm worklist = add_list(worklist, group, 0); 31033034Sdougm } 3104*4653Sdougm } 3105*4653Sdougm if (!dryrun && ret == SA_OK) 31063910Sdougm ret = enable_all_groups(handle, worklist, 1, 0, NULL); 3107*4653Sdougm 3108*4653Sdougm if (ret != SA_OK && ret != SA_BUSY) 31093034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 3110*4653Sdougm sa_errorstr(ret)); 3111*4653Sdougm if (ret == SA_BUSY) 31123034Sdougm ret = SA_OK; 3113*4653Sdougm 31143034Sdougm if (worklist != NULL) 3115*4653Sdougm free_list(worklist); 31163034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 3117*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 3118*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 31193034Sdougm } 31203034Sdougm return (ret); 31213034Sdougm } 31223034Sdougm 31233034Sdougm /* 31243034Sdougm * disable_group(group, setstate) 31253034Sdougm * 3126*4653Sdougm * Disable all the shares in the specified group honoring the setstate 31273034Sdougm * argument. This is a helper for disable_all_groups in order to 31283034Sdougm * simplify regular and subgroup (zfs) disabling. Group has already 31293034Sdougm * been checked for non-NULL. 31303034Sdougm */ 31313034Sdougm 31323034Sdougm static int 31333034Sdougm disable_group(sa_group_t group) 31343034Sdougm { 31353034Sdougm sa_share_t share; 31363034Sdougm int ret = SA_OK; 31373034Sdougm 31383034Sdougm for (share = sa_get_share(group, NULL); 31393034Sdougm share != NULL && ret == SA_OK; 31403034Sdougm share = sa_get_next_share(share)) { 3141*4653Sdougm ret = sa_disable_share(share, NULL); 3142*4653Sdougm if (ret == SA_NO_SUCH_PATH) { 3143*4653Sdougm /* 3144*4653Sdougm * this is OK since the path is gone. we can't 3145*4653Sdougm * re-share it anyway so no error. 3146*4653Sdougm */ 3147*4653Sdougm ret = SA_OK; 3148*4653Sdougm } 31493034Sdougm } 31503034Sdougm return (ret); 31513034Sdougm } 31523034Sdougm 31533034Sdougm 31543034Sdougm /* 31553034Sdougm * disable_all_groups(work, setstate) 31563034Sdougm * 31573034Sdougm * helper function that disables the shares in the list of groups 31583034Sdougm * provided. It optionally marks the group as disabled. Used by both 31593034Sdougm * enable and start subcommands. 31603034Sdougm */ 31613034Sdougm 31623034Sdougm static int 31633910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 31643034Sdougm { 31653034Sdougm int ret = SA_OK; 31663034Sdougm sa_group_t subgroup, group; 31673034Sdougm 31683034Sdougm while (work != NULL && ret == SA_OK) { 3169*4653Sdougm group = (sa_group_t)work->item; 3170*4653Sdougm if (setstate) 3171*4653Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 3172*4653Sdougm if (ret == SA_OK) { 3173*4653Sdougm char *name; 3174*4653Sdougm name = sa_get_group_attr(group, "name"); 3175*4653Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 3176*4653Sdougm /* need to get the sub-groups for stopping */ 3177*4653Sdougm for (subgroup = sa_get_sub_group(group); 3178*4653Sdougm subgroup != NULL; 3179*4653Sdougm subgroup = sa_get_next_group(subgroup)) { 3180*4653Sdougm ret = disable_group(subgroup); 3181*4653Sdougm } 3182*4653Sdougm } else { 3183*4653Sdougm ret = disable_group(group); 3184*4653Sdougm } 3185*4653Sdougm /* 3186*4653Sdougm * We don't want to "disable" since it won't come 3187*4653Sdougm * up after a reboot. The SMF framework should do 3188*4653Sdougm * the right thing. On enable we do want to do 3189*4653Sdougm * something. 3190*4653Sdougm */ 31913034Sdougm } 3192*4653Sdougm work = work->next; 31933034Sdougm } 31943034Sdougm if (ret == SA_OK) 3195*4653Sdougm ret = sa_update_config(handle); 31963034Sdougm return (ret); 31973034Sdougm } 31983034Sdougm 31993034Sdougm /* 32003034Sdougm * sa_disable_group(flags, argc, argv) 32013034Sdougm * 32023034Sdougm * Implements the disable subcommand 32033034Sdougm */ 32043034Sdougm 32053034Sdougm int 32063910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 32073034Sdougm { 32083034Sdougm int verbose = 0; 32093034Sdougm int dryrun = 0; 32103034Sdougm int all = 0; 32113034Sdougm int c; 32123034Sdougm int ret = SA_OK; 32133034Sdougm char *protocol; 32143034Sdougm char *state; 32153034Sdougm struct list *worklist = NULL; 3216*4653Sdougm sa_group_t group; 32173034Sdougm int auth = 1; 32183034Sdougm 32193034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 3220*4653Sdougm switch (c) { 3221*4653Sdougm case 'a': 3222*4653Sdougm all = 1; 3223*4653Sdougm break; 3224*4653Sdougm case 'n': 3225*4653Sdougm dryrun++; 3226*4653Sdougm break; 3227*4653Sdougm case 'P': 3228*4653Sdougm protocol = optarg; 3229*4653Sdougm if (!sa_valid_protocol(protocol)) { 3230*4653Sdougm (void) printf(gettext( 3231*4653Sdougm "Invalid protocol specified: %s\n"), 3232*4653Sdougm protocol); 3233*4653Sdougm return (SA_INVALID_PROTOCOL); 3234*4653Sdougm } 3235*4653Sdougm break; 3236*4653Sdougm case 'v': 3237*4653Sdougm verbose++; 3238*4653Sdougm break; 3239*4653Sdougm default: 3240*4653Sdougm case 'h': 3241*4653Sdougm case '?': 3242*4653Sdougm (void) printf(gettext("usage: %s\n"), 3243*4653Sdougm sa_get_usage(USAGE_DISABLE)); 3244*4653Sdougm return (0); 32453034Sdougm } 32463034Sdougm } 32473034Sdougm 32483034Sdougm if (optind == argc && !all) { 32493034Sdougm (void) printf(gettext("usage: %s\n"), 3250*4653Sdougm sa_get_usage(USAGE_DISABLE)); 32513034Sdougm (void) printf(gettext("\tmust specify group\n")); 3252*4653Sdougm return (SA_NO_SUCH_PATH); 3253*4653Sdougm } 3254*4653Sdougm if (!all) { 3255*4653Sdougm while (optind < argc) { 32563910Sdougm group = sa_get_group(handle, argv[optind]); 32573034Sdougm if (group != NULL) { 3258*4653Sdougm auth &= check_authorizations(argv[optind], 3259*4653Sdougm flags); 3260*4653Sdougm state = sa_get_group_attr(group, "state"); 3261*4653Sdougm if (state == NULL || 3262*4653Sdougm strcmp(state, "disabled") == 0) { 3263*4653Sdougm /* already disabled */ 3264*4653Sdougm if (verbose) 3265*4653Sdougm (void) printf(gettext( 3266*4653Sdougm "Group \"%s\" is " 3267*4653Sdougm "already disabled\n"), 3268*4653Sdougm argv[optind]); 3269*4653Sdougm ret = SA_BUSY; /* already disable */ 3270*4653Sdougm } else { 3271*4653Sdougm worklist = add_list(worklist, group, 0); 3272*4653Sdougm if (verbose) 3273*4653Sdougm (void) printf(gettext( 3274*4653Sdougm "Disabling group " 3275*4653Sdougm "\"%s\"\n"), argv[optind]); 3276*4653Sdougm } 3277*4653Sdougm if (state != NULL) 3278*4653Sdougm sa_free_attr_string(state); 32793034Sdougm } else { 3280*4653Sdougm ret = SA_NO_SUCH_GROUP; 32813034Sdougm } 32823034Sdougm optind++; 3283*4653Sdougm } 3284*4653Sdougm } else { 3285*4653Sdougm for (group = sa_get_group(handle, NULL); 3286*4653Sdougm group != NULL; 3287*4653Sdougm group = sa_get_next_group(group)) 32883034Sdougm worklist = add_list(worklist, group, 0); 32893034Sdougm } 3290*4653Sdougm 3291*4653Sdougm if (ret == SA_OK && !dryrun) 3292*4653Sdougm ret = disable_all_groups(handle, worklist, 1); 3293*4653Sdougm if (ret != SA_OK && ret != SA_BUSY) 3294*4653Sdougm (void) printf(gettext("Could not disable group: %s\n"), 3295*4653Sdougm sa_errorstr(ret)); 3296*4653Sdougm if (ret == SA_BUSY) 3297*4653Sdougm ret = SA_OK; 32983034Sdougm if (worklist != NULL) 3299*4653Sdougm free_list(worklist); 3300*4653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 3301*4653Sdougm (void) printf(gettext("Command would fail: %s\n"), 3302*4653Sdougm sa_errorstr(SA_NO_PERMISSION)); 33033034Sdougm return (ret); 33043034Sdougm } 33053034Sdougm 33063034Sdougm /* 33073034Sdougm * sa_start_group(flags, argc, argv) 33083034Sdougm * 33093034Sdougm * Implements the start command. 33103034Sdougm * This is similar to enable except it doesn't change the state 33113034Sdougm * of the group(s) and only enables shares if the group is already 33123034Sdougm * enabled. 33133034Sdougm */ 3314*4653Sdougm /*ARGSUSED*/ 33153034Sdougm int 33163910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 33173034Sdougm { 33183034Sdougm int verbose = 0; 33193034Sdougm int all = 0; 33203034Sdougm int c; 33213034Sdougm int ret = SMF_EXIT_OK; 33223034Sdougm char *protocol = NULL; 33233034Sdougm char *state; 33243034Sdougm struct list *worklist = NULL; 3325*4653Sdougm sa_group_t group; 33263034Sdougm 33273034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3328*4653Sdougm switch (c) { 3329*4653Sdougm case 'a': 3330*4653Sdougm all = 1; 3331*4653Sdougm break; 3332*4653Sdougm case 'P': 3333*4653Sdougm protocol = optarg; 3334*4653Sdougm if (!sa_valid_protocol(protocol)) { 3335*4653Sdougm (void) printf(gettext( 3336*4653Sdougm "Invalid protocol specified: %s\n"), 33373034Sdougm protocol); 3338*4653Sdougm return (SA_INVALID_PROTOCOL); 3339*4653Sdougm } 3340*4653Sdougm break; 3341*4653Sdougm case 'v': 3342*4653Sdougm verbose++; 3343*4653Sdougm break; 3344*4653Sdougm default: 3345*4653Sdougm case 'h': 3346*4653Sdougm case '?': 3347*4653Sdougm (void) printf(gettext("usage: %s\n"), 3348*4653Sdougm sa_get_usage(USAGE_START)); 3349*4653Sdougm return (SA_OK); 33503034Sdougm } 33513034Sdougm } 33523034Sdougm 33533034Sdougm if (optind == argc && !all) { 33543034Sdougm (void) printf(gettext("usage: %s\n"), 3355*4653Sdougm sa_get_usage(USAGE_START)); 3356*4653Sdougm return (SMF_EXIT_ERR_FATAL); 3357*4653Sdougm } 3358*4653Sdougm 3359*4653Sdougm if (!all) { 3360*4653Sdougm while (optind < argc) { 33613910Sdougm group = sa_get_group(handle, argv[optind]); 33623034Sdougm if (group != NULL) { 3363*4653Sdougm state = sa_get_group_attr(group, "state"); 3364*4653Sdougm if (state == NULL || 3365*4653Sdougm strcmp(state, "enabled") == 0) { 3366*4653Sdougm worklist = add_list(worklist, group, 0); 3367*4653Sdougm if (verbose) 3368*4653Sdougm (void) printf(gettext( 3369*4653Sdougm "Starting group \"%s\"\n"), 3370*4653Sdougm argv[optind]); 3371*4653Sdougm } else { 3372*4653Sdougm /* 3373*4653Sdougm * Determine if there are any 3374*4653Sdougm * protocols. if there aren't any, 3375*4653Sdougm * then there isn't anything to do in 3376*4653Sdougm * any case so no error. 3377*4653Sdougm */ 3378*4653Sdougm if (sa_get_optionset(group, 3379*4653Sdougm protocol) != NULL) { 3380*4653Sdougm ret = SMF_EXIT_OK; 3381*4653Sdougm } 33823034Sdougm } 3383*4653Sdougm if (state != NULL) 3384*4653Sdougm sa_free_attr_string(state); 33853034Sdougm } 33863034Sdougm optind++; 3387*4653Sdougm } 3388*4653Sdougm } else { 3389*4653Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 3390*4653Sdougm group = sa_get_next_group(group)) { 33913034Sdougm state = sa_get_group_attr(group, "state"); 33923034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 3393*4653Sdougm worklist = add_list(worklist, group, 0); 33943034Sdougm if (state != NULL) 3395*4653Sdougm sa_free_attr_string(state); 33963034Sdougm } 33973034Sdougm } 3398*4653Sdougm 3399*4653Sdougm (void) enable_all_groups(handle, worklist, 0, 1, NULL); 3400*4653Sdougm 34013034Sdougm if (worklist != NULL) 3402*4653Sdougm free_list(worklist); 34033034Sdougm return (ret); 34043034Sdougm } 34053034Sdougm 34063034Sdougm /* 34073034Sdougm * sa_stop_group(flags, argc, argv) 34083034Sdougm * 34093034Sdougm * Implements the stop command. 34103034Sdougm * This is similar to disable except it doesn't change the state 34113034Sdougm * of the group(s) and only disables shares if the group is already 34123034Sdougm * enabled. 34133034Sdougm */ 3414*4653Sdougm /*ARGSUSED*/ 34153034Sdougm int 34163910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 34173034Sdougm { 34183034Sdougm int verbose = 0; 34193034Sdougm int all = 0; 34203034Sdougm int c; 34213034Sdougm int ret = SMF_EXIT_OK; 34223034Sdougm char *protocol = NULL; 34233034Sdougm char *state; 34243034Sdougm struct list *worklist = NULL; 3425*4653Sdougm sa_group_t group; 34263034Sdougm 34273034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3428*4653Sdougm switch (c) { 3429*4653Sdougm case 'a': 3430*4653Sdougm all = 1; 3431*4653Sdougm break; 3432*4653Sdougm case 'P': 3433*4653Sdougm protocol = optarg; 3434*4653Sdougm if (!sa_valid_protocol(protocol)) { 3435*4653Sdougm (void) printf(gettext( 3436*4653Sdougm "Invalid protocol specified: %s\n"), 3437*4653Sdougm protocol); 3438*4653Sdougm return (SA_INVALID_PROTOCOL); 3439*4653Sdougm } 3440*4653Sdougm break; 3441*4653Sdougm case 'v': 3442*4653Sdougm verbose++; 3443*4653Sdougm break; 3444*4653Sdougm default: 3445*4653Sdougm case 'h': 3446*4653Sdougm case '?': 3447*4653Sdougm (void) printf(gettext("usage: %s\n"), 3448*4653Sdougm sa_get_usage(USAGE_STOP)); 3449*4653Sdougm return (0); 34503034Sdougm } 34513034Sdougm } 34523034Sdougm 34533034Sdougm if (optind == argc && !all) { 3454*4653Sdougm (void) printf(gettext("usage: %s\n"), 3455*4653Sdougm sa_get_usage(USAGE_STOP)); 3456*4653Sdougm return (SMF_EXIT_ERR_FATAL); 3457*4653Sdougm } else if (!all) { 3458*4653Sdougm while (optind < argc) { 34593910Sdougm group = sa_get_group(handle, argv[optind]); 34603034Sdougm if (group != NULL) { 3461*4653Sdougm state = sa_get_group_attr(group, "state"); 3462*4653Sdougm if (state == NULL || 3463*4653Sdougm strcmp(state, "enabled") == 0) { 3464*4653Sdougm worklist = add_list(worklist, group, 0); 3465*4653Sdougm if (verbose) 3466*4653Sdougm (void) printf(gettext( 3467*4653Sdougm "Stopping group \"%s\"\n"), 3468*4653Sdougm argv[optind]); 3469*4653Sdougm } else { 3470*4653Sdougm ret = SMF_EXIT_OK; 3471*4653Sdougm } 3472*4653Sdougm if (state != NULL) 3473*4653Sdougm sa_free_attr_string(state); 34743034Sdougm } 34753034Sdougm optind++; 3476*4653Sdougm } 3477*4653Sdougm } else { 3478*4653Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 3479*4653Sdougm group = sa_get_next_group(group)) { 34803034Sdougm state = sa_get_group_attr(group, "state"); 34813034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 3482*4653Sdougm worklist = add_list(worklist, group, 0); 34833034Sdougm if (state != NULL) 3484*4653Sdougm sa_free_attr_string(state); 34853034Sdougm } 34863034Sdougm } 3487*4653Sdougm 3488*4653Sdougm (void) disable_all_groups(handle, worklist, 0); 3489*4653Sdougm ret = sa_update_config(handle); 3490*4653Sdougm 34913034Sdougm if (worklist != NULL) 3492*4653Sdougm free_list(worklist); 34933034Sdougm return (ret); 34943034Sdougm } 34953034Sdougm 34963034Sdougm /* 34973034Sdougm * remove_all_options(share, proto) 34983034Sdougm * 34993034Sdougm * Removes all options on a share. 35003034Sdougm */ 35013034Sdougm 35023034Sdougm static void 35033034Sdougm remove_all_options(sa_share_t share, char *proto) 35043034Sdougm { 35053034Sdougm sa_optionset_t optionset; 35063034Sdougm sa_security_t security; 35073034Sdougm sa_security_t prevsec = NULL; 35083034Sdougm 35093034Sdougm optionset = sa_get_optionset(share, proto); 35103034Sdougm if (optionset != NULL) 3511*4653Sdougm (void) sa_destroy_optionset(optionset); 35123034Sdougm for (security = sa_get_security(share, NULL, NULL); 35133034Sdougm security != NULL; 35143034Sdougm security = sa_get_next_security(security)) { 3515*4653Sdougm char *type; 35163034Sdougm /* 3517*4653Sdougm * We walk through the list. prevsec keeps the 35183034Sdougm * previous security so we can delete it without 35193034Sdougm * destroying the list. 35203034Sdougm */ 3521*4653Sdougm if (prevsec != NULL) { 3522*4653Sdougm /* remove the previously seen security */ 3523*4653Sdougm (void) sa_destroy_security(prevsec); 3524*4653Sdougm /* set to NULL so we don't try multiple times */ 3525*4653Sdougm prevsec = NULL; 3526*4653Sdougm } 3527*4653Sdougm type = sa_get_security_attr(security, "type"); 3528*4653Sdougm if (type != NULL) { 3529*4653Sdougm /* 3530*4653Sdougm * if the security matches the specified protocol, we 3531*4653Sdougm * want to remove it. prevsec holds it until either 3532*4653Sdougm * the next pass or we fall out of the loop. 3533*4653Sdougm */ 3534*4653Sdougm if (strcmp(type, proto) == 0) 3535*4653Sdougm prevsec = security; 3536*4653Sdougm sa_free_attr_string(type); 3537*4653Sdougm } 35383034Sdougm } 35393034Sdougm /* in case there is one left */ 35403034Sdougm if (prevsec != NULL) 3541*4653Sdougm (void) sa_destroy_security(prevsec); 35423034Sdougm } 35433034Sdougm 35443034Sdougm 35453034Sdougm /* 35463034Sdougm * for legacy support, we need to handle the old syntax. This is what 35473034Sdougm * we get if sharemgr is called with the name "share" rather than 35483034Sdougm * sharemgr. 35493034Sdougm */ 35503034Sdougm 35513034Sdougm static int 35523034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 35533034Sdougm { 35543034Sdougm int err; 35553034Sdougm 35563034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 35573034Sdougm if (err > buffsize) 3558*4653Sdougm return (-1); 35593034Sdougm return (0); 35603034Sdougm } 35613034Sdougm 35623034Sdougm 35633034Sdougm /* 35643034Sdougm * check_legacy_cmd(proto, cmd) 35653034Sdougm * 35663034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 35673034Sdougm * executable. 35683034Sdougm */ 35693034Sdougm 35703034Sdougm static int 35713034Sdougm check_legacy_cmd(char *path) 35723034Sdougm { 35733034Sdougm struct stat st; 35743034Sdougm int ret = 0; 35753034Sdougm 35763034Sdougm if (stat(path, &st) == 0) { 3577*4653Sdougm if (S_ISREG(st.st_mode) && 3578*4653Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 3579*4653Sdougm ret = 1; 35803034Sdougm } 35813034Sdougm return (ret); 35823034Sdougm } 35833034Sdougm 35843034Sdougm /* 35853034Sdougm * run_legacy_command(proto, cmd, argv) 35863034Sdougm * 3587*4653Sdougm * We know the command exists, so attempt to execute it with all the 35883034Sdougm * arguments. This implements full legacy share support for those 35893034Sdougm * protocols that don't have plugin providers. 35903034Sdougm */ 35913034Sdougm 35923034Sdougm static int 35933034Sdougm run_legacy_command(char *path, char *argv[]) 35943034Sdougm { 35953034Sdougm int ret; 35963034Sdougm 35973034Sdougm ret = execv(path, argv); 35983034Sdougm if (ret < 0) { 3599*4653Sdougm switch (errno) { 3600*4653Sdougm case EACCES: 3601*4653Sdougm ret = SA_NO_PERMISSION; 3602*4653Sdougm break; 3603*4653Sdougm default: 3604*4653Sdougm ret = SA_SYSTEM_ERR; 3605*4653Sdougm break; 3606*4653Sdougm } 36073034Sdougm } 36083034Sdougm return (ret); 36093034Sdougm } 36103034Sdougm 36113034Sdougm /* 36123348Sdougm * out_share(out, group, proto) 36133034Sdougm * 36143034Sdougm * Display the share information in the format that the "share" 36153034Sdougm * command has traditionally used. 36163034Sdougm */ 36173034Sdougm 36183034Sdougm static void 36193348Sdougm out_share(FILE *out, sa_group_t group, char *proto) 36203034Sdougm { 36213034Sdougm sa_share_t share; 36223034Sdougm char resfmt[128]; 36233034Sdougm 3624*4653Sdougm for (share = sa_get_share(group, NULL); 3625*4653Sdougm share != NULL; 3626*4653Sdougm share = sa_get_next_share(share)) { 3627*4653Sdougm char *path; 3628*4653Sdougm char *type; 3629*4653Sdougm char *resource; 3630*4653Sdougm char *description; 3631*4653Sdougm char *groupname; 3632*4653Sdougm char *sharedstate; 3633*4653Sdougm int shared = 1; 3634*4653Sdougm char *soptions; 3635*4653Sdougm 3636*4653Sdougm sharedstate = sa_get_share_attr(share, "shared"); 3637*4653Sdougm path = sa_get_share_attr(share, "path"); 3638*4653Sdougm type = sa_get_share_attr(share, "type"); 3639*4653Sdougm resource = sa_get_share_attr(share, "resource"); 3640*4653Sdougm groupname = sa_get_group_attr(group, "name"); 3641*4653Sdougm 3642*4653Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 3643*4653Sdougm sa_free_attr_string(groupname); 3644*4653Sdougm groupname = NULL; 3645*4653Sdougm } 3646*4653Sdougm description = sa_get_share_description(share); 3647*4653Sdougm 3648*4653Sdougm /* Want the sharetab version if it exists */ 3649*4653Sdougm soptions = sa_get_share_attr(share, "shareopts"); 3650*4653Sdougm 3651*4653Sdougm if (sharedstate == NULL) 3652*4653Sdougm shared = 0; 3653*4653Sdougm 3654*4653Sdougm if (soptions == NULL) 3655*4653Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 3656*4653Sdougm 3657*4653Sdougm if (shared) { 3658*4653Sdougm /* only active shares go here */ 3659*4653Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 3660*4653Sdougm resource != NULL ? resource : "-", 3661*4653Sdougm groupname != NULL ? "@" : "", 3662*4653Sdougm groupname != NULL ? groupname : ""); 3663*4653Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 3664*4653Sdougm resfmt, path, 3665*4653Sdougm (soptions != NULL && strlen(soptions) > 0) ? 3666*4653Sdougm soptions : "rw", 3667*4653Sdougm (description != NULL) ? description : ""); 3668*4653Sdougm } 3669*4653Sdougm 3670*4653Sdougm if (path != NULL) 3671*4653Sdougm sa_free_attr_string(path); 3672*4653Sdougm if (type != NULL) 3673*4653Sdougm sa_free_attr_string(type); 3674*4653Sdougm if (resource != NULL) 3675*4653Sdougm sa_free_attr_string(resource); 3676*4653Sdougm if (groupname != NULL) 3677*4653Sdougm sa_free_attr_string(groupname); 3678*4653Sdougm if (description != NULL) 3679*4653Sdougm sa_free_share_description(description); 3680*4653Sdougm if (sharedstate != NULL) 3681*4653Sdougm sa_free_attr_string(sharedstate); 3682*4653Sdougm if (soptions != NULL) 3683*4653Sdougm sa_format_free(soptions); 36843034Sdougm } 36853034Sdougm } 36863034Sdougm 36873034Sdougm /* 36883034Sdougm * output_legacy_file(out, proto) 36893034Sdougm * 36903034Sdougm * Walk all of the groups for the specified protocol and call 36913034Sdougm * out_share() to format and write in the format displayed by the 36923034Sdougm * "share" command with no arguments. 36933034Sdougm */ 36943034Sdougm 36953034Sdougm static void 36963910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 36973034Sdougm { 36983034Sdougm sa_group_t group; 36993034Sdougm 37003910Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 3701*4653Sdougm group = sa_get_next_group(group)) { 3702*4653Sdougm char *options; 3703*4653Sdougm char *zfs; 37043034Sdougm 37053034Sdougm /* 3706*4653Sdougm * Get default options preformated, being careful to 37073034Sdougm * handle legacy shares differently from new style 37083034Sdougm * shares. Legacy share have options on the share. 37093034Sdougm */ 37103034Sdougm 3711*4653Sdougm zfs = sa_get_group_attr(group, "zfs"); 3712*4653Sdougm if (zfs != NULL) { 3713*4653Sdougm sa_group_t zgroup; 3714*4653Sdougm sa_free_attr_string(zfs); 3715*4653Sdougm options = sa_proto_legacy_format(proto, group, 1); 3716*4653Sdougm for (zgroup = sa_get_sub_group(group); 3717*4653Sdougm zgroup != NULL; 3718*4653Sdougm zgroup = sa_get_next_group(zgroup)) { 3719*4653Sdougm 3720*4653Sdougm /* got a group, so display it */ 3721*4653Sdougm out_share(out, zgroup, proto); 3722*4653Sdougm } 3723*4653Sdougm } else { 3724*4653Sdougm options = sa_proto_legacy_format(proto, group, 1); 3725*4653Sdougm out_share(out, group, proto); 37263034Sdougm } 3727*4653Sdougm if (options != NULL) 3728*4653Sdougm free(options); 37293034Sdougm } 37303034Sdougm } 37313034Sdougm 3732*4653Sdougm /*ARGSUSED*/ 37333034Sdougm int 37343910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 37353034Sdougm { 37363034Sdougm char *protocol = "nfs"; 37373034Sdougm char *options = NULL; 37383034Sdougm char *description = NULL; 37393034Sdougm char *groupname = NULL; 37403034Sdougm char *sharepath = NULL; 37413034Sdougm char *resource = NULL; 37423034Sdougm char *groupstatus = NULL; 37433034Sdougm int persist = SA_SHARE_TRANSIENT; 37443034Sdougm int argsused = 0; 37453034Sdougm int c; 37463034Sdougm int ret = SA_OK; 37473034Sdougm int zfs = 0; 37483034Sdougm int true_legacy = 0; 37493034Sdougm int curtype = SA_SHARE_TRANSIENT; 37503034Sdougm char cmd[MAXPATHLEN]; 3751*4653Sdougm sa_group_t group = NULL; 3752*4653Sdougm sa_share_t share; 3753*4653Sdougm char dir[MAXPATHLEN]; 37543034Sdougm 37553034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 3756*4653Sdougm switch (c) { 3757*4653Sdougm case 'd': 3758*4653Sdougm description = optarg; 3759*4653Sdougm argsused++; 3760*4653Sdougm break; 3761*4653Sdougm case 'F': 3762*4653Sdougm protocol = optarg; 3763*4653Sdougm if (!sa_valid_protocol(protocol)) { 3764*4653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 3765*4653Sdougm protocol, "share") == 0 && 3766*4653Sdougm check_legacy_cmd(cmd)) { 3767*4653Sdougm true_legacy++; 3768*4653Sdougm } else { 3769*4653Sdougm (void) fprintf(stderr, gettext( 3770*4653Sdougm "Invalid protocol specified: " 3771*4653Sdougm "%s\n"), protocol); 3772*4653Sdougm return (SA_INVALID_PROTOCOL); 3773*4653Sdougm } 3774*4653Sdougm } 3775*4653Sdougm break; 3776*4653Sdougm case 'o': 3777*4653Sdougm options = optarg; 3778*4653Sdougm argsused++; 3779*4653Sdougm break; 3780*4653Sdougm case 'p': 3781*4653Sdougm persist = SA_SHARE_PERMANENT; 3782*4653Sdougm argsused++; 3783*4653Sdougm break; 3784*4653Sdougm case 'h': 3785*4653Sdougm case '?': 3786*4653Sdougm default: 3787*4653Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 3788*4653Sdougm sa_get_usage(USAGE_SHARE)); 3789*4653Sdougm return (SA_OK); 37903034Sdougm } 3791*4653Sdougm } 3792*4653Sdougm 3793*4653Sdougm /* Have the info so construct what is needed */ 3794*4653Sdougm if (!argsused && optind == argc) { 3795*4653Sdougm /* display current info in share format */ 3796*4653Sdougm (void) output_legacy_file(stdout, "nfs", handle); 3797*4653Sdougm return (ret); 37983034Sdougm } 37993034Sdougm 3800*4653Sdougm /* We are modifying the configuration */ 3801*4653Sdougm if (optind == argc) { 38023034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 3803*4653Sdougm sa_get_usage(USAGE_SHARE)); 38043034Sdougm return (SA_LEGACY_ERR); 3805*4653Sdougm } 3806*4653Sdougm if (true_legacy) { 3807*4653Sdougm /* If still using legacy share/unshare, exec it */ 38083034Sdougm ret = run_legacy_command(cmd, argv); 38093034Sdougm return (ret); 3810*4653Sdougm } 3811*4653Sdougm 3812*4653Sdougm sharepath = argv[optind++]; 3813*4653Sdougm if (optind < argc) { 38143034Sdougm resource = argv[optind]; 38153034Sdougm groupname = strchr(resource, '@'); 38163034Sdougm if (groupname != NULL) 3817*4653Sdougm *groupname++ = '\0'; 3818*4653Sdougm } 3819*4653Sdougm if (realpath(sharepath, dir) == NULL) 38203034Sdougm ret = SA_BAD_PATH; 3821*4653Sdougm else 38223034Sdougm sharepath = dir; 3823*4653Sdougm if (ret == SA_OK) 38243910Sdougm share = sa_find_share(handle, sharepath); 3825*4653Sdougm else 38263034Sdougm share = NULL; 3827*4653Sdougm 3828*4653Sdougm if (groupname != NULL) { 3829*4653Sdougm ret = SA_NOT_ALLOWED; 3830*4653Sdougm } else if (ret == SA_OK) { 38313034Sdougm char *legacygroup = "default"; 38323034Sdougm /* 3833*4653Sdougm * The legacy group is always present and zfs groups 38343034Sdougm * come and go. zfs shares may be in sub-groups and 38353034Sdougm * the zfs share will already be in that group so it 38363034Sdougm * isn't an error. 38373034Sdougm */ 38383034Sdougm /* 3839*4653Sdougm * If the share exists (not NULL), then make sure it 3840*4653Sdougm * is one we want to handle by getting the parent 3841*4653Sdougm * group. 38423034Sdougm */ 3843*4653Sdougm if (share != NULL) 3844*4653Sdougm group = sa_get_parent_group(share); 3845*4653Sdougm else 3846*4653Sdougm group = sa_get_group(handle, legacygroup); 3847*4653Sdougm 38483034Sdougm if (group != NULL) { 3849*4653Sdougm groupstatus = group_status(group); 3850*4653Sdougm if (share == NULL) { 3851*4653Sdougm share = sa_add_share(group, sharepath, 3852*4653Sdougm persist, &ret); 3853*4653Sdougm if (share == NULL && 3854*4653Sdougm ret == SA_DUPLICATE_NAME) { 3855*4653Sdougm /* 3856*4653Sdougm * Could be a ZFS path being started 3857*4653Sdougm */ 3858*4653Sdougm if (sa_zfs_is_shared(handle, 3859*4653Sdougm sharepath)) { 3860*4653Sdougm ret = SA_OK; 3861*4653Sdougm group = sa_get_group(handle, 3862*4653Sdougm "zfs"); 3863*4653Sdougm if (group == NULL) { 3864*4653Sdougm /* 3865*4653Sdougm * This shouldn't 3866*4653Sdougm * happen. 3867*4653Sdougm */ 3868*4653Sdougm ret = SA_CONFIG_ERR; 3869*4653Sdougm } else { 3870*4653Sdougm share = sa_add_share( 3871*4653Sdougm group, sharepath, 3872*4653Sdougm persist, &ret); 3873*4653Sdougm } 3874*4653Sdougm } 38753034Sdougm } 3876*4653Sdougm } else { 3877*4653Sdougm char *type; 3878*4653Sdougm /* 3879*4653Sdougm * May want to change persist state, but the 3880*4653Sdougm * important thing is to change options. We 3881*4653Sdougm * need to change them regardless of the 3882*4653Sdougm * source. 3883*4653Sdougm */ 3884*4653Sdougm if (sa_zfs_is_shared(handle, sharepath)) { 3885*4653Sdougm zfs = 1; 38863034Sdougm } 3887*4653Sdougm remove_all_options(share, protocol); 3888*4653Sdougm type = sa_get_share_attr(share, "type"); 3889*4653Sdougm if (type != NULL && 3890*4653Sdougm strcmp(type, "transient") != 0) { 3891*4653Sdougm curtype = SA_SHARE_PERMANENT; 3892*4653Sdougm } 3893*4653Sdougm if (type != NULL) 3894*4653Sdougm sa_free_attr_string(type); 3895*4653Sdougm if (curtype != persist) { 3896*4653Sdougm (void) sa_set_share_attr(share, "type", 3897*4653Sdougm persist == SA_SHARE_PERMANENT ? 3898*4653Sdougm "persist" : "transient"); 3899*4653Sdougm } 39003108Sdougm } 3901*4653Sdougm /* Have a group to hold this share path */ 3902*4653Sdougm if (ret == SA_OK && options != NULL && 3903*4653Sdougm strlen(options) > 0) { 3904*4653Sdougm ret = sa_parse_legacy_options(share, 3905*4653Sdougm options, 3906*4653Sdougm protocol); 39073034Sdougm } 3908*4653Sdougm if (!zfs) { 3909*4653Sdougm /* 3910*4653Sdougm * ZFS shares never have resource or 3911*4653Sdougm * description and we can't store the values 3912*4653Sdougm * so don't try. 3913*4653Sdougm */ 3914*4653Sdougm if (ret == SA_OK && description != NULL) 3915*4653Sdougm ret = sa_set_share_description(share, 3916*4653Sdougm description); 3917*4653Sdougm if (ret == SA_OK && resource != NULL) 3918*4653Sdougm ret = sa_set_share_attr(share, 3919*4653Sdougm "resource", resource); 39203034Sdougm } 3921*4653Sdougm if (ret == SA_OK) { 3922*4653Sdougm if (strcmp(groupstatus, "enabled") == 0) 3923*4653Sdougm ret = sa_enable_share(share, protocol); 3924*4653Sdougm if (ret == SA_OK && 3925*4653Sdougm persist == SA_SHARE_PERMANENT) { 3926*4653Sdougm (void) sa_update_legacy(share, 3927*4653Sdougm protocol); 3928*4653Sdougm } 3929*4653Sdougm if (ret == SA_OK) 3930*4653Sdougm ret = sa_update_config(handle); 3931*4653Sdougm } 39323034Sdougm } else { 3933*4653Sdougm ret = SA_SYSTEM_ERR; 39343034Sdougm } 39353034Sdougm } 39363034Sdougm if (ret != SA_OK) { 3937*4653Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 3938*4653Sdougm sharepath, sa_errorstr(ret)); 3939*4653Sdougm ret = SA_LEGACY_ERR; 39403034Sdougm 39413034Sdougm } 39423034Sdougm return (ret); 39433034Sdougm } 39443034Sdougm 39453034Sdougm /* 39463034Sdougm * sa_legacy_unshare(flags, argc, argv) 39473034Sdougm * 39483034Sdougm * Implements the original unshare command. 39493034Sdougm */ 3950*4653Sdougm /*ARGSUSED*/ 39513034Sdougm int 39523910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 39533034Sdougm { 39543034Sdougm char *protocol = "nfs"; /* for now */ 39553034Sdougm char *options = NULL; 39563034Sdougm char *sharepath = NULL; 39573034Sdougm int persist = SA_SHARE_TRANSIENT; 39583034Sdougm int argsused = 0; 39593034Sdougm int c; 39603034Sdougm int ret = SA_OK; 39613034Sdougm int true_legacy = 0; 39623034Sdougm char cmd[MAXPATHLEN]; 39633034Sdougm 39643034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 3965*4653Sdougm switch (c) { 3966*4653Sdougm case 'h': 3967*4653Sdougm case '?': 3968*4653Sdougm break; 3969*4653Sdougm case 'F': 3970*4653Sdougm protocol = optarg; 3971*4653Sdougm if (!sa_valid_protocol(protocol)) { 3972*4653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 3973*4653Sdougm protocol, "unshare") == 0 && 3974*4653Sdougm check_legacy_cmd(cmd)) { 3975*4653Sdougm true_legacy++; 3976*4653Sdougm } else { 3977*4653Sdougm (void) printf(gettext( 3978*4653Sdougm "Invalid file system name\n")); 3979*4653Sdougm return (SA_INVALID_PROTOCOL); 3980*4653Sdougm } 3981*4653Sdougm } 3982*4653Sdougm break; 3983*4653Sdougm case 'o': 3984*4653Sdougm options = optarg; 3985*4653Sdougm argsused++; 3986*4653Sdougm break; 3987*4653Sdougm case 'p': 3988*4653Sdougm persist = SA_SHARE_PERMANENT; 3989*4653Sdougm argsused++; 3990*4653Sdougm break; 3991*4653Sdougm default: 3992*4653Sdougm (void) printf(gettext("usage: %s\n"), 3993*4653Sdougm sa_get_usage(USAGE_UNSHARE)); 3994*4653Sdougm return (SA_OK); 39953034Sdougm } 39963034Sdougm } 39973034Sdougm 3998*4653Sdougm /* Have the info so construct what is needed */ 3999*4653Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 4000*4653Sdougm ret = SA_SYNTAX_ERR; 40013034Sdougm } else { 4002*4653Sdougm sa_share_t share; 4003*4653Sdougm char dir[MAXPATHLEN]; 4004*4653Sdougm if (true_legacy) { 4005*4653Sdougm /* if still using legacy share/unshare, exec it */ 4006*4653Sdougm ret = run_legacy_command(cmd, argv); 4007*4653Sdougm return (ret); 4008*4653Sdougm } 40093663Sdougm /* 40103663Sdougm * Find the path in the internal configuration. If it 40113663Sdougm * isn't found, attempt to resolve the path via 40123663Sdougm * realpath() and try again. 40133663Sdougm */ 4014*4653Sdougm sharepath = argv[optind++]; 4015*4653Sdougm share = sa_find_share(handle, sharepath); 4016*4653Sdougm if (share == NULL) { 4017*4653Sdougm if (realpath(sharepath, dir) == NULL) { 4018*4653Sdougm ret = SA_NO_SUCH_PATH; 4019*4653Sdougm } else { 4020*4653Sdougm share = sa_find_share(handle, dir); 4021*4653Sdougm } 40223663Sdougm } 4023*4653Sdougm if (share != NULL) { 4024*4653Sdougm ret = sa_disable_share(share, protocol); 4025*4653Sdougm /* 4026*4653Sdougm * Errors are ok and removal should still occur. The 4027*4653Sdougm * legacy unshare is more forgiving of errors than the 4028*4653Sdougm * remove-share subcommand which may need the force 4029*4653Sdougm * flag set for some error conditions. That is, the 4030*4653Sdougm * "unshare" command will always unshare if it can 4031*4653Sdougm * while "remove-share" might require the force option. 4032*4653Sdougm */ 4033*4653Sdougm if (persist == SA_SHARE_PERMANENT) { 4034*4653Sdougm ret = sa_remove_share(share); 4035*4653Sdougm if (ret == SA_OK) 4036*4653Sdougm ret = sa_update_config(handle); 4037*4653Sdougm } 4038*4653Sdougm } else { 4039*4653Sdougm ret = SA_NOT_SHARED; 40403663Sdougm } 40413034Sdougm } 40423034Sdougm switch (ret) { 40433034Sdougm default: 4044*4653Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 4045*4653Sdougm ret = SA_LEGACY_ERR; 4046*4653Sdougm break; 40473034Sdougm case SA_SYNTAX_ERR: 4048*4653Sdougm (void) printf(gettext("usage: %s\n"), 4049*4653Sdougm sa_get_usage(USAGE_UNSHARE)); 4050*4653Sdougm break; 40513034Sdougm case SA_OK: 4052*4653Sdougm break; 40533034Sdougm } 40543034Sdougm return (ret); 40553034Sdougm } 40563034Sdougm 40573034Sdougm /* 4058*4653Sdougm * Common commands that implement the sub-commands used by all 40593034Sdougm * protcols. The entries are found via the lookup command 40603034Sdougm */ 40613034Sdougm 40623034Sdougm static sa_command_t commands[] = { 40633034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 40643034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 40653034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 40663034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 40673034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 40683034Sdougm {"list", 0, sa_list, USAGE_LIST}, 40693034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 40703034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 40713034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 40723034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 40733034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 40743034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 40753034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 40763034Sdougm SVC_SET|SVC_ACTION}, 40773034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 40783034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 40793034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 40803034Sdougm {NULL, 0, NULL, NULL} 40813034Sdougm }; 40823034Sdougm 40833034Sdougm static char * 40843034Sdougm sa_get_usage(sa_usage_t index) 40853034Sdougm { 40863034Sdougm char *ret = NULL; 40873034Sdougm switch (index) { 40883034Sdougm case USAGE_ADD_SHARE: 4089*4653Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 4090*4653Sdougm "[-d \"description text\"] -s sharepath group"); 4091*4653Sdougm break; 40923034Sdougm case USAGE_CREATE: 4093*4653Sdougm ret = gettext( 4094*4653Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 4095*4653Sdougm break; 40963034Sdougm case USAGE_DELETE: 4097*4653Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 4098*4653Sdougm break; 40993034Sdougm case USAGE_DISABLE: 4100*4653Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 4101*4653Sdougm break; 41023034Sdougm case USAGE_ENABLE: 4103*4653Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 4104*4653Sdougm break; 41053034Sdougm case USAGE_LIST: 4106*4653Sdougm ret = gettext("list [-vh] [-P proto]"); 4107*4653Sdougm break; 41083034Sdougm case USAGE_MOVE_SHARE: 4109*4653Sdougm ret = gettext( 4110*4653Sdougm "move-share [-nvh] -s sharepath destination-group"); 4111*4653Sdougm break; 41123034Sdougm case USAGE_REMOVE_SHARE: 4113*4653Sdougm ret = gettext("remove-share [-fnvh] -s sharepath group"); 4114*4653Sdougm break; 41153034Sdougm case USAGE_SET: 4116*4653Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 4117*4653Sdougm "[-p property=value]* [-s sharepath] group"); 4118*4653Sdougm break; 41193034Sdougm case USAGE_SET_SECURITY: 4120*4653Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 4121*4653Sdougm "[-p property=value]* group"); 4122*4653Sdougm break; 41233034Sdougm case USAGE_SET_SHARE: 4124*4653Sdougm ret = gettext("set-share [-nh] [-r resource] " 4125*4653Sdougm "[-d \"description text\"] -s sharepath group"); 4126*4653Sdougm break; 41273034Sdougm case USAGE_SHOW: 4128*4653Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 4129*4653Sdougm break; 41303034Sdougm case USAGE_SHARE: 4131*4653Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 4132*4653Sdougm "[-d description] [pathname [resourcename]]"); 4133*4653Sdougm break; 41343034Sdougm case USAGE_START: 4135*4653Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 4136*4653Sdougm break; 41373034Sdougm case USAGE_STOP: 4138*4653Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 4139*4653Sdougm break; 41403034Sdougm case USAGE_UNSET: 4141*4653Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 4142*4653Sdougm "[-p property]* group"); 4143*4653Sdougm break; 41443034Sdougm case USAGE_UNSET_SECURITY: 4145*4653Sdougm ret = gettext("unset-security [-nvh] -P proto -S security-type" 4146*4653Sdougm " [-p property]* group"); 4147*4653Sdougm break; 41483034Sdougm case USAGE_UNSHARE: 4149*4653Sdougm ret = gettext( 4150*4653Sdougm "unshare [-F fstype] [-p] sharepath"); 4151*4653Sdougm break; 41523034Sdougm } 41533034Sdougm return (ret); 41543034Sdougm } 41553034Sdougm 41563034Sdougm /* 41573034Sdougm * sa_lookup(cmd, proto) 41583034Sdougm * 41593034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 41603034Sdougm * eventually provide a way to provide protocol specific sub-commands. 41613034Sdougm */ 4162*4653Sdougm /*ARGSUSED*/ 41633034Sdougm sa_command_t * 41643034Sdougm sa_lookup(char *cmd, char *proto) 41653034Sdougm { 41663034Sdougm int i; 41673034Sdougm size_t len; 41683034Sdougm 41693034Sdougm len = strlen(cmd); 41703034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 4171*4653Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 4172*4653Sdougm return (&commands[i]); 41733034Sdougm } 41743034Sdougm return (NULL); 41753034Sdougm } 41763034Sdougm 4177*4653Sdougm /*ARGSUSED*/ 41783034Sdougm void 41793034Sdougm sub_command_help(char *proto) 41803034Sdougm { 41813034Sdougm int i; 41823034Sdougm 41833034Sdougm (void) printf(gettext("\tsub-commands:\n")); 41843034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 4185*4653Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 4186*4653Sdougm (void) printf("\t%s\n", 4187*4653Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 41883034Sdougm } 41893034Sdougm } 4190