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) { 724653Sdougm 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) { 904653Sdougm new->next = NULL; 914653Sdougm new->item = item; 924653Sdougm new->itemdata = data; 933034Sdougm } else { 944653Sdougm return (listp); 953034Sdougm } 963034Sdougm 973034Sdougm if (listp == NULL) 984653Sdougm 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) { 1164653Sdougm tmp = listp; 1174653Sdougm listp = listp->next; 1184653Sdougm 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; 1374653Sdougm int ret = B_TRUE; 1383034Sdougm uid_t uid; 1393034Sdougm struct passwd *pw = NULL; 1403034Sdougm 1413034Sdougm uid = getuid(); 1423034Sdougm pw = getpwuid(uid); 1434653Sdougm if (pw == NULL) { 1444653Sdougm ret = B_FALSE; 1454653Sdougm } else { 1464653Sdougm /* 1474653Sdougm * Since names are restricted to SA_MAX_NAME_LEN won't 1484653Sdougm * overflow. 1494653Sdougm */ 1504653Sdougm (void) snprintf(svcstring, sizeof (svcstring), "%s:%s", 1514653Sdougm SA_SVC_FMRI_BASE, instname); 1524653Sdougm handle = scf_handle_create(SCF_VERSION); 1534653Sdougm if (handle != NULL) { 1544653Sdougm if (scf_handle_bind(handle) == 0) { 1554653Sdougm switch (which) { 1564653Sdougm case SVC_SET: 1574653Sdougm prop = scf_simple_prop_get(handle, 1584653Sdougm svcstring, "general", 1594653Sdougm SVC_AUTH_VALUE); 1604653Sdougm break; 1614653Sdougm case SVC_ACTION: 1624653Sdougm prop = scf_simple_prop_get(handle, 1634653Sdougm svcstring, "general", 1644653Sdougm SVC_AUTH_ACTION); 1654653Sdougm break; 1664653Sdougm } 1674653Sdougm } 1683034Sdougm } 1693034Sdougm } 1703034Sdougm /* make sure we have an authorization string property */ 1713034Sdougm if (prop != NULL) { 1724653Sdougm int i; 1734653Sdougm numauths = scf_simple_prop_numvalues(prop); 1744653Sdougm for (ret = 0, i = 0; i < numauths; i++) { 1754653Sdougm authstr = scf_simple_prop_next_astring(prop); 1764653Sdougm if (authstr != NULL) { 1774653Sdougm /* check if this user has one of the strings */ 1784653Sdougm if (chkauthattr(authstr, pw->pw_name)) { 1794653Sdougm ret = 1; 1804653Sdougm break; 1814653Sdougm } 1824653Sdougm } 1833034Sdougm } 1844653Sdougm endauthattr(); 1854653Sdougm scf_simple_prop_free(prop); 1863034Sdougm } else { 1874653Sdougm /* no authorization string defined */ 1884653Sdougm ret = 0; 1893034Sdougm } 1903034Sdougm if (handle != NULL) 1914653Sdougm 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) 2114653Sdougm ret1 = check_authorization(instname, SVC_SET); 2123034Sdougm if (flags & SVC_ACTION) 2134653Sdougm ret2 = check_authorization(instname, SVC_ACTION); 2143034Sdougm switch (flags) { 2153034Sdougm case SVC_ACTION: 2164653Sdougm ret = ret2; 2174653Sdougm break; 2183034Sdougm case SVC_SET: 2194653Sdougm ret = ret1; 2204653Sdougm break; 2213034Sdougm case SVC_ACTION|SVC_SET: 2224653Sdougm ret = ret1 & ret2; 2234653Sdougm break; 2243034Sdougm default: 2254653Sdougm /* if not flags set, we assume we don't need authorizations */ 2264653Sdougm 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)) { 2474653Sdougm if (updateproto != NULL) 2484653Sdougm (void) sa_update_legacy(share, updateproto); 2494653Sdougm (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) { 2674653Sdougm state = sa_get_group_attr(group, "state"); 2684653Sdougm if (state != NULL) { 2694653Sdougm if (strcmp(state, "enabled") == 0) 2704653Sdougm ret = B_TRUE; 2714653Sdougm sa_free_attr_string(state); 2724653Sdougm } 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) { 2964653Sdougm 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 */ 3044653Sdougm if (setstate == B_TRUE) { 3054653Sdougm ret = sa_set_group_attr(group, "state", "enabled"); 3064653Sdougm if (ret != SA_OK) 3074653Sdougm break; 3084653Sdougm } 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 */ 3174653Sdougm if (!isenabled(group)) 3184653Sdougm continue; 3194653Sdougm 3204653Sdougm /* if itemdata != NULL then a single share */ 3214653Sdougm if (work->itemdata != NULL) { 3224653Sdougm ret = sa_enable_share((sa_share_t)work->itemdata, NULL); 3233034Sdougm } 3244653Sdougm if (ret != SA_OK) 3254653Sdougm break; 3264653Sdougm 3274653Sdougm /* if itemdata == NULL then the whole group */ 3284653Sdougm if (work->itemdata == NULL) { 3294653Sdougm zfs = sa_get_group_attr(group, "zfs"); 3304653Sdougm /* 3314653Sdougm * if the share is managed by ZFS, don't 3324653Sdougm * update any of the protocols since ZFS is 3334653Sdougm * handling this. updateproto will contain 3344653Sdougm * the name of the protocol that we want to 3354653Sdougm * update legacy files for. 3364653Sdougm */ 3374653Sdougm enable_group(group, zfs == NULL ? updateproto : NULL); 3384653Sdougm for (subgroup = sa_get_sub_group(group); 3394653Sdougm subgroup != NULL; 3404653Sdougm subgroup = sa_get_next_group(subgroup)) { 3414653Sdougm /* never update legacy for ZFS subgroups */ 3424653Sdougm enable_group(subgroup, NULL); 3433034Sdougm } 3443034Sdougm } 3454653Sdougm if (online) { 3464653Sdougm zfs = sa_get_group_attr(group, "zfs"); 3474653Sdougm name = sa_get_group_attr(group, "name"); 3484653Sdougm if (name != NULL) { 3494653Sdougm if (zfs == NULL) { 3504653Sdougm (void) snprintf(instance, 3514653Sdougm sizeof (instance), "%s:%s", 3524653Sdougm SA_SVC_FMRI_BASE, name); 3534653Sdougm state = smf_get_state(instance); 3544653Sdougm if (state == NULL || 3554653Sdougm strcmp(state, "online") != 0) { 3564653Sdougm (void) smf_enable_instance( 3574653Sdougm instance, 0); 3584653Sdougm free(state); 3594653Sdougm } 3604653Sdougm } else { 3614653Sdougm sa_free_attr_string(zfs); 3624653Sdougm zfs = NULL; 3634653Sdougm } 3644653Sdougm if (name != NULL) 3654653Sdougm sa_free_attr_string(name); 3664653Sdougm } 3674653Sdougm } 3683034Sdougm } 3693034Sdougm if (ret == SA_OK) { 3704653Sdougm 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) { 3924653Sdougm char *optname; 3934653Sdougm 3944653Sdougm optname = optlist->optname; 3954653Sdougm ret = OPT_ADD_OK; 3964653Sdougm /* extract property/value pair */ 3974653Sdougm if (sa_is_security(optname, proto)) { 3984653Sdougm if (!security) 3994653Sdougm ret = OPT_ADD_SECURITY; 4004653Sdougm } else { 4014653Sdougm if (security) 4024653Sdougm ret = OPT_ADD_PROPERTY; 4034653Sdougm } 4044653Sdougm if (ret != OPT_ADD_OK) { 4054653Sdougm if (notfirst == 0) 4064653Sdougm (void) printf( 4074653Sdougm gettext("Property syntax error: ")); 4084653Sdougm switch (ret) { 4094653Sdougm case OPT_ADD_SYNTAX: 4104653Sdougm (void) printf(gettext("%ssyntax error: %s"), 4113034Sdougm sep, optname); 4124653Sdougm sep = ", "; 4134653Sdougm break; 4144653Sdougm case OPT_ADD_SECURITY: 4154653Sdougm (void) printf(gettext("%s%s requires -S"), 4163034Sdougm optname, sep); 4174653Sdougm sep = ", "; 4184653Sdougm break; 4194653Sdougm case OPT_ADD_PROPERTY: 4204653Sdougm (void) printf( 4214653Sdougm gettext("%s%s not supported with -S"), 4223034Sdougm optname, sep); 4234653Sdougm sep = ", "; 4244653Sdougm break; 4254653Sdougm } 4264653Sdougm notfirst++; 4273034Sdougm } 4283034Sdougm } 4293034Sdougm if (notfirst) { 4304653Sdougm (void) printf("\n"); 4314653Sdougm 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) { 4644653Sdougm if (sec == NULL) 4654653Sdougm parent = sa_get_optionset(object, proto); 4664653Sdougm else 4674653Sdougm parent = sa_get_security(object, sec, proto); 4683034Sdougm } 4693034Sdougm 4703034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 4714653Sdougm if (cur->optvalue == NULL) 4724653Sdougm continue; 4733034Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 4743034Sdougm if (prop == NULL) 4754653Sdougm ret = SA_NO_MEMORY; 4763034Sdougm if (ret != SA_OK || 4773034Sdougm (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 4784653Sdougm (void) printf( 4794653Sdougm gettext("Could not add property %s: %s\n"), 4804653Sdougm 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) { 5044653Sdougm optionset = sa_create_optionset(group, proto); 5054653Sdougm result = 1; /* adding a protocol is a change */ 5063034Sdougm } 5074653Sdougm if (optionset == NULL) { 5084653Sdougm ret = SA_NO_MEMORY; 5094653Sdougm goto out; 5104653Sdougm } 5114653Sdougm 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 */ 5194653Sdougm if (optlist->optvalue != NULL) { 5204653Sdougm prop = sa_create_property(optlist->optname, 5214653Sdougm optlist->optvalue); 5224653Sdougm if (prop != NULL) { 5234653Sdougm ret = sa_valid_property(optionset, 5244653Sdougm proto, prop); 5254653Sdougm if (ret != SA_OK) { 5264653Sdougm (void) sa_remove_property(prop); 5274653Sdougm (void) printf(gettext("Could " 5284653Sdougm "not add property " 5294653Sdougm "%s: %s\n"), 5304653Sdougm optlist->optname, 5314653Sdougm sa_errorstr(ret)); 5324653Sdougm } 5334653Sdougm } 5344653Sdougm if (ret == SA_OK) { 5354653Sdougm ret = sa_add_property(optionset, prop); 5364653Sdougm if (ret != SA_OK) { 5374653Sdougm (void) printf(gettext( 5384653Sdougm "Could not add property " 5394653Sdougm "%s: %s\n"), 5404653Sdougm optlist->optname, 5414653Sdougm sa_errorstr(ret)); 5424653Sdougm } else { 5434653Sdougm /* there was a change */ 5444653Sdougm result = 1; 5454653Sdougm } 5464653Sdougm } 5473034Sdougm } 5484653Sdougm } else { 5494653Sdougm ret = sa_update_property(prop, optlist->optvalue); 5504653Sdougm /* should check to see if value changed */ 5514653Sdougm if (ret != SA_OK) { 5524653Sdougm (void) printf(gettext("Could not update " 5534653Sdougm "property %s: %s\n"), optlist->optname, 5544653Sdougm sa_errorstr(ret)); 5554653Sdougm } else { 5563034Sdougm result = 1; 5573034Sdougm } 5583034Sdougm } 5593034Sdougm optlist = optlist->next; 5603034Sdougm } 5614653Sdougm ret = sa_commit_properties(optionset, 0); 5624653Sdougm 5634653Sdougm out: 5643034Sdougm if (err != NULL) 5654653Sdougm *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) { 5914653Sdougm switch (c) { 5924653Sdougm case 'v': 5934653Sdougm verbose++; 5944653Sdougm break; 5954653Sdougm case 'n': 5964653Sdougm dryrun++; 5974653Sdougm break; 5984653Sdougm case 'P': 5994653Sdougm protocol = optarg; 6004653Sdougm if (sa_valid_protocol(protocol)) 6014653Sdougm break; 6024653Sdougm (void) printf(gettext( 6034653Sdougm "Invalid protocol specified: %s\n"), protocol); 6044653Sdougm return (SA_INVALID_PROTOCOL); 6054653Sdougm break; 6064653Sdougm case 'p': 6074653Sdougm ret = add_opt(&optlist, optarg, 0); 6084653Sdougm switch (ret) { 6094653Sdougm case OPT_ADD_SYNTAX: 6104653Sdougm (void) printf(gettext( 6114653Sdougm "Property syntax error for property: %s\n"), 6124653Sdougm optarg); 6134653Sdougm return (SA_SYNTAX_ERR); 6144653Sdougm case OPT_ADD_SECURITY: 6154653Sdougm (void) printf(gettext( 6164653Sdougm "Security properties need " 6174653Sdougm "to be set with set-security: %s\n"), 6184653Sdougm optarg); 6194653Sdougm return (SA_SYNTAX_ERR); 6204653Sdougm default: 6214653Sdougm break; 6224653Sdougm } 6234653Sdougm break; 6244653Sdougm default: 6254653Sdougm case 'h': 6264653Sdougm case '?': 6274653Sdougm (void) printf(gettext("usage: %s\n"), 6284653Sdougm sa_get_usage(USAGE_CREATE)); 6294653Sdougm return (0); 6303034Sdougm } 6313034Sdougm } 6323034Sdougm 6333034Sdougm if (optind >= argc) { 6344653Sdougm (void) printf(gettext("usage: %s\n"), 6354653Sdougm sa_get_usage(USAGE_CREATE)); 6364653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 6374653Sdougm return (SA_BAD_PATH); 6383034Sdougm } 6393034Sdougm 6403034Sdougm if ((optind + 1) < argc) { 6414653Sdougm (void) printf(gettext("usage: %s\n"), 6424653Sdougm sa_get_usage(USAGE_CREATE)); 6434653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 6444653Sdougm return (SA_SYNTAX_ERR); 6453034Sdougm } 6463034Sdougm 6473034Sdougm if (protocol == NULL && optlist != NULL) { 6484653Sdougm /* lookup default protocol */ 6494653Sdougm (void) printf(gettext("usage: %s\n"), 6504653Sdougm sa_get_usage(USAGE_CREATE)); 6514653Sdougm (void) printf(gettext("\tprotocol must be specified " 6524653Sdougm "with properties\n")); 6534653Sdougm return (SA_INVALID_PROTOCOL); 6543034Sdougm } 6553034Sdougm 6563034Sdougm if (optlist != NULL) 6574653Sdougm ret = chk_opt(optlist, 0, protocol); 6583034Sdougm if (ret == OPT_ADD_SECURITY) { 6594653Sdougm (void) printf(gettext("Security properties not " 6604653Sdougm "supported with create\n")); 6614653Sdougm return (SA_SYNTAX_ERR); 6623034Sdougm } 6633034Sdougm 6643034Sdougm /* 6654653Sdougm * 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) { 6764653Sdougm /* group exists so must be a protocol add */ 6774653Sdougm if (protocol != NULL) { 6784653Sdougm if (has_protocol(group, protocol)) { 6794653Sdougm (void) printf(gettext( 6804653Sdougm "Group \"%s\" already exists" 6814653Sdougm " with protocol %s\n"), groupname, 6824653Sdougm protocol); 6834653Sdougm ret = SA_DUPLICATE_NAME; 6844653Sdougm } 6854653Sdougm } else { 6864653Sdougm /* must add new protocol */ 6874653Sdougm (void) printf(gettext( 6884653Sdougm "Group already exists and no protocol " 6894653Sdougm "specified.\n")); 6904653Sdougm ret = SA_DUPLICATE_NAME; 6913034Sdougm } 6923034Sdougm } else { 6933034Sdougm /* 6943034Sdougm * is it a valid name? Must comply with SMF instance 6953034Sdougm * name restrictions. 6963034Sdougm */ 6974653Sdougm if (!sa_valid_group_name(groupname)) { 6984653Sdougm ret = SA_INVALID_NAME; 6994653Sdougm (void) printf(gettext("Invalid group name: %s\n"), 7004653Sdougm groupname); 7014653Sdougm } 7023034Sdougm } 7033034Sdougm if (ret == SA_OK) { 7044653Sdougm /* check protocol vs optlist */ 7054653Sdougm if (optlist != NULL) { 7064653Sdougm /* check options, if any, for validity */ 7074653Sdougm ret = valid_options(optlist, protocol, group, NULL); 7084653Sdougm } 7093034Sdougm } 7103034Sdougm if (ret == SA_OK && !dryrun) { 7114653Sdougm if (group == NULL) { 7124653Sdougm group = sa_create_group(handle, (char *)groupname, 7134653Sdougm &err); 7143034Sdougm } 7154653Sdougm if (group != NULL) { 7164653Sdougm sa_optionset_t optionset; 7174653Sdougm if (optlist != NULL) { 7184653Sdougm (void) add_optionset(group, optlist, protocol, 7194653Sdougm &ret); 7204653Sdougm } else if (protocol != NULL) { 7214653Sdougm optionset = sa_create_optionset(group, 7224653Sdougm protocol); 7234653Sdougm if (optionset == NULL) 7244653Sdougm ret = SA_NO_MEMORY; 7254653Sdougm } else if (protocol == NULL) { 7264653Sdougm char **protolist; 7274653Sdougm int numprotos, i; 7284653Sdougm numprotos = sa_get_protocols(&protolist); 7294653Sdougm for (i = 0; i < numprotos; i++) { 7304653Sdougm optionset = sa_create_optionset(group, 7314653Sdougm protolist[i]); 7324653Sdougm } 7334653Sdougm if (protolist != NULL) 7344653Sdougm free(protolist); 7354653Sdougm } 7363034Sdougm /* 7374653Sdougm * We have a group and legal additions 7383034Sdougm */ 7394653Sdougm if (ret == SA_OK) { 7404653Sdougm /* 7414653Sdougm * Commit to configuration for protocols that 7424653Sdougm * need to do block updates. For NFS, this 7434653Sdougm * doesn't do anything but it will be run for 7444653Sdougm * all protocols that implement the 7454653Sdougm * appropriate plugin. 7464653Sdougm */ 7474653Sdougm ret = sa_update_config(handle); 7484653Sdougm } else { 7494653Sdougm if (group != NULL) 7504653Sdougm (void) sa_remove_group(group); 7514653Sdougm } 7523034Sdougm } else { 7534653Sdougm ret = err; 7544653Sdougm (void) printf(gettext("Could not create group: %s\n"), 7554653Sdougm sa_errorstr(ret)); 7563034Sdougm } 7573034Sdougm } 7583034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 7594653Sdougm (void) printf(gettext("Command would fail: %s\n"), 7604653Sdougm sa_errorstr(SA_NO_PERMISSION)); 7614653Sdougm 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) { 7814653Sdougm if (strcmp(state, "enabled") == 0) { 7824653Sdougm enabled = 1; 7834653Sdougm } 7844653Sdougm 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) { 8114653Sdougm switch (c) { 8124653Sdougm case 'v': 8134653Sdougm verbose++; 8144653Sdougm break; 8154653Sdougm case 'n': 8164653Sdougm dryrun++; 8174653Sdougm break; 8184653Sdougm case 'P': 8194653Sdougm protocol = optarg; 8204653Sdougm if (!sa_valid_protocol(protocol)) { 8214653Sdougm (void) printf(gettext("Invalid protocol " 8224653Sdougm "specified: %s\n"), protocol); 8234653Sdougm return (SA_INVALID_PROTOCOL); 8244653Sdougm } 8254653Sdougm break; 8264653Sdougm case 'S': 8274653Sdougm sectype = optarg; 8284653Sdougm break; 8294653Sdougm case 'f': 8304653Sdougm force++; 8314653Sdougm break; 8324653Sdougm default: 8334653Sdougm case 'h': 8344653Sdougm case '?': 8354653Sdougm (void) printf(gettext("usage: %s\n"), 8364653Sdougm sa_get_usage(USAGE_DELETE)); 8374653Sdougm return (0); 8383034Sdougm } 8393034Sdougm } 8403034Sdougm 8413034Sdougm if (optind >= argc) { 8424653Sdougm (void) printf(gettext("usage: %s\n"), 8434653Sdougm sa_get_usage(USAGE_DELETE)); 8444653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 8454653Sdougm return (SA_SYNTAX_ERR); 8463034Sdougm } 8473034Sdougm 8483034Sdougm if ((optind + 1) < argc) { 8494653Sdougm (void) printf(gettext("usage: %s\n"), 8504653Sdougm sa_get_usage(USAGE_DELETE)); 8514653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 8524653Sdougm return (SA_SYNTAX_ERR); 8533034Sdougm } 8543034Sdougm 8553034Sdougm if (sectype != NULL && protocol == NULL) { 8564653Sdougm (void) printf(gettext("usage: %s\n"), 8574653Sdougm sa_get_usage(USAGE_DELETE)); 8584653Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 8594653Sdougm "specified.\n")); 8604653Sdougm 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; 8784653Sdougm goto done; 8794653Sdougm } 8804653Sdougm auth = check_authorizations(groupname, flags); 8814653Sdougm if (protocol == NULL) { 8823034Sdougm share = sa_get_share(group, NULL); 8833034Sdougm if (share != NULL) 8844653Sdougm ret = SA_BUSY; 8853034Sdougm if (share == NULL || (share != NULL && force == 1)) { 8864653Sdougm ret = SA_OK; 8874653Sdougm if (!dryrun) { 8884653Sdougm while (share != NULL) { 8894653Sdougm sa_share_t next_share; 8904653Sdougm next_share = sa_get_next_share(share); 8914653Sdougm /* 8924653Sdougm * need to do the disable of 8934653Sdougm * each share, but don't 8944653Sdougm * actually do anything on a 8954653Sdougm * dryrun. 8964653Sdougm */ 8974653Sdougm ret = sa_disable_share(share, NULL); 8984653Sdougm ret = sa_remove_share(share); 8994653Sdougm share = next_share; 9004653Sdougm } 9014653Sdougm ret = sa_remove_group(group); 9023034Sdougm } 9033034Sdougm } 9044653Sdougm /* Commit to configuration if not a dryrun */ 9053034Sdougm if (!dryrun && ret == SA_OK) { 9064653Sdougm ret = sa_update_config(handle); 9073034Sdougm } 9084653Sdougm } else { 9093034Sdougm /* a protocol delete */ 9103034Sdougm sa_optionset_t optionset; 9113034Sdougm sa_security_t security; 9124653Sdougm if (sectype != NULL) { 9134653Sdougm /* only delete specified security */ 9144653Sdougm security = sa_get_security(group, sectype, protocol); 9154653Sdougm if (security != NULL && !dryrun) 9164653Sdougm ret = sa_destroy_security(security); 9174653Sdougm else 9184653Sdougm ret = SA_INVALID_PROTOCOL; 9193034Sdougm } else { 9204653Sdougm optionset = sa_get_optionset(group, protocol); 9214653Sdougm if (optionset != NULL && !dryrun) { 9224653Sdougm /* 9234653Sdougm * have an optionset with 9244653Sdougm * protocol to delete 9254653Sdougm */ 9264653Sdougm ret = sa_destroy_optionset(optionset); 9274653Sdougm /* 9284653Sdougm * Now find all security sets 9294653Sdougm * for the protocol and remove 9304653Sdougm * them. Don't remove other 9314653Sdougm * protocols. 9324653Sdougm */ 9334653Sdougm for (security = 9344653Sdougm sa_get_security(group, NULL, NULL); 9354653Sdougm ret == SA_OK && security != NULL; 9364653Sdougm security = sa_get_next_security(security)) { 9374653Sdougm char *secprot; 9384653Sdougm secprot = sa_get_security_attr(security, 9394653Sdougm "type"); 9404653Sdougm if (secprot != NULL && 9414653Sdougm strcmp(secprot, protocol) == 0) 9424653Sdougm ret = sa_destroy_security( 9434653Sdougm security); 9444653Sdougm if (secprot != NULL) 9454653Sdougm sa_free_attr_string(secprot); 9464653Sdougm } 9474653Sdougm } else { 9484653Sdougm if (!dryrun) 9494653Sdougm ret = SA_INVALID_PROTOCOL; 9503034Sdougm } 9513034Sdougm } 9523034Sdougm } 9534653Sdougm 9544653Sdougm done: 9553034Sdougm if (ret != SA_OK) { 9564653Sdougm (void) printf(gettext("Could not delete group: %s\n"), 9574653Sdougm sa_errorstr(ret)); 9583034Sdougm } else if (dryrun && !auth && verbose) { 9594653Sdougm (void) printf(gettext("Command would fail: %s\n"), 9604653Sdougm 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) { 9784653Sdougm buff = (char *)malloc(64); 9794653Sdougm if (buff == NULL) 9804653Sdougm return (NULL); 9814653Sdougm *buffsize = 64; 9824653Sdougm buff[0] = '\0'; 9833034Sdougm } 9843034Sdougm limit = strlen(buff) + strlen(str) + 1; 9853034Sdougm if (limit > *buffsize) { 9864653Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 9874653Sdougm buff = realloc(buff, limit); 9883034Sdougm } 9893034Sdougm if (buff != NULL) { 9904653Sdougm (void) strcat(buff, str); 9913034Sdougm } else { 9924653Sdougm /* if it fails, fail it hard */ 9934653Sdougm if (orig_buff != NULL) 9944653Sdougm 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) { 10214653Sdougm for (optionset = sa_get_optionset(group, NULL); 10224653Sdougm optionset != NULL && buff != NULL; 10234653Sdougm optionset = sa_get_next_optionset(optionset)) { 10244653Sdougm /* 10254653Sdougm * extract out the protocol type from this optionset 10264653Sdougm * and append it to the buffer "buff". strndupr() will 10274653Sdougm * reallocate space as necessay. 10284653Sdougm */ 10294653Sdougm proto = sa_get_optionset_attr(optionset, "type"); 10304653Sdougm if (proto != NULL) { 10314653Sdougm if (addspace++) 10324653Sdougm buff = strndupr(buff, " ", &buffsize); 10334653Sdougm buff = strndupr(buff, proto, &buffsize); 10344653Sdougm sa_free_attr_string(proto); 10354653Sdougm } 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 10484653Sdougm /*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) { 10584653Sdougm switch (c) { 10594653Sdougm case 'v': 10604653Sdougm verbose++; 10614653Sdougm break; 10624653Sdougm case 'P': 10634653Sdougm protocol = optarg; 10644653Sdougm if (!sa_valid_protocol(protocol)) { 10654653Sdougm (void) printf(gettext( 10664653Sdougm "Invalid protocol specified: %s\n"), 10674653Sdougm protocol); 10684653Sdougm return (SA_INVALID_PROTOCOL); 10694653Sdougm } 10704653Sdougm break; 10714653Sdougm default: 10724653Sdougm case 'h': 10734653Sdougm case '?': 10744653Sdougm (void) printf(gettext("usage: %s\n"), 10754653Sdougm sa_get_usage(USAGE_LIST)); 10764653Sdougm return (0); 10773034Sdougm } 10783034Sdougm } 10793034Sdougm 10804653Sdougm for (group = sa_get_group(handle, NULL); 10814653Sdougm group != NULL; 10823034Sdougm group = sa_get_next_group(group)) { 10834653Sdougm char *name; 10844653Sdougm char *proto; 10854653Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 10864653Sdougm name = sa_get_group_attr(group, "name"); 10874653Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 10884653Sdougm (void) printf("%s", (char *)name); 10894653Sdougm if (verbose) { 10904653Sdougm /* 10914653Sdougm * Need the list of protocols 10924653Sdougm * and current status once 10934653Sdougm * available. We do want to 10944653Sdougm * translate the 10954653Sdougm * enabled/disabled text here. 10964653Sdougm */ 10974653Sdougm (void) printf("\t%s", isenabled(group) ? 10984653Sdougm gettext("enabled") : 10994653Sdougm gettext("disabled")); 11004653Sdougm proto = group_proto(group); 11014653Sdougm if (proto != NULL) { 11024653Sdougm (void) printf("\t%s", 11034653Sdougm (char *)proto); 11044653Sdougm free(proto); 11054653Sdougm } 11064653Sdougm } 11074653Sdougm (void) printf("\n"); 11083034Sdougm } 11094653Sdougm if (name != NULL) 11104653Sdougm 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 11334653Sdougm if (sec == NULL) 11344653Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 11354653Sdougm else 11364653Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 11373034Sdougm 11383034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 11394653Sdougm prop != NULL; 11404653Sdougm 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 */ 11484653Sdougm type = sa_get_property_attr(prop, "type"); 11494653Sdougm value = sa_get_property_attr(prop, "value"); 11504653Sdougm if (type != NULL) { 11514653Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 11524653Sdougm spacer = 1; 11534653Sdougm if (value != NULL) 11544653Sdougm (void) printf("\"%s\"", value); 11554653Sdougm else 11564653Sdougm (void) printf("\"\""); 11574653Sdougm } 11584653Sdougm if (type != NULL) 11594653Sdougm sa_free_attr_string(type); 11603034Sdougm if (value != NULL) 11614653Sdougm 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) { 11884653Sdougm optionset = sa_get_optionset(group, protocol); 11894653Sdougm if (optionset != NULL) { 11904653Sdougm (void) printf("%s", prefix); 11914653Sdougm prefix = ""; 11924653Sdougm out_properties(optionset, protocol, NULL); 11934653Sdougm } 11944653Sdougm security = sa_get_security(group, protocol, NULL); 11954653Sdougm if (security != NULL) { 11964653Sdougm (void) printf("%s", prefix); 11974653Sdougm prefix = ""; 11984653Sdougm out_properties(security, protocol, NULL); 11994653Sdougm } 12003034Sdougm } else { 12014653Sdougm for (optionset = sa_get_optionset(group, protocol); 12024653Sdougm optionset != NULL; 12034653Sdougm optionset = sa_get_next_optionset(optionset)) { 12044653Sdougm 12054653Sdougm value = sa_get_optionset_attr(optionset, "type"); 12064653Sdougm (void) printf("%s", prefix); 12074653Sdougm prefix = ""; 12084653Sdougm out_properties(optionset, value, 0); 12094653Sdougm if (value != NULL) 12104653Sdougm sa_free_attr_string(value); 12114653Sdougm } 12124653Sdougm for (security = sa_get_security(group, NULL, protocol); 12134653Sdougm security != NULL; 12144653Sdougm security = sa_get_next_security(security)) { 12154653Sdougm 12164653Sdougm value = sa_get_security_attr(security, "type"); 12174653Sdougm secvalue = sa_get_security_attr(security, "sectype"); 12184653Sdougm (void) printf("%s", prefix); 12194653Sdougm prefix = ""; 12204653Sdougm out_properties(security, value, secvalue); 12214653Sdougm if (value != NULL) 12224653Sdougm sa_free_attr_string(value); 12234653Sdougm if (secvalue != NULL) 12244653Sdougm sa_free_attr_string(secvalue); 12254653Sdougm } 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) { 12504653Sdougm if (proto != NULL && !has_protocol(group, proto)) { 12514653Sdougm sa_free_attr_string(groupname); 12524653Sdougm return; 12534653Sdougm } 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 */ 12614653Sdougm zfs = sa_get_group_attr(group, "zfs"); 12624653Sdougm if (zfs != NULL) { 12634653Sdougm iszfs = 1; 12644653Sdougm sa_free_attr_string(zfs); 12653034Sdougm } 12664653Sdougm share = sa_get_share(group, NULL); 12674653Sdougm if (subgroup == NULL) 12684653Sdougm (void) printf("%s", groupname); 12694653Sdougm else 12704653Sdougm (void) printf(" %s/%s", subgroup, groupname); 12714653Sdougm if (properties) 12724653Sdougm show_properties(group, proto, ""); 12734653Sdougm (void) printf("\n"); 12744653Sdougm if (strcmp(groupname, "zfs") == 0) { 12754653Sdougm sa_group_t zgroup; 12764653Sdougm 12774653Sdougm for (zgroup = sa_get_sub_group(group); 12784653Sdougm zgroup != NULL; 12794653Sdougm zgroup = sa_get_next_group(zgroup)) { 12804653Sdougm show_group(zgroup, verbose, properties, proto, 12814653Sdougm "zfs"); 12824653Sdougm } 12834653Sdougm sa_free_attr_string(groupname); 12844653Sdougm return; 12854653Sdougm } 12863034Sdougm /* 12874653Sdougm * Have a group, so list the contents. Resource and 12883034Sdougm * description are only listed if verbose is set. 12893034Sdougm */ 12904653Sdougm for (share = sa_get_share(group, NULL); 12914653Sdougm share != NULL; 12924653Sdougm share = sa_get_next_share(share)) { 12934653Sdougm sharepath = sa_get_share_attr(share, "path"); 12944653Sdougm if (sharepath != NULL) { 12954653Sdougm if (verbose) { 12964653Sdougm resource = sa_get_share_attr(share, 12974653Sdougm "resource"); 12984653Sdougm description = 12994653Sdougm sa_get_share_description(share); 13004653Sdougm type = sa_get_share_attr(share, 13014653Sdougm "type"); 13024653Sdougm if (type != NULL && !iszfs && 13034653Sdougm strcmp(type, "transient") == 0) 13044653Sdougm (void) printf("\t* "); 13054653Sdougm else 13064653Sdougm (void) printf("\t "); 13074653Sdougm if (resource != NULL && 13084653Sdougm strlen(resource) > 0) { 13094653Sdougm (void) printf("%s=%s", 13104653Sdougm resource, sharepath); 13114653Sdougm } else { 13124653Sdougm (void) printf("%s", sharepath); 13134653Sdougm } 13144653Sdougm if (resource != NULL) 13154653Sdougm sa_free_attr_string(resource); 13164653Sdougm if (properties) 13174653Sdougm show_properties(share, NULL, 13184653Sdougm "\t"); 13194653Sdougm if (description != NULL) { 13204653Sdougm if (strlen(description) > 0) { 13214653Sdougm (void) printf( 13224653Sdougm "\t\"%s\"", 13234653Sdougm description); 13244653Sdougm } 13254653Sdougm sa_free_share_description( 13264653Sdougm description); 13274653Sdougm } 13284653Sdougm if (type != NULL) 13294653Sdougm sa_free_attr_string(type); 13304653Sdougm } else { 13314653Sdougm (void) printf("\t%s", sharepath); 13324653Sdougm if (properties) 13334653Sdougm show_properties(share, NULL, 13344653Sdougm "\t"); 13354653Sdougm } 13364653Sdougm (void) printf("\n"); 13374653Sdougm 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) { 13614653Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 13624653Sdougm if (root != NULL) 13634653Sdougm 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) { 13834653Sdougm 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 13984653Sdougm /*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) { 14124653Sdougm switch (c) { 14134653Sdougm case 'v': 14144653Sdougm verbose++; 14154653Sdougm break; 14164653Sdougm case 'p': 14174653Sdougm properties++; 14184653Sdougm break; 14194653Sdougm case 'P': 14204653Sdougm protocol = optarg; 14214653Sdougm if (!sa_valid_protocol(protocol)) { 14224653Sdougm (void) printf(gettext( 14234653Sdougm "Invalid protocol specified: %s\n"), 14244653Sdougm protocol); 14254653Sdougm return (SA_INVALID_PROTOCOL); 14264653Sdougm } 14274653Sdougm break; 14284653Sdougm case 'x': 14294653Sdougm xml++; 14304653Sdougm break; 14314653Sdougm default: 14324653Sdougm case 'h': 14334653Sdougm case '?': 14344653Sdougm (void) printf(gettext("usage: %s\n"), 14354653Sdougm sa_get_usage(USAGE_SHOW)); 14364653Sdougm return (0); 14373034Sdougm } 14383034Sdougm } 14393034Sdougm 14403034Sdougm if (xml) { 14414653Sdougm doc = show_group_xml_init(); 14424653Sdougm if (doc == NULL) 14434653Sdougm ret = SA_NO_MEMORY; 14443034Sdougm } 14453034Sdougm 14463034Sdougm if (optind == argc) { 14474653Sdougm /* No group specified so go through them all */ 14484653Sdougm for (group = sa_get_group(handle, NULL); 14494653Sdougm group != NULL; 14504653Sdougm group = sa_get_next_group(group)) { 14514653Sdougm /* 14524653Sdougm * Have a group so check if one we want and then list 14534653Sdougm * contents with appropriate options. 14544653Sdougm */ 14554653Sdougm if (xml) 14564653Sdougm show_group_xml(doc, group); 14574653Sdougm else 14584653Sdougm show_group(group, verbose, properties, protocol, 14594653Sdougm NULL); 14604653Sdougm } 14613034Sdougm } else { 14624653Sdougm /* Have a specified list of groups */ 14634653Sdougm for (; optind < argc; optind++) { 14644653Sdougm group = sa_get_group(handle, argv[optind]); 14654653Sdougm if (group != NULL) { 14664653Sdougm if (xml) 14674653Sdougm show_group_xml(doc, group); 14684653Sdougm else 14694653Sdougm show_group(group, verbose, properties, 14704653Sdougm protocol, NULL); 14714653Sdougm } else { 14724653Sdougm (void) printf(gettext("%s: not found\n"), 14734653Sdougm argv[optind]); 14744653Sdougm ret = SA_NO_SUCH_GROUP; 14754653Sdougm } 14763034Sdougm } 14773034Sdougm } 14783034Sdougm if (xml && ret == SA_OK) { 14794653Sdougm xmlDocFormatDump(stdout, doc, 1); 14804653Sdougm 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) 15114653Sdougm sa_free_attr_string(value); 15123034Sdougm /* remove legacy config if necessary */ 15133034Sdougm if (update_legacy) 15144653Sdougm ret = sa_delete_legacy(share); 15153034Sdougm zfs = sa_get_group_attr(group, "zfs"); 15163034Sdougm if (zfs != NULL) { 15174653Sdougm iszfs++; 15184653Sdougm 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)) { 15304653Sdougm value = sa_get_optionset_attr(optionset, "type"); 15314653Sdougm if (value != NULL) { 15324653Sdougm if (enabled) 15334653Sdougm ret = sa_enable_share(share, value); 15344653Sdougm if (update_legacy && !iszfs) 15354653Sdougm (void) sa_update_legacy(share, value); 15364653Sdougm sa_free_attr_string(value); 15374653Sdougm } 15383034Sdougm } 15393034Sdougm if (ret == SA_OK) 15404653Sdougm (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) { 15674653Sdougm switch (c) { 15684653Sdougm case 'n': 15694653Sdougm dryrun++; 15704653Sdougm break; 15714653Sdougm case 'v': 15724653Sdougm verbose++; 15734653Sdougm break; 15744653Sdougm case 'd': 15754653Sdougm description = optarg; 15764653Sdougm break; 15774653Sdougm case 'r': 15784653Sdougm resource = optarg; 15794653Sdougm break; 15804653Sdougm case 's': 15814653Sdougm /* 15824653Sdougm * Save share path into group. Currently limit 15834653Sdougm * to one share per command. 15844653Sdougm */ 15854653Sdougm if (sharepath != NULL) { 15864653Sdougm (void) printf(gettext( 15874653Sdougm "Adding multiple shares not supported\n")); 15884653Sdougm return (1); 15894653Sdougm } 15904653Sdougm sharepath = optarg; 15914653Sdougm break; 15924653Sdougm case 't': 15934653Sdougm persist = SA_SHARE_TRANSIENT; 15944653Sdougm break; 15954653Sdougm default: 15964653Sdougm case 'h': 15974653Sdougm case '?': 15984653Sdougm (void) printf(gettext("usage: %s\n"), 15994653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 16004653Sdougm return (0); 16013034Sdougm } 16023034Sdougm } 16033034Sdougm 16043034Sdougm if (optind >= argc) { 16054653Sdougm (void) printf(gettext("usage: %s\n"), 16064653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 16074653Sdougm if (dryrun || sharepath != NULL || description != NULL || 16084653Sdougm resource != NULL || verbose || persist) { 16094653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 16104653Sdougm ret = SA_NO_SUCH_GROUP; 16114653Sdougm } else { 16124653Sdougm ret = SA_OK; 16134653Sdougm } 16143034Sdougm } else { 16154653Sdougm if (sharepath == NULL) { 16164653Sdougm (void) printf(gettext("usage: %s\n"), 16174653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 16184653Sdougm (void) printf(gettext( 16194653Sdougm "\t-s sharepath must be specified\n")); 16204653Sdougm return (SA_BAD_PATH); 16214653Sdougm } 16223034Sdougm if (realpath(sharepath, dir) == NULL) { 16234653Sdougm (void) printf(gettext( 16244653Sdougm "Path is not valid: %s\n"), sharepath); 16254653Sdougm return (SA_BAD_PATH); 16263034Sdougm } else { 16274653Sdougm sharepath = dir; 16283034Sdougm } 16294653Sdougm 16304653Sdougm /* Check for valid syntax */ 16314653Sdougm if (resource != NULL && strpbrk(resource, " \t/") != NULL) { 16324653Sdougm (void) printf(gettext("usage: %s\n"), 16334653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 16344653Sdougm (void) printf(gettext( 16354653Sdougm "\tresource must not contain white" 16364653Sdougm "space or '/' characters\n")); 16374653Sdougm return (SA_BAD_PATH); 16383034Sdougm } 16393910Sdougm group = sa_get_group(handle, argv[optind]); 16404653Sdougm if (group == NULL) { 16414653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 16424653Sdougm argv[optind]); 16434653Sdougm return (SA_NO_SUCH_GROUP); 16444653Sdougm } 16454653Sdougm auth = check_authorizations(argv[optind], flags); 16464653Sdougm share = sa_find_share(handle, sharepath); 16474653Sdougm if (share != NULL) { 16483034Sdougm group = sa_get_parent_group(share); 16493034Sdougm if (group != NULL) { 16504653Sdougm char *groupname; 16514653Sdougm groupname = sa_get_group_attr( 16524653Sdougm group, "name"); 16534653Sdougm if (groupname != NULL) { 16544653Sdougm (void) printf(gettext( 16554653Sdougm "Share path already " 16564653Sdougm "shared in group " 16574653Sdougm "\"%s\": %s\n"), 16584653Sdougm groupname, sharepath); 16594653Sdougm sa_free_attr_string(groupname); 16604653Sdougm } else { 16614653Sdougm (void) printf(gettext( 16624653Sdougm "Share path already" 16634653Sdougm "shared: %s\n"), 16644653Sdougm groupname, sharepath); 16654653Sdougm } 16663034Sdougm } else { 16674653Sdougm (void) printf(gettext( 16684653Sdougm "Share path %s already shared\n"), 16693034Sdougm sharepath); 16703034Sdougm } 16714653Sdougm return (SA_DUPLICATE_NAME); 16724653Sdougm } else { 16733034Sdougm /* 16744653Sdougm * Need to check that resource name is 16754653Sdougm * unique at some point. Path checking 16764653Sdougm * should use the "normal" rules which 16774653Sdougm * don't check the repository. 16783034Sdougm */ 16793034Sdougm if (dryrun) 16804653Sdougm ret = sa_check_path(group, sharepath, 16814653Sdougm SA_CHECK_NORMAL); 16823034Sdougm else 16834653Sdougm share = sa_add_share(group, sharepath, 16844653Sdougm persist, &ret); 16853034Sdougm if (!dryrun && share == NULL) { 16864653Sdougm (void) printf(gettext( 16874653Sdougm "Could not add share: %s\n"), 16884653Sdougm sa_errorstr(ret)); 16893034Sdougm } else { 16904653Sdougm if (!dryrun && ret == SA_OK) { 16914653Sdougm if (resource != NULL && 16924653Sdougm strpbrk(resource, " \t/") == NULL) { 16934653Sdougm ret = sa_set_share_attr(share, 16944653Sdougm "resource", resource); 16954653Sdougm } 16964653Sdougm if (ret == SA_OK && 16974653Sdougm description != NULL) { 16984653Sdougm ret = sa_set_share_description( 16994653Sdougm share, description); 17004653Sdougm } 17014653Sdougm if (ret == SA_OK) { 17024653Sdougm /* Now enable the share(s) */ 17034653Sdougm ret = enable_share(handle, 17044653Sdougm group, share, 1); 17054653Sdougm ret = sa_update_config(handle); 17064653Sdougm } 17074653Sdougm switch (ret) { 17084653Sdougm case SA_DUPLICATE_NAME: 17094653Sdougm (void) printf(gettext( 17104653Sdougm "Resource name in" 17114653Sdougm "use: %s\n"), resource); 17124653Sdougm break; 17134653Sdougm default: 17144653Sdougm (void) printf( 17154653Sdougm gettext("Could not set " 17164653Sdougm "attribute: %s\n"), 17174653Sdougm sa_errorstr(ret)); 17184653Sdougm break; 17194653Sdougm case SA_OK: 17204653Sdougm break; 17214653Sdougm } 17224653Sdougm } else if (dryrun && ret == SA_OK && !auth && 17234653Sdougm verbose) { 17244653Sdougm (void) printf(gettext( 17254653Sdougm "Command would fail: %s\n"), 17264653Sdougm sa_errorstr(SA_NO_PERMISSION)); 17274653Sdougm 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) { 17544653Sdougm switch (c) { 17554653Sdougm case 'n': 17564653Sdougm dryrun++; 17574653Sdougm break; 17584653Sdougm case 'v': 17594653Sdougm verbose++; 17604653Sdougm break; 17614653Sdougm case 's': 17624653Sdougm /* 17634653Sdougm * Remove share path from group. Currently limit 17644653Sdougm * to one share per command. 17654653Sdougm */ 17664653Sdougm if (sharepath != NULL) { 17674653Sdougm (void) printf(gettext("Moving multiple shares" 17684653Sdougm "not supported\n")); 17694653Sdougm return (SA_BAD_PATH); 17704653Sdougm } 17714653Sdougm sharepath = optarg; 17724653Sdougm break; 17734653Sdougm default: 17744653Sdougm case 'h': 17754653Sdougm case '?': 17764653Sdougm (void) printf(gettext("usage: %s\n"), 17774653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 17784653Sdougm return (0); 17793034Sdougm } 17803034Sdougm } 17813034Sdougm 17823034Sdougm if (optind >= argc || sharepath == NULL) { 17833034Sdougm (void) printf(gettext("usage: %s\n"), 17844653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 17854653Sdougm if (dryrun || verbose || sharepath != NULL) { 17864653Sdougm (void) printf(gettext( 17874653Sdougm "\tgroup must be specified\n")); 17884653Sdougm ret = SA_NO_SUCH_GROUP; 17894653Sdougm } else { 17904653Sdougm if (sharepath == NULL) { 17914653Sdougm ret = SA_SYNTAX_ERR; 17924653Sdougm (void) printf(gettext( 17934653Sdougm "\tsharepath must be specified\n")); 17944653Sdougm } else { 17954653Sdougm ret = SA_OK; 17964653Sdougm } 17974653Sdougm } 17984653Sdougm } else { 17994653Sdougm sa_group_t parent; 18004653Sdougm char *zfsold; 18014653Sdougm char *zfsnew; 18024653Sdougm 18033034Sdougm if (sharepath == NULL) { 18044653Sdougm (void) printf(gettext( 18054653Sdougm "sharepath must be specified with the -s " 18064653Sdougm "option\n")); 18074653Sdougm return (SA_BAD_PATH); 18084653Sdougm } 18093910Sdougm group = sa_get_group(handle, argv[optind]); 18104653Sdougm if (group == NULL) { 18114653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 18124653Sdougm argv[optind]); 18134653Sdougm return (SA_NO_SUCH_GROUP); 18144653Sdougm } 18154653Sdougm share = sa_find_share(handle, sharepath); 18164653Sdougm authdst = check_authorizations(argv[optind], flags); 18174653Sdougm if (share == NULL) { 18183034Sdougm (void) printf(gettext("Share not found: %s\n"), 18194653Sdougm sharepath); 18204653Sdougm return (SA_NO_SUCH_PATH); 18214653Sdougm } 18224653Sdougm 18234653Sdougm parent = sa_get_parent_group(share); 18244653Sdougm if (parent != NULL) { 18254653Sdougm char *pname; 18264653Sdougm pname = sa_get_group_attr(parent, "name"); 18274653Sdougm if (pname != NULL) { 18283034Sdougm authsrc = check_authorizations(pname, flags); 18293034Sdougm sa_free_attr_string(pname); 18304653Sdougm } 18314653Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 18324653Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 18334653Sdougm if ((zfsold != NULL && zfsnew == NULL) || 18344653Sdougm (zfsold == NULL && zfsnew != NULL)) { 18353034Sdougm ret = SA_NOT_ALLOWED; 18363034Sdougm } 18374653Sdougm if (zfsold != NULL) 18384653Sdougm sa_free_attr_string(zfsold); 18394653Sdougm if (zfsnew != NULL) 18404653Sdougm sa_free_attr_string(zfsnew); 18414653Sdougm } 18424653Sdougm if (!dryrun && ret == SA_OK) 18434653Sdougm ret = sa_move_share(group, share); 18444653Sdougm 18454653Sdougm if (ret == SA_OK && parent != group && !dryrun) { 18464653Sdougm char *oldstate; 18474653Sdougm ret = sa_update_config(handle); 18484653Sdougm /* 18494653Sdougm * Note that the share may need to be 18504653Sdougm * "unshared" if the new group is 18514653Sdougm * disabled and the old was enabled or 18524653Sdougm * it may need to be share to update 18534653Sdougm * if the new group is enabled. 18544653Sdougm */ 18554653Sdougm oldstate = sa_get_group_attr(parent, "state"); 18564653Sdougm 18574653Sdougm /* enable_share determines what to do */ 18584653Sdougm if (strcmp(oldstate, "enabled") == 0) { 18593034Sdougm (void) sa_disable_share(share, NULL); 18604653Sdougm } 18614653Sdougm (void) enable_share(handle, group, share, 1); 18624653Sdougm if (oldstate != NULL) 18633034Sdougm sa_free_attr_string(oldstate); 18643034Sdougm } 18654653Sdougm 18664653Sdougm if (ret != SA_OK) 18674653Sdougm (void) printf(gettext("Could not move share: %s\n"), 18684653Sdougm sa_errorstr(ret)); 18694653Sdougm 18704653Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 18714653Sdougm verbose) { 18724653Sdougm (void) printf(gettext("Command would fail: %s\n"), 18734653Sdougm sa_errorstr(SA_NO_PERMISSION)); 18744653Sdougm } 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) { 19004653Sdougm switch (c) { 19014653Sdougm case 'n': 19024653Sdougm dryrun++; 19034653Sdougm break; 19044653Sdougm case 'v': 19054653Sdougm verbose++; 19064653Sdougm break; 19074653Sdougm case 'f': 19084653Sdougm force++; 19094653Sdougm break; 19104653Sdougm case 's': 19114653Sdougm /* 19124653Sdougm * Remove share path from group. Currently limit 19134653Sdougm * to one share per command. 19144653Sdougm */ 19154653Sdougm if (sharepath != NULL) { 19164653Sdougm (void) printf(gettext( 19174653Sdougm "Removing multiple shares not " 19183034Sdougm "supported\n")); 19194653Sdougm return (SA_SYNTAX_ERR); 19204653Sdougm } 19214653Sdougm sharepath = optarg; 19224653Sdougm break; 19234653Sdougm default: 19244653Sdougm case 'h': 19254653Sdougm case '?': 19264653Sdougm (void) printf(gettext("usage: %s\n"), 19274653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 19284653Sdougm return (0); 19293034Sdougm } 19303034Sdougm } 19313034Sdougm 19323034Sdougm if (optind >= argc || sharepath == NULL) { 19334653Sdougm if (sharepath == NULL) { 19343034Sdougm (void) printf(gettext("usage: %s\n"), 19354653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 19364653Sdougm (void) printf(gettext( 19374653Sdougm "\t-s sharepath must be specified\n")); 19384653Sdougm ret = SA_BAD_PATH; 19394653Sdougm } else { 19404653Sdougm ret = SA_OK; 19414653Sdougm } 19423034Sdougm } 19434653Sdougm if (ret != SA_OK) { 19444653Sdougm return (ret); 19454653Sdougm } 19464653Sdougm 19474653Sdougm if (optind < argc) { 19483034Sdougm if ((optind + 1) < argc) { 19494653Sdougm (void) printf(gettext("Extraneous group(s) at end of " 19504653Sdougm "command\n")); 19514653Sdougm ret = SA_SYNTAX_ERR; 19523034Sdougm } else { 19534653Sdougm group = sa_get_group(handle, argv[optind]); 19544653Sdougm if (group == NULL) { 19554653Sdougm (void) printf(gettext( 19564653Sdougm "Group \"%s\" not found\n"), argv[optind]); 19574653Sdougm ret = SA_NO_SUCH_GROUP; 19584653Sdougm } 19593034Sdougm } 19604653Sdougm } else { 19613034Sdougm group = NULL; 19624653Sdougm } 19634653Sdougm 19644653Sdougm /* 19654653Sdougm * Lookup the path in the internal configuration. Care 19664653Sdougm * must be taken to handle the case where the 19674653Sdougm * underlying path has been removed since we need to 19684653Sdougm * be able to deal with that as well. 19694653Sdougm */ 19704653Sdougm if (ret == SA_OK) { 19713034Sdougm if (group != NULL) 19724653Sdougm share = sa_get_share(group, sharepath); 19733034Sdougm else 19744653Sdougm 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) { 19864653Sdougm if (realpath(sharepath, dir) == NULL) { 19874653Sdougm ret = SA_BAD_PATH; 19884653Sdougm (void) printf(gettext( 19894653Sdougm "Path is not valid: %s\n"), sharepath); 19904653Sdougm } else { 19914653Sdougm if (group != NULL) 19924653Sdougm share = sa_get_share(group, dir); 19934653Sdougm else 19944653Sdougm share = sa_find_share(handle, dir); 19954653Sdougm } 19963663Sdougm } 19974653Sdougm } 19984653Sdougm 19994653Sdougm /* 20004653Sdougm * If there hasn't been an error, there was likely a 20014653Sdougm * path found. If not, give the appropriate error 20024653Sdougm * message and set the return error. If it was found, 20034653Sdougm * then disable the share and then remove it from the 20044653Sdougm * configuration. 20054653Sdougm */ 20064653Sdougm if (ret != SA_OK) { 20074653Sdougm return (ret); 20084653Sdougm } 20094653Sdougm if (share == NULL) { 20104653Sdougm if (group != NULL) 20113034Sdougm (void) printf(gettext("Share not found in group %s:" 20124653Sdougm " %s\n"), argv[optind], sharepath); 20134653Sdougm else 20143034Sdougm (void) printf(gettext("Share not found: %s\n"), 20154653Sdougm sharepath); 20164653Sdougm ret = SA_NO_SUCH_PATH; 20174653Sdougm } else { 20184653Sdougm if (group == NULL) 20193034Sdougm group = sa_get_parent_group(share); 20204653Sdougm if (!dryrun) { 20213034Sdougm if (ret == SA_OK) { 20224653Sdougm ret = sa_disable_share(share, NULL); 20233034Sdougm /* 20244653Sdougm * 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 */ 20304653Sdougm if (ret == SA_OK || ret == SA_NO_SUCH_PATH || 20314653Sdougm ret == SA_NOT_SUPPORTED || 20324653Sdougm ret == SA_SYSTEM_ERR || force) { 20334653Sdougm ret = sa_remove_share(share); 20344653Sdougm } 20354653Sdougm if (ret == SA_OK) 20364653Sdougm ret = sa_update_config(handle); 20373034Sdougm } 20384653Sdougm if (ret != SA_OK) 20394653Sdougm (void) printf(gettext( 20404653Sdougm "Could not remove share: %s\n"), 20414653Sdougm sa_errorstr(ret)); 20424653Sdougm 20434653Sdougm } else if (ret == SA_OK) { 20443034Sdougm char *pname; 20453034Sdougm pname = sa_get_group_attr(group, "name"); 20463034Sdougm if (pname != NULL) { 20474653Sdougm auth = check_authorizations(pname, flags); 20484653Sdougm sa_free_attr_string(pname); 20493034Sdougm } 20503034Sdougm if (!auth && verbose) { 20514653Sdougm (void) printf(gettext( 20524653Sdougm "Command would fail: %s\n"), 20534653Sdougm 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; 20794653Sdougm char *groupname; 20803034Sdougm 20813034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 20824653Sdougm switch (c) { 20834653Sdougm case 'n': 20844653Sdougm dryrun++; 20854653Sdougm break; 20864653Sdougm case 'd': 20874653Sdougm description = optarg; 20884653Sdougm break; 20894653Sdougm case 'r': 20904653Sdougm resource = optarg; 20914653Sdougm break; 20924653Sdougm case 'v': 20934653Sdougm verbose++; 20944653Sdougm break; 20954653Sdougm case 's': 20964653Sdougm /* 20974653Sdougm * Save share path into group. Currently limit 20984653Sdougm * to one share per command. 20994653Sdougm */ 21004653Sdougm if (sharepath != NULL) { 21014653Sdougm (void) printf(gettext( 21024653Sdougm "Updating multiple shares not " 21033034Sdougm "supported\n")); 21044653Sdougm return (SA_BAD_PATH); 21054653Sdougm } 21064653Sdougm sharepath = optarg; 21074653Sdougm break; 21084653Sdougm default: 21094653Sdougm case 'h': 21104653Sdougm case '?': 21114653Sdougm (void) printf(gettext("usage: %s\n"), 21124653Sdougm sa_get_usage(USAGE_SET_SHARE)); 21134653Sdougm return (SA_OK); 21143034Sdougm } 21153034Sdougm } 21164653Sdougm 21173034Sdougm if (optind >= argc || sharepath == NULL) { 21184653Sdougm if (sharepath == NULL) { 21194653Sdougm (void) printf(gettext("usage: %s\n"), 21204653Sdougm sa_get_usage(USAGE_SET_SHARE)); 21214653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 21224653Sdougm ret = SA_BAD_PATH; 21234653Sdougm } else { 21244653Sdougm ret = SA_OK; 21254653Sdougm } 21263034Sdougm } 21273034Sdougm if ((optind + 1) < argc) { 21284653Sdougm (void) printf(gettext("usage: %s\n"), 21294653Sdougm sa_get_usage(USAGE_SET_SHARE)); 21304653Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 21314653Sdougm ret = SA_SYNTAX_ERR; 21323034Sdougm } 21334653Sdougm 21344653Sdougm if (ret != SA_OK) 21354653Sdougm return (ret); 21364653Sdougm 21374653Sdougm if (optind < argc) { 21383034Sdougm groupname = argv[optind]; 21393910Sdougm group = sa_get_group(handle, groupname); 21404653Sdougm } else { 21413034Sdougm group = NULL; 21423034Sdougm groupname = NULL; 21434653Sdougm } 21444653Sdougm share = sa_find_share(handle, sharepath); 21454653Sdougm if (share == NULL) { 21464653Sdougm (void) printf(gettext("Share path \"%s\" not found\n"), 21474653Sdougm sharepath); 21484653Sdougm return (SA_NO_SUCH_PATH); 21494653Sdougm } 21504653Sdougm sharegroup = sa_get_parent_group(share); 21514653Sdougm if (group != NULL && group != sharegroup) { 21524653Sdougm (void) printf(gettext("Group \"%s\" does not contain " 21534653Sdougm "share %s\n"), argv[optind], sharepath); 21544653Sdougm ret = SA_BAD_PATH; 21554653Sdougm } else { 21564653Sdougm int delgroupname = 0; 21574653Sdougm if (groupname == NULL) { 21583034Sdougm groupname = sa_get_group_attr(sharegroup, "name"); 21593034Sdougm delgroupname = 1; 21604653Sdougm } 21614653Sdougm if (groupname != NULL) { 21623034Sdougm auth = check_authorizations(groupname, flags); 21633034Sdougm if (delgroupname) { 21644653Sdougm sa_free_attr_string(groupname); 21654653Sdougm groupname = NULL; 21663034Sdougm } 21674653Sdougm } else { 21683034Sdougm ret = SA_NO_MEMORY; 21694653Sdougm } 21704653Sdougm if (resource != NULL) { 21713034Sdougm if (strpbrk(resource, " \t/") == NULL) { 21724653Sdougm if (!dryrun) { 21734653Sdougm ret = sa_set_share_attr(share, 21744653Sdougm "resource", resource); 21754653Sdougm } else { 21764653Sdougm sa_share_t resshare; 21774653Sdougm resshare = sa_get_resource(sharegroup, 21784653Sdougm resource); 21794653Sdougm if (resshare != NULL && 21804653Sdougm resshare != share) 21814653Sdougm ret = SA_DUPLICATE_NAME; 21824653Sdougm } 21833034Sdougm } else { 21844653Sdougm ret = SA_BAD_PATH; 21854653Sdougm (void) printf(gettext("Resource must not " 21864653Sdougm "contain white space or '/'\n")); 21873034Sdougm } 21884653Sdougm } 21894653Sdougm if (ret == SA_OK && description != NULL) 21903034Sdougm ret = sa_set_share_description(share, description); 21914653Sdougm } 21924653Sdougm if (!dryrun && ret == SA_OK) 21934653Sdougm ret = sa_update_config(handle); 21944653Sdougm 21954653Sdougm switch (ret) { 21964653Sdougm case SA_DUPLICATE_NAME: 21974653Sdougm (void) printf(gettext("Resource name in use: %s\n"), resource); 21984653Sdougm break; 21994653Sdougm default: 22004653Sdougm (void) printf(gettext("Could not set attribute: %s\n"), 22014653Sdougm sa_errorstr(ret)); 22024653Sdougm break; 22034653Sdougm case SA_OK: 22044653Sdougm if (dryrun && !auth && verbose) 22053034Sdougm (void) printf(gettext("Command would fail: %s\n"), 22064653Sdougm sa_errorstr(SA_NO_PERMISSION)); 22074653Sdougm break; 22083034Sdougm } 22094653Sdougm 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); 22304653Sdougm if (security == NULL) 22314653Sdougm security = sa_create_security(group, sectype, proto); 22324653Sdougm 22333034Sdougm if (sectype != NULL) 22344653Sdougm sa_free_attr_string(sectype); 22354653Sdougm 22364653Sdougm if (security == NULL) 22374653Sdougm return (ret); 22384653Sdougm 22394653Sdougm while (optlist != NULL) { 22403034Sdougm sa_property_t prop; 22413034Sdougm prop = sa_get_property(security, optlist->optname); 22423034Sdougm if (prop == NULL) { 22433034Sdougm /* 22444653Sdougm * Add the property, but only if it is 22453034Sdougm * a non-NULL or non-zero length value 22463034Sdougm */ 22474653Sdougm if (optlist->optvalue != NULL) { 22484653Sdougm prop = sa_create_property(optlist->optname, 22494653Sdougm optlist->optvalue); 22504653Sdougm if (prop != NULL) { 22514653Sdougm ret = sa_valid_property(security, proto, 22524653Sdougm prop); 22534653Sdougm if (ret != SA_OK) { 22544653Sdougm (void) sa_remove_property(prop); 22554653Sdougm (void) printf(gettext( 22564653Sdougm "Could not add " 22574653Sdougm "property %s: %s\n"), 22584653Sdougm optlist->optname, 22594653Sdougm sa_errorstr(ret)); 22604653Sdougm } 22614653Sdougm if (ret == SA_OK) { 22624653Sdougm ret = sa_add_property(security, 22634653Sdougm prop); 22644653Sdougm if (ret != SA_OK) { 22654653Sdougm (void) printf(gettext( 22664653Sdougm "Could not add " 22674653Sdougm "property (%s=%s): " 22684653Sdougm "%s\n"), 22694653Sdougm optlist->optname, 22704653Sdougm optlist->optvalue, 22714653Sdougm sa_errorstr(ret)); 22724653Sdougm } else { 22734653Sdougm result = 1; 22744653Sdougm } 22754653Sdougm } 22763034Sdougm } 22773034Sdougm } 22783034Sdougm } else { 22794653Sdougm ret = sa_update_property(prop, optlist->optvalue); 22804653Sdougm result = 1; /* should check if really changed */ 22813034Sdougm } 22823034Sdougm optlist = optlist->next; 22834653Sdougm } 22844653Sdougm /* 22854653Sdougm * When done, properties may have all been removed but 22864653Sdougm * we need to keep the security type itself until 22874653Sdougm * explicitly removed. 22884653Sdougm */ 22894653Sdougm if (result) 22903034Sdougm ret = sa_commit_properties(security, 0); 22913034Sdougm *err = ret; 22923034Sdougm return (result); 22933034Sdougm } 22943034Sdougm 22953034Sdougm /* 2296*5089Sdougm * zfscheck(group, share) 2297*5089Sdougm * 2298*5089Sdougm * For the special case where a share was provided, make sure it is a 2299*5089Sdougm * compatible path for a ZFS property change. The only path 2300*5089Sdougm * acceptable is the path that defines the zfs sub-group (dataset with 2301*5089Sdougm * the sharenfs property set) and not one of the paths that inherited 2302*5089Sdougm * the NFS properties. Returns SA_OK if it is usable and 2303*5089Sdougm * SA_NOT_ALLOWED if it isn't. 2304*5089Sdougm * 2305*5089Sdougm * If group is not a ZFS group/subgroup, we assume OK since the check 2306*5089Sdougm * on return will catch errors for those cases. What we are looking 2307*5089Sdougm * for here is that the group is ZFS and the share is not the defining 2308*5089Sdougm * share. All else is SA_OK. 2309*5089Sdougm */ 2310*5089Sdougm 2311*5089Sdougm static int 2312*5089Sdougm zfscheck(sa_group_t group, sa_share_t share) 2313*5089Sdougm { 2314*5089Sdougm int ret = SA_OK; 2315*5089Sdougm char *attr; 2316*5089Sdougm 2317*5089Sdougm if (sa_group_is_zfs(group)) { 2318*5089Sdougm /* 2319*5089Sdougm * The group is a ZFS group. Does the share represent 2320*5089Sdougm * the dataset that defined the group? It is only OK 2321*5089Sdougm * if the attribute "subgroup" exists on the share and 2322*5089Sdougm * has a value of "true". 2323*5089Sdougm */ 2324*5089Sdougm 2325*5089Sdougm ret = SA_NOT_ALLOWED; 2326*5089Sdougm attr = sa_get_share_attr(share, "subgroup"); 2327*5089Sdougm if (attr != NULL) { 2328*5089Sdougm if (strcmp(attr, "true") == 0) 2329*5089Sdougm ret = SA_OK; 2330*5089Sdougm sa_free_attr_string(attr); 2331*5089Sdougm } 2332*5089Sdougm } 2333*5089Sdougm return (ret); 2334*5089Sdougm } 2335*5089Sdougm 2336*5089Sdougm /* 23373034Sdougm * basic_set(groupname, optlist, protocol, sharepath, dryrun) 23383034Sdougm * 23393034Sdougm * This function implements "set" when a name space (-S) is not 23403034Sdougm * specified. It is a basic set. Options and other CLI parsing has 23413034Sdougm * already been done. 23423034Sdougm */ 23433034Sdougm 23443034Sdougm static int 23453910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 23463910Sdougm char *protocol, char *sharepath, int dryrun) 23473034Sdougm { 23483034Sdougm sa_group_t group; 23493034Sdougm int ret = SA_OK; 23503034Sdougm int change = 0; 23513034Sdougm struct list *worklist = NULL; 23523034Sdougm 23533910Sdougm group = sa_get_group(handle, groupname); 23543034Sdougm if (group != NULL) { 23554653Sdougm sa_share_t share = NULL; 23564653Sdougm if (sharepath != NULL) { 23574653Sdougm share = sa_get_share(group, sharepath); 23584653Sdougm if (share == NULL) { 23594653Sdougm (void) printf(gettext( 23604653Sdougm "Share does not exist in group %s\n"), 23614653Sdougm groupname, sharepath); 23624653Sdougm ret = SA_NO_SUCH_PATH; 2363*5089Sdougm } else { 2364*5089Sdougm /* if ZFS and OK, then only group */ 2365*5089Sdougm ret = zfscheck(group, share); 2366*5089Sdougm if (ret == SA_OK && 2367*5089Sdougm sa_group_is_zfs(group)) 2368*5089Sdougm share = NULL; 2369*5089Sdougm if (ret == SA_NOT_ALLOWED) 2370*5089Sdougm (void) printf(gettext( 2371*5089Sdougm "Properties on ZFS group shares " 2372*5089Sdougm "not supported: %s\n"), sharepath); 23734653Sdougm } 23743034Sdougm } 23754653Sdougm if (ret == SA_OK) { 23764653Sdougm /* group must exist */ 23774653Sdougm ret = valid_options(optlist, protocol, 23784653Sdougm share == NULL ? group : share, NULL); 23794653Sdougm if (ret == SA_OK && !dryrun) { 23804653Sdougm if (share != NULL) 23814653Sdougm change |= add_optionset(share, optlist, 23824653Sdougm protocol, &ret); 23834653Sdougm else 23844653Sdougm change |= add_optionset(group, optlist, 23854653Sdougm protocol, &ret); 23864653Sdougm if (ret == SA_OK && change) 23874653Sdougm worklist = add_list(worklist, group, 23884653Sdougm share); 23894653Sdougm } 23903034Sdougm } 23914653Sdougm free_opt(optlist); 23923034Sdougm } else { 23933034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 23943034Sdougm ret = SA_NO_SUCH_GROUP; 23953034Sdougm } 23963034Sdougm /* 23973034Sdougm * we have a group and potentially legal additions 23983034Sdougm */ 23993034Sdougm 24004653Sdougm /* 24014653Sdougm * Commit to configuration if not a dryrunp and properties 24024653Sdougm * have changed. 24034653Sdougm */ 24044653Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 24053034Sdougm /* properties changed, so update all shares */ 24063910Sdougm (void) enable_all_groups(handle, worklist, 0, 0, protocol); 24074653Sdougm 24083034Sdougm if (worklist != NULL) 24094653Sdougm free_list(worklist); 24103034Sdougm return (ret); 24113034Sdougm } 24123034Sdougm 24133034Sdougm /* 24143034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 24153034Sdougm * 24163034Sdougm * This function implements "set" when a name space (-S) is 24173034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 24183034Sdougm * already been done. 24193034Sdougm */ 24203034Sdougm 24213034Sdougm static int 24223910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 24233910Sdougm char *protocol, char *sharepath, int dryrun, char *sectype) 24243034Sdougm { 24253034Sdougm sa_group_t group; 24263034Sdougm int ret = SA_OK; 24273034Sdougm int change = 0; 24283034Sdougm struct list *worklist = NULL; 24293034Sdougm 24303034Sdougm /* 24313034Sdougm * make sure protcol and sectype are valid 24323034Sdougm */ 24333034Sdougm 24343034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 24354653Sdougm (void) printf(gettext("Option space \"%s\" not valid " 24364653Sdougm "for protocol.\n"), sectype); 24374653Sdougm return (SA_INVALID_SECURITY); 24383034Sdougm } 24393034Sdougm 24403910Sdougm group = sa_get_group(handle, groupname); 24413034Sdougm if (group != NULL) { 24424653Sdougm sa_share_t share = NULL; 24434653Sdougm if (sharepath != NULL) { 24444653Sdougm share = sa_get_share(group, sharepath); 24454653Sdougm if (share == NULL) { 24464653Sdougm (void) printf(gettext( 24474653Sdougm "Share does not exist in group %s\n"), 24484653Sdougm groupname, sharepath); 24494653Sdougm ret = SA_NO_SUCH_PATH; 2450*5089Sdougm } else { 2451*5089Sdougm /* if ZFS and OK, then only group */ 2452*5089Sdougm ret = zfscheck(group, share); 2453*5089Sdougm if (ret == SA_OK && 2454*5089Sdougm sa_group_is_zfs(group)) 2455*5089Sdougm share = NULL; 2456*5089Sdougm if (ret == SA_NOT_ALLOWED) 2457*5089Sdougm (void) printf(gettext( 2458*5089Sdougm "Properties on ZFS group shares " 2459*5089Sdougm "not supported: %s\n"), sharepath); 24604653Sdougm } 24613034Sdougm } 24624653Sdougm if (ret == SA_OK) { 24634653Sdougm /* group must exist */ 24644653Sdougm ret = valid_options(optlist, protocol, 24654653Sdougm share == NULL ? group : share, sectype); 24664653Sdougm if (ret == SA_OK && !dryrun) { 24674653Sdougm if (share != NULL) 24684653Sdougm change = add_security(share, sectype, 24694653Sdougm optlist, protocol, &ret); 24704653Sdougm else 24714653Sdougm change = add_security(group, sectype, 24724653Sdougm optlist, protocol, &ret); 24734653Sdougm if (ret != SA_OK) 24744653Sdougm (void) printf(gettext( 24754653Sdougm "Could not set property: %s\n"), 24764653Sdougm sa_errorstr(ret)); 24774653Sdougm } 24784653Sdougm if (ret == SA_OK && change) 24794653Sdougm worklist = add_list(worklist, group, share); 24803034Sdougm } 24814653Sdougm free_opt(optlist); 24823034Sdougm } else { 24833034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 24843034Sdougm ret = SA_NO_SUCH_GROUP; 24853034Sdougm } 24863034Sdougm /* 24873034Sdougm * we have a group and potentially legal additions 24883034Sdougm */ 24893034Sdougm 24904653Sdougm /* Commit to configuration if not a dryrun */ 24913034Sdougm if (!dryrun && ret == 0) { 24924653Sdougm if (change && worklist != NULL) { 24934653Sdougm /* properties changed, so update all shares */ 24944653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 24954653Sdougm protocol); 24964653Sdougm } 24974653Sdougm ret = sa_update_config(handle); 24983034Sdougm } 24993034Sdougm if (worklist != NULL) 25004653Sdougm free_list(worklist); 25013034Sdougm return (ret); 25023034Sdougm } 25033034Sdougm 25043034Sdougm /* 25053034Sdougm * sa_set(flags, argc, argv) 25063034Sdougm * 25073034Sdougm * Implements the set subcommand. It keys off of -S to determine which 25083034Sdougm * set of operations to actually do. 25093034Sdougm */ 25103034Sdougm 25113034Sdougm int 25123910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 25133034Sdougm { 25143034Sdougm char *groupname; 25153034Sdougm int verbose = 0; 25163034Sdougm int dryrun = 0; 25173034Sdougm int c; 25183034Sdougm char *protocol = NULL; 25193034Sdougm int ret = SA_OK; 25203034Sdougm struct options *optlist = NULL; 25213034Sdougm char *sharepath = NULL; 25223034Sdougm char *optset = NULL; 25233034Sdougm int auth; 25243034Sdougm 25253034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 25264653Sdougm switch (c) { 25274653Sdougm case 'v': 25284653Sdougm verbose++; 25294653Sdougm break; 25304653Sdougm case 'n': 25314653Sdougm dryrun++; 25324653Sdougm break; 25334653Sdougm case 'P': 25344653Sdougm protocol = optarg; 25354653Sdougm if (!sa_valid_protocol(protocol)) { 25364653Sdougm (void) printf(gettext( 25374653Sdougm "Invalid protocol specified: %s\n"), 25384653Sdougm protocol); 25394653Sdougm return (SA_INVALID_PROTOCOL); 25404653Sdougm } 25414653Sdougm break; 25424653Sdougm case 'p': 25434653Sdougm ret = add_opt(&optlist, optarg, 0); 25444653Sdougm switch (ret) { 25454653Sdougm case OPT_ADD_SYNTAX: 25464653Sdougm (void) printf(gettext("Property syntax error:" 25474653Sdougm " %s\n"), optarg); 25484653Sdougm return (SA_SYNTAX_ERR); 25494653Sdougm case OPT_ADD_MEMORY: 25504653Sdougm (void) printf(gettext("No memory to set " 25514653Sdougm "property: %s\n"), optarg); 25524653Sdougm return (SA_NO_MEMORY); 25534653Sdougm default: 25544653Sdougm break; 25554653Sdougm } 25564653Sdougm break; 25574653Sdougm case 's': 25584653Sdougm sharepath = optarg; 25594653Sdougm break; 25604653Sdougm case 'S': 25614653Sdougm optset = optarg; 25624653Sdougm break; 25634653Sdougm default: 25644653Sdougm case 'h': 25654653Sdougm case '?': 25664653Sdougm (void) printf(gettext("usage: %s\n"), 25674653Sdougm sa_get_usage(USAGE_SET)); 25684653Sdougm return (SA_OK); 25693034Sdougm } 25703034Sdougm } 25713034Sdougm 25723034Sdougm if (optlist != NULL) 25734653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 25743034Sdougm 25753034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 25764653Sdougm protocol == NULL || ret != OPT_ADD_OK) { 25774653Sdougm char *sep = "\t"; 25784653Sdougm 25794653Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 25804653Sdougm if (optind >= argc) { 25814653Sdougm (void) printf(gettext("%sgroup must be specified"), 25824653Sdougm sep); 25834653Sdougm sep = ", "; 25844653Sdougm } 25854653Sdougm if (optlist == NULL) { 25864653Sdougm (void) printf(gettext("%sat least one property must be" 25874653Sdougm " specified"), sep); 25884653Sdougm sep = ", "; 25894653Sdougm } 25904653Sdougm if (protocol == NULL) { 25914653Sdougm (void) printf(gettext("%sprotocol must be specified"), 25924653Sdougm sep); 25934653Sdougm sep = ", "; 25944653Sdougm } 25954653Sdougm (void) printf("\n"); 25964653Sdougm ret = SA_SYNTAX_ERR; 25973034Sdougm } else { 25983034Sdougm /* 2599*5089Sdougm * Group already exists so we can proceed after a few 2600*5089Sdougm * additional checks related to ZFS handling. 26013034Sdougm */ 26023034Sdougm 26034653Sdougm groupname = argv[optind]; 2604*5089Sdougm if (strcmp(groupname, "zfs") == 0) { 2605*5089Sdougm (void) printf(gettext("Changing properties for group " 2606*5089Sdougm "\"zfs\" not allowed\n")); 2607*5089Sdougm return (SA_NOT_ALLOWED); 2608*5089Sdougm } 2609*5089Sdougm 26104653Sdougm auth = check_authorizations(groupname, flags); 26114653Sdougm if (optset == NULL) 26124653Sdougm ret = basic_set(handle, groupname, optlist, protocol, 26134653Sdougm sharepath, dryrun); 26144653Sdougm else 26154653Sdougm ret = space_set(handle, groupname, optlist, protocol, 26164653Sdougm sharepath, dryrun, optset); 26174653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 26184653Sdougm (void) printf(gettext("Command would fail: %s\n"), 26194653Sdougm sa_errorstr(SA_NO_PERMISSION)); 26204653Sdougm } 26213034Sdougm } 26223034Sdougm return (ret); 26233034Sdougm } 26243034Sdougm 26253034Sdougm /* 26263034Sdougm * remove_options(group, optlist, proto, *err) 26273034Sdougm * 26284653Sdougm * Helper function to actually remove options from a group after all 26293034Sdougm * preprocessing is done. 26303034Sdougm */ 26313034Sdougm 26323034Sdougm static int 26333034Sdougm remove_options(sa_group_t group, struct options *optlist, 26343034Sdougm char *proto, int *err) 26353034Sdougm { 26363034Sdougm struct options *cur; 26373034Sdougm sa_optionset_t optionset; 26383034Sdougm sa_property_t prop; 26393034Sdougm int change = 0; 26403034Sdougm int ret = SA_OK; 26413034Sdougm 26423034Sdougm optionset = sa_get_optionset(group, proto); 26433034Sdougm if (optionset != NULL) { 26444653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 26454653Sdougm prop = sa_get_property(optionset, cur->optname); 26464653Sdougm if (prop != NULL) { 26474653Sdougm ret = sa_remove_property(prop); 26484653Sdougm if (ret != SA_OK) 26494653Sdougm break; 26504653Sdougm change = 1; 26514653Sdougm } 26523034Sdougm } 26533034Sdougm } 26543034Sdougm if (ret == SA_OK && change) 26554653Sdougm ret = sa_commit_properties(optionset, 0); 26563034Sdougm 26573034Sdougm if (err != NULL) 26584653Sdougm *err = ret; 26593034Sdougm return (change); 26603034Sdougm } 26613034Sdougm 26623034Sdougm /* 26633034Sdougm * valid_unset(group, optlist, proto) 26643034Sdougm * 26653034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 26663034Sdougm * error if a property doesn't exist. 26673034Sdougm */ 26683034Sdougm 26693034Sdougm static int 26703034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 26713034Sdougm { 26723034Sdougm struct options *cur; 26733034Sdougm sa_optionset_t optionset; 26743034Sdougm sa_property_t prop; 26753034Sdougm int ret = SA_OK; 26763034Sdougm 26773034Sdougm optionset = sa_get_optionset(group, proto); 26783034Sdougm if (optionset != NULL) { 26794653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 26804653Sdougm prop = sa_get_property(optionset, cur->optname); 26814653Sdougm if (prop == NULL) { 26824653Sdougm (void) printf(gettext( 26834653Sdougm "Could not unset property %s: not set\n"), 26844653Sdougm cur->optname); 26854653Sdougm ret = SA_NO_SUCH_PROP; 26864653Sdougm } 26873034Sdougm } 26883034Sdougm } 26893034Sdougm return (ret); 26903034Sdougm } 26913034Sdougm 26923034Sdougm /* 26933034Sdougm * valid_unset_security(group, optlist, proto) 26943034Sdougm * 26953034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 26963034Sdougm * error if a property doesn't exist. 26973034Sdougm */ 26983034Sdougm 26993034Sdougm static int 27003034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 27013034Sdougm char *sectype) 27023034Sdougm { 27033034Sdougm struct options *cur; 27043034Sdougm sa_security_t security; 27053034Sdougm sa_property_t prop; 27063034Sdougm int ret = SA_OK; 27073034Sdougm char *sec; 27083034Sdougm 27093034Sdougm sec = sa_proto_space_alias(proto, sectype); 27103034Sdougm security = sa_get_security(group, sec, proto); 27113034Sdougm if (security != NULL) { 27124653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 27134653Sdougm prop = sa_get_property(security, cur->optname); 27144653Sdougm if (prop == NULL) { 27154653Sdougm (void) printf(gettext( 27164653Sdougm "Could not unset property %s: not set\n"), 27174653Sdougm cur->optname); 27184653Sdougm ret = SA_NO_SUCH_PROP; 27194653Sdougm } 27203034Sdougm } 27213034Sdougm } else { 27224653Sdougm (void) printf(gettext( 27234653Sdougm "Could not unset %s: space not defined\n"), sectype); 27244653Sdougm ret = SA_NO_SUCH_SECURITY; 27253034Sdougm } 27263034Sdougm if (sec != NULL) 27274653Sdougm sa_free_attr_string(sec); 27283034Sdougm return (ret); 27293034Sdougm } 27303034Sdougm 27313034Sdougm /* 27323034Sdougm * remove_security(group, optlist, proto) 27333034Sdougm * 27343034Sdougm * Remove the properties since they were checked as valid. 27353034Sdougm */ 27363034Sdougm 27373034Sdougm static int 27383034Sdougm remove_security(sa_group_t group, char *sectype, 27393034Sdougm struct options *optlist, char *proto, int *err) 27403034Sdougm { 27413034Sdougm sa_security_t security; 27423034Sdougm int ret = SA_OK; 27433034Sdougm int change = 0; 27443034Sdougm 27453034Sdougm sectype = sa_proto_space_alias(proto, sectype); 27463034Sdougm security = sa_get_security(group, sectype, proto); 27473034Sdougm if (sectype != NULL) 27484653Sdougm sa_free_attr_string(sectype); 27493034Sdougm 27503034Sdougm if (security != NULL) { 27514653Sdougm while (optlist != NULL) { 27524653Sdougm sa_property_t prop; 27534653Sdougm prop = sa_get_property(security, optlist->optname); 27544653Sdougm if (prop != NULL) { 27554653Sdougm ret = sa_remove_property(prop); 27564653Sdougm if (ret != SA_OK) 27574653Sdougm break; 27584653Sdougm change = 1; 27594653Sdougm } 27604653Sdougm optlist = optlist->next; 27613034Sdougm } 27623034Sdougm /* 27633034Sdougm * when done, properties may have all been removed but 27643034Sdougm * we need to keep the security type itself until 27653034Sdougm * explicitly removed. 27663034Sdougm */ 27674653Sdougm if (ret == SA_OK && change) 27684653Sdougm ret = sa_commit_properties(security, 0); 27693034Sdougm } else { 27704653Sdougm ret = SA_NO_SUCH_PROP; 27713034Sdougm } 27723034Sdougm if (err != NULL) 27734653Sdougm *err = ret; 27743034Sdougm return (change); 27753034Sdougm } 27763034Sdougm 27773034Sdougm /* 27783034Sdougm * basic_unset(groupname, optlist, protocol, sharepath, dryrun) 27793034Sdougm * 27804653Sdougm * Unset non-named optionset properties. 27813034Sdougm */ 27823034Sdougm 27833034Sdougm static int 27843910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 27853910Sdougm char *protocol, char *sharepath, int dryrun) 27863034Sdougm { 27873034Sdougm sa_group_t group; 27883034Sdougm int ret = SA_OK; 27893034Sdougm int change = 0; 27903034Sdougm struct list *worklist = NULL; 27914653Sdougm sa_share_t share = NULL; 27923034Sdougm 27933910Sdougm group = sa_get_group(handle, groupname); 27944653Sdougm if (group == NULL) 27954653Sdougm return (ret); 27964653Sdougm 27974653Sdougm if (sharepath != NULL) { 27983034Sdougm share = sa_get_share(group, sharepath); 27993034Sdougm if (share == NULL) { 28004653Sdougm (void) printf(gettext( 28014653Sdougm "Share does not exist in group %s\n"), 28024653Sdougm groupname, sharepath); 28034653Sdougm ret = SA_NO_SUCH_PATH; 28043034Sdougm } 28054653Sdougm } 28064653Sdougm if (ret == SA_OK) { 28073034Sdougm /* group must exist */ 28083034Sdougm ret = valid_unset(share != NULL ? share : group, 28094653Sdougm optlist, protocol); 28103034Sdougm if (ret == SA_OK && !dryrun) { 28114653Sdougm if (share != NULL) { 28124653Sdougm sa_optionset_t optionset; 28134653Sdougm sa_property_t prop; 28144653Sdougm change |= remove_options(share, optlist, 28154653Sdougm protocol, &ret); 28164653Sdougm /* 28174653Sdougm * If a share optionset is 28184653Sdougm * empty, remove it. 28194653Sdougm */ 28204653Sdougm optionset = sa_get_optionset((sa_share_t)share, 28214653Sdougm protocol); 28224653Sdougm if (optionset != NULL) { 28234653Sdougm prop = sa_get_property(optionset, NULL); 28244653Sdougm if (prop == NULL) 28254653Sdougm (void) sa_destroy_optionset( 28264653Sdougm optionset); 28274653Sdougm } 28284653Sdougm } else { 28294653Sdougm change |= remove_options(group, 28304653Sdougm optlist, protocol, &ret); 28313034Sdougm } 28324653Sdougm if (ret == SA_OK && change) 28334653Sdougm worklist = add_list(worklist, group, 28344653Sdougm share); 28354653Sdougm if (ret != SA_OK) 28364653Sdougm (void) printf(gettext( 28374653Sdougm "Could not remove properties: " 28384653Sdougm "%s\n"), sa_errorstr(ret)); 28393034Sdougm } 28404653Sdougm } else { 28414653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 28424653Sdougm groupname); 28433034Sdougm ret = SA_NO_SUCH_GROUP; 28443034Sdougm } 28454653Sdougm free_opt(optlist); 28463034Sdougm 28473034Sdougm /* 28484653Sdougm * We have a group and potentially legal additions 28494653Sdougm * 28504653Sdougm * Commit to configuration if not a dryrun 28513034Sdougm */ 28523034Sdougm if (!dryrun && ret == SA_OK) { 28534653Sdougm if (change && worklist != NULL) { 28544653Sdougm /* properties changed, so update all shares */ 28554653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 28564653Sdougm protocol); 28574653Sdougm } 28583034Sdougm } 28593034Sdougm if (worklist != NULL) 28604653Sdougm free_list(worklist); 28613034Sdougm return (ret); 28623034Sdougm } 28633034Sdougm 28643034Sdougm /* 28653034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 28663034Sdougm * 28674653Sdougm * Unset named optionset properties. 28683034Sdougm */ 28693034Sdougm static int 28703910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 28713910Sdougm char *protocol, char *sharepath, int dryrun, char *sectype) 28723034Sdougm { 28733034Sdougm sa_group_t group; 28743034Sdougm int ret = SA_OK; 28753034Sdougm int change = 0; 28763034Sdougm struct list *worklist = NULL; 28774653Sdougm sa_share_t share = NULL; 28783034Sdougm 28793910Sdougm group = sa_get_group(handle, groupname); 28804653Sdougm if (group == NULL) { 28814653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 28824653Sdougm return (SA_NO_SUCH_GROUP); 28834653Sdougm } 28844653Sdougm if (sharepath != NULL) { 28853034Sdougm share = sa_get_share(group, sharepath); 28863034Sdougm if (share == NULL) { 28874653Sdougm (void) printf(gettext( 28884653Sdougm "Share does not exist in group %s\n"), 28894653Sdougm groupname, sharepath); 28904653Sdougm return (SA_NO_SUCH_PATH); 28913034Sdougm } 28924653Sdougm } 28934653Sdougm ret = valid_unset_security(share != NULL ? share : group, optlist, 28944653Sdougm protocol, sectype); 28954653Sdougm 28964653Sdougm if (ret == SA_OK && !dryrun) { 28974653Sdougm if (optlist != NULL) { 28983034Sdougm if (share != NULL) { 28994653Sdougm sa_security_t optionset; 29004653Sdougm sa_property_t prop; 29014653Sdougm change = remove_security(share, 29024653Sdougm sectype, optlist, protocol, &ret); 29034653Sdougm 29044653Sdougm /* If a share security is empty, remove it */ 29054653Sdougm optionset = sa_get_security((sa_group_t)share, 29064653Sdougm sectype, protocol); 29074653Sdougm if (optionset != NULL) { 29084653Sdougm prop = sa_get_property(optionset, 29094653Sdougm NULL); 29104653Sdougm if (prop == NULL) 29114653Sdougm ret = sa_destroy_security( 29124653Sdougm optionset); 29134653Sdougm } 29143034Sdougm } else { 29154653Sdougm change = remove_security(group, sectype, 29164653Sdougm optlist, protocol, &ret); 29173034Sdougm } 29184653Sdougm } else { 29193034Sdougm sa_security_t security; 29203034Sdougm char *sec; 29213034Sdougm sec = sa_proto_space_alias(protocol, sectype); 29223034Sdougm security = sa_get_security(group, sec, protocol); 29233034Sdougm if (sec != NULL) 29244653Sdougm sa_free_attr_string(sec); 29253034Sdougm if (security != NULL) { 29264653Sdougm ret = sa_destroy_security(security); 29274653Sdougm if (ret == SA_OK) 29284653Sdougm change = 1; 29293034Sdougm } else { 29304653Sdougm ret = SA_NO_SUCH_PROP; 29313034Sdougm } 29324653Sdougm } 29334653Sdougm if (ret != SA_OK) 29343034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 29354653Sdougm sa_errorstr(ret)); 29363034Sdougm } 29374653Sdougm 29384653Sdougm if (ret == SA_OK && change) 29394653Sdougm worklist = add_list(worklist, group, 0); 29404653Sdougm 29413034Sdougm free_opt(optlist); 29423034Sdougm /* 29434653Sdougm * We have a group and potentially legal additions 29443034Sdougm */ 29453034Sdougm 29464653Sdougm /* Commit to configuration if not a dryrun */ 29473034Sdougm if (!dryrun && ret == 0) { 29483034Sdougm /* properties changed, so update all shares */ 29494653Sdougm if (change && worklist != NULL) 29504653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 29514653Sdougm protocol); 29524653Sdougm ret = sa_update_config(handle); 29533034Sdougm } 29543034Sdougm if (worklist != NULL) 29554653Sdougm free_list(worklist); 29563034Sdougm return (ret); 29573034Sdougm } 29583034Sdougm 29593034Sdougm /* 29603034Sdougm * sa_unset(flags, argc, argv) 29613034Sdougm * 29624653Sdougm * Implements the unset subcommand. Parsing done here and then basic 29633034Sdougm * or space versions of the real code are called. 29643034Sdougm */ 29653034Sdougm 29663034Sdougm int 29673910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 29683034Sdougm { 29693034Sdougm char *groupname; 29703034Sdougm int verbose = 0; 29713034Sdougm int dryrun = 0; 29723034Sdougm int c; 29733034Sdougm char *protocol = NULL; 29743034Sdougm int ret = SA_OK; 29753034Sdougm struct options *optlist = NULL; 29763034Sdougm char *sharepath = NULL; 29773034Sdougm char *optset = NULL; 29783034Sdougm int auth; 29793034Sdougm 29803034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 29814653Sdougm switch (c) { 29824653Sdougm case 'v': 29834653Sdougm verbose++; 29844653Sdougm break; 29854653Sdougm case 'n': 29864653Sdougm dryrun++; 29874653Sdougm break; 29884653Sdougm case 'P': 29894653Sdougm protocol = optarg; 29904653Sdougm if (!sa_valid_protocol(protocol)) { 29914653Sdougm (void) printf(gettext( 29924653Sdougm "Invalid protocol specified: %s\n"), 29934653Sdougm protocol); 29944653Sdougm return (SA_INVALID_PROTOCOL); 29954653Sdougm } 29964653Sdougm break; 29974653Sdougm case 'p': 29984653Sdougm ret = add_opt(&optlist, optarg, 1); 29994653Sdougm switch (ret) { 30004653Sdougm case OPT_ADD_SYNTAX: 30014653Sdougm (void) printf(gettext("Property syntax error " 30024653Sdougm "for property %s\n"), optarg); 30034653Sdougm return (SA_SYNTAX_ERR); 30044653Sdougm 30054653Sdougm case OPT_ADD_PROPERTY: 30064653Sdougm (void) printf(gettext("Properties need to be " 30074653Sdougm "set with set command: %s\n"), optarg); 30084653Sdougm return (SA_SYNTAX_ERR); 30094653Sdougm 30104653Sdougm default: 30114653Sdougm break; 30124653Sdougm } 30134653Sdougm break; 30144653Sdougm case 's': 30154653Sdougm sharepath = optarg; 30164653Sdougm break; 30174653Sdougm case 'S': 30184653Sdougm optset = optarg; 30194653Sdougm break; 30204653Sdougm default: 30214653Sdougm case 'h': 30224653Sdougm case '?': 30234653Sdougm (void) printf(gettext("usage: %s\n"), 30244653Sdougm sa_get_usage(USAGE_UNSET)); 30254653Sdougm return (SA_OK); 30263034Sdougm } 30273034Sdougm } 30283034Sdougm 30293034Sdougm if (optlist != NULL) 30304653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 30313034Sdougm 30323034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 30333034Sdougm protocol == NULL) { 30344653Sdougm char *sep = "\t"; 30354653Sdougm (void) printf(gettext("usage: %s\n"), 30364653Sdougm sa_get_usage(USAGE_UNSET)); 30374653Sdougm if (optind >= argc) { 30384653Sdougm (void) printf(gettext("%sgroup must be specified"), 30394653Sdougm sep); 30404653Sdougm sep = ", "; 30414653Sdougm } 30424653Sdougm if (optlist == NULL) { 30434653Sdougm (void) printf(gettext("%sat least one property must " 30444653Sdougm "be specified"), sep); 30454653Sdougm sep = ", "; 30464653Sdougm } 30474653Sdougm if (protocol == NULL) { 30484653Sdougm (void) printf(gettext("%sprotocol must be specified"), 30494653Sdougm sep); 30504653Sdougm sep = ", "; 30514653Sdougm } 30524653Sdougm (void) printf("\n"); 30534653Sdougm ret = SA_SYNTAX_ERR; 30543034Sdougm } else { 30553034Sdougm 30563034Sdougm /* 30574653Sdougm * If a group already exists, we can only add a new 30583034Sdougm * protocol to it and not create a new one or add the 30593034Sdougm * same protocol again. 30603034Sdougm */ 30613034Sdougm 30624653Sdougm groupname = argv[optind]; 30634653Sdougm auth = check_authorizations(groupname, flags); 30644653Sdougm if (optset == NULL) 30654653Sdougm ret = basic_unset(handle, groupname, optlist, protocol, 30664653Sdougm sharepath, dryrun); 30674653Sdougm else 30684653Sdougm ret = space_unset(handle, groupname, optlist, protocol, 30694653Sdougm sharepath, dryrun, optset); 30704653Sdougm 30714653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 30724653Sdougm (void) printf(gettext("Command would fail: %s\n"), 30734653Sdougm sa_errorstr(SA_NO_PERMISSION)); 30743034Sdougm } 30753034Sdougm return (ret); 30763034Sdougm } 30773034Sdougm 30783034Sdougm /* 30793034Sdougm * sa_enable_group(flags, argc, argv) 30803034Sdougm * 30813034Sdougm * Implements the enable subcommand 30823034Sdougm */ 30833034Sdougm 30843034Sdougm int 30853910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 30863034Sdougm { 30873034Sdougm int verbose = 0; 30883034Sdougm int dryrun = 0; 30893034Sdougm int all = 0; 30903034Sdougm int c; 30913034Sdougm int ret = SA_OK; 30923034Sdougm char *protocol = NULL; 30933034Sdougm char *state; 30943034Sdougm struct list *worklist = NULL; 30953034Sdougm int auth = 1; 30964653Sdougm sa_group_t group; 30973034Sdougm 30983034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 30994653Sdougm switch (c) { 31004653Sdougm case 'a': 31014653Sdougm all = 1; 31024653Sdougm break; 31034653Sdougm case 'n': 31044653Sdougm dryrun++; 31054653Sdougm break; 31064653Sdougm case 'P': 31074653Sdougm protocol = optarg; 31084653Sdougm if (!sa_valid_protocol(protocol)) { 31094653Sdougm (void) printf(gettext( 31104653Sdougm "Invalid protocol specified: %s\n"), 31113034Sdougm protocol); 31124653Sdougm return (SA_INVALID_PROTOCOL); 31134653Sdougm } 31144653Sdougm break; 31154653Sdougm case 'v': 31164653Sdougm verbose++; 31174653Sdougm break; 31184653Sdougm default: 31194653Sdougm case 'h': 31204653Sdougm case '?': 31214653Sdougm (void) printf(gettext("usage: %s\n"), 31224653Sdougm sa_get_usage(USAGE_ENABLE)); 31234653Sdougm return (0); 31243034Sdougm } 31253034Sdougm } 31263034Sdougm 31273034Sdougm if (optind == argc && !all) { 31284653Sdougm (void) printf(gettext("usage: %s\n"), 31294653Sdougm sa_get_usage(USAGE_ENABLE)); 31304653Sdougm (void) printf(gettext("\tmust specify group\n")); 31314653Sdougm return (SA_NO_SUCH_PATH); 31324653Sdougm } 31334653Sdougm if (!all) { 31343034Sdougm while (optind < argc) { 31354653Sdougm group = sa_get_group(handle, argv[optind]); 31364653Sdougm if (group != NULL) { 31374653Sdougm auth &= check_authorizations(argv[optind], 31384653Sdougm flags); 31394653Sdougm state = sa_get_group_attr(group, "state"); 31404653Sdougm if (state != NULL && 31414653Sdougm strcmp(state, "enabled") == 0) { 31424653Sdougm /* already enabled */ 31434653Sdougm if (verbose) 31444653Sdougm (void) printf(gettext( 31454653Sdougm "Group \"%s\" is already " 31464653Sdougm "enabled\n"), 31474653Sdougm argv[optind]); 31484653Sdougm ret = SA_BUSY; /* already enabled */ 31494653Sdougm } else { 31504653Sdougm worklist = add_list(worklist, group, 31514653Sdougm 0); 31524653Sdougm if (verbose) 31534653Sdougm (void) printf(gettext( 31544653Sdougm "Enabling group \"%s\"\n"), 31554653Sdougm argv[optind]); 31564653Sdougm } 31574653Sdougm if (state != NULL) 31584653Sdougm sa_free_attr_string(state); 31593034Sdougm } else { 31604653Sdougm ret = SA_NO_SUCH_GROUP; 31613034Sdougm } 31624653Sdougm optind++; 31633034Sdougm } 31644653Sdougm } else { 31654653Sdougm for (group = sa_get_group(handle, NULL); 31664653Sdougm group != NULL; 31673034Sdougm group = sa_get_next_group(group)) { 31684653Sdougm worklist = add_list(worklist, group, 0); 31693034Sdougm } 31704653Sdougm } 31714653Sdougm if (!dryrun && ret == SA_OK) 31723910Sdougm ret = enable_all_groups(handle, worklist, 1, 0, NULL); 31734653Sdougm 31744653Sdougm if (ret != SA_OK && ret != SA_BUSY) 31753034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 31764653Sdougm sa_errorstr(ret)); 31774653Sdougm if (ret == SA_BUSY) 31783034Sdougm ret = SA_OK; 31794653Sdougm 31803034Sdougm if (worklist != NULL) 31814653Sdougm free_list(worklist); 31823034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 31834653Sdougm (void) printf(gettext("Command would fail: %s\n"), 31844653Sdougm sa_errorstr(SA_NO_PERMISSION)); 31853034Sdougm } 31863034Sdougm return (ret); 31873034Sdougm } 31883034Sdougm 31893034Sdougm /* 31903034Sdougm * disable_group(group, setstate) 31913034Sdougm * 31924653Sdougm * Disable all the shares in the specified group honoring the setstate 31933034Sdougm * argument. This is a helper for disable_all_groups in order to 31943034Sdougm * simplify regular and subgroup (zfs) disabling. Group has already 31953034Sdougm * been checked for non-NULL. 31963034Sdougm */ 31973034Sdougm 31983034Sdougm static int 31993034Sdougm disable_group(sa_group_t group) 32003034Sdougm { 32013034Sdougm sa_share_t share; 32023034Sdougm int ret = SA_OK; 32033034Sdougm 32043034Sdougm for (share = sa_get_share(group, NULL); 32053034Sdougm share != NULL && ret == SA_OK; 32063034Sdougm share = sa_get_next_share(share)) { 32074653Sdougm ret = sa_disable_share(share, NULL); 32084653Sdougm if (ret == SA_NO_SUCH_PATH) { 32094653Sdougm /* 32104653Sdougm * this is OK since the path is gone. we can't 32114653Sdougm * re-share it anyway so no error. 32124653Sdougm */ 32134653Sdougm ret = SA_OK; 32144653Sdougm } 32153034Sdougm } 32163034Sdougm return (ret); 32173034Sdougm } 32183034Sdougm 32193034Sdougm 32203034Sdougm /* 32213034Sdougm * disable_all_groups(work, setstate) 32223034Sdougm * 32233034Sdougm * helper function that disables the shares in the list of groups 32243034Sdougm * provided. It optionally marks the group as disabled. Used by both 32253034Sdougm * enable and start subcommands. 32263034Sdougm */ 32273034Sdougm 32283034Sdougm static int 32293910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 32303034Sdougm { 32313034Sdougm int ret = SA_OK; 32323034Sdougm sa_group_t subgroup, group; 32333034Sdougm 32343034Sdougm while (work != NULL && ret == SA_OK) { 32354653Sdougm group = (sa_group_t)work->item; 32364653Sdougm if (setstate) 32374653Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 32384653Sdougm if (ret == SA_OK) { 32394653Sdougm char *name; 32404653Sdougm name = sa_get_group_attr(group, "name"); 32414653Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 32424653Sdougm /* need to get the sub-groups for stopping */ 32434653Sdougm for (subgroup = sa_get_sub_group(group); 32444653Sdougm subgroup != NULL; 32454653Sdougm subgroup = sa_get_next_group(subgroup)) { 32464653Sdougm ret = disable_group(subgroup); 32474653Sdougm } 32484653Sdougm } else { 32494653Sdougm ret = disable_group(group); 32504653Sdougm } 32514653Sdougm /* 32524653Sdougm * We don't want to "disable" since it won't come 32534653Sdougm * up after a reboot. The SMF framework should do 32544653Sdougm * the right thing. On enable we do want to do 32554653Sdougm * something. 32564653Sdougm */ 32573034Sdougm } 32584653Sdougm work = work->next; 32593034Sdougm } 32603034Sdougm if (ret == SA_OK) 32614653Sdougm ret = sa_update_config(handle); 32623034Sdougm return (ret); 32633034Sdougm } 32643034Sdougm 32653034Sdougm /* 32663034Sdougm * sa_disable_group(flags, argc, argv) 32673034Sdougm * 32683034Sdougm * Implements the disable subcommand 32693034Sdougm */ 32703034Sdougm 32713034Sdougm int 32723910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 32733034Sdougm { 32743034Sdougm int verbose = 0; 32753034Sdougm int dryrun = 0; 32763034Sdougm int all = 0; 32773034Sdougm int c; 32783034Sdougm int ret = SA_OK; 32793034Sdougm char *protocol; 32803034Sdougm char *state; 32813034Sdougm struct list *worklist = NULL; 32824653Sdougm sa_group_t group; 32833034Sdougm int auth = 1; 32843034Sdougm 32853034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 32864653Sdougm switch (c) { 32874653Sdougm case 'a': 32884653Sdougm all = 1; 32894653Sdougm break; 32904653Sdougm case 'n': 32914653Sdougm dryrun++; 32924653Sdougm break; 32934653Sdougm case 'P': 32944653Sdougm protocol = optarg; 32954653Sdougm if (!sa_valid_protocol(protocol)) { 32964653Sdougm (void) printf(gettext( 32974653Sdougm "Invalid protocol specified: %s\n"), 32984653Sdougm protocol); 32994653Sdougm return (SA_INVALID_PROTOCOL); 33004653Sdougm } 33014653Sdougm break; 33024653Sdougm case 'v': 33034653Sdougm verbose++; 33044653Sdougm break; 33054653Sdougm default: 33064653Sdougm case 'h': 33074653Sdougm case '?': 33084653Sdougm (void) printf(gettext("usage: %s\n"), 33094653Sdougm sa_get_usage(USAGE_DISABLE)); 33104653Sdougm return (0); 33113034Sdougm } 33123034Sdougm } 33133034Sdougm 33143034Sdougm if (optind == argc && !all) { 33153034Sdougm (void) printf(gettext("usage: %s\n"), 33164653Sdougm sa_get_usage(USAGE_DISABLE)); 33173034Sdougm (void) printf(gettext("\tmust specify group\n")); 33184653Sdougm return (SA_NO_SUCH_PATH); 33194653Sdougm } 33204653Sdougm if (!all) { 33214653Sdougm while (optind < argc) { 33223910Sdougm group = sa_get_group(handle, argv[optind]); 33233034Sdougm if (group != NULL) { 33244653Sdougm auth &= check_authorizations(argv[optind], 33254653Sdougm flags); 33264653Sdougm state = sa_get_group_attr(group, "state"); 33274653Sdougm if (state == NULL || 33284653Sdougm strcmp(state, "disabled") == 0) { 33294653Sdougm /* already disabled */ 33304653Sdougm if (verbose) 33314653Sdougm (void) printf(gettext( 33324653Sdougm "Group \"%s\" is " 33334653Sdougm "already disabled\n"), 33344653Sdougm argv[optind]); 33354653Sdougm ret = SA_BUSY; /* already disable */ 33364653Sdougm } else { 33374653Sdougm worklist = add_list(worklist, group, 0); 33384653Sdougm if (verbose) 33394653Sdougm (void) printf(gettext( 33404653Sdougm "Disabling group " 33414653Sdougm "\"%s\"\n"), argv[optind]); 33424653Sdougm } 33434653Sdougm if (state != NULL) 33444653Sdougm sa_free_attr_string(state); 33453034Sdougm } else { 33464653Sdougm ret = SA_NO_SUCH_GROUP; 33473034Sdougm } 33483034Sdougm optind++; 33494653Sdougm } 33504653Sdougm } else { 33514653Sdougm for (group = sa_get_group(handle, NULL); 33524653Sdougm group != NULL; 33534653Sdougm group = sa_get_next_group(group)) 33543034Sdougm worklist = add_list(worklist, group, 0); 33553034Sdougm } 33564653Sdougm 33574653Sdougm if (ret == SA_OK && !dryrun) 33584653Sdougm ret = disable_all_groups(handle, worklist, 1); 33594653Sdougm if (ret != SA_OK && ret != SA_BUSY) 33604653Sdougm (void) printf(gettext("Could not disable group: %s\n"), 33614653Sdougm sa_errorstr(ret)); 33624653Sdougm if (ret == SA_BUSY) 33634653Sdougm ret = SA_OK; 33643034Sdougm if (worklist != NULL) 33654653Sdougm free_list(worklist); 33664653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 33674653Sdougm (void) printf(gettext("Command would fail: %s\n"), 33684653Sdougm sa_errorstr(SA_NO_PERMISSION)); 33693034Sdougm return (ret); 33703034Sdougm } 33713034Sdougm 33723034Sdougm /* 33733034Sdougm * sa_start_group(flags, argc, argv) 33743034Sdougm * 33753034Sdougm * Implements the start command. 33763034Sdougm * This is similar to enable except it doesn't change the state 33773034Sdougm * of the group(s) and only enables shares if the group is already 33783034Sdougm * enabled. 33793034Sdougm */ 33804653Sdougm /*ARGSUSED*/ 33813034Sdougm int 33823910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 33833034Sdougm { 33843034Sdougm int verbose = 0; 33853034Sdougm int all = 0; 33863034Sdougm int c; 33873034Sdougm int ret = SMF_EXIT_OK; 33883034Sdougm char *protocol = NULL; 33893034Sdougm char *state; 33903034Sdougm struct list *worklist = NULL; 33914653Sdougm sa_group_t group; 33923034Sdougm 33933034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 33944653Sdougm switch (c) { 33954653Sdougm case 'a': 33964653Sdougm all = 1; 33974653Sdougm break; 33984653Sdougm case 'P': 33994653Sdougm protocol = optarg; 34004653Sdougm if (!sa_valid_protocol(protocol)) { 34014653Sdougm (void) printf(gettext( 34024653Sdougm "Invalid protocol specified: %s\n"), 34033034Sdougm protocol); 34044653Sdougm return (SA_INVALID_PROTOCOL); 34054653Sdougm } 34064653Sdougm break; 34074653Sdougm case 'v': 34084653Sdougm verbose++; 34094653Sdougm break; 34104653Sdougm default: 34114653Sdougm case 'h': 34124653Sdougm case '?': 34134653Sdougm (void) printf(gettext("usage: %s\n"), 34144653Sdougm sa_get_usage(USAGE_START)); 34154653Sdougm return (SA_OK); 34163034Sdougm } 34173034Sdougm } 34183034Sdougm 34193034Sdougm if (optind == argc && !all) { 34203034Sdougm (void) printf(gettext("usage: %s\n"), 34214653Sdougm sa_get_usage(USAGE_START)); 34224653Sdougm return (SMF_EXIT_ERR_FATAL); 34234653Sdougm } 34244653Sdougm 34254653Sdougm if (!all) { 34264653Sdougm while (optind < argc) { 34273910Sdougm group = sa_get_group(handle, argv[optind]); 34283034Sdougm if (group != NULL) { 34294653Sdougm state = sa_get_group_attr(group, "state"); 34304653Sdougm if (state == NULL || 34314653Sdougm strcmp(state, "enabled") == 0) { 34324653Sdougm worklist = add_list(worklist, group, 0); 34334653Sdougm if (verbose) 34344653Sdougm (void) printf(gettext( 34354653Sdougm "Starting group \"%s\"\n"), 34364653Sdougm argv[optind]); 34374653Sdougm } else { 34384653Sdougm /* 34394653Sdougm * Determine if there are any 34404653Sdougm * protocols. if there aren't any, 34414653Sdougm * then there isn't anything to do in 34424653Sdougm * any case so no error. 34434653Sdougm */ 34444653Sdougm if (sa_get_optionset(group, 34454653Sdougm protocol) != NULL) { 34464653Sdougm ret = SMF_EXIT_OK; 34474653Sdougm } 34483034Sdougm } 34494653Sdougm if (state != NULL) 34504653Sdougm sa_free_attr_string(state); 34513034Sdougm } 34523034Sdougm optind++; 34534653Sdougm } 34544653Sdougm } else { 34554653Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 34564653Sdougm group = sa_get_next_group(group)) { 34573034Sdougm state = sa_get_group_attr(group, "state"); 34583034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 34594653Sdougm worklist = add_list(worklist, group, 0); 34603034Sdougm if (state != NULL) 34614653Sdougm sa_free_attr_string(state); 34623034Sdougm } 34633034Sdougm } 34644653Sdougm 34654653Sdougm (void) enable_all_groups(handle, worklist, 0, 1, NULL); 34664653Sdougm 34673034Sdougm if (worklist != NULL) 34684653Sdougm free_list(worklist); 34693034Sdougm return (ret); 34703034Sdougm } 34713034Sdougm 34723034Sdougm /* 34733034Sdougm * sa_stop_group(flags, argc, argv) 34743034Sdougm * 34753034Sdougm * Implements the stop command. 34763034Sdougm * This is similar to disable except it doesn't change the state 34773034Sdougm * of the group(s) and only disables shares if the group is already 34783034Sdougm * enabled. 34793034Sdougm */ 34804653Sdougm /*ARGSUSED*/ 34813034Sdougm int 34823910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 34833034Sdougm { 34843034Sdougm int verbose = 0; 34853034Sdougm int all = 0; 34863034Sdougm int c; 34873034Sdougm int ret = SMF_EXIT_OK; 34883034Sdougm char *protocol = NULL; 34893034Sdougm char *state; 34903034Sdougm struct list *worklist = NULL; 34914653Sdougm sa_group_t group; 34923034Sdougm 34933034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 34944653Sdougm switch (c) { 34954653Sdougm case 'a': 34964653Sdougm all = 1; 34974653Sdougm break; 34984653Sdougm case 'P': 34994653Sdougm protocol = optarg; 35004653Sdougm if (!sa_valid_protocol(protocol)) { 35014653Sdougm (void) printf(gettext( 35024653Sdougm "Invalid protocol specified: %s\n"), 35034653Sdougm protocol); 35044653Sdougm return (SA_INVALID_PROTOCOL); 35054653Sdougm } 35064653Sdougm break; 35074653Sdougm case 'v': 35084653Sdougm verbose++; 35094653Sdougm break; 35104653Sdougm default: 35114653Sdougm case 'h': 35124653Sdougm case '?': 35134653Sdougm (void) printf(gettext("usage: %s\n"), 35144653Sdougm sa_get_usage(USAGE_STOP)); 35154653Sdougm return (0); 35163034Sdougm } 35173034Sdougm } 35183034Sdougm 35193034Sdougm if (optind == argc && !all) { 35204653Sdougm (void) printf(gettext("usage: %s\n"), 35214653Sdougm sa_get_usage(USAGE_STOP)); 35224653Sdougm return (SMF_EXIT_ERR_FATAL); 35234653Sdougm } else if (!all) { 35244653Sdougm while (optind < argc) { 35253910Sdougm group = sa_get_group(handle, argv[optind]); 35263034Sdougm if (group != NULL) { 35274653Sdougm state = sa_get_group_attr(group, "state"); 35284653Sdougm if (state == NULL || 35294653Sdougm strcmp(state, "enabled") == 0) { 35304653Sdougm worklist = add_list(worklist, group, 0); 35314653Sdougm if (verbose) 35324653Sdougm (void) printf(gettext( 35334653Sdougm "Stopping group \"%s\"\n"), 35344653Sdougm argv[optind]); 35354653Sdougm } else { 35364653Sdougm ret = SMF_EXIT_OK; 35374653Sdougm } 35384653Sdougm if (state != NULL) 35394653Sdougm sa_free_attr_string(state); 35403034Sdougm } 35413034Sdougm optind++; 35424653Sdougm } 35434653Sdougm } else { 35444653Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 35454653Sdougm group = sa_get_next_group(group)) { 35463034Sdougm state = sa_get_group_attr(group, "state"); 35473034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 35484653Sdougm worklist = add_list(worklist, group, 0); 35493034Sdougm if (state != NULL) 35504653Sdougm sa_free_attr_string(state); 35513034Sdougm } 35523034Sdougm } 35534653Sdougm 35544653Sdougm (void) disable_all_groups(handle, worklist, 0); 35554653Sdougm ret = sa_update_config(handle); 35564653Sdougm 35573034Sdougm if (worklist != NULL) 35584653Sdougm free_list(worklist); 35593034Sdougm return (ret); 35603034Sdougm } 35613034Sdougm 35623034Sdougm /* 35633034Sdougm * remove_all_options(share, proto) 35643034Sdougm * 35653034Sdougm * Removes all options on a share. 35663034Sdougm */ 35673034Sdougm 35683034Sdougm static void 35693034Sdougm remove_all_options(sa_share_t share, char *proto) 35703034Sdougm { 35713034Sdougm sa_optionset_t optionset; 35723034Sdougm sa_security_t security; 35733034Sdougm sa_security_t prevsec = NULL; 35743034Sdougm 35753034Sdougm optionset = sa_get_optionset(share, proto); 35763034Sdougm if (optionset != NULL) 35774653Sdougm (void) sa_destroy_optionset(optionset); 35783034Sdougm for (security = sa_get_security(share, NULL, NULL); 35793034Sdougm security != NULL; 35803034Sdougm security = sa_get_next_security(security)) { 35814653Sdougm char *type; 35823034Sdougm /* 35834653Sdougm * We walk through the list. prevsec keeps the 35843034Sdougm * previous security so we can delete it without 35853034Sdougm * destroying the list. 35863034Sdougm */ 35874653Sdougm if (prevsec != NULL) { 35884653Sdougm /* remove the previously seen security */ 35894653Sdougm (void) sa_destroy_security(prevsec); 35904653Sdougm /* set to NULL so we don't try multiple times */ 35914653Sdougm prevsec = NULL; 35924653Sdougm } 35934653Sdougm type = sa_get_security_attr(security, "type"); 35944653Sdougm if (type != NULL) { 35954653Sdougm /* 35964653Sdougm * if the security matches the specified protocol, we 35974653Sdougm * want to remove it. prevsec holds it until either 35984653Sdougm * the next pass or we fall out of the loop. 35994653Sdougm */ 36004653Sdougm if (strcmp(type, proto) == 0) 36014653Sdougm prevsec = security; 36024653Sdougm sa_free_attr_string(type); 36034653Sdougm } 36043034Sdougm } 36053034Sdougm /* in case there is one left */ 36063034Sdougm if (prevsec != NULL) 36074653Sdougm (void) sa_destroy_security(prevsec); 36083034Sdougm } 36093034Sdougm 36103034Sdougm 36113034Sdougm /* 36123034Sdougm * for legacy support, we need to handle the old syntax. This is what 36133034Sdougm * we get if sharemgr is called with the name "share" rather than 36143034Sdougm * sharemgr. 36153034Sdougm */ 36163034Sdougm 36173034Sdougm static int 36183034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 36193034Sdougm { 36203034Sdougm int err; 36213034Sdougm 36223034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 36233034Sdougm if (err > buffsize) 36244653Sdougm return (-1); 36253034Sdougm return (0); 36263034Sdougm } 36273034Sdougm 36283034Sdougm 36293034Sdougm /* 36303034Sdougm * check_legacy_cmd(proto, cmd) 36313034Sdougm * 36323034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 36333034Sdougm * executable. 36343034Sdougm */ 36353034Sdougm 36363034Sdougm static int 36373034Sdougm check_legacy_cmd(char *path) 36383034Sdougm { 36393034Sdougm struct stat st; 36403034Sdougm int ret = 0; 36413034Sdougm 36423034Sdougm if (stat(path, &st) == 0) { 36434653Sdougm if (S_ISREG(st.st_mode) && 36444653Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 36454653Sdougm ret = 1; 36463034Sdougm } 36473034Sdougm return (ret); 36483034Sdougm } 36493034Sdougm 36503034Sdougm /* 36513034Sdougm * run_legacy_command(proto, cmd, argv) 36523034Sdougm * 36534653Sdougm * We know the command exists, so attempt to execute it with all the 36543034Sdougm * arguments. This implements full legacy share support for those 36553034Sdougm * protocols that don't have plugin providers. 36563034Sdougm */ 36573034Sdougm 36583034Sdougm static int 36593034Sdougm run_legacy_command(char *path, char *argv[]) 36603034Sdougm { 36613034Sdougm int ret; 36623034Sdougm 36633034Sdougm ret = execv(path, argv); 36643034Sdougm if (ret < 0) { 36654653Sdougm switch (errno) { 36664653Sdougm case EACCES: 36674653Sdougm ret = SA_NO_PERMISSION; 36684653Sdougm break; 36694653Sdougm default: 36704653Sdougm ret = SA_SYSTEM_ERR; 36714653Sdougm break; 36724653Sdougm } 36733034Sdougm } 36743034Sdougm return (ret); 36753034Sdougm } 36763034Sdougm 36773034Sdougm /* 36783348Sdougm * out_share(out, group, proto) 36793034Sdougm * 36803034Sdougm * Display the share information in the format that the "share" 36813034Sdougm * command has traditionally used. 36823034Sdougm */ 36833034Sdougm 36843034Sdougm static void 36853348Sdougm out_share(FILE *out, sa_group_t group, char *proto) 36863034Sdougm { 36873034Sdougm sa_share_t share; 36883034Sdougm char resfmt[128]; 36893034Sdougm 36904653Sdougm for (share = sa_get_share(group, NULL); 36914653Sdougm share != NULL; 36924653Sdougm share = sa_get_next_share(share)) { 36934653Sdougm char *path; 36944653Sdougm char *type; 36954653Sdougm char *resource; 36964653Sdougm char *description; 36974653Sdougm char *groupname; 36984653Sdougm char *sharedstate; 36994653Sdougm int shared = 1; 37004653Sdougm char *soptions; 37014653Sdougm 37024653Sdougm sharedstate = sa_get_share_attr(share, "shared"); 37034653Sdougm path = sa_get_share_attr(share, "path"); 37044653Sdougm type = sa_get_share_attr(share, "type"); 37054653Sdougm resource = sa_get_share_attr(share, "resource"); 37064653Sdougm groupname = sa_get_group_attr(group, "name"); 37074653Sdougm 37084653Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 37094653Sdougm sa_free_attr_string(groupname); 37104653Sdougm groupname = NULL; 37114653Sdougm } 37124653Sdougm description = sa_get_share_description(share); 37134653Sdougm 37144653Sdougm /* Want the sharetab version if it exists */ 37154653Sdougm soptions = sa_get_share_attr(share, "shareopts"); 37164653Sdougm 37174653Sdougm if (sharedstate == NULL) 37184653Sdougm shared = 0; 37194653Sdougm 37204653Sdougm if (soptions == NULL) 37214653Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 37224653Sdougm 37234653Sdougm if (shared) { 37244653Sdougm /* only active shares go here */ 37254653Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 37264653Sdougm resource != NULL ? resource : "-", 37274653Sdougm groupname != NULL ? "@" : "", 37284653Sdougm groupname != NULL ? groupname : ""); 37294653Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 37304653Sdougm resfmt, path, 37314653Sdougm (soptions != NULL && strlen(soptions) > 0) ? 37324653Sdougm soptions : "rw", 37334653Sdougm (description != NULL) ? description : ""); 37344653Sdougm } 37354653Sdougm 37364653Sdougm if (path != NULL) 37374653Sdougm sa_free_attr_string(path); 37384653Sdougm if (type != NULL) 37394653Sdougm sa_free_attr_string(type); 37404653Sdougm if (resource != NULL) 37414653Sdougm sa_free_attr_string(resource); 37424653Sdougm if (groupname != NULL) 37434653Sdougm sa_free_attr_string(groupname); 37444653Sdougm if (description != NULL) 37454653Sdougm sa_free_share_description(description); 37464653Sdougm if (sharedstate != NULL) 37474653Sdougm sa_free_attr_string(sharedstate); 37484653Sdougm if (soptions != NULL) 37494653Sdougm sa_format_free(soptions); 37503034Sdougm } 37513034Sdougm } 37523034Sdougm 37533034Sdougm /* 37543034Sdougm * output_legacy_file(out, proto) 37553034Sdougm * 37563034Sdougm * Walk all of the groups for the specified protocol and call 37573034Sdougm * out_share() to format and write in the format displayed by the 37583034Sdougm * "share" command with no arguments. 37593034Sdougm */ 37603034Sdougm 37613034Sdougm static void 37623910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 37633034Sdougm { 37643034Sdougm sa_group_t group; 37653034Sdougm 37663910Sdougm for (group = sa_get_group(handle, NULL); group != NULL; 37674653Sdougm group = sa_get_next_group(group)) { 37684653Sdougm char *options; 37694653Sdougm char *zfs; 37703034Sdougm 37713034Sdougm /* 37724653Sdougm * Get default options preformated, being careful to 37733034Sdougm * handle legacy shares differently from new style 37743034Sdougm * shares. Legacy share have options on the share. 37753034Sdougm */ 37763034Sdougm 37774653Sdougm zfs = sa_get_group_attr(group, "zfs"); 37784653Sdougm if (zfs != NULL) { 37794653Sdougm sa_group_t zgroup; 37804653Sdougm sa_free_attr_string(zfs); 37814653Sdougm options = sa_proto_legacy_format(proto, group, 1); 37824653Sdougm for (zgroup = sa_get_sub_group(group); 37834653Sdougm zgroup != NULL; 37844653Sdougm zgroup = sa_get_next_group(zgroup)) { 37854653Sdougm 37864653Sdougm /* got a group, so display it */ 37874653Sdougm out_share(out, zgroup, proto); 37884653Sdougm } 37894653Sdougm } else { 37904653Sdougm options = sa_proto_legacy_format(proto, group, 1); 37914653Sdougm out_share(out, group, proto); 37923034Sdougm } 37934653Sdougm if (options != NULL) 37944653Sdougm free(options); 37953034Sdougm } 37963034Sdougm } 37973034Sdougm 37984653Sdougm /*ARGSUSED*/ 37993034Sdougm int 38003910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 38013034Sdougm { 38023034Sdougm char *protocol = "nfs"; 38033034Sdougm char *options = NULL; 38043034Sdougm char *description = NULL; 38053034Sdougm char *groupname = NULL; 38063034Sdougm char *sharepath = NULL; 38073034Sdougm char *resource = NULL; 38083034Sdougm char *groupstatus = NULL; 38093034Sdougm int persist = SA_SHARE_TRANSIENT; 38103034Sdougm int argsused = 0; 38113034Sdougm int c; 38123034Sdougm int ret = SA_OK; 38133034Sdougm int zfs = 0; 38143034Sdougm int true_legacy = 0; 38153034Sdougm int curtype = SA_SHARE_TRANSIENT; 38163034Sdougm char cmd[MAXPATHLEN]; 38174653Sdougm sa_group_t group = NULL; 38184653Sdougm sa_share_t share; 38194653Sdougm char dir[MAXPATHLEN]; 38203034Sdougm 38213034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 38224653Sdougm switch (c) { 38234653Sdougm case 'd': 38244653Sdougm description = optarg; 38254653Sdougm argsused++; 38264653Sdougm break; 38274653Sdougm case 'F': 38284653Sdougm protocol = optarg; 38294653Sdougm if (!sa_valid_protocol(protocol)) { 38304653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 38314653Sdougm protocol, "share") == 0 && 38324653Sdougm check_legacy_cmd(cmd)) { 38334653Sdougm true_legacy++; 38344653Sdougm } else { 38354653Sdougm (void) fprintf(stderr, gettext( 38364653Sdougm "Invalid protocol specified: " 38374653Sdougm "%s\n"), protocol); 38384653Sdougm return (SA_INVALID_PROTOCOL); 38394653Sdougm } 38404653Sdougm } 38414653Sdougm break; 38424653Sdougm case 'o': 38434653Sdougm options = optarg; 38444653Sdougm argsused++; 38454653Sdougm break; 38464653Sdougm case 'p': 38474653Sdougm persist = SA_SHARE_PERMANENT; 38484653Sdougm argsused++; 38494653Sdougm break; 38504653Sdougm case 'h': 38514653Sdougm case '?': 38524653Sdougm default: 38534653Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 38544653Sdougm sa_get_usage(USAGE_SHARE)); 38554653Sdougm return (SA_OK); 38563034Sdougm } 38574653Sdougm } 38584653Sdougm 38594653Sdougm /* Have the info so construct what is needed */ 38604653Sdougm if (!argsused && optind == argc) { 38614653Sdougm /* display current info in share format */ 38624653Sdougm (void) output_legacy_file(stdout, "nfs", handle); 38634653Sdougm return (ret); 38643034Sdougm } 38653034Sdougm 38664653Sdougm /* We are modifying the configuration */ 38674653Sdougm if (optind == argc) { 38683034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 38694653Sdougm sa_get_usage(USAGE_SHARE)); 38703034Sdougm return (SA_LEGACY_ERR); 38714653Sdougm } 38724653Sdougm if (true_legacy) { 38734653Sdougm /* If still using legacy share/unshare, exec it */ 38743034Sdougm ret = run_legacy_command(cmd, argv); 38753034Sdougm return (ret); 38764653Sdougm } 38774653Sdougm 38784653Sdougm sharepath = argv[optind++]; 38794653Sdougm if (optind < argc) { 38803034Sdougm resource = argv[optind]; 38813034Sdougm groupname = strchr(resource, '@'); 38823034Sdougm if (groupname != NULL) 38834653Sdougm *groupname++ = '\0'; 38844653Sdougm } 38854653Sdougm if (realpath(sharepath, dir) == NULL) 38863034Sdougm ret = SA_BAD_PATH; 38874653Sdougm else 38883034Sdougm sharepath = dir; 38894653Sdougm if (ret == SA_OK) 38903910Sdougm share = sa_find_share(handle, sharepath); 38914653Sdougm else 38923034Sdougm share = NULL; 38934653Sdougm 38944653Sdougm if (groupname != NULL) { 38954653Sdougm ret = SA_NOT_ALLOWED; 38964653Sdougm } else if (ret == SA_OK) { 38973034Sdougm char *legacygroup = "default"; 38983034Sdougm /* 38994653Sdougm * The legacy group is always present and zfs groups 39003034Sdougm * come and go. zfs shares may be in sub-groups and 39013034Sdougm * the zfs share will already be in that group so it 39023034Sdougm * isn't an error. 39033034Sdougm */ 39043034Sdougm /* 39054653Sdougm * If the share exists (not NULL), then make sure it 39064653Sdougm * is one we want to handle by getting the parent 39074653Sdougm * group. 39083034Sdougm */ 39094653Sdougm if (share != NULL) 39104653Sdougm group = sa_get_parent_group(share); 39114653Sdougm else 39124653Sdougm group = sa_get_group(handle, legacygroup); 39134653Sdougm 39143034Sdougm if (group != NULL) { 39154653Sdougm groupstatus = group_status(group); 39164653Sdougm if (share == NULL) { 39174653Sdougm share = sa_add_share(group, sharepath, 39184653Sdougm persist, &ret); 39194653Sdougm if (share == NULL && 39204653Sdougm ret == SA_DUPLICATE_NAME) { 39214653Sdougm /* 39224653Sdougm * Could be a ZFS path being started 39234653Sdougm */ 39244653Sdougm if (sa_zfs_is_shared(handle, 39254653Sdougm sharepath)) { 39264653Sdougm ret = SA_OK; 39274653Sdougm group = sa_get_group(handle, 39284653Sdougm "zfs"); 39294653Sdougm if (group == NULL) { 39304653Sdougm /* 39314653Sdougm * This shouldn't 39324653Sdougm * happen. 39334653Sdougm */ 39344653Sdougm ret = SA_CONFIG_ERR; 39354653Sdougm } else { 39364653Sdougm share = sa_add_share( 39374653Sdougm group, sharepath, 39384653Sdougm persist, &ret); 39394653Sdougm } 39404653Sdougm } 39413034Sdougm } 39424653Sdougm } else { 39434653Sdougm char *type; 39444653Sdougm /* 39454653Sdougm * May want to change persist state, but the 39464653Sdougm * important thing is to change options. We 39474653Sdougm * need to change them regardless of the 39484653Sdougm * source. 39494653Sdougm */ 39504653Sdougm if (sa_zfs_is_shared(handle, sharepath)) { 39514653Sdougm zfs = 1; 39523034Sdougm } 39534653Sdougm remove_all_options(share, protocol); 39544653Sdougm type = sa_get_share_attr(share, "type"); 39554653Sdougm if (type != NULL && 39564653Sdougm strcmp(type, "transient") != 0) { 39574653Sdougm curtype = SA_SHARE_PERMANENT; 39584653Sdougm } 39594653Sdougm if (type != NULL) 39604653Sdougm sa_free_attr_string(type); 39614653Sdougm if (curtype != persist) { 39624653Sdougm (void) sa_set_share_attr(share, "type", 39634653Sdougm persist == SA_SHARE_PERMANENT ? 39644653Sdougm "persist" : "transient"); 39654653Sdougm } 39663108Sdougm } 39674653Sdougm /* Have a group to hold this share path */ 39684653Sdougm if (ret == SA_OK && options != NULL && 39694653Sdougm strlen(options) > 0) { 39704653Sdougm ret = sa_parse_legacy_options(share, 39714653Sdougm options, 39724653Sdougm protocol); 39733034Sdougm } 39744653Sdougm if (!zfs) { 39754653Sdougm /* 39764653Sdougm * ZFS shares never have resource or 39774653Sdougm * description and we can't store the values 39784653Sdougm * so don't try. 39794653Sdougm */ 39804653Sdougm if (ret == SA_OK && description != NULL) 39814653Sdougm ret = sa_set_share_description(share, 39824653Sdougm description); 39834653Sdougm if (ret == SA_OK && resource != NULL) 39844653Sdougm ret = sa_set_share_attr(share, 39854653Sdougm "resource", resource); 39863034Sdougm } 39874653Sdougm if (ret == SA_OK) { 39884653Sdougm if (strcmp(groupstatus, "enabled") == 0) 39894653Sdougm ret = sa_enable_share(share, protocol); 39904653Sdougm if (ret == SA_OK && 39914653Sdougm persist == SA_SHARE_PERMANENT) { 39924653Sdougm (void) sa_update_legacy(share, 39934653Sdougm protocol); 39944653Sdougm } 39954653Sdougm if (ret == SA_OK) 39964653Sdougm ret = sa_update_config(handle); 39974653Sdougm } 39983034Sdougm } else { 39994653Sdougm ret = SA_SYSTEM_ERR; 40003034Sdougm } 40013034Sdougm } 40023034Sdougm if (ret != SA_OK) { 40034653Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 40044653Sdougm sharepath, sa_errorstr(ret)); 40054653Sdougm ret = SA_LEGACY_ERR; 40063034Sdougm 40073034Sdougm } 40083034Sdougm return (ret); 40093034Sdougm } 40103034Sdougm 40113034Sdougm /* 40123034Sdougm * sa_legacy_unshare(flags, argc, argv) 40133034Sdougm * 40143034Sdougm * Implements the original unshare command. 40153034Sdougm */ 40164653Sdougm /*ARGSUSED*/ 40173034Sdougm int 40183910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 40193034Sdougm { 40203034Sdougm char *protocol = "nfs"; /* for now */ 40213034Sdougm char *options = NULL; 40223034Sdougm char *sharepath = NULL; 40233034Sdougm int persist = SA_SHARE_TRANSIENT; 40243034Sdougm int argsused = 0; 40253034Sdougm int c; 40263034Sdougm int ret = SA_OK; 40273034Sdougm int true_legacy = 0; 40283034Sdougm char cmd[MAXPATHLEN]; 40293034Sdougm 40303034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 40314653Sdougm switch (c) { 40324653Sdougm case 'h': 40334653Sdougm case '?': 40344653Sdougm break; 40354653Sdougm case 'F': 40364653Sdougm protocol = optarg; 40374653Sdougm if (!sa_valid_protocol(protocol)) { 40384653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 40394653Sdougm protocol, "unshare") == 0 && 40404653Sdougm check_legacy_cmd(cmd)) { 40414653Sdougm true_legacy++; 40424653Sdougm } else { 40434653Sdougm (void) printf(gettext( 40444653Sdougm "Invalid file system name\n")); 40454653Sdougm return (SA_INVALID_PROTOCOL); 40464653Sdougm } 40474653Sdougm } 40484653Sdougm break; 40494653Sdougm case 'o': 40504653Sdougm options = optarg; 40514653Sdougm argsused++; 40524653Sdougm break; 40534653Sdougm case 'p': 40544653Sdougm persist = SA_SHARE_PERMANENT; 40554653Sdougm argsused++; 40564653Sdougm break; 40574653Sdougm default: 40584653Sdougm (void) printf(gettext("usage: %s\n"), 40594653Sdougm sa_get_usage(USAGE_UNSHARE)); 40604653Sdougm return (SA_OK); 40613034Sdougm } 40623034Sdougm } 40633034Sdougm 40644653Sdougm /* Have the info so construct what is needed */ 40654653Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 40664653Sdougm ret = SA_SYNTAX_ERR; 40673034Sdougm } else { 40684653Sdougm sa_share_t share; 40694653Sdougm char dir[MAXPATHLEN]; 40704653Sdougm if (true_legacy) { 40714653Sdougm /* if still using legacy share/unshare, exec it */ 40724653Sdougm ret = run_legacy_command(cmd, argv); 40734653Sdougm return (ret); 40744653Sdougm } 40753663Sdougm /* 40763663Sdougm * Find the path in the internal configuration. If it 40773663Sdougm * isn't found, attempt to resolve the path via 40783663Sdougm * realpath() and try again. 40793663Sdougm */ 40804653Sdougm sharepath = argv[optind++]; 40814653Sdougm share = sa_find_share(handle, sharepath); 40824653Sdougm if (share == NULL) { 40834653Sdougm if (realpath(sharepath, dir) == NULL) { 40844653Sdougm ret = SA_NO_SUCH_PATH; 40854653Sdougm } else { 40864653Sdougm share = sa_find_share(handle, dir); 40874653Sdougm } 40883663Sdougm } 40894653Sdougm if (share != NULL) { 40904653Sdougm ret = sa_disable_share(share, protocol); 40914653Sdougm /* 40924653Sdougm * Errors are ok and removal should still occur. The 40934653Sdougm * legacy unshare is more forgiving of errors than the 40944653Sdougm * remove-share subcommand which may need the force 40954653Sdougm * flag set for some error conditions. That is, the 40964653Sdougm * "unshare" command will always unshare if it can 40974653Sdougm * while "remove-share" might require the force option. 40984653Sdougm */ 40994653Sdougm if (persist == SA_SHARE_PERMANENT) { 41004653Sdougm ret = sa_remove_share(share); 41014653Sdougm if (ret == SA_OK) 41024653Sdougm ret = sa_update_config(handle); 41034653Sdougm } 41044653Sdougm } else { 41054653Sdougm ret = SA_NOT_SHARED; 41063663Sdougm } 41073034Sdougm } 41083034Sdougm switch (ret) { 41093034Sdougm default: 41104653Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 41114653Sdougm ret = SA_LEGACY_ERR; 41124653Sdougm break; 41133034Sdougm case SA_SYNTAX_ERR: 41144653Sdougm (void) printf(gettext("usage: %s\n"), 41154653Sdougm sa_get_usage(USAGE_UNSHARE)); 41164653Sdougm break; 41173034Sdougm case SA_OK: 41184653Sdougm break; 41193034Sdougm } 41203034Sdougm return (ret); 41213034Sdougm } 41223034Sdougm 41233034Sdougm /* 41244653Sdougm * Common commands that implement the sub-commands used by all 41253034Sdougm * protcols. The entries are found via the lookup command 41263034Sdougm */ 41273034Sdougm 41283034Sdougm static sa_command_t commands[] = { 41293034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 41303034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 41313034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 41323034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 41333034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 41343034Sdougm {"list", 0, sa_list, USAGE_LIST}, 41353034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 41363034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 41373034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 41383034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 41393034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 41403034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 41413034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 41423034Sdougm SVC_SET|SVC_ACTION}, 41433034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 41443034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 41453034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 41463034Sdougm {NULL, 0, NULL, NULL} 41473034Sdougm }; 41483034Sdougm 41493034Sdougm static char * 41503034Sdougm sa_get_usage(sa_usage_t index) 41513034Sdougm { 41523034Sdougm char *ret = NULL; 41533034Sdougm switch (index) { 41543034Sdougm case USAGE_ADD_SHARE: 41554653Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 41564653Sdougm "[-d \"description text\"] -s sharepath group"); 41574653Sdougm break; 41583034Sdougm case USAGE_CREATE: 41594653Sdougm ret = gettext( 41604653Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 41614653Sdougm break; 41623034Sdougm case USAGE_DELETE: 41634653Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 41644653Sdougm break; 41653034Sdougm case USAGE_DISABLE: 41664653Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 41674653Sdougm break; 41683034Sdougm case USAGE_ENABLE: 41694653Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 41704653Sdougm break; 41713034Sdougm case USAGE_LIST: 41724653Sdougm ret = gettext("list [-vh] [-P proto]"); 41734653Sdougm break; 41743034Sdougm case USAGE_MOVE_SHARE: 41754653Sdougm ret = gettext( 41764653Sdougm "move-share [-nvh] -s sharepath destination-group"); 41774653Sdougm break; 41783034Sdougm case USAGE_REMOVE_SHARE: 41794653Sdougm ret = gettext("remove-share [-fnvh] -s sharepath group"); 41804653Sdougm break; 41813034Sdougm case USAGE_SET: 41824653Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 41834653Sdougm "[-p property=value]* [-s sharepath] group"); 41844653Sdougm break; 41853034Sdougm case USAGE_SET_SECURITY: 41864653Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 41874653Sdougm "[-p property=value]* group"); 41884653Sdougm break; 41893034Sdougm case USAGE_SET_SHARE: 41904653Sdougm ret = gettext("set-share [-nh] [-r resource] " 41914653Sdougm "[-d \"description text\"] -s sharepath group"); 41924653Sdougm break; 41933034Sdougm case USAGE_SHOW: 41944653Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 41954653Sdougm break; 41963034Sdougm case USAGE_SHARE: 41974653Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 41984653Sdougm "[-d description] [pathname [resourcename]]"); 41994653Sdougm break; 42003034Sdougm case USAGE_START: 42014653Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 42024653Sdougm break; 42033034Sdougm case USAGE_STOP: 42044653Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 42054653Sdougm break; 42063034Sdougm case USAGE_UNSET: 42074653Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 42084653Sdougm "[-p property]* group"); 42094653Sdougm break; 42103034Sdougm case USAGE_UNSET_SECURITY: 42114653Sdougm ret = gettext("unset-security [-nvh] -P proto -S security-type" 42124653Sdougm " [-p property]* group"); 42134653Sdougm break; 42143034Sdougm case USAGE_UNSHARE: 42154653Sdougm ret = gettext( 42164653Sdougm "unshare [-F fstype] [-p] sharepath"); 42174653Sdougm break; 42183034Sdougm } 42193034Sdougm return (ret); 42203034Sdougm } 42213034Sdougm 42223034Sdougm /* 42233034Sdougm * sa_lookup(cmd, proto) 42243034Sdougm * 42253034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 42263034Sdougm * eventually provide a way to provide protocol specific sub-commands. 42273034Sdougm */ 42284653Sdougm /*ARGSUSED*/ 42293034Sdougm sa_command_t * 42303034Sdougm sa_lookup(char *cmd, char *proto) 42313034Sdougm { 42323034Sdougm int i; 42333034Sdougm size_t len; 42343034Sdougm 42353034Sdougm len = strlen(cmd); 42363034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 42374653Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 42384653Sdougm return (&commands[i]); 42393034Sdougm } 42403034Sdougm return (NULL); 42413034Sdougm } 42423034Sdougm 42434653Sdougm /*ARGSUSED*/ 42443034Sdougm void 42453034Sdougm sub_command_help(char *proto) 42463034Sdougm { 42473034Sdougm int i; 42483034Sdougm 42493034Sdougm (void) printf(gettext("\tsub-commands:\n")); 42503034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 42514653Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 42524653Sdougm (void) printf("\t%s\n", 42534653Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 42543034Sdougm } 42553034Sdougm } 4256