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 /* 235772Sas200622 * Copyright 2008 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> 515331Samw #include <assert.h> 525331Samw #include <iconv.h> 535331Samw #include <langinfo.h> 545331Samw #include <dirent.h> 553034Sdougm 563034Sdougm static char *sa_get_usage(sa_usage_t); 573034Sdougm 583034Sdougm /* 593034Sdougm * Implementation of the common sub-commands supported by sharemgr. 603034Sdougm * A number of helper functions are also included. 613034Sdougm */ 623034Sdougm 633034Sdougm /* 643034Sdougm * has_protocol(group, proto) 653034Sdougm * If the group has an optionset with the specified protocol, 663034Sdougm * return true (1) otherwise false (0). 673034Sdougm */ 683034Sdougm static int 693034Sdougm has_protocol(sa_group_t group, char *protocol) 703034Sdougm { 713034Sdougm sa_optionset_t optionset; 723034Sdougm int result = 0; 733034Sdougm 743034Sdougm optionset = sa_get_optionset(group, protocol); 753034Sdougm if (optionset != NULL) { 764653Sdougm result++; 773034Sdougm } 783034Sdougm return (result); 793034Sdougm } 803034Sdougm 813034Sdougm /* 825331Samw * validresource(name) 835331Samw * 845331Samw * Check that name only has valid characters in it. The current valid 855331Samw * set are the printable characters but not including: 865331Samw * " / \ [ ] : | < > + ; , ? * = \t 875331Samw * Note that space is included and there is a maximum length. 885331Samw */ 895331Samw static int 905331Samw validresource(const char *name) 915331Samw { 925331Samw const char *cp; 935331Samw size_t len; 945331Samw 955331Samw if (name == NULL) 965331Samw return (B_FALSE); 975331Samw 985331Samw len = strlen(name); 995331Samw if (len == 0 || len > SA_MAX_RESOURCE_NAME) 1005331Samw return (B_FALSE); 1015331Samw 1025331Samw if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) { 1035331Samw return (B_FALSE); 1045331Samw } 1055331Samw 1065331Samw for (cp = name; *cp != '\0'; cp++) 1075331Samw if (iscntrl(*cp)) 1085331Samw return (B_FALSE); 1095331Samw 1105331Samw return (B_TRUE); 1115331Samw } 1125331Samw 1135331Samw /* 1145331Samw * conv_to_utf8(input) 1155331Samw * 1165331Samw * Convert the input string to utf8 from the current locale. If the 1175331Samw * conversion fails, use the current locale, it is likely close 1185331Samw * enough. For example, the "C" locale is a subset of utf-8. The 1195331Samw * return value may be a new string or the original input string. 1205331Samw */ 1215331Samw 1225331Samw static char * 1235331Samw conv_to_utf8(char *input) 1245331Samw { 1255331Samw iconv_t cd; 1265521Sas200622 char *inval = input; 1275331Samw char *output = input; 1285331Samw char *outleft; 1295331Samw char *curlocale; 1305331Samw size_t bytesleft; 1315331Samw size_t size; 1325331Samw size_t osize; 1335331Samw static int warned = 0; 1345331Samw 1355331Samw curlocale = nl_langinfo(CODESET); 1365331Samw if (curlocale == NULL) 1375331Samw curlocale = "C"; 1385331Samw cd = iconv_open("UTF-8", curlocale); 1395331Samw if (cd != NULL && cd != (iconv_t)-1) { 1405331Samw size = strlen(input); 1415331Samw /* Assume worst case of characters expanding to 4 bytes. */ 1425331Samw bytesleft = size * 4; 1435331Samw output = calloc(bytesleft, 1); 1445331Samw if (output != NULL) { 1455331Samw outleft = output; 1465521Sas200622 /* inval can be modified on return */ 1475521Sas200622 osize = iconv(cd, (const char **)&inval, &size, 1485331Samw &outleft, &bytesleft); 1495331Samw if (osize == (size_t)-1 || size != 0) { 1505331Samw free(output); 1515331Samw output = input; 1525331Samw } 1535521Sas200622 } else { 1545521Sas200622 /* Need to return something. */ 1555521Sas200622 output = input; 1565331Samw } 1575331Samw (void) iconv_close(cd); 1585331Samw } else { 1595331Samw if (!warned) 1605331Samw (void) fprintf(stderr, 1615331Samw gettext("Cannot convert to UTF-8 from %s\n"), 1625331Samw curlocale ? curlocale : gettext("unknown")); 1635331Samw warned = 1; 1645331Samw } 1655331Samw return (output); 1665331Samw } 1675331Samw 1685331Samw /* 1695331Samw * conv_from(input) 1705331Samw * 1715331Samw * Convert the input string from utf8 to current locale. If the 1725331Samw * conversion isn't supported, just use as is. The return value may be 1735331Samw * a new string or the original input string. 1745331Samw */ 1755331Samw 1765331Samw static char * 1775331Samw conv_from_utf8(char *input) 1785331Samw { 1795331Samw iconv_t cd; 1805331Samw char *output = input; 1815521Sas200622 char *inval = input; 1825331Samw char *outleft; 1835331Samw char *curlocale; 1845331Samw size_t bytesleft; 1855331Samw size_t size; 1865331Samw size_t osize; 1875331Samw static int warned = 0; 1885331Samw 1895331Samw curlocale = nl_langinfo(CODESET); 1905331Samw if (curlocale == NULL) 1915331Samw curlocale = "C"; 1925331Samw cd = iconv_open(curlocale, "UTF-8"); 1935331Samw if (cd != NULL && cd != (iconv_t)-1) { 1945331Samw size = strlen(input); 1955331Samw /* Assume worst case of characters expanding to 4 bytes. */ 1965331Samw bytesleft = size * 4; 1975331Samw output = calloc(bytesleft, 1); 1985331Samw if (output != NULL) { 1995331Samw outleft = output; 2005521Sas200622 osize = iconv(cd, (const char **)&inval, &size, 2015331Samw &outleft, &bytesleft); 2025521Sas200622 if (osize == (size_t)-1 || size != 0) 2035331Samw output = input; 2045521Sas200622 } else { 2055521Sas200622 /* Need to return something. */ 2065521Sas200622 output = input; 2075331Samw } 2085331Samw (void) iconv_close(cd); 2095331Samw } else { 2105331Samw if (!warned) 2115331Samw (void) fprintf(stderr, 2125331Samw gettext("Cannot convert to %s from UTF-8\n"), 2135331Samw curlocale ? curlocale : gettext("unknown")); 2145331Samw warned = 1; 2155331Samw } 2165331Samw return (output); 2175331Samw } 2185331Samw 2195885Sdougm /* 2205885Sdougm * print_rsrc_desc(resource, sharedesc) 2215885Sdougm * 2225885Sdougm * Print the resource description string after converting from UTF8 to 2235885Sdougm * the current locale. If sharedesc is not NULL and there is no 2245885Sdougm * description on the resource, use sharedesc. sharedesc will already 2255885Sdougm * be converted to UTF8. 2265885Sdougm */ 2275885Sdougm 2285331Samw static void 2295885Sdougm print_rsrc_desc(sa_resource_t resource, char *sharedesc) 2305331Samw { 2315331Samw char *description; 2325331Samw char *desc; 2335331Samw 2345885Sdougm if (resource == NULL) 2355885Sdougm return; 2365885Sdougm 2375331Samw description = sa_get_resource_description(resource); 2385331Samw if (description != NULL) { 2395331Samw desc = conv_from_utf8(description); 2405331Samw if (desc != description) { 2415331Samw sa_free_share_description(description); 2425331Samw description = desc; 2435331Samw } 2445885Sdougm } else if (sharedesc != NULL) { 2455885Sdougm description = strdup(sharedesc); 2465885Sdougm } 2475885Sdougm if (description != NULL) { 2485331Samw (void) printf("\t\"%s\"", description); 2495331Samw sa_free_share_description(description); 2505331Samw } 2515331Samw } 2525331Samw 2535885Sdougm /* 2545885Sdougm * set_resource_desc(share, description) 2555885Sdougm * 2565885Sdougm * Set the share description value after converting the description 2575885Sdougm * string to UTF8 from the current locale. 2585885Sdougm */ 2595885Sdougm 2605885Sdougm static int 2615885Sdougm set_resource_desc(sa_share_t share, char *description) 2625885Sdougm { 2635885Sdougm char *desc; 2645885Sdougm int ret; 2655885Sdougm 2665885Sdougm desc = conv_to_utf8(description); 2675885Sdougm ret = sa_set_resource_description(share, desc); 2685885Sdougm if (description != desc) 2695885Sdougm sa_free_share_description(desc); 2705885Sdougm return (ret); 2715885Sdougm } 2725885Sdougm 2735885Sdougm /* 2745885Sdougm * set_share_desc(share, description) 2755885Sdougm * 2765885Sdougm * Set the resource description value after converting the description 2775885Sdougm * string to UTF8 from the current locale. 2785885Sdougm */ 2795885Sdougm 2805331Samw static int 2815331Samw set_share_desc(sa_share_t share, char *description) 2825331Samw { 2835331Samw char *desc; 2845331Samw int ret; 2855331Samw 2865331Samw desc = conv_to_utf8(description); 2875331Samw ret = sa_set_share_description(share, desc); 2885331Samw if (description != desc) 2895331Samw sa_free_share_description(desc); 2905331Samw return (ret); 2915331Samw } 2925331Samw 2935331Samw /* 2945331Samw * add_list(list, item, data, proto) 2955331Samw * Adds a new list member that points holds item in the list. 2963034Sdougm * If list is NULL, it starts a new list. The function returns 2973034Sdougm * the first member of the list. 2983034Sdougm */ 2993034Sdougm struct list * 3005331Samw add_list(struct list *listp, void *item, void *data, char *proto) 3013034Sdougm { 3023034Sdougm struct list *new, *tmp; 3033034Sdougm 3043034Sdougm new = malloc(sizeof (struct list)); 3053034Sdougm if (new != NULL) { 3064653Sdougm new->next = NULL; 3074653Sdougm new->item = item; 3084653Sdougm new->itemdata = data; 3095331Samw new->proto = proto; 3103034Sdougm } else { 3114653Sdougm return (listp); 3123034Sdougm } 3133034Sdougm 3143034Sdougm if (listp == NULL) 3154653Sdougm return (new); 3163034Sdougm 3173034Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 3183034Sdougm /* get to end of list */ 3193034Sdougm } 3203034Sdougm tmp->next = new; 3213034Sdougm return (listp); 3223034Sdougm } 3233034Sdougm 3243034Sdougm /* 3253034Sdougm * free_list(list) 3263034Sdougm * Given a list, free all the members of the list; 3273034Sdougm */ 3283034Sdougm static void 3293034Sdougm free_list(struct list *listp) 3303034Sdougm { 3313034Sdougm struct list *tmp; 3323034Sdougm while (listp != NULL) { 3334653Sdougm tmp = listp; 3344653Sdougm listp = listp->next; 3354653Sdougm free(tmp); 3363034Sdougm } 3373034Sdougm } 3383034Sdougm 3393034Sdougm /* 3403034Sdougm * check_authorization(instname, which) 3413034Sdougm * 3423034Sdougm * Checks to see if the specific type of authorization in which is 3433034Sdougm * enabled for the user in this SMF service instance. 3443034Sdougm */ 3453034Sdougm 3463034Sdougm static int 3473034Sdougm check_authorization(char *instname, int which) 3483034Sdougm { 3493034Sdougm scf_handle_t *handle = NULL; 3503034Sdougm scf_simple_prop_t *prop = NULL; 3513034Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 3523034Sdougm char *authstr = NULL; 3533034Sdougm ssize_t numauths; 3544653Sdougm int ret = B_TRUE; 3553034Sdougm uid_t uid; 3563034Sdougm struct passwd *pw = NULL; 3573034Sdougm 3583034Sdougm uid = getuid(); 3593034Sdougm pw = getpwuid(uid); 3604653Sdougm if (pw == NULL) { 3614653Sdougm ret = B_FALSE; 3624653Sdougm } else { 3634653Sdougm /* 3644653Sdougm * Since names are restricted to SA_MAX_NAME_LEN won't 3654653Sdougm * overflow. 3664653Sdougm */ 3674653Sdougm (void) snprintf(svcstring, sizeof (svcstring), "%s:%s", 3684653Sdougm SA_SVC_FMRI_BASE, instname); 3694653Sdougm handle = scf_handle_create(SCF_VERSION); 3704653Sdougm if (handle != NULL) { 3714653Sdougm if (scf_handle_bind(handle) == 0) { 3724653Sdougm switch (which) { 3734653Sdougm case SVC_SET: 3744653Sdougm prop = scf_simple_prop_get(handle, 3754653Sdougm svcstring, "general", 3764653Sdougm SVC_AUTH_VALUE); 3774653Sdougm break; 3784653Sdougm case SVC_ACTION: 3794653Sdougm prop = scf_simple_prop_get(handle, 3804653Sdougm svcstring, "general", 3814653Sdougm SVC_AUTH_ACTION); 3824653Sdougm break; 3834653Sdougm } 3844653Sdougm } 3853034Sdougm } 3863034Sdougm } 3873034Sdougm /* make sure we have an authorization string property */ 3883034Sdougm if (prop != NULL) { 3894653Sdougm int i; 3904653Sdougm numauths = scf_simple_prop_numvalues(prop); 3914653Sdougm for (ret = 0, i = 0; i < numauths; i++) { 3924653Sdougm authstr = scf_simple_prop_next_astring(prop); 3934653Sdougm if (authstr != NULL) { 3944653Sdougm /* check if this user has one of the strings */ 3954653Sdougm if (chkauthattr(authstr, pw->pw_name)) { 3964653Sdougm ret = 1; 3974653Sdougm break; 3984653Sdougm } 3994653Sdougm } 4003034Sdougm } 4014653Sdougm endauthattr(); 4024653Sdougm scf_simple_prop_free(prop); 4033034Sdougm } else { 4044653Sdougm /* no authorization string defined */ 4054653Sdougm ret = 0; 4063034Sdougm } 4073034Sdougm if (handle != NULL) 4084653Sdougm scf_handle_destroy(handle); 4093034Sdougm return (ret); 4103034Sdougm } 4113034Sdougm 4123034Sdougm /* 4133034Sdougm * check_authorizations(instname, flags) 4143034Sdougm * 4153034Sdougm * check all the needed authorizations for the user in this service 4163034Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 4173034Sdougm * there are authorizations for the user or not. 4183034Sdougm */ 4193034Sdougm 4203034Sdougm static int 4213034Sdougm check_authorizations(char *instname, int flags) 4223034Sdougm { 4233034Sdougm int ret1 = 0; 4243034Sdougm int ret2 = 0; 4253034Sdougm int ret; 4263034Sdougm 4273034Sdougm if (flags & SVC_SET) 4284653Sdougm ret1 = check_authorization(instname, SVC_SET); 4293034Sdougm if (flags & SVC_ACTION) 4304653Sdougm ret2 = check_authorization(instname, SVC_ACTION); 4313034Sdougm switch (flags) { 4323034Sdougm case SVC_ACTION: 4334653Sdougm ret = ret2; 4344653Sdougm break; 4353034Sdougm case SVC_SET: 4364653Sdougm ret = ret1; 4374653Sdougm break; 4383034Sdougm case SVC_ACTION|SVC_SET: 4394653Sdougm ret = ret1 & ret2; 4404653Sdougm break; 4413034Sdougm default: 4424653Sdougm /* if not flags set, we assume we don't need authorizations */ 4434653Sdougm ret = 1; 4443034Sdougm } 4453034Sdougm return (ret); 4463034Sdougm } 4473034Sdougm 4483034Sdougm /* 4495331Samw * notify_or_enable_share(share, protocol) 4505331Samw * 4515331Samw * Since some protocols don't want an "enable" when properties change, 4525331Samw * this function will use the protocol specific notify function 4535331Samw * first. If that fails, it will then attempt to use the 4545331Samw * sa_enable_share(). "protocol" is the protocol that was specified 4555331Samw * on the command line. 4565331Samw */ 4575331Samw static void 4585331Samw notify_or_enable_share(sa_share_t share, char *protocol) 4595331Samw { 4605331Samw sa_group_t group; 4615331Samw sa_optionset_t opt; 4625331Samw int ret = SA_OK; 4635331Samw char *path; 4645331Samw char *groupproto; 4655331Samw sa_share_t parent = share; 4665331Samw 4675331Samw /* If really a resource, get parent share */ 4685331Samw if (!sa_is_share(share)) { 4695331Samw parent = sa_get_resource_parent((sa_resource_t)share); 4705331Samw } 4715331Samw 4725331Samw /* 4735331Samw * Now that we've got a share in "parent", make sure it has a path. 4745331Samw */ 4755331Samw path = sa_get_share_attr(parent, "path"); 4765331Samw if (path == NULL) 4775331Samw return; 4785331Samw 4795331Samw group = sa_get_parent_group(parent); 4805331Samw 4815331Samw if (group == NULL) { 4825331Samw sa_free_attr_string(path); 4835331Samw return; 4845331Samw } 4855331Samw for (opt = sa_get_optionset(group, NULL); 4865331Samw opt != NULL; 4875331Samw opt = sa_get_next_optionset(opt)) { 4885331Samw groupproto = sa_get_optionset_attr(opt, "type"); 4895331Samw if (groupproto == NULL || 4905331Samw (protocol != NULL && strcmp(groupproto, protocol) != 0)) { 4915331Samw sa_free_attr_string(groupproto); 4925331Samw continue; 4935331Samw } 4945331Samw if (sa_is_share(share)) { 4955331Samw if ((ret = sa_proto_change_notify(share, 4965331Samw groupproto)) != SA_OK) { 4975331Samw ret = sa_enable_share(share, groupproto); 4985331Samw if (ret != SA_OK) { 4995331Samw (void) printf( 5005331Samw gettext("Could not reenable" 5015331Samw " share %s: %s\n"), 5025331Samw path, sa_errorstr(ret)); 5035331Samw } 5045331Samw } 5055331Samw } else { 5065331Samw /* Must be a resource */ 5075331Samw if ((ret = sa_proto_notify_resource(share, 5085331Samw groupproto)) != SA_OK) { 5095331Samw ret = sa_enable_resource(share, groupproto); 5105331Samw if (ret != SA_OK) { 5115331Samw (void) printf( 5125331Samw gettext("Could not " 5135331Samw "reenable resource %s: " 5145331Samw "%s\n"), path, 5155331Samw sa_errorstr(ret)); 5165331Samw } 5175331Samw } 5185331Samw } 5195331Samw sa_free_attr_string(groupproto); 5205331Samw } 5215331Samw sa_free_attr_string(path); 5225331Samw } 5235331Samw 5245331Samw /* 5255331Samw * enable_group(group, updateproto, notify, proto) 5263082Sdougm * 5273082Sdougm * enable all the shares in the specified group. This is a helper for 5283082Sdougm * enable_all_groups in order to simplify regular and subgroup (zfs) 5295331Samw * enabling. Group has already been checked for non-NULL. If notify 5305331Samw * is non-zero, attempt to use the notify interface rather than 5315331Samw * enable. 5323082Sdougm */ 5333082Sdougm static void 5345331Samw enable_group(sa_group_t group, char *updateproto, int notify, char *proto) 5353082Sdougm { 5363082Sdougm sa_share_t share; 5373082Sdougm 5383082Sdougm for (share = sa_get_share(group, NULL); 5393082Sdougm share != NULL; 5403082Sdougm share = sa_get_next_share(share)) { 5414653Sdougm if (updateproto != NULL) 5424653Sdougm (void) sa_update_legacy(share, updateproto); 5435331Samw if (notify) 5445331Samw notify_or_enable_share(share, proto); 5455331Samw else 5465331Samw (void) sa_enable_share(share, proto); 5473082Sdougm } 5483082Sdougm } 5493082Sdougm 5503082Sdougm /* 5514241Sdougm * isenabled(group) 5524241Sdougm * 5534241Sdougm * Returns B_TRUE if the group is enabled or B_FALSE if it isn't. 5544241Sdougm * Moved to separate function to reduce clutter in the code. 5554241Sdougm */ 5564241Sdougm 5574241Sdougm static int 5584241Sdougm isenabled(sa_group_t group) 5594241Sdougm { 5604241Sdougm char *state; 5614241Sdougm int ret = B_FALSE; 5624241Sdougm 5634241Sdougm if (group != NULL) { 5644653Sdougm state = sa_get_group_attr(group, "state"); 5654653Sdougm if (state != NULL) { 5665331Samw 5674653Sdougm if (strcmp(state, "enabled") == 0) 5684653Sdougm ret = B_TRUE; 5694653Sdougm sa_free_attr_string(state); 5704653Sdougm } 5714241Sdougm } 5724241Sdougm return (ret); 5734241Sdougm } 5744241Sdougm 5754241Sdougm /* 5763082Sdougm * enable_all_groups(list, setstate, online, updateproto) 5775331Samw * 5785331Samw * Given a list of groups, enable each one found. If updateproto is 5795331Samw * not NULL, then update all the shares for the protocol that was 5805331Samw * passed in. If enable is non-zero, tell enable_group to try the 5815331Samw * notify interface since this is a property change. 5823034Sdougm */ 5833034Sdougm static int 5843910Sdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate, 5855331Samw int online, char *updateproto, int enable) 5863034Sdougm { 5874241Sdougm int ret; 5883034Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 5893034Sdougm char *state; 5903034Sdougm char *name; 5913034Sdougm char *zfs = NULL; 5923034Sdougm sa_group_t group; 5933082Sdougm sa_group_t subgroup; 5943034Sdougm 5954241Sdougm for (ret = SA_OK; work != NULL; work = work->next) { 5964653Sdougm group = (sa_group_t)work->item; 5974241Sdougm 5984241Sdougm /* 5994241Sdougm * If setstate == TRUE, then make sure to set 6004241Sdougm * enabled. This needs to be done here in order for 6014241Sdougm * the isenabled check to succeed on a newly enabled 6024241Sdougm * group. 6034241Sdougm */ 6044653Sdougm if (setstate == B_TRUE) { 6054653Sdougm ret = sa_set_group_attr(group, "state", "enabled"); 6064653Sdougm if (ret != SA_OK) 6074653Sdougm break; 6084653Sdougm } 6094241Sdougm 6104241Sdougm /* 6114241Sdougm * Check to see if group is enabled. If it isn't, skip 6124241Sdougm * the rest. We don't want shares starting if the 6134241Sdougm * group is disabled. The properties may have been 6144241Sdougm * updated, but there won't be a change until the 6154241Sdougm * group is enabled. 6164241Sdougm */ 6174653Sdougm if (!isenabled(group)) 6184653Sdougm continue; 6194653Sdougm 6204653Sdougm /* if itemdata != NULL then a single share */ 6214653Sdougm if (work->itemdata != NULL) { 6225331Samw if (enable) { 6235331Samw if (work->itemdata != NULL) 6245331Samw notify_or_enable_share(work->itemdata, 6255331Samw updateproto); 6265331Samw else 6275331Samw ret = SA_CONFIG_ERR; 6285331Samw } else { 6295331Samw if (sa_is_share(work->itemdata)) { 6305331Samw ret = sa_enable_share( 6315331Samw (sa_share_t)work->itemdata, 6325331Samw updateproto); 6335331Samw } else { 6345331Samw ret = sa_enable_resource( 6355331Samw (sa_resource_t)work->itemdata, 6365331Samw updateproto); 6375331Samw } 6385331Samw } 6393034Sdougm } 6404653Sdougm if (ret != SA_OK) 6414653Sdougm break; 6424653Sdougm 6434653Sdougm /* if itemdata == NULL then the whole group */ 6444653Sdougm if (work->itemdata == NULL) { 6454653Sdougm zfs = sa_get_group_attr(group, "zfs"); 6464653Sdougm /* 6475331Samw * If the share is managed by ZFS, don't 6484653Sdougm * update any of the protocols since ZFS is 6495331Samw * handling this. Updateproto will contain 6504653Sdougm * the name of the protocol that we want to 6514653Sdougm * update legacy files for. 6524653Sdougm */ 6535331Samw enable_group(group, zfs == NULL ? updateproto : NULL, 6545331Samw enable, work->proto); 6554653Sdougm for (subgroup = sa_get_sub_group(group); 6564653Sdougm subgroup != NULL; 6574653Sdougm subgroup = sa_get_next_group(subgroup)) { 6584653Sdougm /* never update legacy for ZFS subgroups */ 6595331Samw enable_group(subgroup, NULL, enable, 6605331Samw work->proto); 6613034Sdougm } 6623034Sdougm } 6634653Sdougm if (online) { 6644653Sdougm zfs = sa_get_group_attr(group, "zfs"); 6654653Sdougm name = sa_get_group_attr(group, "name"); 6664653Sdougm if (name != NULL) { 6674653Sdougm if (zfs == NULL) { 6684653Sdougm (void) snprintf(instance, 6694653Sdougm sizeof (instance), "%s:%s", 6704653Sdougm SA_SVC_FMRI_BASE, name); 6714653Sdougm state = smf_get_state(instance); 6724653Sdougm if (state == NULL || 6734653Sdougm strcmp(state, "online") != 0) { 6744653Sdougm (void) smf_enable_instance( 6754653Sdougm instance, 0); 6764653Sdougm free(state); 6774653Sdougm } 6784653Sdougm } else { 6794653Sdougm sa_free_attr_string(zfs); 6804653Sdougm zfs = NULL; 6814653Sdougm } 6824653Sdougm if (name != NULL) 6834653Sdougm sa_free_attr_string(name); 6844653Sdougm } 6854653Sdougm } 6863034Sdougm } 6873034Sdougm if (ret == SA_OK) { 6884653Sdougm ret = sa_update_config(handle); 6893034Sdougm } 6903034Sdougm return (ret); 6913034Sdougm } 6923034Sdougm 6933034Sdougm /* 6943034Sdougm * chk_opt(optlistp, security, proto) 6953034Sdougm * 6963034Sdougm * Do a sanity check on the optlist provided for the protocol. This 6973034Sdougm * is a syntax check and verification that the property is either a 6983034Sdougm * general or specific to a names optionset. 6993034Sdougm */ 7003034Sdougm 7013034Sdougm static int 7023034Sdougm chk_opt(struct options *optlistp, int security, char *proto) 7033034Sdougm { 7043034Sdougm struct options *optlist; 7053034Sdougm char *sep = ""; 7063034Sdougm int notfirst = 0; 7073034Sdougm int ret; 7083034Sdougm 7093034Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 7104653Sdougm char *optname; 7114653Sdougm 7124653Sdougm optname = optlist->optname; 7134653Sdougm ret = OPT_ADD_OK; 7144653Sdougm /* extract property/value pair */ 7154653Sdougm if (sa_is_security(optname, proto)) { 7164653Sdougm if (!security) 7174653Sdougm ret = OPT_ADD_SECURITY; 7184653Sdougm } else { 7194653Sdougm if (security) 7204653Sdougm ret = OPT_ADD_PROPERTY; 7214653Sdougm } 7224653Sdougm if (ret != OPT_ADD_OK) { 7234653Sdougm if (notfirst == 0) 7244653Sdougm (void) printf( 7254653Sdougm gettext("Property syntax error: ")); 7264653Sdougm switch (ret) { 7274653Sdougm case OPT_ADD_SYNTAX: 7284653Sdougm (void) printf(gettext("%ssyntax error: %s"), 7293034Sdougm sep, optname); 7304653Sdougm sep = ", "; 7314653Sdougm break; 7324653Sdougm case OPT_ADD_SECURITY: 7334653Sdougm (void) printf(gettext("%s%s requires -S"), 7343034Sdougm optname, sep); 7354653Sdougm sep = ", "; 7364653Sdougm break; 7374653Sdougm case OPT_ADD_PROPERTY: 7384653Sdougm (void) printf( 7394653Sdougm gettext("%s%s not supported with -S"), 7403034Sdougm optname, sep); 7414653Sdougm sep = ", "; 7424653Sdougm break; 7434653Sdougm } 7444653Sdougm notfirst++; 7453034Sdougm } 7463034Sdougm } 7473034Sdougm if (notfirst) { 7484653Sdougm (void) printf("\n"); 7494653Sdougm ret = SA_SYNTAX_ERR; 7503034Sdougm } 7513034Sdougm return (ret); 7523034Sdougm } 7533034Sdougm 7543034Sdougm /* 7553034Sdougm * free_opt(optlist) 7563034Sdougm * Free the specified option list. 7573034Sdougm */ 7583034Sdougm static void 7593034Sdougm free_opt(struct options *optlist) 7603034Sdougm { 7613034Sdougm struct options *nextopt; 7623034Sdougm while (optlist != NULL) { 7633034Sdougm nextopt = optlist->next; 7643034Sdougm free(optlist); 7653034Sdougm optlist = nextopt; 7663034Sdougm } 7673034Sdougm } 7683034Sdougm 7693034Sdougm /* 7703034Sdougm * check property list for valid properties 7713034Sdougm * A null value is a remove which is always valid. 7723034Sdougm */ 7733034Sdougm static int 7743034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec) 7753034Sdougm { 7763034Sdougm int ret = SA_OK; 7773034Sdougm struct options *cur; 7783034Sdougm sa_property_t prop; 7793034Sdougm sa_optionset_t parent = NULL; 7803034Sdougm 7813034Sdougm if (object != NULL) { 7824653Sdougm if (sec == NULL) 7834653Sdougm parent = sa_get_optionset(object, proto); 7844653Sdougm else 7854653Sdougm parent = sa_get_security(object, sec, proto); 7863034Sdougm } 7873034Sdougm 7883034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 7894653Sdougm if (cur->optvalue == NULL) 7904653Sdougm continue; 7913034Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 7923034Sdougm if (prop == NULL) 7934653Sdougm ret = SA_NO_MEMORY; 7943034Sdougm if (ret != SA_OK || 7953034Sdougm (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 7964653Sdougm (void) printf( 7974653Sdougm gettext("Could not add property %s: %s\n"), 7984653Sdougm cur->optname, sa_errorstr(ret)); 7993034Sdougm } 8003034Sdougm (void) sa_remove_property(prop); 8013034Sdougm } 8023034Sdougm return (ret); 8033034Sdougm } 8043034Sdougm 8053034Sdougm /* 8063034Sdougm * add_optionset(group, optlist, protocol, *err) 8073034Sdougm * Add the options in optlist to an optionset and then add the optionset 8083034Sdougm * to the group. 8093034Sdougm * 8103034Sdougm * The return value indicates if there was a "change" while errors are 8113034Sdougm * returned via the *err parameters. 8123034Sdougm */ 8133034Sdougm static int 8143034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 8153034Sdougm { 8163034Sdougm sa_optionset_t optionset; 8173034Sdougm int ret = SA_OK; 8185331Samw int result = B_FALSE; 8193034Sdougm 8203034Sdougm optionset = sa_get_optionset(group, proto); 8213034Sdougm if (optionset == NULL) { 8224653Sdougm optionset = sa_create_optionset(group, proto); 8235331Samw if (optionset == NULL) 8245331Samw ret = SA_NO_MEMORY; 8255331Samw result = B_TRUE; /* adding a protocol is a change */ 8263034Sdougm } 8274653Sdougm if (optionset == NULL) { 8284653Sdougm ret = SA_NO_MEMORY; 8294653Sdougm goto out; 8304653Sdougm } 8314653Sdougm while (optlist != NULL) { 8323034Sdougm sa_property_t prop; 8333034Sdougm prop = sa_get_property(optionset, optlist->optname); 8343034Sdougm if (prop == NULL) { 8353034Sdougm /* 8363034Sdougm * add the property, but only if it is 8373034Sdougm * a non-NULL or non-zero length value 8383034Sdougm */ 8394653Sdougm if (optlist->optvalue != NULL) { 8404653Sdougm prop = sa_create_property(optlist->optname, 8414653Sdougm optlist->optvalue); 8424653Sdougm if (prop != NULL) { 8434653Sdougm ret = sa_valid_property(optionset, 8444653Sdougm proto, prop); 8454653Sdougm if (ret != SA_OK) { 8464653Sdougm (void) sa_remove_property(prop); 8474653Sdougm (void) printf(gettext("Could " 8484653Sdougm "not add property " 8494653Sdougm "%s: %s\n"), 8504653Sdougm optlist->optname, 8514653Sdougm sa_errorstr(ret)); 8524653Sdougm } 8534653Sdougm } 8544653Sdougm if (ret == SA_OK) { 8554653Sdougm ret = sa_add_property(optionset, prop); 8564653Sdougm if (ret != SA_OK) { 8574653Sdougm (void) printf(gettext( 8584653Sdougm "Could not add property " 8594653Sdougm "%s: %s\n"), 8604653Sdougm optlist->optname, 8614653Sdougm sa_errorstr(ret)); 8624653Sdougm } else { 8634653Sdougm /* there was a change */ 8645331Samw result = B_TRUE; 8654653Sdougm } 8664653Sdougm } 8673034Sdougm } 8684653Sdougm } else { 8694653Sdougm ret = sa_update_property(prop, optlist->optvalue); 8704653Sdougm /* should check to see if value changed */ 8714653Sdougm if (ret != SA_OK) { 8724653Sdougm (void) printf(gettext("Could not update " 8734653Sdougm "property %s: %s\n"), optlist->optname, 8744653Sdougm sa_errorstr(ret)); 8754653Sdougm } else { 8765331Samw result = B_TRUE; 8773034Sdougm } 8783034Sdougm } 8793034Sdougm optlist = optlist->next; 8803034Sdougm } 8814653Sdougm ret = sa_commit_properties(optionset, 0); 8824653Sdougm 8834653Sdougm out: 8843034Sdougm if (err != NULL) 8854653Sdougm *err = ret; 8863034Sdougm return (result); 8873034Sdougm } 8883034Sdougm 8893034Sdougm /* 8905331Samw * resource_compliant(group) 8915331Samw * 8925331Samw * Go through all the shares in the group. Assume compliant, but if 8935331Samw * any share doesn't have at least one resource name, it isn't 8945331Samw * compliant. 8955331Samw */ 8965331Samw static int 8975331Samw resource_compliant(sa_group_t group) 8985331Samw { 8995331Samw sa_share_t share; 9005331Samw 9015331Samw for (share = sa_get_share(group, NULL); share != NULL; 9025331Samw share = sa_get_next_share(share)) { 9035331Samw if (sa_get_share_resource(share, NULL) == NULL) { 9045331Samw return (B_FALSE); 9055331Samw } 9065331Samw } 9075331Samw return (B_TRUE); 9085331Samw } 9095331Samw 9105331Samw /* 9115331Samw * fix_path(path) 9125331Samw * 9135331Samw * change all illegal characters to something else. For now, all get 9145331Samw * converted to '_' and the leading '/' is stripped off. This is used 9155331Samw * to construct an resource name (SMB share name) that is valid. 9165331Samw * Caller must pass a valid path. 9175331Samw */ 9185331Samw static void 9195331Samw fix_path(char *path) 9205331Samw { 9215331Samw char *cp; 9225331Samw size_t len; 9235331Samw 9245331Samw assert(path != NULL); 9255331Samw 9265331Samw /* make sure we are appropriate length */ 9275331Samw cp = path + 1; /* skip leading slash */ 9285331Samw while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) { 9295331Samw cp = strchr(cp, '/'); 9305331Samw if (cp != NULL) 9315331Samw cp++; 9325331Samw } 9335331Samw /* two cases - cp == NULL and cp is substring of path */ 9345331Samw if (cp == NULL) { 9355331Samw /* just take last SA_MAX_RESOURCE_NAME chars */ 9365331Samw len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME; 9375331Samw (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME); 9385331Samw path[SA_MAX_RESOURCE_NAME] = '\0'; 9395331Samw } else { 9405331Samw len = strlen(cp) + 1; 9415331Samw (void) memmove(path, cp, len); 9425331Samw } 9435331Samw 9445331Samw /* 9455331Samw * Don't want any of the characters that are not allowed 9465331Samw * in and SMB share name. Replace them with '_'. 9475331Samw */ 9485331Samw while (*path) { 9495331Samw switch (*path) { 9505331Samw case '/': 9515331Samw case '"': 9525331Samw case '\\': 9535331Samw case '[': 9545331Samw case ']': 9555331Samw case ':': 9565331Samw case '|': 9575331Samw case '<': 9585331Samw case '>': 9595331Samw case '+': 9605331Samw case ';': 9615331Samw case ',': 9625331Samw case '?': 9635331Samw case '*': 9645331Samw case '=': 9655331Samw case '\t': 9665331Samw *path = '_'; 9675331Samw break; 9685331Samw } 9695331Samw path++; 9705331Samw } 9715331Samw } 9725331Samw 9735331Samw /* 9745331Samw * name_adjust(path, count) 9755331Samw * 9765331Samw * Add a ~<count> in place of last few characters. The total number of 9775331Samw * characters is dependent on count. 9785331Samw */ 9795331Samw #define MAX_MANGLE_NUMBER 10000 9805331Samw 9815331Samw static int 9825331Samw name_adjust(char *path, int count) 9835331Samw { 9845331Samw size_t len; 9855331Samw 9865331Samw len = strlen(path) - 2; 9875331Samw if (count > 10) 9885331Samw len--; 9895331Samw if (count > 100) 9905331Samw len--; 9915331Samw if (count > 1000) 9925331Samw len--; 9935331Samw if (len > 0) 9945331Samw (void) sprintf(path + len, "~%d", count); 9955331Samw else 9965331Samw return (SA_BAD_VALUE); 9975331Samw 9985331Samw return (SA_OK); 9995331Samw } 10005331Samw 10015331Samw /* 10025331Samw * make_resources(group) 10035331Samw * 10045331Samw * Go through all the shares in the group and make them have resource 10055331Samw * names. 10065331Samw */ 10075331Samw static void 10085331Samw make_resources(sa_group_t group) 10095331Samw { 10105331Samw sa_share_t share; 10115331Samw int count; 10125331Samw int err = SA_OK; 10135331Samw 10145331Samw for (share = sa_get_share(group, NULL); share != NULL; 10155331Samw share = sa_get_next_share(share)) { 10165331Samw /* Skip those with resources */ 10175331Samw if (sa_get_share_resource(share, NULL) == NULL) { 10185331Samw char *path; 10195331Samw path = sa_get_share_attr(share, "path"); 10205331Samw if (path == NULL) 10215331Samw continue; 10225331Samw fix_path(path); 10235331Samw count = 0; /* reset for next resource */ 10245331Samw while (sa_add_resource(share, path, 10255331Samw SA_SHARE_PERMANENT, &err) == NULL && 10265331Samw err == SA_DUPLICATE_NAME) { 10275331Samw int ret; 10285331Samw ret = name_adjust(path, count); 10295331Samw count++; 10305331Samw if (ret != SA_OK || 10315331Samw count >= MAX_MANGLE_NUMBER) { 10325331Samw (void) printf(gettext( 10335331Samw "Cannot create resource name for" 10345331Samw " path: %s\n"), path); 10355331Samw break; 10365331Samw } 10375331Samw } 10385331Samw sa_free_attr_string(path); 10395331Samw } 10405331Samw } 10415331Samw } 10425331Samw 10435331Samw /* 10443034Sdougm * sa_create(flags, argc, argv) 10453034Sdougm * create a new group 10463034Sdougm * this may or may not have a protocol associated with it. 10473034Sdougm * No protocol means "all" protocols in this case. 10483034Sdougm */ 10493034Sdougm static int 10503910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[]) 10513034Sdougm { 10523034Sdougm char *groupname; 10533034Sdougm 10543034Sdougm sa_group_t group; 10555331Samw int force = 0; 10563034Sdougm int verbose = 0; 10573034Sdougm int dryrun = 0; 10583034Sdougm int c; 10593034Sdougm char *protocol = NULL; 10603034Sdougm int ret = SA_OK; 10613034Sdougm struct options *optlist = NULL; 1062*6019Sdougm int err = SA_OK; 10633034Sdougm int auth; 10643034Sdougm 10655331Samw while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) { 10664653Sdougm switch (c) { 10675331Samw case 'f': 10685331Samw force++; 10695331Samw break; 10704653Sdougm case 'v': 10714653Sdougm verbose++; 10724653Sdougm break; 10734653Sdougm case 'n': 10744653Sdougm dryrun++; 10754653Sdougm break; 10764653Sdougm case 'P': 10775331Samw if (protocol != NULL) { 10785331Samw (void) printf(gettext("Specifying " 10795331Samw "multiple protocols " 10805331Samw "not supported: %s\n"), protocol); 10815331Samw return (SA_SYNTAX_ERR); 10825331Samw } 10834653Sdougm protocol = optarg; 10844653Sdougm if (sa_valid_protocol(protocol)) 10854653Sdougm break; 10864653Sdougm (void) printf(gettext( 10874653Sdougm "Invalid protocol specified: %s\n"), protocol); 10884653Sdougm return (SA_INVALID_PROTOCOL); 10894653Sdougm break; 10904653Sdougm case 'p': 10914653Sdougm ret = add_opt(&optlist, optarg, 0); 10924653Sdougm switch (ret) { 10934653Sdougm case OPT_ADD_SYNTAX: 10944653Sdougm (void) printf(gettext( 10954653Sdougm "Property syntax error for property: %s\n"), 10964653Sdougm optarg); 10974653Sdougm return (SA_SYNTAX_ERR); 10984653Sdougm case OPT_ADD_SECURITY: 10994653Sdougm (void) printf(gettext( 11004653Sdougm "Security properties need " 11014653Sdougm "to be set with set-security: %s\n"), 11024653Sdougm optarg); 11034653Sdougm return (SA_SYNTAX_ERR); 11044653Sdougm default: 11054653Sdougm break; 11064653Sdougm } 11074653Sdougm break; 1108*6019Sdougm case 'h': 1109*6019Sdougm /* optopt on valid arg isn't defined */ 1110*6019Sdougm optopt = c; 1111*6019Sdougm /*FALLTHROUGH*/ 1112*6019Sdougm case '?': 11134653Sdougm default: 1114*6019Sdougm /* 1115*6019Sdougm * Since a bad option gets to here, sort it 1116*6019Sdougm * out and return a syntax error return value 1117*6019Sdougm * if necessary. 1118*6019Sdougm */ 1119*6019Sdougm switch (optopt) { 1120*6019Sdougm default: 1121*6019Sdougm err = SA_SYNTAX_ERR; 1122*6019Sdougm break; 1123*6019Sdougm case 'h': 1124*6019Sdougm case '?': 1125*6019Sdougm break; 1126*6019Sdougm } 11274653Sdougm (void) printf(gettext("usage: %s\n"), 11284653Sdougm sa_get_usage(USAGE_CREATE)); 1129*6019Sdougm return (err); 11303034Sdougm } 11313034Sdougm } 11323034Sdougm 11333034Sdougm if (optind >= argc) { 11344653Sdougm (void) printf(gettext("usage: %s\n"), 11354653Sdougm sa_get_usage(USAGE_CREATE)); 11364653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 11374653Sdougm return (SA_BAD_PATH); 11383034Sdougm } 11393034Sdougm 11403034Sdougm if ((optind + 1) < argc) { 11414653Sdougm (void) printf(gettext("usage: %s\n"), 11424653Sdougm sa_get_usage(USAGE_CREATE)); 11434653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 11444653Sdougm return (SA_SYNTAX_ERR); 11453034Sdougm } 11463034Sdougm 11473034Sdougm if (protocol == NULL && optlist != NULL) { 11484653Sdougm /* lookup default protocol */ 11494653Sdougm (void) printf(gettext("usage: %s\n"), 11504653Sdougm sa_get_usage(USAGE_CREATE)); 11514653Sdougm (void) printf(gettext("\tprotocol must be specified " 11524653Sdougm "with properties\n")); 11534653Sdougm return (SA_INVALID_PROTOCOL); 11543034Sdougm } 11553034Sdougm 11563034Sdougm if (optlist != NULL) 11574653Sdougm ret = chk_opt(optlist, 0, protocol); 11583034Sdougm if (ret == OPT_ADD_SECURITY) { 11594653Sdougm (void) printf(gettext("Security properties not " 11604653Sdougm "supported with create\n")); 11614653Sdougm return (SA_SYNTAX_ERR); 11623034Sdougm } 11633034Sdougm 11643034Sdougm /* 11654653Sdougm * If a group already exists, we can only add a new protocol 11663034Sdougm * to it and not create a new one or add the same protocol 11673034Sdougm * again. 11683034Sdougm */ 11693034Sdougm 11703034Sdougm groupname = argv[optind]; 11713034Sdougm 11723034Sdougm auth = check_authorizations(groupname, flags); 11733034Sdougm 11743910Sdougm group = sa_get_group(handle, groupname); 11753034Sdougm if (group != NULL) { 11764653Sdougm /* group exists so must be a protocol add */ 11774653Sdougm if (protocol != NULL) { 11784653Sdougm if (has_protocol(group, protocol)) { 11794653Sdougm (void) printf(gettext( 11804653Sdougm "Group \"%s\" already exists" 11814653Sdougm " with protocol %s\n"), groupname, 11824653Sdougm protocol); 11834653Sdougm ret = SA_DUPLICATE_NAME; 11845997Sdougm } else if (strcmp(groupname, "default") == 0 && 11855997Sdougm strcmp(protocol, "nfs") != 0) { 11865997Sdougm (void) printf(gettext( 11875997Sdougm "Group \"%s\" only allows protocol " 11885997Sdougm "\"%s\"\n"), groupname, "nfs"); 11895997Sdougm ret = SA_INVALID_PROTOCOL; 11904653Sdougm } 11914653Sdougm } else { 11924653Sdougm /* must add new protocol */ 11934653Sdougm (void) printf(gettext( 11944653Sdougm "Group already exists and no protocol " 11954653Sdougm "specified.\n")); 11964653Sdougm ret = SA_DUPLICATE_NAME; 11973034Sdougm } 11983034Sdougm } else { 11993034Sdougm /* 12003034Sdougm * is it a valid name? Must comply with SMF instance 12013034Sdougm * name restrictions. 12023034Sdougm */ 12034653Sdougm if (!sa_valid_group_name(groupname)) { 12044653Sdougm ret = SA_INVALID_NAME; 12054653Sdougm (void) printf(gettext("Invalid group name: %s\n"), 12064653Sdougm groupname); 12074653Sdougm } 12083034Sdougm } 12093034Sdougm if (ret == SA_OK) { 12104653Sdougm /* check protocol vs optlist */ 12114653Sdougm if (optlist != NULL) { 12124653Sdougm /* check options, if any, for validity */ 12134653Sdougm ret = valid_options(optlist, protocol, group, NULL); 12144653Sdougm } 12153034Sdougm } 12163034Sdougm if (ret == SA_OK && !dryrun) { 12174653Sdougm if (group == NULL) { 12184653Sdougm group = sa_create_group(handle, (char *)groupname, 12194653Sdougm &err); 12203034Sdougm } 12214653Sdougm if (group != NULL) { 12224653Sdougm sa_optionset_t optionset; 12235331Samw /* 12245331Samw * First check to see if the new protocol is one that 12255331Samw * requires resource names and make sure we are 12265331Samw * compliant before proceeding. 12275331Samw */ 12285331Samw if (protocol != NULL) { 12295331Samw uint64_t features; 12305331Samw 12315331Samw features = sa_proto_get_featureset(protocol); 12325331Samw if ((features & SA_FEATURE_RESOURCE) && 12335331Samw !resource_compliant(group)) { 12345331Samw if (force) { 12355331Samw make_resources(group); 12365331Samw } else { 12375331Samw ret = SA_RESOURCE_REQUIRED; 12385331Samw (void) printf( 12395331Samw gettext("Protocol " 12405331Samw "requires resource " 12415331Samw "names to be " 12425331Samw "set: %s\n"), 12435331Samw protocol); 12445331Samw goto err; 12455331Samw } 12465331Samw } 12475331Samw } 12484653Sdougm if (optlist != NULL) { 12494653Sdougm (void) add_optionset(group, optlist, protocol, 12504653Sdougm &ret); 12514653Sdougm } else if (protocol != NULL) { 12524653Sdougm optionset = sa_create_optionset(group, 12534653Sdougm protocol); 12544653Sdougm if (optionset == NULL) 12554653Sdougm ret = SA_NO_MEMORY; 12564653Sdougm } else if (protocol == NULL) { 12574653Sdougm char **protolist; 12584653Sdougm int numprotos, i; 12594653Sdougm numprotos = sa_get_protocols(&protolist); 12604653Sdougm for (i = 0; i < numprotos; i++) { 12614653Sdougm optionset = sa_create_optionset(group, 12624653Sdougm protolist[i]); 12634653Sdougm } 12644653Sdougm if (protolist != NULL) 12654653Sdougm free(protolist); 12664653Sdougm } 12673034Sdougm /* 12684653Sdougm * We have a group and legal additions 12693034Sdougm */ 12704653Sdougm if (ret == SA_OK) { 12714653Sdougm /* 12724653Sdougm * Commit to configuration for protocols that 12734653Sdougm * need to do block updates. For NFS, this 12744653Sdougm * doesn't do anything but it will be run for 12754653Sdougm * all protocols that implement the 12764653Sdougm * appropriate plugin. 12774653Sdougm */ 12784653Sdougm ret = sa_update_config(handle); 12794653Sdougm } else { 12804653Sdougm if (group != NULL) 12814653Sdougm (void) sa_remove_group(group); 12824653Sdougm } 12833034Sdougm } else { 12844653Sdougm ret = err; 12854653Sdougm (void) printf(gettext("Could not create group: %s\n"), 12864653Sdougm sa_errorstr(ret)); 12873034Sdougm } 12883034Sdougm } 12893034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 12904653Sdougm (void) printf(gettext("Command would fail: %s\n"), 12914653Sdougm sa_errorstr(SA_NO_PERMISSION)); 12924653Sdougm ret = SA_NO_PERMISSION; 12933034Sdougm } 12945331Samw err: 12953034Sdougm free_opt(optlist); 12963034Sdougm return (ret); 12973034Sdougm } 12983034Sdougm 12993034Sdougm /* 13003034Sdougm * group_status(group) 13013034Sdougm * 13023034Sdougm * return the current status (enabled/disabled) of the group. 13033034Sdougm */ 13043034Sdougm 13053034Sdougm static char * 13063034Sdougm group_status(sa_group_t group) 13073034Sdougm { 13083034Sdougm char *state; 13093034Sdougm int enabled = 0; 13103034Sdougm 13113034Sdougm state = sa_get_group_attr(group, "state"); 13123034Sdougm if (state != NULL) { 13134653Sdougm if (strcmp(state, "enabled") == 0) { 13144653Sdougm enabled = 1; 13154653Sdougm } 13164653Sdougm sa_free_attr_string(state); 13173034Sdougm } 13184255Sdougm return (enabled ? "enabled" : "disabled"); 13193034Sdougm } 13203034Sdougm 13213034Sdougm /* 13223034Sdougm * sa_delete(flags, argc, argv) 13233034Sdougm * 13243034Sdougm * Delete a group. 13253034Sdougm */ 13263034Sdougm 13273034Sdougm static int 13283910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[]) 13293034Sdougm { 13303034Sdougm char *groupname; 13313034Sdougm sa_group_t group; 13323034Sdougm sa_share_t share; 13333034Sdougm int verbose = 0; 13343034Sdougm int dryrun = 0; 13353034Sdougm int force = 0; 13363034Sdougm int c; 13373034Sdougm char *protocol = NULL; 13383034Sdougm char *sectype = NULL; 13393034Sdougm int ret = SA_OK; 13403034Sdougm int auth; 13413034Sdougm 13423034Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 13434653Sdougm switch (c) { 13444653Sdougm case 'v': 13454653Sdougm verbose++; 13464653Sdougm break; 13474653Sdougm case 'n': 13484653Sdougm dryrun++; 13494653Sdougm break; 13504653Sdougm case 'P': 13515331Samw if (protocol != NULL) { 13525331Samw (void) printf(gettext("Specifying " 13535331Samw "multiple protocols " 13545331Samw "not supported: %s\n"), protocol); 13555331Samw return (SA_SYNTAX_ERR); 13565331Samw } 13574653Sdougm protocol = optarg; 13584653Sdougm if (!sa_valid_protocol(protocol)) { 13594653Sdougm (void) printf(gettext("Invalid protocol " 13605331Samw "specified: %s\n"), protocol); 13614653Sdougm return (SA_INVALID_PROTOCOL); 13624653Sdougm } 13634653Sdougm break; 13644653Sdougm case 'S': 13655331Samw if (sectype != NULL) { 13665331Samw (void) printf(gettext("Specifying " 13675331Samw "multiple property " 13685331Samw "spaces not supported: %s\n"), sectype); 13695331Samw return (SA_SYNTAX_ERR); 13705331Samw } 13714653Sdougm sectype = optarg; 13724653Sdougm break; 13734653Sdougm case 'f': 13744653Sdougm force++; 13754653Sdougm break; 1376*6019Sdougm case 'h': 1377*6019Sdougm /* optopt on valid arg isn't defined */ 1378*6019Sdougm optopt = c; 1379*6019Sdougm /*FALLTHROUGH*/ 1380*6019Sdougm case '?': 13814653Sdougm default: 1382*6019Sdougm /* 1383*6019Sdougm * Since a bad option gets to here, sort it 1384*6019Sdougm * out and return a syntax error return value 1385*6019Sdougm * if necessary. 1386*6019Sdougm */ 1387*6019Sdougm switch (optopt) { 1388*6019Sdougm default: 1389*6019Sdougm ret = SA_SYNTAX_ERR; 1390*6019Sdougm break; 1391*6019Sdougm case 'h': 1392*6019Sdougm case '?': 1393*6019Sdougm break; 1394*6019Sdougm } 13954653Sdougm (void) printf(gettext("usage: %s\n"), 13964653Sdougm sa_get_usage(USAGE_DELETE)); 1397*6019Sdougm return (ret); 13983034Sdougm } 13993034Sdougm } 14003034Sdougm 14013034Sdougm if (optind >= argc) { 14024653Sdougm (void) printf(gettext("usage: %s\n"), 14034653Sdougm sa_get_usage(USAGE_DELETE)); 14044653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 14054653Sdougm return (SA_SYNTAX_ERR); 14063034Sdougm } 14073034Sdougm 14083034Sdougm if ((optind + 1) < argc) { 14094653Sdougm (void) printf(gettext("usage: %s\n"), 14104653Sdougm sa_get_usage(USAGE_DELETE)); 14114653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 14124653Sdougm return (SA_SYNTAX_ERR); 14133034Sdougm } 14143034Sdougm 14153034Sdougm if (sectype != NULL && protocol == NULL) { 14164653Sdougm (void) printf(gettext("usage: %s\n"), 14174653Sdougm sa_get_usage(USAGE_DELETE)); 14184653Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 14194653Sdougm "specified.\n")); 14204653Sdougm return (SA_SYNTAX_ERR); 14213034Sdougm } 14223034Sdougm 14233034Sdougm /* 14243034Sdougm * Determine if the group already exists since it must in 14253034Sdougm * order to be removed. 14263034Sdougm * 14273034Sdougm * We can delete when: 14283034Sdougm * 14293034Sdougm * - group is empty 14303034Sdougm * - force flag is set 14313034Sdougm * - if protocol specified, only delete the protocol 14323034Sdougm */ 14333034Sdougm 14343034Sdougm groupname = argv[optind]; 14353910Sdougm group = sa_get_group(handle, groupname); 14363034Sdougm if (group == NULL) { 14373034Sdougm ret = SA_NO_SUCH_GROUP; 14384653Sdougm goto done; 14394653Sdougm } 14404653Sdougm auth = check_authorizations(groupname, flags); 14414653Sdougm if (protocol == NULL) { 14423034Sdougm share = sa_get_share(group, NULL); 14433034Sdougm if (share != NULL) 14444653Sdougm ret = SA_BUSY; 14453034Sdougm if (share == NULL || (share != NULL && force == 1)) { 14464653Sdougm ret = SA_OK; 14474653Sdougm if (!dryrun) { 14484653Sdougm while (share != NULL) { 14494653Sdougm sa_share_t next_share; 14504653Sdougm next_share = sa_get_next_share(share); 14514653Sdougm /* 14524653Sdougm * need to do the disable of 14534653Sdougm * each share, but don't 14544653Sdougm * actually do anything on a 14554653Sdougm * dryrun. 14564653Sdougm */ 14574653Sdougm ret = sa_disable_share(share, NULL); 14584653Sdougm ret = sa_remove_share(share); 14594653Sdougm share = next_share; 14604653Sdougm } 14614653Sdougm ret = sa_remove_group(group); 14623034Sdougm } 14633034Sdougm } 14644653Sdougm /* Commit to configuration if not a dryrun */ 14653034Sdougm if (!dryrun && ret == SA_OK) { 14664653Sdougm ret = sa_update_config(handle); 14673034Sdougm } 14684653Sdougm } else { 14693034Sdougm /* a protocol delete */ 14703034Sdougm sa_optionset_t optionset; 14713034Sdougm sa_security_t security; 14725331Samw if (sectype != NULL) { 14734653Sdougm /* only delete specified security */ 14744653Sdougm security = sa_get_security(group, sectype, protocol); 14754653Sdougm if (security != NULL && !dryrun) 14764653Sdougm ret = sa_destroy_security(security); 14774653Sdougm else 14784653Sdougm ret = SA_INVALID_PROTOCOL; 14793034Sdougm } else { 14804653Sdougm optionset = sa_get_optionset(group, protocol); 14814653Sdougm if (optionset != NULL && !dryrun) { 14824653Sdougm /* 14834653Sdougm * have an optionset with 14844653Sdougm * protocol to delete 14854653Sdougm */ 14864653Sdougm ret = sa_destroy_optionset(optionset); 14874653Sdougm /* 14884653Sdougm * Now find all security sets 14894653Sdougm * for the protocol and remove 14904653Sdougm * them. Don't remove other 14914653Sdougm * protocols. 14924653Sdougm */ 14934653Sdougm for (security = 14944653Sdougm sa_get_security(group, NULL, NULL); 14954653Sdougm ret == SA_OK && security != NULL; 14964653Sdougm security = sa_get_next_security(security)) { 14974653Sdougm char *secprot; 14984653Sdougm secprot = sa_get_security_attr(security, 14994653Sdougm "type"); 15004653Sdougm if (secprot != NULL && 15014653Sdougm strcmp(secprot, protocol) == 0) 15024653Sdougm ret = sa_destroy_security( 15034653Sdougm security); 15044653Sdougm if (secprot != NULL) 15054653Sdougm sa_free_attr_string(secprot); 15064653Sdougm } 15074653Sdougm } else { 15084653Sdougm if (!dryrun) 15094653Sdougm ret = SA_INVALID_PROTOCOL; 15103034Sdougm } 15113034Sdougm } 15125331Samw /* 15135331Samw * With the protocol items removed, make sure that all 15145331Samw * the shares are updated in the legacy files, if 15155331Samw * necessary. 15165331Samw */ 15175331Samw for (share = sa_get_share(group, NULL); 15185331Samw share != NULL; 15195331Samw share = sa_get_next_share(share)) { 15205331Samw (void) sa_delete_legacy(share, protocol); 15215331Samw } 15223034Sdougm } 15234653Sdougm 15244653Sdougm done: 15253034Sdougm if (ret != SA_OK) { 15264653Sdougm (void) printf(gettext("Could not delete group: %s\n"), 15274653Sdougm sa_errorstr(ret)); 15283034Sdougm } else if (dryrun && !auth && verbose) { 15294653Sdougm (void) printf(gettext("Command would fail: %s\n"), 15304653Sdougm sa_errorstr(SA_NO_PERMISSION)); 15313034Sdougm } 15323034Sdougm return (ret); 15333034Sdougm } 15343034Sdougm 15353034Sdougm /* 15363034Sdougm * strndupr(*buff, str, buffsize) 15373034Sdougm * 15383034Sdougm * used with small strings to duplicate and possibly increase the 15393034Sdougm * buffer size of a string. 15403034Sdougm */ 15413034Sdougm static char * 15423034Sdougm strndupr(char *buff, char *str, int *buffsize) 15433034Sdougm { 15443034Sdougm int limit; 15453034Sdougm char *orig_buff = buff; 15463034Sdougm 15473034Sdougm if (buff == NULL) { 15484653Sdougm buff = (char *)malloc(64); 15494653Sdougm if (buff == NULL) 15504653Sdougm return (NULL); 15514653Sdougm *buffsize = 64; 15524653Sdougm buff[0] = '\0'; 15533034Sdougm } 15543034Sdougm limit = strlen(buff) + strlen(str) + 1; 15553034Sdougm if (limit > *buffsize) { 15564653Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 15574653Sdougm buff = realloc(buff, limit); 15583034Sdougm } 15593034Sdougm if (buff != NULL) { 15604653Sdougm (void) strcat(buff, str); 15613034Sdougm } else { 15624653Sdougm /* if it fails, fail it hard */ 15634653Sdougm if (orig_buff != NULL) 15644653Sdougm free(orig_buff); 15653034Sdougm } 15663034Sdougm return (buff); 15673034Sdougm } 15683034Sdougm 15693034Sdougm /* 15703034Sdougm * group_proto(group) 15713034Sdougm * 15723034Sdougm * return a string of all the protocols (space separated) associated 15733034Sdougm * with this group. 15743034Sdougm */ 15753034Sdougm 15763034Sdougm static char * 15773034Sdougm group_proto(sa_group_t group) 15783034Sdougm { 15793034Sdougm sa_optionset_t optionset; 15803034Sdougm char *proto; 15813034Sdougm char *buff = NULL; 15823034Sdougm int buffsize = 0; 15833034Sdougm int addspace = 0; 15843034Sdougm /* 15853034Sdougm * get the protocol list by finding the optionsets on this 15863034Sdougm * group and extracting the type value. The initial call to 15873034Sdougm * strndupr() initailizes buff. 15883034Sdougm */ 15893034Sdougm buff = strndupr(buff, "", &buffsize); 15903034Sdougm if (buff != NULL) { 15914653Sdougm for (optionset = sa_get_optionset(group, NULL); 15924653Sdougm optionset != NULL && buff != NULL; 15934653Sdougm optionset = sa_get_next_optionset(optionset)) { 15944653Sdougm /* 15954653Sdougm * extract out the protocol type from this optionset 15964653Sdougm * and append it to the buffer "buff". strndupr() will 15974653Sdougm * reallocate space as necessay. 15984653Sdougm */ 15994653Sdougm proto = sa_get_optionset_attr(optionset, "type"); 16004653Sdougm if (proto != NULL) { 16014653Sdougm if (addspace++) 16024653Sdougm buff = strndupr(buff, " ", &buffsize); 16034653Sdougm buff = strndupr(buff, proto, &buffsize); 16044653Sdougm sa_free_attr_string(proto); 16054653Sdougm } 16063034Sdougm } 16073034Sdougm } 16083034Sdougm return (buff); 16093034Sdougm } 16103034Sdougm 16113034Sdougm /* 16123034Sdougm * sa_list(flags, argc, argv) 16133034Sdougm * 16143034Sdougm * implements the "list" subcommand to list groups and optionally 16153034Sdougm * their state and protocols. 16163034Sdougm */ 16173034Sdougm 16183034Sdougm static int 16193910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[]) 16203034Sdougm { 16213034Sdougm sa_group_t group; 16223034Sdougm int verbose = 0; 16233034Sdougm int c; 16243034Sdougm char *protocol = NULL; 1625*6019Sdougm int ret = SA_OK; 16265331Samw #ifdef lint 16275331Samw flags = flags; 16285331Samw #endif 16293034Sdougm 16303034Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 16314653Sdougm switch (c) { 16324653Sdougm case 'v': 16334653Sdougm verbose++; 16344653Sdougm break; 16354653Sdougm case 'P': 16365331Samw if (protocol != NULL) { 16375331Samw (void) printf(gettext( 16385331Samw "Specifying multiple protocols " 16395331Samw "not supported: %s\n"), 16405331Samw protocol); 16415331Samw return (SA_SYNTAX_ERR); 16425331Samw } 16434653Sdougm protocol = optarg; 16444653Sdougm if (!sa_valid_protocol(protocol)) { 16454653Sdougm (void) printf(gettext( 16464653Sdougm "Invalid protocol specified: %s\n"), 16474653Sdougm protocol); 16484653Sdougm return (SA_INVALID_PROTOCOL); 16494653Sdougm } 16504653Sdougm break; 1651*6019Sdougm case 'h': 1652*6019Sdougm /* optopt on valid arg isn't defined */ 1653*6019Sdougm optopt = c; 1654*6019Sdougm /*FALLTHROUGH*/ 1655*6019Sdougm case '?': 16564653Sdougm default: 1657*6019Sdougm /* 1658*6019Sdougm * Since a bad option gets to here, sort it 1659*6019Sdougm * out and return a syntax error return value 1660*6019Sdougm * if necessary. 1661*6019Sdougm */ 1662*6019Sdougm switch (optopt) { 1663*6019Sdougm default: 1664*6019Sdougm ret = SA_SYNTAX_ERR; 1665*6019Sdougm break; 1666*6019Sdougm case 'h': 1667*6019Sdougm case '?': 1668*6019Sdougm break; 1669*6019Sdougm } 16704653Sdougm (void) printf(gettext("usage: %s\n"), 16714653Sdougm sa_get_usage(USAGE_LIST)); 1672*6019Sdougm return (ret); 16733034Sdougm } 16743034Sdougm } 16753034Sdougm 16765885Sdougm if (optind != argc) { 16775885Sdougm (void) printf(gettext("usage: %s\n"), 16785885Sdougm sa_get_usage(USAGE_LIST)); 16795885Sdougm return (SA_SYNTAX_ERR); 16805885Sdougm } 16815885Sdougm 16824653Sdougm for (group = sa_get_group(handle, NULL); 16834653Sdougm group != NULL; 16843034Sdougm group = sa_get_next_group(group)) { 16854653Sdougm char *name; 16864653Sdougm char *proto; 16874653Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 16884653Sdougm name = sa_get_group_attr(group, "name"); 16894653Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 16904653Sdougm (void) printf("%s", (char *)name); 16914653Sdougm if (verbose) { 16924653Sdougm /* 16934653Sdougm * Need the list of protocols 16944653Sdougm * and current status once 16954653Sdougm * available. We do want to 16964653Sdougm * translate the 16974653Sdougm * enabled/disabled text here. 16984653Sdougm */ 16994653Sdougm (void) printf("\t%s", isenabled(group) ? 17004653Sdougm gettext("enabled") : 17014653Sdougm gettext("disabled")); 17024653Sdougm proto = group_proto(group); 17034653Sdougm if (proto != NULL) { 17044653Sdougm (void) printf("\t%s", 17054653Sdougm (char *)proto); 17064653Sdougm free(proto); 17074653Sdougm } 17084653Sdougm } 17094653Sdougm (void) printf("\n"); 17103034Sdougm } 17114653Sdougm if (name != NULL) 17124653Sdougm sa_free_attr_string(name); 17133034Sdougm } 17143034Sdougm } 17153034Sdougm return (0); 17163034Sdougm } 17173034Sdougm 17183034Sdougm /* 17193034Sdougm * out_properties(optionset, proto, sec) 17203034Sdougm * 17213034Sdougm * Format the properties and encode the protocol and optional named 17223034Sdougm * optionset into the string. 17233034Sdougm * 17243034Sdougm * format is protocol[:name]=(property-list) 17253034Sdougm */ 17263034Sdougm 17273034Sdougm static void 17283034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 17293034Sdougm { 17303034Sdougm char *type; 17313034Sdougm char *value; 17323034Sdougm int spacer; 17333034Sdougm sa_property_t prop; 17343034Sdougm 17354653Sdougm if (sec == NULL) 17364653Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 17374653Sdougm else 17384653Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 17393034Sdougm 17403034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 17414653Sdougm prop != NULL; 17424653Sdougm prop = sa_get_next_property(prop)) { 17433034Sdougm 17443034Sdougm /* 17453034Sdougm * extract the property name/value and output with 17463034Sdougm * appropriate spacing. I.e. no prefixed space the 17473034Sdougm * first time through but a space on subsequent 17483034Sdougm * properties. 17493034Sdougm */ 17504653Sdougm type = sa_get_property_attr(prop, "type"); 17514653Sdougm value = sa_get_property_attr(prop, "value"); 17524653Sdougm if (type != NULL) { 17534653Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 17544653Sdougm spacer = 1; 17554653Sdougm if (value != NULL) 17564653Sdougm (void) printf("\"%s\"", value); 17574653Sdougm else 17584653Sdougm (void) printf("\"\""); 17594653Sdougm } 17604653Sdougm if (type != NULL) 17614653Sdougm sa_free_attr_string(type); 17623034Sdougm if (value != NULL) 17634653Sdougm sa_free_attr_string(value); 17643034Sdougm } 17653034Sdougm (void) printf(")"); 17663034Sdougm } 17673034Sdougm 17683034Sdougm /* 17693034Sdougm * show_properties(group, protocol, prefix) 17703034Sdougm * 17713034Sdougm * print the properties for a group. If protocol is NULL, do all 17723034Sdougm * protocols otherwise only the specified protocol. All security 17733034Sdougm * (named groups specific to the protocol) are included. 17743034Sdougm * 17753034Sdougm * The "prefix" is always applied. The caller knows whether it wants 17763034Sdougm * some type of prefix string (white space) or not. Once the prefix 17773034Sdougm * has been output, it is reduced to the zero length string for the 17783034Sdougm * remainder of the property output. 17793034Sdougm */ 17803034Sdougm 17813034Sdougm static void 17823034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 17833034Sdougm { 17843034Sdougm sa_optionset_t optionset; 17853034Sdougm sa_security_t security; 17863034Sdougm char *value; 17873034Sdougm char *secvalue; 17883034Sdougm 17893034Sdougm if (protocol != NULL) { 17904653Sdougm optionset = sa_get_optionset(group, protocol); 17914653Sdougm if (optionset != NULL) { 17924653Sdougm (void) printf("%s", prefix); 17934653Sdougm prefix = ""; 17944653Sdougm out_properties(optionset, protocol, NULL); 17954653Sdougm } 17964653Sdougm security = sa_get_security(group, protocol, NULL); 17974653Sdougm if (security != NULL) { 17984653Sdougm (void) printf("%s", prefix); 17994653Sdougm prefix = ""; 18004653Sdougm out_properties(security, protocol, NULL); 18014653Sdougm } 18023034Sdougm } else { 18034653Sdougm for (optionset = sa_get_optionset(group, protocol); 18044653Sdougm optionset != NULL; 18054653Sdougm optionset = sa_get_next_optionset(optionset)) { 18064653Sdougm 18074653Sdougm value = sa_get_optionset_attr(optionset, "type"); 18084653Sdougm (void) printf("%s", prefix); 18094653Sdougm prefix = ""; 18104653Sdougm out_properties(optionset, value, 0); 18114653Sdougm if (value != NULL) 18124653Sdougm sa_free_attr_string(value); 18134653Sdougm } 18144653Sdougm for (security = sa_get_security(group, NULL, protocol); 18154653Sdougm security != NULL; 18164653Sdougm security = sa_get_next_security(security)) { 18174653Sdougm 18184653Sdougm value = sa_get_security_attr(security, "type"); 18194653Sdougm secvalue = sa_get_security_attr(security, "sectype"); 18204653Sdougm (void) printf("%s", prefix); 18214653Sdougm prefix = ""; 18224653Sdougm out_properties(security, value, secvalue); 18234653Sdougm if (value != NULL) 18244653Sdougm sa_free_attr_string(value); 18254653Sdougm if (secvalue != NULL) 18264653Sdougm sa_free_attr_string(secvalue); 18274653Sdougm } 18283034Sdougm } 18293034Sdougm } 18303034Sdougm 18313034Sdougm /* 18325331Samw * get_resource(share) 18335331Samw * 18345331Samw * Get the first resource name, if any, and fix string to be in 18355331Samw * current locale and have quotes if it has embedded spaces. Return 18365331Samw * an attr string that must be freed. 18375331Samw */ 18385331Samw 18395331Samw static char * 18405331Samw get_resource(sa_share_t share) 18415331Samw { 18425331Samw sa_resource_t resource; 18435331Samw char *resstring = NULL; 18445331Samw char *retstring; 18455331Samw 18465331Samw if ((resource = sa_get_share_resource(share, NULL)) != NULL) { 18475331Samw resstring = sa_get_resource_attr(resource, "name"); 18485331Samw if (resstring != NULL) { 18495331Samw char *cp; 18505331Samw int len; 18515331Samw 18525331Samw retstring = conv_from_utf8(resstring); 18535331Samw if (retstring != resstring) { 18545331Samw sa_free_attr_string(resstring); 18555331Samw resstring = retstring; 18565331Samw } 18575331Samw if (strpbrk(resstring, " ") != NULL) { 18585331Samw /* account for quotes */ 18595331Samw len = strlen(resstring) + 3; 18605331Samw cp = calloc(len, sizeof (char)); 18615331Samw if (cp != NULL) { 18625331Samw (void) snprintf(cp, len, 18635331Samw "\"%s\"", resstring); 18645331Samw sa_free_attr_string(resstring); 18655331Samw resstring = cp; 18665331Samw } else { 18675331Samw sa_free_attr_string(resstring); 18685331Samw resstring = NULL; 18695331Samw } 18705331Samw } 18715331Samw } 18725331Samw } 18735331Samw return (resstring); 18745331Samw } 18755331Samw 18765331Samw /* 18775331Samw * has_resource_with_opt(share) 18785331Samw * 18795331Samw * Check to see if the share has any resource names with optionsets 18805331Samw * set. Also indicate if multiple resource names since the syntax 18815331Samw * would be about the same. 18825331Samw */ 18835331Samw static int 18845331Samw has_resource_with_opt(sa_share_t share) 18855331Samw { 18865331Samw sa_resource_t resource; 18875331Samw int ret = B_FALSE; 18885331Samw 18895331Samw for (resource = sa_get_share_resource(share, NULL); 18905331Samw resource != NULL; 18915331Samw resource = sa_get_next_resource(resource)) { 18925331Samw 18935331Samw if (sa_get_optionset(resource, NULL) != NULL) { 18945331Samw ret = B_TRUE; 18955331Samw break; 18965331Samw } 18975331Samw } 18985331Samw return (ret); 18995331Samw } 19005331Samw 19015331Samw /* 19025331Samw * has_multiple_resource(share) 19035331Samw * 19045885Sdougm * Check to see if the share has multiple resource names since 19055885Sdougm * the syntax would be about the same. 19065331Samw */ 19075885Sdougm static boolean_t 19085331Samw has_multiple_resource(sa_share_t share) 19095331Samw { 19105331Samw sa_resource_t resource; 19115331Samw int num; 19125331Samw 19135331Samw for (num = 0, resource = sa_get_share_resource(share, NULL); 19145331Samw resource != NULL; 19155331Samw resource = sa_get_next_resource(resource)) { 19165331Samw num++; 19175331Samw if (num > 1) 19185331Samw return (B_TRUE); 19195331Samw } 19205331Samw return (B_FALSE); 19215331Samw } 19225331Samw 19235331Samw /* 19245331Samw * show_share(share, verbose, properties, proto, iszfs, sharepath) 19255331Samw * 19265331Samw * print out the share information. With the addition of resource as a 19275331Samw * full object that can have multiple instances below the share, we 19285331Samw * need to display that as well. 19295331Samw */ 19305331Samw 19315331Samw static void 19325331Samw show_share(sa_share_t share, int verbose, int properties, char *proto, 19335331Samw int iszfs, char *sharepath) 19345331Samw { 19355331Samw char *drive; 19365331Samw char *exclude; 19375331Samw sa_resource_t resource = NULL; 19385331Samw char *description; 19395331Samw char *rsrcname; 19405331Samw int rsrcwithopt; 19415885Sdougm boolean_t multiple; 19425331Samw char *type; 19435331Samw 19445331Samw rsrcwithopt = has_resource_with_opt(share); 19455331Samw 19465331Samw if (verbose || (properties && rsrcwithopt)) { 19475331Samw /* First, indicate if transient */ 19485331Samw type = sa_get_share_attr(share, "type"); 19495331Samw if (type != NULL && !iszfs && verbose && 19505331Samw strcmp(type, "transient") == 0) 19515331Samw (void) printf("\t* "); 19525331Samw else 19535331Samw (void) printf("\t "); 19545331Samw 19555331Samw if (type != NULL) 19565331Samw sa_free_attr_string(type); 19575331Samw 19585331Samw /* 19595331Samw * If we came in with verbose, we want to handle the case of 19605331Samw * multiple resources as though they had properties set. 19615331Samw */ 19625331Samw multiple = has_multiple_resource(share); 19635331Samw 19645885Sdougm /* 19655885Sdougm * if there is a description on the share and there 19665885Sdougm * are resources, treat as multiple resources in order 19675885Sdougm * to get all descriptions displayed. 19685885Sdougm */ 19695885Sdougm description = sa_get_share_description(share); 19705885Sdougm resource = sa_get_share_resource(share, NULL); 19715885Sdougm 19725885Sdougm if (description != NULL && resource != NULL) 19735885Sdougm multiple = B_TRUE; 19745885Sdougm 19755331Samw /* Next, if not multiple follow old model */ 19765331Samw if (!multiple && !rsrcwithopt) { 19775331Samw rsrcname = get_resource(share); 19785331Samw if (rsrcname != NULL && strlen(rsrcname) > 0) { 19795331Samw (void) printf("%s=%s", rsrcname, sharepath); 19805331Samw } else { 19815331Samw (void) printf("%s", sharepath); 19825331Samw } 19835331Samw if (rsrcname != NULL) 19845331Samw sa_free_attr_string(rsrcname); 19855885Sdougm /* Print the description string if there is one. */ 19865885Sdougm print_rsrc_desc(resource, description); 19875331Samw } else { 19885331Samw /* Treat as simple and then resources come later */ 19895331Samw (void) printf("%s", sharepath); 19905331Samw } 19915331Samw drive = sa_get_share_attr(share, "drive-letter"); 19925331Samw if (drive != NULL) { 19935331Samw if (strlen(drive) > 0) 19945331Samw (void) printf(gettext("\tdrive-letter=\"%s:\""), 19955331Samw drive); 19965331Samw sa_free_attr_string(drive); 19975331Samw } 19985331Samw if (properties) 19995331Samw show_properties(share, proto, "\t"); 20005331Samw exclude = sa_get_share_attr(share, "exclude"); 20015331Samw if (exclude != NULL) { 20025331Samw (void) printf(gettext("\tnot-shared-with=[%s]"), 20035331Samw exclude); 20045331Samw sa_free_attr_string(exclude); 20055331Samw } 20065885Sdougm 20075331Samw if (description != NULL) { 20085885Sdougm print_rsrc_desc((sa_resource_t)share, description); 20095331Samw } 20105331Samw /* 20115331Samw * If there are resource names with options, show them 20125331Samw * here, with one line per resource. Resource specific 20135331Samw * options are at the end of the line followed by 20145331Samw * description, if any. 20155331Samw */ 20165331Samw if (rsrcwithopt || multiple) { 20175331Samw for (resource = sa_get_share_resource(share, NULL); 20185331Samw resource != NULL; 20195331Samw resource = sa_get_next_resource(resource)) { 20205331Samw int has_space; 20215331Samw char *rsrc; 20225331Samw 20235331Samw (void) printf("\n\t\t "); 20245331Samw rsrcname = sa_get_resource_attr(resource, 20255331Samw "name"); 20265331Samw if (rsrcname == NULL) 20275331Samw continue; 20285331Samw 20295331Samw rsrc = conv_from_utf8(rsrcname); 20305331Samw has_space = strpbrk(rsrc, " ") != NULL; 20315331Samw 20325331Samw if (has_space) 20335331Samw (void) printf("\"%s\"=%s", rsrc, 20345331Samw sharepath); 20355331Samw else 20365331Samw (void) printf("%s=%s", rsrc, 20375331Samw sharepath); 20385331Samw if (rsrc != rsrcname) 20395331Samw sa_free_attr_string(rsrc); 20405331Samw sa_free_attr_string(rsrcname); 20415331Samw if (properties || rsrcwithopt) 20425331Samw show_properties(resource, proto, "\t"); 20435331Samw 20445331Samw /* Get description string if any */ 20455885Sdougm print_rsrc_desc(resource, description); 20465331Samw } 20475331Samw } 20485885Sdougm if (description != NULL) 20495885Sdougm sa_free_share_description(description); 20505331Samw } else { 20515331Samw (void) printf("\t %s", sharepath); 20525331Samw if (properties) 20535331Samw show_properties(share, proto, "\t"); 20545331Samw } 20555331Samw (void) printf("\n"); 20565331Samw } 20575331Samw 20585331Samw /* 20593034Sdougm * show_group(group, verbose, properties, proto, subgroup) 20603034Sdougm * 20613034Sdougm * helper function to show the contents of a group. 20623034Sdougm */ 20633034Sdougm 20643034Sdougm static void 20653034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 20665331Samw char *subgroup) 20673034Sdougm { 20683034Sdougm sa_share_t share; 20693034Sdougm char *groupname; 20703034Sdougm char *zfs = NULL; 20713034Sdougm int iszfs = 0; 20725331Samw char *sharepath; 20733034Sdougm 20743034Sdougm groupname = sa_get_group_attr(group, "name"); 20753034Sdougm if (groupname != NULL) { 20764653Sdougm if (proto != NULL && !has_protocol(group, proto)) { 20774653Sdougm sa_free_attr_string(groupname); 20784653Sdougm return; 20794653Sdougm } 20803034Sdougm /* 20813034Sdougm * check to see if the group is managed by ZFS. If 20823034Sdougm * there is an attribute, then it is. A non-NULL zfs 20833034Sdougm * variable will trigger the different way to display 20843034Sdougm * and will remove the transient property indicator 20853034Sdougm * from the output. 20863034Sdougm */ 20874653Sdougm zfs = sa_get_group_attr(group, "zfs"); 20884653Sdougm if (zfs != NULL) { 20894653Sdougm iszfs = 1; 20904653Sdougm sa_free_attr_string(zfs); 20913034Sdougm } 20924653Sdougm share = sa_get_share(group, NULL); 20934653Sdougm if (subgroup == NULL) 20944653Sdougm (void) printf("%s", groupname); 20954653Sdougm else 20964653Sdougm (void) printf(" %s/%s", subgroup, groupname); 20974653Sdougm if (properties) 20984653Sdougm show_properties(group, proto, ""); 20994653Sdougm (void) printf("\n"); 21004653Sdougm if (strcmp(groupname, "zfs") == 0) { 21014653Sdougm sa_group_t zgroup; 21024653Sdougm 21034653Sdougm for (zgroup = sa_get_sub_group(group); 21044653Sdougm zgroup != NULL; 21054653Sdougm zgroup = sa_get_next_group(zgroup)) { 21064653Sdougm show_group(zgroup, verbose, properties, proto, 21074653Sdougm "zfs"); 21084653Sdougm } 21094653Sdougm sa_free_attr_string(groupname); 21104653Sdougm return; 21114653Sdougm } 21123034Sdougm /* 21134653Sdougm * Have a group, so list the contents. Resource and 21143034Sdougm * description are only listed if verbose is set. 21153034Sdougm */ 21164653Sdougm for (share = sa_get_share(group, NULL); 21174653Sdougm share != NULL; 21184653Sdougm share = sa_get_next_share(share)) { 21194653Sdougm sharepath = sa_get_share_attr(share, "path"); 21204653Sdougm if (sharepath != NULL) { 21215331Samw show_share(share, verbose, properties, proto, 21225331Samw iszfs, sharepath); 21234653Sdougm sa_free_attr_string(sharepath); 21243034Sdougm } 21253034Sdougm } 21263034Sdougm } 21273034Sdougm if (groupname != NULL) { 21283034Sdougm sa_free_attr_string(groupname); 21293034Sdougm } 21303034Sdougm } 21313034Sdougm 21323034Sdougm /* 21333034Sdougm * show_group_xml_init() 21343034Sdougm * 21353034Sdougm * Create an XML document that will be used to display config info via 21363034Sdougm * XML format. 21373034Sdougm */ 21383034Sdougm 21393034Sdougm xmlDocPtr 21403034Sdougm show_group_xml_init() 21413034Sdougm { 21423034Sdougm xmlDocPtr doc; 21433034Sdougm xmlNodePtr root; 21443034Sdougm 21453034Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 21463034Sdougm if (doc != NULL) { 21474653Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 21484653Sdougm if (root != NULL) 21494653Sdougm xmlDocSetRootElement(doc, root); 21503034Sdougm } 21513034Sdougm return (doc); 21523034Sdougm } 21533034Sdougm 21543034Sdougm /* 21553034Sdougm * show_group_xml(doc, group) 21563034Sdougm * 21573034Sdougm * Copy the group info into the XML doc. 21583034Sdougm */ 21593034Sdougm 21603034Sdougm static void 21613034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 21623034Sdougm { 21633034Sdougm xmlNodePtr node; 21643034Sdougm xmlNodePtr root; 21653034Sdougm 21663034Sdougm root = xmlDocGetRootElement(doc); 21673034Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 21683034Sdougm if (node != NULL && root != NULL) { 21694653Sdougm xmlAddChild(root, node); 21703034Sdougm /* 21713034Sdougm * In the future, we may have interally used tags that 21723034Sdougm * should not appear in the XML output. Remove 21733034Sdougm * anything we don't want to show here. 21743034Sdougm */ 21753034Sdougm } 21763034Sdougm } 21773034Sdougm 21783034Sdougm /* 21793034Sdougm * sa_show(flags, argc, argv) 21803034Sdougm * 21813034Sdougm * Implements the show subcommand. 21823034Sdougm */ 21833034Sdougm 21843034Sdougm int 21853910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[]) 21863034Sdougm { 21873034Sdougm sa_group_t group; 21883034Sdougm int verbose = 0; 21893034Sdougm int properties = 0; 21903034Sdougm int c; 21913034Sdougm int ret = SA_OK; 21923034Sdougm char *protocol = NULL; 21933034Sdougm int xml = 0; 21943034Sdougm xmlDocPtr doc; 21955331Samw #ifdef lint 21965331Samw flags = flags; 21975331Samw #endif 21983034Sdougm 21993034Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 22004653Sdougm switch (c) { 22014653Sdougm case 'v': 22024653Sdougm verbose++; 22034653Sdougm break; 22044653Sdougm case 'p': 22054653Sdougm properties++; 22064653Sdougm break; 22074653Sdougm case 'P': 22085331Samw if (protocol != NULL) { 22095331Samw (void) printf(gettext( 22105331Samw "Specifying multiple protocols " 22115331Samw "not supported: %s\n"), 22125331Samw protocol); 22135331Samw return (SA_SYNTAX_ERR); 22145331Samw } 22154653Sdougm protocol = optarg; 22164653Sdougm if (!sa_valid_protocol(protocol)) { 22174653Sdougm (void) printf(gettext( 22184653Sdougm "Invalid protocol specified: %s\n"), 22194653Sdougm protocol); 22204653Sdougm return (SA_INVALID_PROTOCOL); 22214653Sdougm } 22224653Sdougm break; 22234653Sdougm case 'x': 22244653Sdougm xml++; 22254653Sdougm break; 2226*6019Sdougm case 'h': 2227*6019Sdougm /* optopt on valid arg isn't defined */ 2228*6019Sdougm optopt = c; 2229*6019Sdougm /*FALLTHROUGH*/ 2230*6019Sdougm case '?': 22314653Sdougm default: 2232*6019Sdougm /* 2233*6019Sdougm * Since a bad option gets to here, sort it 2234*6019Sdougm * out and return a syntax error return value 2235*6019Sdougm * if necessary. 2236*6019Sdougm */ 2237*6019Sdougm switch (optopt) { 2238*6019Sdougm default: 2239*6019Sdougm ret = SA_SYNTAX_ERR; 2240*6019Sdougm break; 2241*6019Sdougm case 'h': 2242*6019Sdougm case '?': 2243*6019Sdougm break; 2244*6019Sdougm } 22454653Sdougm (void) printf(gettext("usage: %s\n"), 22464653Sdougm sa_get_usage(USAGE_SHOW)); 2247*6019Sdougm return (ret); 22483034Sdougm } 22493034Sdougm } 22503034Sdougm 22513034Sdougm if (xml) { 22524653Sdougm doc = show_group_xml_init(); 22534653Sdougm if (doc == NULL) 22544653Sdougm ret = SA_NO_MEMORY; 22553034Sdougm } 22563034Sdougm 22573034Sdougm if (optind == argc) { 22584653Sdougm /* No group specified so go through them all */ 22594653Sdougm for (group = sa_get_group(handle, NULL); 22604653Sdougm group != NULL; 22614653Sdougm group = sa_get_next_group(group)) { 22624653Sdougm /* 22634653Sdougm * Have a group so check if one we want and then list 22644653Sdougm * contents with appropriate options. 22654653Sdougm */ 22664653Sdougm if (xml) 22674653Sdougm show_group_xml(doc, group); 22684653Sdougm else 22694653Sdougm show_group(group, verbose, properties, protocol, 22704653Sdougm NULL); 22714653Sdougm } 22723034Sdougm } else { 22734653Sdougm /* Have a specified list of groups */ 22744653Sdougm for (; optind < argc; optind++) { 22754653Sdougm group = sa_get_group(handle, argv[optind]); 22764653Sdougm if (group != NULL) { 22774653Sdougm if (xml) 22784653Sdougm show_group_xml(doc, group); 22794653Sdougm else 22804653Sdougm show_group(group, verbose, properties, 22814653Sdougm protocol, NULL); 22824653Sdougm } else { 22834653Sdougm (void) printf(gettext("%s: not found\n"), 22844653Sdougm argv[optind]); 22854653Sdougm ret = SA_NO_SUCH_GROUP; 22864653Sdougm } 22873034Sdougm } 22883034Sdougm } 22893034Sdougm if (xml && ret == SA_OK) { 22904653Sdougm xmlDocFormatDump(stdout, doc, 1); 22914653Sdougm xmlFreeDoc(doc); 22923034Sdougm } 22933034Sdougm return (ret); 22943034Sdougm 22953034Sdougm } 22963034Sdougm 22973034Sdougm /* 22983034Sdougm * enable_share(group, share, update_legacy) 22993034Sdougm * 23003034Sdougm * helper function to enable a share if the group is enabled. 23013034Sdougm */ 23023034Sdougm 23033034Sdougm static int 23043910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 23055331Samw int update_legacy) 23063034Sdougm { 23073034Sdougm char *value; 23083034Sdougm int enabled; 23093034Sdougm sa_optionset_t optionset; 23105331Samw int err; 23113034Sdougm int ret = SA_OK; 23123034Sdougm char *zfs = NULL; 23133034Sdougm int iszfs = 0; 23145331Samw int isshare; 23153034Sdougm 23163034Sdougm /* 23173034Sdougm * need to enable this share if the group is enabled but not 23183034Sdougm * otherwise. The enable is also done on each protocol 23193034Sdougm * represented in the group. 23203034Sdougm */ 23213034Sdougm value = sa_get_group_attr(group, "state"); 23223034Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 23233034Sdougm if (value != NULL) 23244653Sdougm sa_free_attr_string(value); 23253034Sdougm /* remove legacy config if necessary */ 23263034Sdougm if (update_legacy) 23275331Samw ret = sa_delete_legacy(share, NULL); 23283034Sdougm zfs = sa_get_group_attr(group, "zfs"); 23293034Sdougm if (zfs != NULL) { 23304653Sdougm iszfs++; 23314653Sdougm sa_free_attr_string(zfs); 23323034Sdougm } 23333034Sdougm 23343034Sdougm /* 23353034Sdougm * Step through each optionset at the group level and 23363034Sdougm * enable the share based on the protocol type. This 23373034Sdougm * works because protocols must be set on the group 23383034Sdougm * for the protocol to be enabled. 23393034Sdougm */ 23405331Samw isshare = sa_is_share(share); 23413034Sdougm for (optionset = sa_get_optionset(group, NULL); 23423034Sdougm optionset != NULL && ret == SA_OK; 23433034Sdougm optionset = sa_get_next_optionset(optionset)) { 23444653Sdougm value = sa_get_optionset_attr(optionset, "type"); 23454653Sdougm if (value != NULL) { 23465331Samw if (enabled) { 23475331Samw if (isshare) { 23485331Samw err = sa_enable_share(share, value); 23495331Samw } else { 23505331Samw err = sa_enable_resource(share, value); 23515331Samw if (err == SA_NOT_SUPPORTED) { 23525331Samw sa_share_t parent; 23535331Samw parent = sa_get_resource_parent( 23545331Samw share); 23555331Samw if (parent != NULL) 23565331Samw err = sa_enable_share( 23575331Samw parent, value); 23585331Samw } 23595331Samw } 23605331Samw if (err != SA_OK) { 23615331Samw ret = err; 23625331Samw (void) printf(gettext( 23635331Samw "Failed to enable share for " 23645331Samw "\"%s\": %s\n"), 23655331Samw value, sa_errorstr(ret)); 23665331Samw } 23675331Samw } 23685331Samw /* 23695331Samw * If we want to update the legacy, use a copy of 23705331Samw * share so we can avoid breaking the loop we are in 23715331Samw * since we might also need to go up the tree to the 23725331Samw * parent. 23735331Samw */ 23745331Samw if (update_legacy && !iszfs) { 23755331Samw sa_share_t update = share; 23765331Samw if (!sa_is_share(share)) { 23775331Samw update = sa_get_resource_parent(share); 23785331Samw } 23795331Samw (void) sa_update_legacy(update, value); 23805331Samw } 23814653Sdougm sa_free_attr_string(value); 23824653Sdougm } 23833034Sdougm } 23843034Sdougm if (ret == SA_OK) 23854653Sdougm (void) sa_update_config(handle); 23863034Sdougm return (ret); 23873034Sdougm } 23883034Sdougm 23893034Sdougm /* 23905331Samw * sa_require_resource(group) 23915331Samw * 23925331Samw * if any of the defined protocols on the group require resource 23935331Samw * names, then all shares must have them. 23945331Samw */ 23955331Samw 23965331Samw static int 23975331Samw sa_require_resource(sa_group_t group) 23985331Samw { 23995331Samw sa_optionset_t optionset; 24005331Samw 24015331Samw for (optionset = sa_get_optionset(group, NULL); 24025331Samw optionset != NULL; 24035331Samw optionset = sa_get_next_optionset(optionset)) { 24045331Samw char *proto; 24055331Samw 24065331Samw proto = sa_get_optionset_attr(optionset, "type"); 24075331Samw if (proto != NULL) { 24085331Samw uint64_t features; 24095331Samw 24105331Samw features = sa_proto_get_featureset(proto); 24115331Samw if (features & SA_FEATURE_RESOURCE) { 24125331Samw sa_free_attr_string(proto); 24135331Samw return (B_TRUE); 24145331Samw } 24155331Samw sa_free_attr_string(proto); 24165331Samw } 24175331Samw } 24185331Samw return (B_FALSE); 24195331Samw } 24205331Samw 24215331Samw /* 24223034Sdougm * sa_addshare(flags, argc, argv) 24233034Sdougm * 24243034Sdougm * implements add-share subcommand. 24253034Sdougm */ 24263034Sdougm 24275331Samw static int 24283910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 24293034Sdougm { 24303034Sdougm int verbose = 0; 24313034Sdougm int dryrun = 0; 24323034Sdougm int c; 24333034Sdougm int ret = SA_OK; 24343034Sdougm sa_group_t group; 24353034Sdougm sa_share_t share; 24365331Samw sa_resource_t resource = NULL; 24373034Sdougm char *sharepath = NULL; 24383034Sdougm char *description = NULL; 24395331Samw char *rsrcname = NULL; 24405331Samw char *rsrc = NULL; 24413034Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 24423034Sdougm int auth; 24433034Sdougm char dir[MAXPATHLEN]; 24443034Sdougm 24453034Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 24464653Sdougm switch (c) { 24474653Sdougm case 'n': 24484653Sdougm dryrun++; 24494653Sdougm break; 24504653Sdougm case 'v': 24514653Sdougm verbose++; 24524653Sdougm break; 24534653Sdougm case 'd': 24544653Sdougm description = optarg; 24554653Sdougm break; 24564653Sdougm case 'r': 24575331Samw if (rsrcname != NULL) { 24585331Samw (void) printf(gettext("Adding multiple " 24595331Samw "resource names not" 24605331Samw " supported\n")); 24615331Samw return (SA_SYNTAX_ERR); 24625331Samw } 24635331Samw rsrcname = optarg; 24644653Sdougm break; 24654653Sdougm case 's': 24664653Sdougm /* 24674653Sdougm * Save share path into group. Currently limit 24684653Sdougm * to one share per command. 24694653Sdougm */ 24704653Sdougm if (sharepath != NULL) { 24714653Sdougm (void) printf(gettext( 24724653Sdougm "Adding multiple shares not supported\n")); 24735331Samw return (SA_SYNTAX_ERR); 24744653Sdougm } 24754653Sdougm sharepath = optarg; 24764653Sdougm break; 24774653Sdougm case 't': 24784653Sdougm persist = SA_SHARE_TRANSIENT; 24794653Sdougm break; 2480*6019Sdougm case 'h': 2481*6019Sdougm /* optopt on valid arg isn't defined */ 2482*6019Sdougm optopt = c; 2483*6019Sdougm /*FALLTHROUGH*/ 2484*6019Sdougm case '?': 24854653Sdougm default: 2486*6019Sdougm /* 2487*6019Sdougm * Since a bad option gets to here, sort it 2488*6019Sdougm * out and return a syntax error return value 2489*6019Sdougm * if necessary. 2490*6019Sdougm */ 2491*6019Sdougm switch (optopt) { 2492*6019Sdougm default: 2493*6019Sdougm ret = SA_SYNTAX_ERR; 2494*6019Sdougm break; 2495*6019Sdougm case 'h': 2496*6019Sdougm case '?': 2497*6019Sdougm break; 2498*6019Sdougm } 24994653Sdougm (void) printf(gettext("usage: %s\n"), 25004653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 2501*6019Sdougm return (ret); 25023034Sdougm } 25033034Sdougm } 25043034Sdougm 25053034Sdougm if (optind >= argc) { 25064653Sdougm (void) printf(gettext("usage: %s\n"), 25074653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 25084653Sdougm if (dryrun || sharepath != NULL || description != NULL || 25095331Samw rsrcname != NULL || verbose || persist) { 25104653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 25114653Sdougm ret = SA_NO_SUCH_GROUP; 25124653Sdougm } else { 25134653Sdougm ret = SA_OK; 25144653Sdougm } 25153034Sdougm } else { 25164653Sdougm if (sharepath == NULL) { 25174653Sdougm (void) printf(gettext("usage: %s\n"), 25184653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 25194653Sdougm (void) printf(gettext( 25204653Sdougm "\t-s sharepath must be specified\n")); 25215331Samw ret = SA_BAD_PATH; 25224653Sdougm } 25235331Samw if (ret == SA_OK) { 25245331Samw if (realpath(sharepath, dir) == NULL) { 25255331Samw ret = SA_BAD_PATH; 25265331Samw (void) printf(gettext("Path " 25275331Samw "is not valid: %s\n"), 25285331Samw sharepath); 25295331Samw } else { 25305331Samw sharepath = dir; 25315331Samw } 25323034Sdougm } 25335331Samw if (ret == SA_OK && rsrcname != NULL) { 25345331Samw /* check for valid syntax */ 25355331Samw if (validresource(rsrcname)) { 25365331Samw rsrc = conv_to_utf8(rsrcname); 25375331Samw resource = sa_find_resource(handle, rsrc); 25385331Samw if (resource != NULL) { 25395331Samw /* 25405331Samw * Resource names must be 25415331Samw * unique in the system 25425331Samw */ 25435331Samw ret = SA_DUPLICATE_NAME; 25445331Samw (void) printf(gettext("usage: %s\n"), 25455331Samw sa_get_usage(USAGE_ADD_SHARE)); 25465331Samw (void) printf(gettext( 25475331Samw "\tresource names must be unique " 25485331Samw "in the system\n")); 25495331Samw } 25505331Samw } else { 25515331Samw (void) printf(gettext("usage: %s\n"), 25525331Samw sa_get_usage(USAGE_ADD_SHARE)); 25535331Samw (void) printf(gettext( 25545331Samw "\tresource names use restricted " 25555331Samw "character set\n")); 25565331Samw ret = SA_INVALID_NAME; 25575331Samw } 25583034Sdougm } 25595331Samw 25605331Samw if (ret != SA_OK) { 25615331Samw if (rsrc != NULL && rsrcname != rsrc) 25625331Samw sa_free_attr_string(rsrc); 25635331Samw return (ret); 25644653Sdougm } 25655331Samw 25664653Sdougm share = sa_find_share(handle, sharepath); 25674653Sdougm if (share != NULL) { 25685331Samw if (rsrcname == NULL) { 25695331Samw /* 25705331Samw * Can only have a duplicate share if a new 25715331Samw * resource name is being added. 25725331Samw */ 25735331Samw ret = SA_DUPLICATE_NAME; 25745331Samw (void) printf(gettext("Share path already " 25755331Samw "shared: %s\n"), sharepath); 25765331Samw } 25775331Samw } 25785331Samw if (ret != SA_OK) 25795331Samw return (ret); 25805331Samw 25815331Samw group = sa_get_group(handle, argv[optind]); 25825331Samw if (group != NULL) { 25835331Samw if (sa_require_resource(group) == B_TRUE && 25845331Samw rsrcname == NULL) { 25855331Samw (void) printf(gettext( 25865331Samw "Resource name is required " 25875331Samw "by at least one enabled protocol " 25885331Samw "in group\n")); 25895331Samw return (SA_RESOURCE_REQUIRED); 25905331Samw } 25915331Samw if (share == NULL && ret == SA_OK) { 25925331Samw if (dryrun) 25935331Samw ret = sa_check_path(group, sharepath, 25945331Samw SA_CHECK_NORMAL); 25955331Samw else 25965331Samw share = sa_add_share(group, sharepath, 25975331Samw persist, &ret); 25985331Samw } 25995331Samw /* 26005331Samw * Make sure this isn't an attempt to put a resourced 26015331Samw * share into a different group than it already is in. 26025331Samw */ 26035331Samw if (share != NULL) { 26045331Samw sa_group_t parent; 26055331Samw parent = sa_get_parent_group(share); 26065331Samw if (parent != group) { 26075331Samw ret = SA_DUPLICATE_NAME; 26084653Sdougm (void) printf(gettext( 26094653Sdougm "Share path already " 26105331Samw "shared: %s\n"), sharepath); 26114653Sdougm } 26123034Sdougm } 26133034Sdougm if (!dryrun && share == NULL) { 26144653Sdougm (void) printf(gettext( 26154653Sdougm "Could not add share: %s\n"), 26164653Sdougm sa_errorstr(ret)); 26173034Sdougm } else { 26185331Samw auth = check_authorizations(argv[optind], 26195331Samw flags); 26204653Sdougm if (!dryrun && ret == SA_OK) { 26215331Samw if (rsrcname != NULL) { 26225331Samw resource = sa_add_resource( 26235331Samw share, 26245331Samw rsrc, 26255331Samw SA_SHARE_PERMANENT, 26265331Samw &ret); 26274653Sdougm } 26284653Sdougm if (ret == SA_OK && 26294653Sdougm description != NULL) { 26305885Sdougm if (resource != NULL) 26315885Sdougm ret = 26325885Sdougm set_resource_desc( 26335885Sdougm resource, 26345885Sdougm description); 26355885Sdougm else 26365331Samw ret = 26375331Samw set_share_desc( 26385331Samw share, 26395331Samw description); 26404653Sdougm } 26414653Sdougm if (ret == SA_OK) { 26425331Samw /* now enable the share(s) */ 26435331Samw if (resource != NULL) { 26445331Samw ret = enable_share( 26455331Samw handle, 26465331Samw group, 26475331Samw resource, 26485331Samw 1); 26495331Samw } else { 26505331Samw ret = enable_share( 26515331Samw handle, 26525331Samw group, 26535331Samw share, 26545331Samw 1); 26555331Samw } 26564653Sdougm ret = sa_update_config(handle); 26574653Sdougm } 26584653Sdougm switch (ret) { 26594653Sdougm case SA_DUPLICATE_NAME: 26604653Sdougm (void) printf(gettext( 26614653Sdougm "Resource name in" 26625331Samw "use: %s\n"), 26635331Samw rsrcname); 26644653Sdougm break; 26654653Sdougm default: 26665331Samw (void) printf(gettext( 26675331Samw "Could not set " 26684653Sdougm "attribute: %s\n"), 26694653Sdougm sa_errorstr(ret)); 26704653Sdougm break; 26714653Sdougm case SA_OK: 26724653Sdougm break; 26734653Sdougm } 26745331Samw } else if (dryrun && ret == SA_OK && 26755331Samw !auth && verbose) { 26764653Sdougm (void) printf(gettext( 26774653Sdougm "Command would fail: %s\n"), 26784653Sdougm sa_errorstr(SA_NO_PERMISSION)); 26794653Sdougm ret = SA_NO_PERMISSION; 26803034Sdougm } 26813034Sdougm } 26825331Samw } else { 26835331Samw switch (ret) { 26845331Samw default: 26855331Samw (void) printf(gettext( 26865331Samw "Group \"%s\" not found\n"), argv[optind]); 26875331Samw ret = SA_NO_SUCH_GROUP; 26885331Samw break; 26895331Samw case SA_BAD_PATH: 26905331Samw case SA_DUPLICATE_NAME: 26915331Samw break; 26925331Samw } 26933034Sdougm } 26943034Sdougm } 26953034Sdougm return (ret); 26963034Sdougm } 26973034Sdougm 26983034Sdougm /* 26993034Sdougm * sa_moveshare(flags, argc, argv) 27003034Sdougm * 27013034Sdougm * implements move-share subcommand. 27023034Sdougm */ 27033034Sdougm 27043034Sdougm int 27053910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 27063034Sdougm { 27073034Sdougm int verbose = 0; 27083034Sdougm int dryrun = 0; 27093034Sdougm int c; 27103034Sdougm int ret = SA_OK; 27113034Sdougm sa_group_t group; 27123034Sdougm sa_share_t share; 27135331Samw char *rsrcname = NULL; 27143034Sdougm char *sharepath = NULL; 27153034Sdougm int authsrc = 0, authdst = 0; 27165885Sdougm char dir[MAXPATHLEN]; 27173034Sdougm 27185331Samw while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) { 27194653Sdougm switch (c) { 27204653Sdougm case 'n': 27214653Sdougm dryrun++; 27224653Sdougm break; 27234653Sdougm case 'v': 27244653Sdougm verbose++; 27254653Sdougm break; 27265331Samw case 'r': 27275331Samw if (rsrcname != NULL) { 27285331Samw (void) printf(gettext( 27295331Samw "Moving multiple resource names not" 27305331Samw " supported\n")); 27315331Samw return (SA_SYNTAX_ERR); 27325331Samw } 27335331Samw rsrcname = optarg; 27345331Samw break; 27354653Sdougm case 's': 27364653Sdougm /* 27374653Sdougm * Remove share path from group. Currently limit 27384653Sdougm * to one share per command. 27394653Sdougm */ 27404653Sdougm if (sharepath != NULL) { 27414653Sdougm (void) printf(gettext("Moving multiple shares" 27425331Samw " not supported\n")); 27435331Samw return (SA_SYNTAX_ERR); 27444653Sdougm } 27454653Sdougm sharepath = optarg; 27464653Sdougm break; 2747*6019Sdougm case 'h': 2748*6019Sdougm /* optopt on valid arg isn't defined */ 2749*6019Sdougm optopt = c; 2750*6019Sdougm /*FALLTHROUGH*/ 2751*6019Sdougm case '?': 27524653Sdougm default: 2753*6019Sdougm /* 2754*6019Sdougm * Since a bad option gets to here, sort it 2755*6019Sdougm * out and return a syntax error return value 2756*6019Sdougm * if necessary. 2757*6019Sdougm */ 2758*6019Sdougm switch (optopt) { 2759*6019Sdougm default: 2760*6019Sdougm ret = SA_SYNTAX_ERR; 2761*6019Sdougm break; 2762*6019Sdougm case 'h': 2763*6019Sdougm case '?': 2764*6019Sdougm break; 2765*6019Sdougm } 27664653Sdougm (void) printf(gettext("usage: %s\n"), 27674653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 2768*6019Sdougm return (ret); 27693034Sdougm } 27703034Sdougm } 27713034Sdougm 27723034Sdougm if (optind >= argc || sharepath == NULL) { 27735331Samw (void) printf(gettext("usage: %s\n"), 27745331Samw sa_get_usage(USAGE_MOVE_SHARE)); 27755331Samw if (dryrun || verbose || sharepath != NULL) { 27765331Samw (void) printf(gettext("\tgroup must be specified\n")); 27775331Samw ret = SA_NO_SUCH_GROUP; 27785331Samw } else { 27795331Samw if (sharepath == NULL) { 27805331Samw ret = SA_SYNTAX_ERR; 27814653Sdougm (void) printf(gettext( 27825331Samw "\tsharepath must be specified\n")); 27834653Sdougm } else { 27845331Samw ret = SA_OK; 27854653Sdougm } 27865331Samw } 27874653Sdougm } else { 27884653Sdougm sa_group_t parent; 27894653Sdougm char *zfsold; 27904653Sdougm char *zfsnew; 27914653Sdougm 27923034Sdougm if (sharepath == NULL) { 27934653Sdougm (void) printf(gettext( 27944653Sdougm "sharepath must be specified with the -s " 27954653Sdougm "option\n")); 27964653Sdougm return (SA_BAD_PATH); 27974653Sdougm } 27983910Sdougm group = sa_get_group(handle, argv[optind]); 27994653Sdougm if (group == NULL) { 28004653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 28014653Sdougm argv[optind]); 28024653Sdougm return (SA_NO_SUCH_GROUP); 28034653Sdougm } 28044653Sdougm share = sa_find_share(handle, sharepath); 28055885Sdougm /* 28065885Sdougm * If a share wasn't found, it may have been a symlink 28075885Sdougm * or has a trailing '/'. Try again after resolving 28085885Sdougm * with realpath(). 28095885Sdougm */ 28105885Sdougm if (share == NULL) { 28115885Sdougm if (realpath(sharepath, dir) == NULL) { 28125885Sdougm (void) printf(gettext("Path " 28135885Sdougm "is not valid: %s\n"), 28145885Sdougm sharepath); 28155885Sdougm return (SA_BAD_PATH); 28165885Sdougm } 28175885Sdougm sharepath = dir; 28185885Sdougm share = sa_find_share(handle, sharepath); 28195885Sdougm } 28204653Sdougm if (share == NULL) { 28213034Sdougm (void) printf(gettext("Share not found: %s\n"), 28224653Sdougm sharepath); 28234653Sdougm return (SA_NO_SUCH_PATH); 28244653Sdougm } 28255885Sdougm authdst = check_authorizations(argv[optind], flags); 28264653Sdougm 28274653Sdougm parent = sa_get_parent_group(share); 28284653Sdougm if (parent != NULL) { 28294653Sdougm char *pname; 28304653Sdougm pname = sa_get_group_attr(parent, "name"); 28314653Sdougm if (pname != NULL) { 28323034Sdougm authsrc = check_authorizations(pname, flags); 28333034Sdougm sa_free_attr_string(pname); 28344653Sdougm } 28354653Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 28364653Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 28374653Sdougm if ((zfsold != NULL && zfsnew == NULL) || 28384653Sdougm (zfsold == NULL && zfsnew != NULL)) { 28393034Sdougm ret = SA_NOT_ALLOWED; 28403034Sdougm } 28414653Sdougm if (zfsold != NULL) 28424653Sdougm sa_free_attr_string(zfsold); 28434653Sdougm if (zfsnew != NULL) 28444653Sdougm sa_free_attr_string(zfsnew); 28454653Sdougm } 28464653Sdougm 28474653Sdougm if (ret == SA_OK && parent != group && !dryrun) { 28484653Sdougm char *oldstate; 28494653Sdougm /* 28504653Sdougm * Note that the share may need to be 28515331Samw * "unshared" if the new group is disabled and 28525331Samw * the old was enabled or it may need to be 28535331Samw * share to update if the new group is 28545331Samw * enabled. We disable before the move and 28555331Samw * will have to enable after the move in order 28565331Samw * to cleanup entries for protocols that 28575331Samw * aren't in the new group. 28584653Sdougm */ 28594653Sdougm oldstate = sa_get_group_attr(parent, "state"); 28604653Sdougm 28614653Sdougm /* enable_share determines what to do */ 28625331Samw if (strcmp(oldstate, "enabled") == 0) 28633034Sdougm (void) sa_disable_share(share, NULL); 28645331Samw 28654653Sdougm if (oldstate != NULL) 28663034Sdougm sa_free_attr_string(oldstate); 28673034Sdougm } 28684653Sdougm 28695331Samw if (!dryrun && ret == SA_OK) 28705331Samw ret = sa_move_share(group, share); 28715331Samw 28725331Samw /* 28735331Samw * Reenable and update any config information. 28745331Samw */ 28755331Samw if (ret == SA_OK && parent != group && !dryrun) { 28765331Samw ret = sa_update_config(handle); 28775331Samw 28785331Samw (void) enable_share(handle, group, share, 1); 28795331Samw } 28805331Samw 28814653Sdougm if (ret != SA_OK) 28824653Sdougm (void) printf(gettext("Could not move share: %s\n"), 28834653Sdougm sa_errorstr(ret)); 28844653Sdougm 28854653Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 28864653Sdougm verbose) { 28874653Sdougm (void) printf(gettext("Command would fail: %s\n"), 28884653Sdougm sa_errorstr(SA_NO_PERMISSION)); 28894653Sdougm } 28903034Sdougm } 28913034Sdougm return (ret); 28923034Sdougm } 28933034Sdougm 28943034Sdougm /* 28953034Sdougm * sa_removeshare(flags, argc, argv) 28963034Sdougm * 28973034Sdougm * implements remove-share subcommand. 28983034Sdougm */ 28993034Sdougm 29003034Sdougm int 29013910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 29023034Sdougm { 29033034Sdougm int verbose = 0; 29043034Sdougm int dryrun = 0; 29053034Sdougm int force = 0; 29063034Sdougm int c; 29073034Sdougm int ret = SA_OK; 29083034Sdougm sa_group_t group; 29095331Samw sa_resource_t resource = NULL; 29105331Samw sa_share_t share = NULL; 29115331Samw char *rsrcname = NULL; 29123034Sdougm char *sharepath = NULL; 29133034Sdougm char dir[MAXPATHLEN]; 29143034Sdougm int auth; 29153034Sdougm 29165331Samw while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) { 29174653Sdougm switch (c) { 29184653Sdougm case 'n': 29194653Sdougm dryrun++; 29204653Sdougm break; 29214653Sdougm case 'v': 29224653Sdougm verbose++; 29234653Sdougm break; 29244653Sdougm case 'f': 29254653Sdougm force++; 29264653Sdougm break; 29274653Sdougm case 's': 29284653Sdougm /* 29294653Sdougm * Remove share path from group. Currently limit 29304653Sdougm * to one share per command. 29314653Sdougm */ 29324653Sdougm if (sharepath != NULL) { 29334653Sdougm (void) printf(gettext( 29344653Sdougm "Removing multiple shares not " 29353034Sdougm "supported\n")); 29364653Sdougm return (SA_SYNTAX_ERR); 29374653Sdougm } 29384653Sdougm sharepath = optarg; 29394653Sdougm break; 29405331Samw case 'r': 29415331Samw /* 29425331Samw * Remove share from group if last resource or remove 29435331Samw * resource from share if multiple resources. 29445331Samw */ 29455331Samw if (rsrcname != NULL) { 29465331Samw (void) printf(gettext( 29475331Samw "Removing multiple resource names not " 29485331Samw "supported\n")); 29495331Samw return (SA_SYNTAX_ERR); 29505331Samw } 29515331Samw rsrcname = optarg; 29525331Samw break; 2953*6019Sdougm case 'h': 2954*6019Sdougm /* optopt on valid arg isn't defined */ 2955*6019Sdougm optopt = c; 2956*6019Sdougm /*FALLTHROUGH*/ 2957*6019Sdougm case '?': 29584653Sdougm default: 2959*6019Sdougm /* 2960*6019Sdougm * Since a bad option gets to here, sort it 2961*6019Sdougm * out and return a syntax error return value 2962*6019Sdougm * if necessary. 2963*6019Sdougm */ 2964*6019Sdougm switch (optopt) { 2965*6019Sdougm default: 2966*6019Sdougm ret = SA_SYNTAX_ERR; 2967*6019Sdougm break; 2968*6019Sdougm case 'h': 2969*6019Sdougm case '?': 2970*6019Sdougm break; 2971*6019Sdougm } 29724653Sdougm (void) printf(gettext("usage: %s\n"), 29734653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 2974*6019Sdougm return (ret); 29753034Sdougm } 29763034Sdougm } 29773034Sdougm 29785331Samw if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) { 29795331Samw if (sharepath == NULL && rsrcname == NULL) { 29803034Sdougm (void) printf(gettext("usage: %s\n"), 29814653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 29825331Samw (void) printf(gettext("\t-s sharepath or -r resource" 29835331Samw " must be specified\n")); 29844653Sdougm ret = SA_BAD_PATH; 29854653Sdougm } else { 29864653Sdougm ret = SA_OK; 29874653Sdougm } 29883034Sdougm } 29894653Sdougm if (ret != SA_OK) { 29904653Sdougm return (ret); 29914653Sdougm } 29924653Sdougm 29934653Sdougm if (optind < argc) { 29943034Sdougm if ((optind + 1) < argc) { 29954653Sdougm (void) printf(gettext("Extraneous group(s) at end of " 29964653Sdougm "command\n")); 29974653Sdougm ret = SA_SYNTAX_ERR; 29983034Sdougm } else { 29994653Sdougm group = sa_get_group(handle, argv[optind]); 30004653Sdougm if (group == NULL) { 30014653Sdougm (void) printf(gettext( 30024653Sdougm "Group \"%s\" not found\n"), argv[optind]); 30034653Sdougm ret = SA_NO_SUCH_GROUP; 30044653Sdougm } 30053034Sdougm } 30064653Sdougm } else { 30073034Sdougm group = NULL; 30084653Sdougm } 30094653Sdougm 30105331Samw if (rsrcname != NULL) { 30115331Samw resource = sa_find_resource(handle, rsrcname); 30125331Samw if (resource == NULL) { 30135331Samw ret = SA_NO_SUCH_RESOURCE; 30145331Samw (void) printf(gettext( 30155331Samw "Resource name not found for share: %s\n"), 30165331Samw rsrcname); 30175331Samw } 30185331Samw } 30195331Samw 30204653Sdougm /* 30214653Sdougm * Lookup the path in the internal configuration. Care 30224653Sdougm * must be taken to handle the case where the 30234653Sdougm * underlying path has been removed since we need to 30244653Sdougm * be able to deal with that as well. 30254653Sdougm */ 30264653Sdougm if (ret == SA_OK) { 30275331Samw if (sharepath != NULL) { 30285331Samw if (group != NULL) 30295331Samw share = sa_get_share(group, sharepath); 30305331Samw else 30315331Samw share = sa_find_share(handle, sharepath); 30325331Samw } 30335331Samw 30345331Samw if (resource != NULL) { 30355331Samw sa_share_t rsrcshare; 30365331Samw rsrcshare = sa_get_resource_parent(resource); 30375331Samw if (share == NULL) 30385331Samw share = rsrcshare; 30395331Samw else if (share != rsrcshare) { 30405331Samw ret = SA_NO_SUCH_RESOURCE; 30415331Samw (void) printf(gettext( 30425331Samw "Bad resource name for share: %s\n"), 30435331Samw rsrcname); 30445331Samw share = NULL; 30455331Samw } 30465331Samw } 30475331Samw 30483663Sdougm /* 30493663Sdougm * If we didn't find the share with the provided path, 30503663Sdougm * it may be a symlink so attempt to resolve it using 30513663Sdougm * realpath and try again. Realpath will resolve any 30523663Sdougm * symlinks and place them in "dir". Note that 30533663Sdougm * sharepath is only used for the lookup the first 30543663Sdougm * time and later for error messages. dir will be used 30553663Sdougm * on the second attempt. Once a share is found, all 30563663Sdougm * operations are based off of the share variable. 30573663Sdougm */ 30583663Sdougm if (share == NULL) { 30594653Sdougm if (realpath(sharepath, dir) == NULL) { 30604653Sdougm ret = SA_BAD_PATH; 30614653Sdougm (void) printf(gettext( 30624653Sdougm "Path is not valid: %s\n"), sharepath); 30634653Sdougm } else { 30644653Sdougm if (group != NULL) 30654653Sdougm share = sa_get_share(group, dir); 30664653Sdougm else 30674653Sdougm share = sa_find_share(handle, dir); 30684653Sdougm } 30693663Sdougm } 30704653Sdougm } 30714653Sdougm 30724653Sdougm /* 30734653Sdougm * If there hasn't been an error, there was likely a 30744653Sdougm * path found. If not, give the appropriate error 30754653Sdougm * message and set the return error. If it was found, 30764653Sdougm * then disable the share and then remove it from the 30774653Sdougm * configuration. 30784653Sdougm */ 30794653Sdougm if (ret != SA_OK) { 30804653Sdougm return (ret); 30814653Sdougm } 30824653Sdougm if (share == NULL) { 30834653Sdougm if (group != NULL) 30843034Sdougm (void) printf(gettext("Share not found in group %s:" 30854653Sdougm " %s\n"), argv[optind], sharepath); 30864653Sdougm else 30873034Sdougm (void) printf(gettext("Share not found: %s\n"), 30884653Sdougm sharepath); 30895331Samw ret = SA_NO_SUCH_PATH; 30904653Sdougm } else { 30914653Sdougm if (group == NULL) 30923034Sdougm group = sa_get_parent_group(share); 30934653Sdougm if (!dryrun) { 30943034Sdougm if (ret == SA_OK) { 30955331Samw if (resource != NULL) 30965331Samw ret = sa_disable_resource(resource, 30975331Samw NULL); 30985331Samw else 30995331Samw ret = sa_disable_share(share, NULL); 31003034Sdougm /* 31014653Sdougm * We don't care if it fails since it 31023663Sdougm * could be disabled already. Some 31033663Sdougm * unexpected errors could occur that 31043663Sdougm * prevent removal, so also check for 31053663Sdougm * force being set. 31063034Sdougm */ 31075331Samw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 31085331Samw ret == SA_NOT_SUPPORTED || 31095331Samw ret == SA_SYSTEM_ERR || force) && 31105331Samw resource == NULL) 31115331Samw ret = sa_remove_share(share); 31125331Samw 31135331Samw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 31144653Sdougm ret == SA_NOT_SUPPORTED || 31155331Samw ret == SA_SYSTEM_ERR || force) && 31165331Samw resource != NULL) { 31175331Samw ret = sa_remove_resource(resource); 31185331Samw if (ret == SA_OK) { 31195331Samw /* 31205331Samw * If this was the 31215331Samw * last one, remove 31225331Samw * the share as well. 31235331Samw */ 31245331Samw resource = 31255331Samw sa_get_share_resource( 31265331Samw share, NULL); 31275331Samw if (resource == NULL) 31285331Samw ret = sa_remove_share( 31295331Samw share); 31305331Samw } 31314653Sdougm } 31324653Sdougm if (ret == SA_OK) 31334653Sdougm ret = sa_update_config(handle); 31343034Sdougm } 31354653Sdougm if (ret != SA_OK) 31365331Samw (void) printf(gettext("Could not remove share:" 31375331Samw " %s\n"), sa_errorstr(ret)); 31384653Sdougm } else if (ret == SA_OK) { 31393034Sdougm char *pname; 31403034Sdougm pname = sa_get_group_attr(group, "name"); 31413034Sdougm if (pname != NULL) { 31424653Sdougm auth = check_authorizations(pname, flags); 31434653Sdougm sa_free_attr_string(pname); 31443034Sdougm } 31453034Sdougm if (!auth && verbose) { 31464653Sdougm (void) printf(gettext( 31474653Sdougm "Command would fail: %s\n"), 31484653Sdougm sa_errorstr(SA_NO_PERMISSION)); 31493034Sdougm } 31503034Sdougm } 31513034Sdougm } 31523034Sdougm return (ret); 31533034Sdougm } 31543034Sdougm 31553034Sdougm /* 31563034Sdougm * sa_set_share(flags, argc, argv) 31573034Sdougm * 31583034Sdougm * implements set-share subcommand. 31593034Sdougm */ 31603034Sdougm 31613034Sdougm int 31623910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 31633034Sdougm { 31643034Sdougm int dryrun = 0; 31653034Sdougm int c; 31663034Sdougm int ret = SA_OK; 31673034Sdougm sa_group_t group, sharegroup; 31685772Sas200622 sa_share_t share = NULL; 31695331Samw sa_resource_t resource = NULL; 31703034Sdougm char *sharepath = NULL; 31713034Sdougm char *description = NULL; 31725331Samw char *rsrcname = NULL; 31735331Samw char *rsrc = NULL; 31745331Samw char *newname = NULL; 31755331Samw char *newrsrc; 31765331Samw char *groupname = NULL; 31773034Sdougm int auth; 31783034Sdougm int verbose = 0; 31793034Sdougm 31803034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 31814653Sdougm switch (c) { 31824653Sdougm case 'n': 31834653Sdougm dryrun++; 31844653Sdougm break; 31854653Sdougm case 'd': 31864653Sdougm description = optarg; 31874653Sdougm break; 31884653Sdougm case 'v': 31894653Sdougm verbose++; 31904653Sdougm break; 31915331Samw case 'r': 31925331Samw /* 31935331Samw * Update share by resource name 31945331Samw */ 31955331Samw if (rsrcname != NULL) { 31965331Samw (void) printf(gettext( 31975331Samw "Updating multiple resource names not " 31985331Samw "supported\n")); 31995331Samw return (SA_SYNTAX_ERR); 32005331Samw } 32015331Samw rsrcname = optarg; 32025331Samw break; 32034653Sdougm case 's': 32044653Sdougm /* 32054653Sdougm * Save share path into group. Currently limit 32064653Sdougm * to one share per command. 32074653Sdougm */ 32084653Sdougm if (sharepath != NULL) { 32094653Sdougm (void) printf(gettext( 32104653Sdougm "Updating multiple shares not " 32113034Sdougm "supported\n")); 32125331Samw return (SA_SYNTAX_ERR); 32134653Sdougm } 32144653Sdougm sharepath = optarg; 32154653Sdougm break; 3216*6019Sdougm case 'h': 3217*6019Sdougm /* optopt on valid arg isn't defined */ 3218*6019Sdougm optopt = c; 3219*6019Sdougm /*FALLTHROUGH*/ 3220*6019Sdougm case '?': 32214653Sdougm default: 3222*6019Sdougm /* 3223*6019Sdougm * Since a bad option gets to here, sort it 3224*6019Sdougm * out and return a syntax error return value 3225*6019Sdougm * if necessary. 3226*6019Sdougm */ 3227*6019Sdougm switch (optopt) { 3228*6019Sdougm default: 3229*6019Sdougm ret = SA_SYNTAX_ERR; 3230*6019Sdougm break; 3231*6019Sdougm case 'h': 3232*6019Sdougm case '?': 3233*6019Sdougm break; 3234*6019Sdougm } 32354653Sdougm (void) printf(gettext("usage: %s\n"), 32364653Sdougm sa_get_usage(USAGE_SET_SHARE)); 3237*6019Sdougm return (ret); 32383034Sdougm } 32393034Sdougm } 32404653Sdougm 32415331Samw if (optind >= argc && sharepath == NULL && rsrcname == NULL) { 32424653Sdougm if (sharepath == NULL) { 32434653Sdougm (void) printf(gettext("usage: %s\n"), 32444653Sdougm sa_get_usage(USAGE_SET_SHARE)); 32454653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 32464653Sdougm ret = SA_BAD_PATH; 32474653Sdougm } else { 32484653Sdougm ret = SA_OK; 32494653Sdougm } 32503034Sdougm } 32513034Sdougm if ((optind + 1) < argc) { 32524653Sdougm (void) printf(gettext("usage: %s\n"), 32534653Sdougm sa_get_usage(USAGE_SET_SHARE)); 32544653Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 32554653Sdougm ret = SA_SYNTAX_ERR; 32563034Sdougm } 32574653Sdougm 32585331Samw /* 32595331Samw * Must have at least one of sharepath and rsrcrname. 32605331Samw * It is a syntax error to be missing both. 32615331Samw */ 32625331Samw if (sharepath == NULL && rsrcname == NULL) { 32635331Samw (void) printf(gettext("usage: %s\n"), 32645331Samw sa_get_usage(USAGE_SET_SHARE)); 32655331Samw ret = SA_SYNTAX_ERR; 32665331Samw } 32675331Samw 32684653Sdougm if (ret != SA_OK) 32694653Sdougm return (ret); 32704653Sdougm 32714653Sdougm if (optind < argc) { 32723034Sdougm groupname = argv[optind]; 32733910Sdougm group = sa_get_group(handle, groupname); 32744653Sdougm } else { 32753034Sdougm group = NULL; 32763034Sdougm groupname = NULL; 32774653Sdougm } 32785331Samw if (rsrcname != NULL) { 32795331Samw /* 32805331Samw * If rsrcname exists, split rename syntax and then 32815331Samw * convert to utf 8 if no errors. 32825331Samw */ 32835331Samw newname = strchr(rsrcname, '='); 32845331Samw if (newname != NULL) { 32855331Samw *newname++ = '\0'; 32865331Samw } 32875331Samw if (!validresource(rsrcname)) { 32885331Samw ret = SA_INVALID_NAME; 32895331Samw (void) printf(gettext("Invalid resource name: " 32905331Samw "\"%s\"\n"), rsrcname); 32915331Samw } else { 32925331Samw rsrc = conv_to_utf8(rsrcname); 32935331Samw } 32945331Samw if (newname != NULL) { 32955331Samw if (!validresource(newname)) { 32965331Samw ret = SA_INVALID_NAME; 32975331Samw (void) printf(gettext("Invalid resource name: " 32985331Samw "%s\n"), newname); 32995331Samw } else { 33005331Samw newrsrc = conv_to_utf8(newname); 33015331Samw } 33025331Samw } 33035331Samw } 33045331Samw 33055331Samw if (ret != SA_OK) { 33065331Samw if (rsrcname != NULL && rsrcname != rsrc) 33075331Samw sa_free_attr_string(rsrc); 33085331Samw if (newname != NULL && newname != newrsrc) 33095331Samw sa_free_attr_string(newrsrc); 33105331Samw return (ret); 33115331Samw } 33125331Samw 33135331Samw if (sharepath != NULL) { 33145331Samw share = sa_find_share(handle, sharepath); 33155331Samw } else if (rsrcname != NULL) { 33165331Samw resource = sa_find_resource(handle, rsrc); 33175772Sas200622 if (resource != NULL) 33185331Samw share = sa_get_resource_parent(resource); 33195772Sas200622 else 33205772Sas200622 ret = SA_NO_SUCH_RESOURCE; 33215331Samw } 33225331Samw if (share != NULL) { 33235331Samw sharegroup = sa_get_parent_group(share); 33245331Samw if (group != NULL && group != sharegroup) { 33255331Samw (void) printf(gettext("Group \"%s\" does not contain " 33265331Samw "share %s\n"), 33275331Samw argv[optind], sharepath); 33285331Samw ret = SA_BAD_PATH; 33295331Samw } else { 33305331Samw int delgroupname = 0; 33315331Samw if (groupname == NULL) { 33325331Samw groupname = sa_get_group_attr(sharegroup, 33335331Samw "name"); 33345331Samw delgroupname = 1; 33355331Samw } 33365331Samw if (groupname != NULL) { 33375331Samw auth = check_authorizations(groupname, flags); 33385331Samw if (delgroupname) { 33395331Samw sa_free_attr_string(groupname); 33405331Samw groupname = NULL; 33415331Samw } 33425331Samw } else { 33435331Samw ret = SA_NO_MEMORY; 33445331Samw } 33455331Samw if (rsrcname != NULL) { 33465331Samw resource = sa_find_resource(handle, rsrc); 33475331Samw if (!dryrun) { 33485331Samw if (newname != NULL && 33495331Samw resource != NULL) 33505331Samw ret = sa_rename_resource( 33515331Samw resource, newrsrc); 33525331Samw else if (newname != NULL) 33535331Samw ret = SA_NO_SUCH_RESOURCE; 33545331Samw if (newname != NULL && 33555331Samw newname != newrsrc) 33565331Samw sa_free_attr_string(newrsrc); 33575331Samw } 33585331Samw if (rsrc != rsrcname) 33595331Samw sa_free_attr_string(rsrc); 33605331Samw } 33615331Samw 33625331Samw /* 33635331Samw * If the user has set a description, it will be 33645331Samw * on the resource if -r was used otherwise it 33655331Samw * must be on the share. 33665331Samw */ 33675967Scp160787 if (!dryrun && ret == SA_OK && description != NULL) { 33685967Scp160787 char *desc; 33695967Scp160787 desc = conv_to_utf8(description); 33705331Samw if (resource != NULL) 33715967Scp160787 ret = sa_set_resource_description( 33725967Scp160787 resource, desc); 33735331Samw else 33745967Scp160787 ret = sa_set_share_description(share, 33755967Scp160787 desc); 33765967Scp160787 if (desc != description) 33775967Scp160787 sa_free_share_description(desc); 33785331Samw } 33795331Samw } 33805331Samw if (!dryrun && ret == SA_OK) { 33815331Samw if (resource != NULL) 33825331Samw (void) sa_enable_resource(resource, NULL); 33835331Samw ret = sa_update_config(handle); 33845331Samw } 33855331Samw switch (ret) { 33865331Samw case SA_DUPLICATE_NAME: 33875331Samw (void) printf(gettext("Resource name in use: %s\n"), 33885331Samw rsrcname); 33895331Samw break; 33905331Samw default: 33915331Samw (void) printf(gettext("Could not set: %s\n"), 33925331Samw sa_errorstr(ret)); 33935331Samw break; 33945331Samw case SA_OK: 33955331Samw if (dryrun && !auth && verbose) { 33965331Samw (void) printf(gettext( 33975331Samw "Command would fail: %s\n"), 33985331Samw sa_errorstr(SA_NO_PERMISSION)); 33995331Samw } 34005331Samw break; 34015331Samw } 34025331Samw } else { 34035772Sas200622 switch (ret) { 34045772Sas200622 case SA_NO_SUCH_RESOURCE: 34055772Sas200622 (void) printf(gettext("Resource \"%s\" not found\n"), 34065772Sas200622 rsrcname); 34075772Sas200622 break; 34085772Sas200622 default: 34095772Sas200622 if (sharepath != NULL) { 34105772Sas200622 (void) printf( 34115772Sas200622 gettext("Share path \"%s\" not found\n"), 34125772Sas200622 sharepath); 34135772Sas200622 ret = SA_NO_SUCH_PATH; 34145772Sas200622 } else { 34155772Sas200622 (void) printf(gettext("Set failed: %s\n"), 34165772Sas200622 sa_errorstr(ret)); 34175772Sas200622 } 34185772Sas200622 } 34193034Sdougm } 34204653Sdougm 34213034Sdougm return (ret); 34223034Sdougm } 34233034Sdougm 34243034Sdougm /* 34253034Sdougm * add_security(group, sectype, optlist, proto, *err) 34263034Sdougm * 34273034Sdougm * Helper function to add a security option (named optionset) to the 34283034Sdougm * group. 34293034Sdougm */ 34303034Sdougm 34313034Sdougm static int 34323034Sdougm add_security(sa_group_t group, char *sectype, 34335331Samw struct options *optlist, char *proto, int *err) 34343034Sdougm { 34353034Sdougm sa_security_t security; 34363034Sdougm int ret = SA_OK; 34373034Sdougm int result = 0; 34383034Sdougm 34393034Sdougm sectype = sa_proto_space_alias(proto, sectype); 34403034Sdougm security = sa_get_security(group, sectype, proto); 34414653Sdougm if (security == NULL) 34424653Sdougm security = sa_create_security(group, sectype, proto); 34434653Sdougm 34443034Sdougm if (sectype != NULL) 34454653Sdougm sa_free_attr_string(sectype); 34464653Sdougm 34474653Sdougm if (security == NULL) 34484653Sdougm return (ret); 34494653Sdougm 34504653Sdougm while (optlist != NULL) { 34513034Sdougm sa_property_t prop; 34523034Sdougm prop = sa_get_property(security, optlist->optname); 34533034Sdougm if (prop == NULL) { 34543034Sdougm /* 34554653Sdougm * Add the property, but only if it is 34563034Sdougm * a non-NULL or non-zero length value 34573034Sdougm */ 34584653Sdougm if (optlist->optvalue != NULL) { 34594653Sdougm prop = sa_create_property(optlist->optname, 34604653Sdougm optlist->optvalue); 34614653Sdougm if (prop != NULL) { 34625331Samw ret = sa_valid_property(security, 34635331Samw proto, prop); 34644653Sdougm if (ret != SA_OK) { 34654653Sdougm (void) sa_remove_property(prop); 34664653Sdougm (void) printf(gettext( 34674653Sdougm "Could not add " 34684653Sdougm "property %s: %s\n"), 34694653Sdougm optlist->optname, 34704653Sdougm sa_errorstr(ret)); 34714653Sdougm } 34724653Sdougm if (ret == SA_OK) { 34734653Sdougm ret = sa_add_property(security, 34744653Sdougm prop); 34754653Sdougm if (ret != SA_OK) { 34764653Sdougm (void) printf(gettext( 34774653Sdougm "Could not add " 34785331Samw "property (%s=%s):" 34795331Samw " %s\n"), 34804653Sdougm optlist->optname, 34814653Sdougm optlist->optvalue, 34824653Sdougm sa_errorstr(ret)); 34834653Sdougm } else { 34844653Sdougm result = 1; 34854653Sdougm } 34864653Sdougm } 34873034Sdougm } 34883034Sdougm } 34893034Sdougm } else { 34904653Sdougm ret = sa_update_property(prop, optlist->optvalue); 34914653Sdougm result = 1; /* should check if really changed */ 34923034Sdougm } 34933034Sdougm optlist = optlist->next; 34944653Sdougm } 34954653Sdougm /* 34964653Sdougm * When done, properties may have all been removed but 34974653Sdougm * we need to keep the security type itself until 34984653Sdougm * explicitly removed. 34994653Sdougm */ 35004653Sdougm if (result) 35013034Sdougm ret = sa_commit_properties(security, 0); 35023034Sdougm *err = ret; 35033034Sdougm return (result); 35043034Sdougm } 35053034Sdougm 35063034Sdougm /* 35075089Sdougm * zfscheck(group, share) 35085089Sdougm * 35095089Sdougm * For the special case where a share was provided, make sure it is a 35105089Sdougm * compatible path for a ZFS property change. The only path 35115089Sdougm * acceptable is the path that defines the zfs sub-group (dataset with 35125089Sdougm * the sharenfs property set) and not one of the paths that inherited 35135089Sdougm * the NFS properties. Returns SA_OK if it is usable and 35145089Sdougm * SA_NOT_ALLOWED if it isn't. 35155089Sdougm * 35165089Sdougm * If group is not a ZFS group/subgroup, we assume OK since the check 35175089Sdougm * on return will catch errors for those cases. What we are looking 35185089Sdougm * for here is that the group is ZFS and the share is not the defining 35195089Sdougm * share. All else is SA_OK. 35205089Sdougm */ 35215089Sdougm 35225089Sdougm static int 35235089Sdougm zfscheck(sa_group_t group, sa_share_t share) 35245089Sdougm { 35255089Sdougm int ret = SA_OK; 35265089Sdougm char *attr; 35275089Sdougm 35285089Sdougm if (sa_group_is_zfs(group)) { 35295089Sdougm /* 35305089Sdougm * The group is a ZFS group. Does the share represent 35315089Sdougm * the dataset that defined the group? It is only OK 35325089Sdougm * if the attribute "subgroup" exists on the share and 35335089Sdougm * has a value of "true". 35345089Sdougm */ 35355089Sdougm 35365089Sdougm ret = SA_NOT_ALLOWED; 35375089Sdougm attr = sa_get_share_attr(share, "subgroup"); 35385089Sdougm if (attr != NULL) { 35395089Sdougm if (strcmp(attr, "true") == 0) 35405089Sdougm ret = SA_OK; 35415089Sdougm sa_free_attr_string(attr); 35425089Sdougm } 35435089Sdougm } 35445089Sdougm return (ret); 35455089Sdougm } 35465089Sdougm 35475089Sdougm /* 35485331Samw * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 35493034Sdougm * 35503034Sdougm * This function implements "set" when a name space (-S) is not 35513034Sdougm * specified. It is a basic set. Options and other CLI parsing has 35523034Sdougm * already been done. 35535331Samw * 35545331Samw * "rsrcname" is a "resource name". If it is non-NULL, it must match 35555331Samw * the sharepath if present or group if present, otherwise it is used 35565331Samw * to set options. 35575331Samw * 35585331Samw * Resource names may take options if the protocol supports it. If the 35595331Samw * protocol doesn't support resource level options, rsrcname is just 35605331Samw * an alias for the share. 35613034Sdougm */ 35623034Sdougm 35633034Sdougm static int 35643910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 35655331Samw char *protocol, char *sharepath, char *rsrcname, int dryrun) 35663034Sdougm { 35673034Sdougm sa_group_t group; 35683034Sdougm int ret = SA_OK; 35693034Sdougm int change = 0; 35703034Sdougm struct list *worklist = NULL; 35713034Sdougm 35723910Sdougm group = sa_get_group(handle, groupname); 35733034Sdougm if (group != NULL) { 35744653Sdougm sa_share_t share = NULL; 35755331Samw sa_resource_t resource = NULL; 35765331Samw 35775331Samw /* 35785331Samw * If there is a sharepath, make sure it belongs to 35795331Samw * the group. 35805331Samw */ 35814653Sdougm if (sharepath != NULL) { 35824653Sdougm share = sa_get_share(group, sharepath); 35834653Sdougm if (share == NULL) { 35844653Sdougm (void) printf(gettext( 35854653Sdougm "Share does not exist in group %s\n"), 35864653Sdougm groupname, sharepath); 35874653Sdougm ret = SA_NO_SUCH_PATH; 35885089Sdougm } else { 35895089Sdougm /* if ZFS and OK, then only group */ 35905089Sdougm ret = zfscheck(group, share); 35915089Sdougm if (ret == SA_OK && 35925089Sdougm sa_group_is_zfs(group)) 35935089Sdougm share = NULL; 35945089Sdougm if (ret == SA_NOT_ALLOWED) 35955089Sdougm (void) printf(gettext( 35965089Sdougm "Properties on ZFS group shares " 35975089Sdougm "not supported: %s\n"), sharepath); 35984653Sdougm } 35993034Sdougm } 36005331Samw 36015331Samw /* 36025331Samw * If a resource name exists, make sure it belongs to 36035331Samw * the share if present else it belongs to the 36045331Samw * group. Also check the protocol to see if it 36055331Samw * supports resource level properties or not. If not, 36065331Samw * use share only. 36075331Samw */ 36085331Samw if (rsrcname != NULL) { 36095331Samw if (share != NULL) { 36105331Samw resource = sa_get_share_resource(share, 36115331Samw rsrcname); 36125331Samw if (resource == NULL) 36135331Samw ret = SA_NO_SUCH_RESOURCE; 36145331Samw } else { 36155331Samw resource = sa_get_resource(group, rsrcname); 36165331Samw if (resource != NULL) 36175331Samw share = sa_get_resource_parent( 36185331Samw resource); 36195331Samw else 36205331Samw ret = SA_NO_SUCH_RESOURCE; 36215331Samw } 36225331Samw if (ret == SA_OK && resource != NULL) { 36235331Samw uint64_t features; 36245331Samw /* 36255331Samw * Check to see if the resource can take 36265331Samw * properties. If so, stick the resource into 36275331Samw * "share" so it will all just work. 36285331Samw */ 36295331Samw features = sa_proto_get_featureset(protocol); 36305331Samw if (features & SA_FEATURE_RESOURCE) 36315331Samw share = (sa_share_t)resource; 36325331Samw } 36335331Samw } 36345331Samw 36354653Sdougm if (ret == SA_OK) { 36364653Sdougm /* group must exist */ 36374653Sdougm ret = valid_options(optlist, protocol, 36384653Sdougm share == NULL ? group : share, NULL); 36394653Sdougm if (ret == SA_OK && !dryrun) { 36404653Sdougm if (share != NULL) 36414653Sdougm change |= add_optionset(share, optlist, 36424653Sdougm protocol, &ret); 36434653Sdougm else 36444653Sdougm change |= add_optionset(group, optlist, 36454653Sdougm protocol, &ret); 36464653Sdougm if (ret == SA_OK && change) 36474653Sdougm worklist = add_list(worklist, group, 36485331Samw share, protocol); 36494653Sdougm } 36503034Sdougm } 36514653Sdougm free_opt(optlist); 36523034Sdougm } else { 36533034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 36543034Sdougm ret = SA_NO_SUCH_GROUP; 36553034Sdougm } 36563034Sdougm /* 36573034Sdougm * we have a group and potentially legal additions 36583034Sdougm */ 36593034Sdougm 36604653Sdougm /* 36614653Sdougm * Commit to configuration if not a dryrunp and properties 36624653Sdougm * have changed. 36634653Sdougm */ 36644653Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 36653034Sdougm /* properties changed, so update all shares */ 36665331Samw (void) enable_all_groups(handle, worklist, 0, 0, protocol, 36675331Samw B_TRUE); 36684653Sdougm 36693034Sdougm if (worklist != NULL) 36704653Sdougm free_list(worklist); 36713034Sdougm return (ret); 36723034Sdougm } 36733034Sdougm 36743034Sdougm /* 36753034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 36763034Sdougm * 36773034Sdougm * This function implements "set" when a name space (-S) is 36783034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 36793034Sdougm * already been done. 36803034Sdougm */ 36813034Sdougm 36823034Sdougm static int 36833910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 36845331Samw char *protocol, char *sharepath, int dryrun, char *sectype) 36853034Sdougm { 36863034Sdougm sa_group_t group; 36873034Sdougm int ret = SA_OK; 36883034Sdougm int change = 0; 36893034Sdougm struct list *worklist = NULL; 36903034Sdougm 36913034Sdougm /* 36923034Sdougm * make sure protcol and sectype are valid 36933034Sdougm */ 36943034Sdougm 36953034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 36964653Sdougm (void) printf(gettext("Option space \"%s\" not valid " 36974653Sdougm "for protocol.\n"), sectype); 36984653Sdougm return (SA_INVALID_SECURITY); 36993034Sdougm } 37003034Sdougm 37013910Sdougm group = sa_get_group(handle, groupname); 37023034Sdougm if (group != NULL) { 37034653Sdougm sa_share_t share = NULL; 37044653Sdougm if (sharepath != NULL) { 37054653Sdougm share = sa_get_share(group, sharepath); 37064653Sdougm if (share == NULL) { 37074653Sdougm (void) printf(gettext( 37084653Sdougm "Share does not exist in group %s\n"), 37094653Sdougm groupname, sharepath); 37104653Sdougm ret = SA_NO_SUCH_PATH; 37115089Sdougm } else { 37125089Sdougm /* if ZFS and OK, then only group */ 37135089Sdougm ret = zfscheck(group, share); 37145089Sdougm if (ret == SA_OK && 37155089Sdougm sa_group_is_zfs(group)) 37165089Sdougm share = NULL; 37175089Sdougm if (ret == SA_NOT_ALLOWED) 37185089Sdougm (void) printf(gettext( 37195089Sdougm "Properties on ZFS group shares " 37205089Sdougm "not supported: %s\n"), sharepath); 37214653Sdougm } 37223034Sdougm } 37234653Sdougm if (ret == SA_OK) { 37244653Sdougm /* group must exist */ 37254653Sdougm ret = valid_options(optlist, protocol, 37264653Sdougm share == NULL ? group : share, sectype); 37274653Sdougm if (ret == SA_OK && !dryrun) { 37284653Sdougm if (share != NULL) 37294653Sdougm change = add_security(share, sectype, 37304653Sdougm optlist, protocol, &ret); 37314653Sdougm else 37324653Sdougm change = add_security(group, sectype, 37334653Sdougm optlist, protocol, &ret); 37344653Sdougm if (ret != SA_OK) 37354653Sdougm (void) printf(gettext( 37364653Sdougm "Could not set property: %s\n"), 37374653Sdougm sa_errorstr(ret)); 37384653Sdougm } 37394653Sdougm if (ret == SA_OK && change) 37405331Samw worklist = add_list(worklist, group, share, 37415331Samw protocol); 37423034Sdougm } 37434653Sdougm free_opt(optlist); 37443034Sdougm } else { 37453034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 37463034Sdougm ret = SA_NO_SUCH_GROUP; 37473034Sdougm } 37485331Samw 37493034Sdougm /* 37505331Samw * We have a group and potentially legal additions. 37513034Sdougm */ 37523034Sdougm 37534653Sdougm /* Commit to configuration if not a dryrun */ 37543034Sdougm if (!dryrun && ret == 0) { 37554653Sdougm if (change && worklist != NULL) { 37564653Sdougm /* properties changed, so update all shares */ 37574653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 37585331Samw protocol, B_TRUE); 37594653Sdougm } 37604653Sdougm ret = sa_update_config(handle); 37613034Sdougm } 37623034Sdougm if (worklist != NULL) 37634653Sdougm free_list(worklist); 37643034Sdougm return (ret); 37653034Sdougm } 37663034Sdougm 37673034Sdougm /* 37683034Sdougm * sa_set(flags, argc, argv) 37693034Sdougm * 37703034Sdougm * Implements the set subcommand. It keys off of -S to determine which 37713034Sdougm * set of operations to actually do. 37723034Sdougm */ 37733034Sdougm 37743034Sdougm int 37753910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 37763034Sdougm { 37773034Sdougm char *groupname; 37783034Sdougm int verbose = 0; 37793034Sdougm int dryrun = 0; 37803034Sdougm int c; 37813034Sdougm char *protocol = NULL; 37823034Sdougm int ret = SA_OK; 37833034Sdougm struct options *optlist = NULL; 37845331Samw char *rsrcname = NULL; 37853034Sdougm char *sharepath = NULL; 37863034Sdougm char *optset = NULL; 37873034Sdougm int auth; 37883034Sdougm 37895331Samw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 37904653Sdougm switch (c) { 37914653Sdougm case 'v': 37924653Sdougm verbose++; 37934653Sdougm break; 37944653Sdougm case 'n': 37954653Sdougm dryrun++; 37964653Sdougm break; 37974653Sdougm case 'P': 37985331Samw if (protocol != NULL) { 37995331Samw (void) printf(gettext( 38005331Samw "Specifying multiple protocols " 38015331Samw "not supported: %s\n"), protocol); 38025331Samw return (SA_SYNTAX_ERR); 38035331Samw } 38044653Sdougm protocol = optarg; 38054653Sdougm if (!sa_valid_protocol(protocol)) { 38064653Sdougm (void) printf(gettext( 38074653Sdougm "Invalid protocol specified: %s\n"), 38084653Sdougm protocol); 38094653Sdougm return (SA_INVALID_PROTOCOL); 38104653Sdougm } 38114653Sdougm break; 38124653Sdougm case 'p': 38134653Sdougm ret = add_opt(&optlist, optarg, 0); 38144653Sdougm switch (ret) { 38154653Sdougm case OPT_ADD_SYNTAX: 38164653Sdougm (void) printf(gettext("Property syntax error:" 38174653Sdougm " %s\n"), optarg); 38184653Sdougm return (SA_SYNTAX_ERR); 38194653Sdougm case OPT_ADD_MEMORY: 38204653Sdougm (void) printf(gettext("No memory to set " 38214653Sdougm "property: %s\n"), optarg); 38224653Sdougm return (SA_NO_MEMORY); 38234653Sdougm default: 38244653Sdougm break; 38254653Sdougm } 38264653Sdougm break; 38275331Samw case 'r': 38285331Samw if (rsrcname != NULL) { 38295331Samw (void) printf(gettext( 38305331Samw "Setting multiple resource names not" 38315331Samw " supported\n")); 38325331Samw return (SA_SYNTAX_ERR); 38335331Samw } 38345331Samw rsrcname = optarg; 38355331Samw break; 38364653Sdougm case 's': 38375331Samw if (sharepath != NULL) { 38385331Samw (void) printf(gettext( 38395331Samw "Setting multiple shares not supported\n")); 38405331Samw return (SA_SYNTAX_ERR); 38415331Samw } 38424653Sdougm sharepath = optarg; 38434653Sdougm break; 38444653Sdougm case 'S': 38455331Samw if (optset != NULL) { 38465331Samw (void) printf(gettext( 38475331Samw "Specifying multiple property " 38485331Samw "spaces not supported: %s\n"), optset); 38495331Samw return (SA_SYNTAX_ERR); 38505331Samw } 38514653Sdougm optset = optarg; 38524653Sdougm break; 3853*6019Sdougm case 'h': 3854*6019Sdougm /* optopt on valid arg isn't defined */ 3855*6019Sdougm optopt = c; 3856*6019Sdougm /*FALLTHROUGH*/ 3857*6019Sdougm case '?': 38584653Sdougm default: 3859*6019Sdougm /* 3860*6019Sdougm * Since a bad option gets to here, sort it 3861*6019Sdougm * out and return a syntax error return value 3862*6019Sdougm * if necessary. 3863*6019Sdougm */ 3864*6019Sdougm switch (optopt) { 3865*6019Sdougm default: 3866*6019Sdougm ret = SA_SYNTAX_ERR; 3867*6019Sdougm break; 3868*6019Sdougm case 'h': 3869*6019Sdougm case '?': 3870*6019Sdougm break; 3871*6019Sdougm } 38724653Sdougm (void) printf(gettext("usage: %s\n"), 38734653Sdougm sa_get_usage(USAGE_SET)); 3874*6019Sdougm return (ret); 38753034Sdougm } 38763034Sdougm } 38773034Sdougm 38783034Sdougm if (optlist != NULL) 38794653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 38803034Sdougm 38813034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 38824653Sdougm protocol == NULL || ret != OPT_ADD_OK) { 38834653Sdougm char *sep = "\t"; 38844653Sdougm 38854653Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 38864653Sdougm if (optind >= argc) { 38874653Sdougm (void) printf(gettext("%sgroup must be specified"), 38884653Sdougm sep); 38894653Sdougm sep = ", "; 38904653Sdougm } 38914653Sdougm if (optlist == NULL) { 38924653Sdougm (void) printf(gettext("%sat least one property must be" 38934653Sdougm " specified"), sep); 38944653Sdougm sep = ", "; 38954653Sdougm } 38964653Sdougm if (protocol == NULL) { 38974653Sdougm (void) printf(gettext("%sprotocol must be specified"), 38984653Sdougm sep); 38994653Sdougm sep = ", "; 39004653Sdougm } 39014653Sdougm (void) printf("\n"); 39024653Sdougm ret = SA_SYNTAX_ERR; 39033034Sdougm } else { 39043034Sdougm /* 39055089Sdougm * Group already exists so we can proceed after a few 39065089Sdougm * additional checks related to ZFS handling. 39073034Sdougm */ 39083034Sdougm 39094653Sdougm groupname = argv[optind]; 39105089Sdougm if (strcmp(groupname, "zfs") == 0) { 39115089Sdougm (void) printf(gettext("Changing properties for group " 39125089Sdougm "\"zfs\" not allowed\n")); 39135089Sdougm return (SA_NOT_ALLOWED); 39145089Sdougm } 39155089Sdougm 39164653Sdougm auth = check_authorizations(groupname, flags); 39174653Sdougm if (optset == NULL) 39184653Sdougm ret = basic_set(handle, groupname, optlist, protocol, 39195331Samw sharepath, rsrcname, dryrun); 39204653Sdougm else 39214653Sdougm ret = space_set(handle, groupname, optlist, protocol, 39224653Sdougm sharepath, dryrun, optset); 39234653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 39244653Sdougm (void) printf(gettext("Command would fail: %s\n"), 39254653Sdougm sa_errorstr(SA_NO_PERMISSION)); 39264653Sdougm } 39273034Sdougm } 39283034Sdougm return (ret); 39293034Sdougm } 39303034Sdougm 39313034Sdougm /* 39323034Sdougm * remove_options(group, optlist, proto, *err) 39333034Sdougm * 39344653Sdougm * Helper function to actually remove options from a group after all 39353034Sdougm * preprocessing is done. 39363034Sdougm */ 39373034Sdougm 39383034Sdougm static int 39393034Sdougm remove_options(sa_group_t group, struct options *optlist, 39405331Samw char *proto, int *err) 39413034Sdougm { 39423034Sdougm struct options *cur; 39433034Sdougm sa_optionset_t optionset; 39443034Sdougm sa_property_t prop; 39453034Sdougm int change = 0; 39463034Sdougm int ret = SA_OK; 39473034Sdougm 39483034Sdougm optionset = sa_get_optionset(group, proto); 39493034Sdougm if (optionset != NULL) { 39504653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 39514653Sdougm prop = sa_get_property(optionset, cur->optname); 39524653Sdougm if (prop != NULL) { 39534653Sdougm ret = sa_remove_property(prop); 39544653Sdougm if (ret != SA_OK) 39554653Sdougm break; 39564653Sdougm change = 1; 39574653Sdougm } 39583034Sdougm } 39593034Sdougm } 39603034Sdougm if (ret == SA_OK && change) 39614653Sdougm ret = sa_commit_properties(optionset, 0); 39623034Sdougm 39633034Sdougm if (err != NULL) 39644653Sdougm *err = ret; 39653034Sdougm return (change); 39663034Sdougm } 39673034Sdougm 39683034Sdougm /* 39693034Sdougm * valid_unset(group, optlist, proto) 39703034Sdougm * 39713034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 39723034Sdougm * error if a property doesn't exist. 39733034Sdougm */ 39743034Sdougm 39753034Sdougm static int 39763034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 39773034Sdougm { 39783034Sdougm struct options *cur; 39793034Sdougm sa_optionset_t optionset; 39803034Sdougm sa_property_t prop; 39813034Sdougm int ret = SA_OK; 39823034Sdougm 39833034Sdougm optionset = sa_get_optionset(group, proto); 39843034Sdougm if (optionset != NULL) { 39854653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 39864653Sdougm prop = sa_get_property(optionset, cur->optname); 39874653Sdougm if (prop == NULL) { 39884653Sdougm (void) printf(gettext( 39894653Sdougm "Could not unset property %s: not set\n"), 39904653Sdougm cur->optname); 39914653Sdougm ret = SA_NO_SUCH_PROP; 39924653Sdougm } 39933034Sdougm } 39943034Sdougm } 39953034Sdougm return (ret); 39963034Sdougm } 39973034Sdougm 39983034Sdougm /* 39993034Sdougm * valid_unset_security(group, optlist, proto) 40003034Sdougm * 40013034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 40023034Sdougm * error if a property doesn't exist. 40033034Sdougm */ 40043034Sdougm 40053034Sdougm static int 40063034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 40075331Samw char *sectype) 40083034Sdougm { 40093034Sdougm struct options *cur; 40103034Sdougm sa_security_t security; 40113034Sdougm sa_property_t prop; 40123034Sdougm int ret = SA_OK; 40133034Sdougm char *sec; 40143034Sdougm 40153034Sdougm sec = sa_proto_space_alias(proto, sectype); 40163034Sdougm security = sa_get_security(group, sec, proto); 40173034Sdougm if (security != NULL) { 40184653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 40194653Sdougm prop = sa_get_property(security, cur->optname); 40204653Sdougm if (prop == NULL) { 40214653Sdougm (void) printf(gettext( 40224653Sdougm "Could not unset property %s: not set\n"), 40234653Sdougm cur->optname); 40244653Sdougm ret = SA_NO_SUCH_PROP; 40254653Sdougm } 40263034Sdougm } 40273034Sdougm } else { 40284653Sdougm (void) printf(gettext( 40294653Sdougm "Could not unset %s: space not defined\n"), sectype); 40304653Sdougm ret = SA_NO_SUCH_SECURITY; 40313034Sdougm } 40323034Sdougm if (sec != NULL) 40334653Sdougm sa_free_attr_string(sec); 40343034Sdougm return (ret); 40353034Sdougm } 40363034Sdougm 40373034Sdougm /* 40383034Sdougm * remove_security(group, optlist, proto) 40393034Sdougm * 40403034Sdougm * Remove the properties since they were checked as valid. 40413034Sdougm */ 40423034Sdougm 40433034Sdougm static int 40443034Sdougm remove_security(sa_group_t group, char *sectype, 40455331Samw struct options *optlist, char *proto, int *err) 40463034Sdougm { 40473034Sdougm sa_security_t security; 40483034Sdougm int ret = SA_OK; 40493034Sdougm int change = 0; 40503034Sdougm 40513034Sdougm sectype = sa_proto_space_alias(proto, sectype); 40523034Sdougm security = sa_get_security(group, sectype, proto); 40533034Sdougm if (sectype != NULL) 40544653Sdougm sa_free_attr_string(sectype); 40553034Sdougm 40563034Sdougm if (security != NULL) { 40574653Sdougm while (optlist != NULL) { 40584653Sdougm sa_property_t prop; 40594653Sdougm prop = sa_get_property(security, optlist->optname); 40604653Sdougm if (prop != NULL) { 40614653Sdougm ret = sa_remove_property(prop); 40624653Sdougm if (ret != SA_OK) 40634653Sdougm break; 40644653Sdougm change = 1; 40654653Sdougm } 40664653Sdougm optlist = optlist->next; 40673034Sdougm } 40683034Sdougm /* 40693034Sdougm * when done, properties may have all been removed but 40703034Sdougm * we need to keep the security type itself until 40713034Sdougm * explicitly removed. 40723034Sdougm */ 40734653Sdougm if (ret == SA_OK && change) 40744653Sdougm ret = sa_commit_properties(security, 0); 40753034Sdougm } else { 40764653Sdougm ret = SA_NO_SUCH_PROP; 40773034Sdougm } 40783034Sdougm if (err != NULL) 40794653Sdougm *err = ret; 40803034Sdougm return (change); 40813034Sdougm } 40823034Sdougm 40833034Sdougm /* 40845331Samw * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 40853034Sdougm * 40864653Sdougm * Unset non-named optionset properties. 40873034Sdougm */ 40883034Sdougm 40893034Sdougm static int 40903910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 40915331Samw char *protocol, char *sharepath, char *rsrcname, int dryrun) 40923034Sdougm { 40933034Sdougm sa_group_t group; 40943034Sdougm int ret = SA_OK; 40953034Sdougm int change = 0; 40963034Sdougm struct list *worklist = NULL; 40974653Sdougm sa_share_t share = NULL; 40985331Samw sa_resource_t resource = NULL; 40993034Sdougm 41003910Sdougm group = sa_get_group(handle, groupname); 41014653Sdougm if (group == NULL) 41024653Sdougm return (ret); 41034653Sdougm 41045331Samw /* 41055331Samw * If there is a sharepath, make sure it belongs to 41065331Samw * the group. 41075331Samw */ 41084653Sdougm if (sharepath != NULL) { 41093034Sdougm share = sa_get_share(group, sharepath); 41103034Sdougm if (share == NULL) { 41114653Sdougm (void) printf(gettext( 41124653Sdougm "Share does not exist in group %s\n"), 41134653Sdougm groupname, sharepath); 41144653Sdougm ret = SA_NO_SUCH_PATH; 41153034Sdougm } 41164653Sdougm } 41175331Samw /* 41185331Samw * If a resource name exists, make sure it belongs to 41195331Samw * the share if present else it belongs to the 41205331Samw * group. Also check the protocol to see if it 41215331Samw * supports resource level properties or not. If not, 41225331Samw * use share only. 41235331Samw */ 41245331Samw if (rsrcname != NULL) { 41255331Samw if (share != NULL) { 41265331Samw resource = sa_get_share_resource(share, rsrcname); 41275331Samw if (resource == NULL) 41285331Samw ret = SA_NO_SUCH_RESOURCE; 41295331Samw } else { 41305331Samw resource = sa_get_resource(group, rsrcname); 41315331Samw if (resource != NULL) { 41325331Samw share = sa_get_resource_parent(resource); 41335331Samw } else { 41345331Samw ret = SA_NO_SUCH_RESOURCE; 41355331Samw } 41365331Samw } 41375331Samw if (ret == SA_OK && resource != NULL) { 41385331Samw uint64_t features; 41395331Samw /* 41405331Samw * Check to see if the resource can take 41415331Samw * properties. If so, stick the resource into 41425331Samw * "share" so it will all just work. 41435331Samw */ 41445331Samw features = sa_proto_get_featureset(protocol); 41455331Samw if (features & SA_FEATURE_RESOURCE) 41465331Samw share = (sa_share_t)resource; 41475331Samw } 41485331Samw } 41495331Samw 41504653Sdougm if (ret == SA_OK) { 41513034Sdougm /* group must exist */ 41523034Sdougm ret = valid_unset(share != NULL ? share : group, 41534653Sdougm optlist, protocol); 41543034Sdougm if (ret == SA_OK && !dryrun) { 41554653Sdougm if (share != NULL) { 41564653Sdougm sa_optionset_t optionset; 41574653Sdougm sa_property_t prop; 41584653Sdougm change |= remove_options(share, optlist, 41594653Sdougm protocol, &ret); 41604653Sdougm /* 41614653Sdougm * If a share optionset is 41624653Sdougm * empty, remove it. 41634653Sdougm */ 41644653Sdougm optionset = sa_get_optionset((sa_share_t)share, 41654653Sdougm protocol); 41664653Sdougm if (optionset != NULL) { 41674653Sdougm prop = sa_get_property(optionset, NULL); 41684653Sdougm if (prop == NULL) 41694653Sdougm (void) sa_destroy_optionset( 41704653Sdougm optionset); 41714653Sdougm } 41724653Sdougm } else { 41734653Sdougm change |= remove_options(group, 41744653Sdougm optlist, protocol, &ret); 41753034Sdougm } 41764653Sdougm if (ret == SA_OK && change) 41775331Samw worklist = add_list(worklist, group, share, 41785331Samw protocol); 41794653Sdougm if (ret != SA_OK) 41804653Sdougm (void) printf(gettext( 41814653Sdougm "Could not remove properties: " 41824653Sdougm "%s\n"), sa_errorstr(ret)); 41833034Sdougm } 41844653Sdougm } else { 41855331Samw (void) printf(gettext("Group \"%s\" not found\n"), groupname); 41863034Sdougm ret = SA_NO_SUCH_GROUP; 41873034Sdougm } 41884653Sdougm free_opt(optlist); 41893034Sdougm 41903034Sdougm /* 41914653Sdougm * We have a group and potentially legal additions 41924653Sdougm * 41934653Sdougm * Commit to configuration if not a dryrun 41943034Sdougm */ 41953034Sdougm if (!dryrun && ret == SA_OK) { 41964653Sdougm if (change && worklist != NULL) { 41974653Sdougm /* properties changed, so update all shares */ 41984653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 41995331Samw protocol, B_TRUE); 42004653Sdougm } 42013034Sdougm } 42023034Sdougm if (worklist != NULL) 42034653Sdougm free_list(worklist); 42043034Sdougm return (ret); 42053034Sdougm } 42063034Sdougm 42073034Sdougm /* 42083034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 42093034Sdougm * 42104653Sdougm * Unset named optionset properties. 42113034Sdougm */ 42123034Sdougm static int 42133910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 42145331Samw char *protocol, char *sharepath, int dryrun, char *sectype) 42153034Sdougm { 42163034Sdougm sa_group_t group; 42173034Sdougm int ret = SA_OK; 42183034Sdougm int change = 0; 42193034Sdougm struct list *worklist = NULL; 42204653Sdougm sa_share_t share = NULL; 42213034Sdougm 42223910Sdougm group = sa_get_group(handle, groupname); 42234653Sdougm if (group == NULL) { 42244653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 42254653Sdougm return (SA_NO_SUCH_GROUP); 42264653Sdougm } 42274653Sdougm if (sharepath != NULL) { 42283034Sdougm share = sa_get_share(group, sharepath); 42293034Sdougm if (share == NULL) { 42304653Sdougm (void) printf(gettext( 42314653Sdougm "Share does not exist in group %s\n"), 42324653Sdougm groupname, sharepath); 42334653Sdougm return (SA_NO_SUCH_PATH); 42343034Sdougm } 42354653Sdougm } 42365331Samw ret = valid_unset_security(share != NULL ? share : group, 42375331Samw optlist, protocol, sectype); 42384653Sdougm 42394653Sdougm if (ret == SA_OK && !dryrun) { 42404653Sdougm if (optlist != NULL) { 42413034Sdougm if (share != NULL) { 42424653Sdougm sa_security_t optionset; 42434653Sdougm sa_property_t prop; 42444653Sdougm change = remove_security(share, 42454653Sdougm sectype, optlist, protocol, &ret); 42464653Sdougm 42474653Sdougm /* If a share security is empty, remove it */ 42484653Sdougm optionset = sa_get_security((sa_group_t)share, 42494653Sdougm sectype, protocol); 42504653Sdougm if (optionset != NULL) { 42514653Sdougm prop = sa_get_property(optionset, 42524653Sdougm NULL); 42534653Sdougm if (prop == NULL) 42544653Sdougm ret = sa_destroy_security( 42554653Sdougm optionset); 42564653Sdougm } 42573034Sdougm } else { 42584653Sdougm change = remove_security(group, sectype, 42594653Sdougm optlist, protocol, &ret); 42603034Sdougm } 42614653Sdougm } else { 42623034Sdougm sa_security_t security; 42633034Sdougm char *sec; 42643034Sdougm sec = sa_proto_space_alias(protocol, sectype); 42653034Sdougm security = sa_get_security(group, sec, protocol); 42663034Sdougm if (sec != NULL) 42674653Sdougm sa_free_attr_string(sec); 42683034Sdougm if (security != NULL) { 42694653Sdougm ret = sa_destroy_security(security); 42704653Sdougm if (ret == SA_OK) 42714653Sdougm change = 1; 42723034Sdougm } else { 42734653Sdougm ret = SA_NO_SUCH_PROP; 42743034Sdougm } 42754653Sdougm } 42764653Sdougm if (ret != SA_OK) 42773034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 42784653Sdougm sa_errorstr(ret)); 42793034Sdougm } 42804653Sdougm 42814653Sdougm if (ret == SA_OK && change) 42825331Samw worklist = add_list(worklist, group, 0, protocol); 42834653Sdougm 42843034Sdougm free_opt(optlist); 42853034Sdougm /* 42864653Sdougm * We have a group and potentially legal additions 42873034Sdougm */ 42883034Sdougm 42894653Sdougm /* Commit to configuration if not a dryrun */ 42903034Sdougm if (!dryrun && ret == 0) { 42913034Sdougm /* properties changed, so update all shares */ 42924653Sdougm if (change && worklist != NULL) 42934653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 42945331Samw protocol, B_TRUE); 42954653Sdougm ret = sa_update_config(handle); 42963034Sdougm } 42973034Sdougm if (worklist != NULL) 42984653Sdougm free_list(worklist); 42993034Sdougm return (ret); 43003034Sdougm } 43013034Sdougm 43023034Sdougm /* 43033034Sdougm * sa_unset(flags, argc, argv) 43043034Sdougm * 43054653Sdougm * Implements the unset subcommand. Parsing done here and then basic 43063034Sdougm * or space versions of the real code are called. 43073034Sdougm */ 43083034Sdougm 43093034Sdougm int 43103910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 43113034Sdougm { 43123034Sdougm char *groupname; 43133034Sdougm int verbose = 0; 43143034Sdougm int dryrun = 0; 43153034Sdougm int c; 43163034Sdougm char *protocol = NULL; 43173034Sdougm int ret = SA_OK; 43183034Sdougm struct options *optlist = NULL; 43195331Samw char *rsrcname = NULL; 43203034Sdougm char *sharepath = NULL; 43213034Sdougm char *optset = NULL; 43223034Sdougm int auth; 43233034Sdougm 43245331Samw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 43254653Sdougm switch (c) { 43264653Sdougm case 'v': 43274653Sdougm verbose++; 43284653Sdougm break; 43294653Sdougm case 'n': 43304653Sdougm dryrun++; 43314653Sdougm break; 43324653Sdougm case 'P': 43335331Samw if (protocol != NULL) { 43345331Samw (void) printf(gettext( 43355331Samw "Specifying multiple protocols " 43365331Samw "not supported: %s\n"), protocol); 43375331Samw return (SA_SYNTAX_ERR); 43385331Samw } 43394653Sdougm protocol = optarg; 43404653Sdougm if (!sa_valid_protocol(protocol)) { 43414653Sdougm (void) printf(gettext( 43424653Sdougm "Invalid protocol specified: %s\n"), 43434653Sdougm protocol); 43444653Sdougm return (SA_INVALID_PROTOCOL); 43454653Sdougm } 43464653Sdougm break; 43474653Sdougm case 'p': 43484653Sdougm ret = add_opt(&optlist, optarg, 1); 43494653Sdougm switch (ret) { 43504653Sdougm case OPT_ADD_SYNTAX: 43514653Sdougm (void) printf(gettext("Property syntax error " 43524653Sdougm "for property %s\n"), optarg); 43534653Sdougm return (SA_SYNTAX_ERR); 43544653Sdougm 43554653Sdougm case OPT_ADD_PROPERTY: 43564653Sdougm (void) printf(gettext("Properties need to be " 43574653Sdougm "set with set command: %s\n"), optarg); 43584653Sdougm return (SA_SYNTAX_ERR); 43594653Sdougm 43604653Sdougm default: 43614653Sdougm break; 43624653Sdougm } 43634653Sdougm break; 43645331Samw case 'r': 43655331Samw /* 43665331Samw * Unset properties on resource if applicable or on 43675331Samw * share if resource for this protocol doesn't use 43685331Samw * resources. 43695331Samw */ 43705331Samw if (rsrcname != NULL) { 43715331Samw (void) printf(gettext( 43725331Samw "Unsetting multiple resource " 43735331Samw "names not supported\n")); 43745331Samw return (SA_SYNTAX_ERR); 43755331Samw } 43765331Samw rsrcname = optarg; 43775331Samw break; 43784653Sdougm case 's': 43795331Samw if (sharepath != NULL) { 43805331Samw (void) printf(gettext( 43815331Samw "Adding multiple shares not supported\n")); 43825331Samw return (SA_SYNTAX_ERR); 43835331Samw } 43844653Sdougm sharepath = optarg; 43854653Sdougm break; 43864653Sdougm case 'S': 43875331Samw if (optset != NULL) { 43885331Samw (void) printf(gettext( 43895331Samw "Specifying multiple property " 43905331Samw "spaces not supported: %s\n"), optset); 43915331Samw return (SA_SYNTAX_ERR); 43925331Samw } 43934653Sdougm optset = optarg; 43944653Sdougm break; 4395*6019Sdougm case 'h': 4396*6019Sdougm /* optopt on valid arg isn't defined */ 4397*6019Sdougm optopt = c; 4398*6019Sdougm /*FALLTHROUGH*/ 4399*6019Sdougm case '?': 44004653Sdougm default: 4401*6019Sdougm /* 4402*6019Sdougm * Since a bad option gets to here, sort it 4403*6019Sdougm * out and return a syntax error return value 4404*6019Sdougm * if necessary. 4405*6019Sdougm */ 4406*6019Sdougm switch (optopt) { 4407*6019Sdougm default: 4408*6019Sdougm ret = SA_SYNTAX_ERR; 4409*6019Sdougm break; 4410*6019Sdougm case 'h': 4411*6019Sdougm case '?': 4412*6019Sdougm break; 4413*6019Sdougm } 44144653Sdougm (void) printf(gettext("usage: %s\n"), 44154653Sdougm sa_get_usage(USAGE_UNSET)); 4416*6019Sdougm return (ret); 44173034Sdougm } 44183034Sdougm } 44193034Sdougm 44203034Sdougm if (optlist != NULL) 44214653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 44223034Sdougm 44233034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 44243034Sdougm protocol == NULL) { 44254653Sdougm char *sep = "\t"; 44264653Sdougm (void) printf(gettext("usage: %s\n"), 44274653Sdougm sa_get_usage(USAGE_UNSET)); 44284653Sdougm if (optind >= argc) { 44294653Sdougm (void) printf(gettext("%sgroup must be specified"), 44304653Sdougm sep); 44314653Sdougm sep = ", "; 44324653Sdougm } 44334653Sdougm if (optlist == NULL) { 44344653Sdougm (void) printf(gettext("%sat least one property must " 44354653Sdougm "be specified"), sep); 44364653Sdougm sep = ", "; 44374653Sdougm } 44384653Sdougm if (protocol == NULL) { 44394653Sdougm (void) printf(gettext("%sprotocol must be specified"), 44404653Sdougm sep); 44414653Sdougm sep = ", "; 44424653Sdougm } 44434653Sdougm (void) printf("\n"); 44444653Sdougm ret = SA_SYNTAX_ERR; 44453034Sdougm } else { 44463034Sdougm 44473034Sdougm /* 44484653Sdougm * If a group already exists, we can only add a new 44493034Sdougm * protocol to it and not create a new one or add the 44503034Sdougm * same protocol again. 44513034Sdougm */ 44523034Sdougm 44534653Sdougm groupname = argv[optind]; 44544653Sdougm auth = check_authorizations(groupname, flags); 44554653Sdougm if (optset == NULL) 44564653Sdougm ret = basic_unset(handle, groupname, optlist, protocol, 44575331Samw sharepath, rsrcname, dryrun); 44584653Sdougm else 44594653Sdougm ret = space_unset(handle, groupname, optlist, protocol, 44604653Sdougm sharepath, dryrun, optset); 44614653Sdougm 44624653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 44634653Sdougm (void) printf(gettext("Command would fail: %s\n"), 44644653Sdougm sa_errorstr(SA_NO_PERMISSION)); 44653034Sdougm } 44663034Sdougm return (ret); 44673034Sdougm } 44683034Sdougm 44693034Sdougm /* 44703034Sdougm * sa_enable_group(flags, argc, argv) 44713034Sdougm * 44723034Sdougm * Implements the enable subcommand 44733034Sdougm */ 44743034Sdougm 44753034Sdougm int 44763910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 44773034Sdougm { 44783034Sdougm int verbose = 0; 44793034Sdougm int dryrun = 0; 44803034Sdougm int all = 0; 44813034Sdougm int c; 44823034Sdougm int ret = SA_OK; 44833034Sdougm char *protocol = NULL; 44843034Sdougm char *state; 44853034Sdougm struct list *worklist = NULL; 44863034Sdougm int auth = 1; 44874653Sdougm sa_group_t group; 44883034Sdougm 44893034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 44904653Sdougm switch (c) { 44914653Sdougm case 'a': 44924653Sdougm all = 1; 44934653Sdougm break; 44944653Sdougm case 'n': 44954653Sdougm dryrun++; 44964653Sdougm break; 44974653Sdougm case 'P': 44985331Samw if (protocol != NULL) { 44995331Samw (void) printf(gettext( 45005331Samw "Specifying multiple protocols " 45015331Samw "not supported: %s\n"), protocol); 45025331Samw return (SA_SYNTAX_ERR); 45035331Samw } 45044653Sdougm protocol = optarg; 45054653Sdougm if (!sa_valid_protocol(protocol)) { 45064653Sdougm (void) printf(gettext( 45074653Sdougm "Invalid protocol specified: %s\n"), 45083034Sdougm protocol); 45094653Sdougm return (SA_INVALID_PROTOCOL); 45104653Sdougm } 45114653Sdougm break; 45124653Sdougm case 'v': 45134653Sdougm verbose++; 45144653Sdougm break; 45154653Sdougm case 'h': 4516*6019Sdougm /* optopt on valid arg isn't defined */ 4517*6019Sdougm optopt = c; 4518*6019Sdougm /*FALLTHROUGH*/ 45194653Sdougm case '?': 4520*6019Sdougm default: 4521*6019Sdougm /* 4522*6019Sdougm * Since a bad option gets to here, sort it 4523*6019Sdougm * out and return a syntax error return value 4524*6019Sdougm * if necessary. 4525*6019Sdougm */ 4526*6019Sdougm switch (optopt) { 4527*6019Sdougm default: 4528*6019Sdougm ret = SA_SYNTAX_ERR; 4529*6019Sdougm break; 4530*6019Sdougm case 'h': 4531*6019Sdougm case '?': 4532*6019Sdougm (void) printf(gettext("usage: %s\n"), 4533*6019Sdougm sa_get_usage(USAGE_ENABLE)); 4534*6019Sdougm return (ret); 4535*6019Sdougm } 45363034Sdougm } 45373034Sdougm } 45383034Sdougm 45393034Sdougm if (optind == argc && !all) { 45404653Sdougm (void) printf(gettext("usage: %s\n"), 45414653Sdougm sa_get_usage(USAGE_ENABLE)); 45424653Sdougm (void) printf(gettext("\tmust specify group\n")); 45434653Sdougm return (SA_NO_SUCH_PATH); 45444653Sdougm } 45454653Sdougm if (!all) { 45463034Sdougm while (optind < argc) { 45474653Sdougm group = sa_get_group(handle, argv[optind]); 45484653Sdougm if (group != NULL) { 45494653Sdougm auth &= check_authorizations(argv[optind], 45504653Sdougm flags); 45514653Sdougm state = sa_get_group_attr(group, "state"); 45524653Sdougm if (state != NULL && 45534653Sdougm strcmp(state, "enabled") == 0) { 45544653Sdougm /* already enabled */ 45554653Sdougm if (verbose) 45564653Sdougm (void) printf(gettext( 45574653Sdougm "Group \"%s\" is already " 45584653Sdougm "enabled\n"), 45594653Sdougm argv[optind]); 45604653Sdougm ret = SA_BUSY; /* already enabled */ 45614653Sdougm } else { 45624653Sdougm worklist = add_list(worklist, group, 45635331Samw 0, protocol); 45644653Sdougm if (verbose) 45654653Sdougm (void) printf(gettext( 45664653Sdougm "Enabling group \"%s\"\n"), 45674653Sdougm argv[optind]); 45684653Sdougm } 45694653Sdougm if (state != NULL) 45704653Sdougm sa_free_attr_string(state); 45713034Sdougm } else { 45724653Sdougm ret = SA_NO_SUCH_GROUP; 45733034Sdougm } 45744653Sdougm optind++; 45753034Sdougm } 45764653Sdougm } else { 45774653Sdougm for (group = sa_get_group(handle, NULL); 45784653Sdougm group != NULL; 45793034Sdougm group = sa_get_next_group(group)) { 45805331Samw worklist = add_list(worklist, group, 0, protocol); 45813034Sdougm } 45824653Sdougm } 45834653Sdougm if (!dryrun && ret == SA_OK) 45845331Samw ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE); 45854653Sdougm 45864653Sdougm if (ret != SA_OK && ret != SA_BUSY) 45873034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 45884653Sdougm sa_errorstr(ret)); 45894653Sdougm if (ret == SA_BUSY) 45903034Sdougm ret = SA_OK; 45914653Sdougm 45923034Sdougm if (worklist != NULL) 45934653Sdougm free_list(worklist); 45943034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 45954653Sdougm (void) printf(gettext("Command would fail: %s\n"), 45964653Sdougm sa_errorstr(SA_NO_PERMISSION)); 45973034Sdougm } 45983034Sdougm return (ret); 45993034Sdougm } 46003034Sdougm 46013034Sdougm /* 46025331Samw * disable_group(group, proto) 46033034Sdougm * 46045331Samw * Disable all the shares in the specified group.. This is a helper 46055331Samw * for disable_all_groups in order to simplify regular and subgroup 46065331Samw * (zfs) disabling. Group has already been checked for non-NULL. 46073034Sdougm */ 46083034Sdougm 46093034Sdougm static int 46105331Samw disable_group(sa_group_t group, char *proto) 46113034Sdougm { 46123034Sdougm sa_share_t share; 46133034Sdougm int ret = SA_OK; 46143034Sdougm 46155331Samw /* 46165331Samw * If the protocol isn't enabled, skip it and treat as 46175331Samw * successful. 46185331Samw */ 46195331Samw if (!has_protocol(group, proto)) 46205331Samw return (ret); 46215331Samw 46223034Sdougm for (share = sa_get_share(group, NULL); 46233034Sdougm share != NULL && ret == SA_OK; 46243034Sdougm share = sa_get_next_share(share)) { 46255331Samw ret = sa_disable_share(share, proto); 46264653Sdougm if (ret == SA_NO_SUCH_PATH) { 46274653Sdougm /* 46284653Sdougm * this is OK since the path is gone. we can't 46294653Sdougm * re-share it anyway so no error. 46304653Sdougm */ 46314653Sdougm ret = SA_OK; 46324653Sdougm } 46333034Sdougm } 46343034Sdougm return (ret); 46353034Sdougm } 46363034Sdougm 46373034Sdougm /* 46383034Sdougm * disable_all_groups(work, setstate) 46393034Sdougm * 46403034Sdougm * helper function that disables the shares in the list of groups 46413034Sdougm * provided. It optionally marks the group as disabled. Used by both 46423034Sdougm * enable and start subcommands. 46433034Sdougm */ 46443034Sdougm 46453034Sdougm static int 46463910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 46473034Sdougm { 46483034Sdougm int ret = SA_OK; 46493034Sdougm sa_group_t subgroup, group; 46503034Sdougm 46513034Sdougm while (work != NULL && ret == SA_OK) { 46524653Sdougm group = (sa_group_t)work->item; 46534653Sdougm if (setstate) 46544653Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 46554653Sdougm if (ret == SA_OK) { 46564653Sdougm char *name; 46574653Sdougm name = sa_get_group_attr(group, "name"); 46584653Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 46594653Sdougm /* need to get the sub-groups for stopping */ 46604653Sdougm for (subgroup = sa_get_sub_group(group); 46614653Sdougm subgroup != NULL; 46624653Sdougm subgroup = sa_get_next_group(subgroup)) { 46635331Samw ret = disable_group(subgroup, 46645331Samw work->proto); 46654653Sdougm } 46664653Sdougm } else { 46675331Samw ret = disable_group(group, work->proto); 46684653Sdougm } 46694653Sdougm /* 46704653Sdougm * We don't want to "disable" since it won't come 46714653Sdougm * up after a reboot. The SMF framework should do 46724653Sdougm * the right thing. On enable we do want to do 46734653Sdougm * something. 46744653Sdougm */ 46753034Sdougm } 46764653Sdougm work = work->next; 46773034Sdougm } 46783034Sdougm if (ret == SA_OK) 46794653Sdougm ret = sa_update_config(handle); 46803034Sdougm return (ret); 46813034Sdougm } 46823034Sdougm 46833034Sdougm /* 46843034Sdougm * sa_disable_group(flags, argc, argv) 46853034Sdougm * 46863034Sdougm * Implements the disable subcommand 46873034Sdougm */ 46883034Sdougm 46893034Sdougm int 46903910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 46913034Sdougm { 46923034Sdougm int verbose = 0; 46933034Sdougm int dryrun = 0; 46943034Sdougm int all = 0; 46953034Sdougm int c; 46963034Sdougm int ret = SA_OK; 46975331Samw char *protocol = NULL; 46983034Sdougm char *state; 46993034Sdougm struct list *worklist = NULL; 47004653Sdougm sa_group_t group; 47013034Sdougm int auth = 1; 47023034Sdougm 47033034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 47044653Sdougm switch (c) { 47054653Sdougm case 'a': 47064653Sdougm all = 1; 47074653Sdougm break; 47084653Sdougm case 'n': 47094653Sdougm dryrun++; 47104653Sdougm break; 47114653Sdougm case 'P': 47125331Samw if (protocol != NULL) { 47135331Samw (void) printf(gettext( 47145331Samw "Specifying multiple protocols " 47155331Samw "not supported: %s\n"), protocol); 47165331Samw return (SA_SYNTAX_ERR); 47175331Samw } 47184653Sdougm protocol = optarg; 47194653Sdougm if (!sa_valid_protocol(protocol)) { 47204653Sdougm (void) printf(gettext( 47214653Sdougm "Invalid protocol specified: %s\n"), 47224653Sdougm protocol); 47234653Sdougm return (SA_INVALID_PROTOCOL); 47244653Sdougm } 47254653Sdougm break; 47264653Sdougm case 'v': 47274653Sdougm verbose++; 47284653Sdougm break; 4729*6019Sdougm case 'h': 4730*6019Sdougm /* optopt on valid arg isn't defined */ 4731*6019Sdougm optopt = c; 4732*6019Sdougm /*FALLTHROUGH*/ 4733*6019Sdougm case '?': 47344653Sdougm default: 4735*6019Sdougm /* 4736*6019Sdougm * Since a bad option gets to here, sort it 4737*6019Sdougm * out and return a syntax error return value 4738*6019Sdougm * if necessary. 4739*6019Sdougm */ 4740*6019Sdougm switch (optopt) { 4741*6019Sdougm default: 4742*6019Sdougm ret = SA_SYNTAX_ERR; 4743*6019Sdougm break; 4744*6019Sdougm case 'h': 4745*6019Sdougm case '?': 4746*6019Sdougm break; 4747*6019Sdougm } 47484653Sdougm (void) printf(gettext("usage: %s\n"), 47494653Sdougm sa_get_usage(USAGE_DISABLE)); 4750*6019Sdougm return (ret); 47513034Sdougm } 47523034Sdougm } 47533034Sdougm 47543034Sdougm if (optind == argc && !all) { 47553034Sdougm (void) printf(gettext("usage: %s\n"), 47564653Sdougm sa_get_usage(USAGE_DISABLE)); 47573034Sdougm (void) printf(gettext("\tmust specify group\n")); 47584653Sdougm return (SA_NO_SUCH_PATH); 47594653Sdougm } 47604653Sdougm if (!all) { 47614653Sdougm while (optind < argc) { 47623910Sdougm group = sa_get_group(handle, argv[optind]); 47633034Sdougm if (group != NULL) { 47644653Sdougm auth &= check_authorizations(argv[optind], 47654653Sdougm flags); 47664653Sdougm state = sa_get_group_attr(group, "state"); 47674653Sdougm if (state == NULL || 47684653Sdougm strcmp(state, "disabled") == 0) { 47694653Sdougm /* already disabled */ 47704653Sdougm if (verbose) 47714653Sdougm (void) printf(gettext( 47724653Sdougm "Group \"%s\" is " 47734653Sdougm "already disabled\n"), 47744653Sdougm argv[optind]); 47755331Samw ret = SA_BUSY; /* already disabled */ 47764653Sdougm } else { 47775331Samw worklist = add_list(worklist, group, 0, 47785331Samw protocol); 47794653Sdougm if (verbose) 47804653Sdougm (void) printf(gettext( 47814653Sdougm "Disabling group " 47824653Sdougm "\"%s\"\n"), argv[optind]); 47834653Sdougm } 47844653Sdougm if (state != NULL) 47854653Sdougm sa_free_attr_string(state); 47863034Sdougm } else { 47874653Sdougm ret = SA_NO_SUCH_GROUP; 47883034Sdougm } 47893034Sdougm optind++; 47904653Sdougm } 47914653Sdougm } else { 47924653Sdougm for (group = sa_get_group(handle, NULL); 47934653Sdougm group != NULL; 47944653Sdougm group = sa_get_next_group(group)) 47955331Samw worklist = add_list(worklist, group, 0, protocol); 47963034Sdougm } 47974653Sdougm 47984653Sdougm if (ret == SA_OK && !dryrun) 47994653Sdougm ret = disable_all_groups(handle, worklist, 1); 48004653Sdougm if (ret != SA_OK && ret != SA_BUSY) 48014653Sdougm (void) printf(gettext("Could not disable group: %s\n"), 48024653Sdougm sa_errorstr(ret)); 48034653Sdougm if (ret == SA_BUSY) 48044653Sdougm ret = SA_OK; 48053034Sdougm if (worklist != NULL) 48064653Sdougm free_list(worklist); 48074653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 48084653Sdougm (void) printf(gettext("Command would fail: %s\n"), 48094653Sdougm sa_errorstr(SA_NO_PERMISSION)); 48103034Sdougm return (ret); 48113034Sdougm } 48123034Sdougm 48133034Sdougm /* 48143034Sdougm * sa_start_group(flags, argc, argv) 48153034Sdougm * 48163034Sdougm * Implements the start command. 48173034Sdougm * This is similar to enable except it doesn't change the state 48183034Sdougm * of the group(s) and only enables shares if the group is already 48193034Sdougm * enabled. 48203034Sdougm */ 48215331Samw 48223034Sdougm int 48233910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 48243034Sdougm { 48253034Sdougm int verbose = 0; 48263034Sdougm int all = 0; 48273034Sdougm int c; 48283034Sdougm int ret = SMF_EXIT_OK; 48293034Sdougm char *protocol = NULL; 48303034Sdougm char *state; 48313034Sdougm struct list *worklist = NULL; 48324653Sdougm sa_group_t group; 48335331Samw #ifdef lint 48345331Samw flags = flags; 48355331Samw #endif 48363034Sdougm 48373034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 48384653Sdougm switch (c) { 48394653Sdougm case 'a': 48404653Sdougm all = 1; 48414653Sdougm break; 48424653Sdougm case 'P': 48435331Samw if (protocol != NULL) { 48445331Samw (void) printf(gettext( 48455331Samw "Specifying multiple protocols " 48465331Samw "not supported: %s\n"), protocol); 48475331Samw return (SA_SYNTAX_ERR); 48485331Samw } 48494653Sdougm protocol = optarg; 48504653Sdougm if (!sa_valid_protocol(protocol)) { 48514653Sdougm (void) printf(gettext( 48524653Sdougm "Invalid protocol specified: %s\n"), 48533034Sdougm protocol); 48544653Sdougm return (SA_INVALID_PROTOCOL); 48554653Sdougm } 48564653Sdougm break; 48574653Sdougm case 'v': 48584653Sdougm verbose++; 48594653Sdougm break; 4860*6019Sdougm case 'h': 4861*6019Sdougm /* optopt on valid arg isn't defined */ 4862*6019Sdougm optopt = c; 4863*6019Sdougm /*FALLTHROUGH*/ 4864*6019Sdougm case '?': 48654653Sdougm default: 4866*6019Sdougm /* 4867*6019Sdougm * Since a bad option gets to here, sort it 4868*6019Sdougm * out and return a syntax error return value 4869*6019Sdougm * if necessary. 4870*6019Sdougm */ 4871*6019Sdougm ret = SA_OK; 4872*6019Sdougm switch (optopt) { 4873*6019Sdougm default: 4874*6019Sdougm ret = SA_SYNTAX_ERR; 4875*6019Sdougm break; 4876*6019Sdougm case 'h': 4877*6019Sdougm case '?': 4878*6019Sdougm break; 4879*6019Sdougm } 48804653Sdougm (void) printf(gettext("usage: %s\n"), 48814653Sdougm sa_get_usage(USAGE_START)); 4882*6019Sdougm return (ret); 48833034Sdougm } 48843034Sdougm } 48853034Sdougm 48863034Sdougm if (optind == argc && !all) { 48873034Sdougm (void) printf(gettext("usage: %s\n"), 48884653Sdougm sa_get_usage(USAGE_START)); 48894653Sdougm return (SMF_EXIT_ERR_FATAL); 48904653Sdougm } 48914653Sdougm 48924653Sdougm if (!all) { 48934653Sdougm while (optind < argc) { 48943910Sdougm group = sa_get_group(handle, argv[optind]); 48953034Sdougm if (group != NULL) { 48964653Sdougm state = sa_get_group_attr(group, "state"); 48974653Sdougm if (state == NULL || 48984653Sdougm strcmp(state, "enabled") == 0) { 48995331Samw worklist = add_list(worklist, group, 0, 49005331Samw protocol); 49014653Sdougm if (verbose) 49024653Sdougm (void) printf(gettext( 49034653Sdougm "Starting group \"%s\"\n"), 49044653Sdougm argv[optind]); 49054653Sdougm } else { 49064653Sdougm /* 49074653Sdougm * Determine if there are any 49085331Samw * protocols. If there aren't any, 49094653Sdougm * then there isn't anything to do in 49104653Sdougm * any case so no error. 49114653Sdougm */ 49124653Sdougm if (sa_get_optionset(group, 49134653Sdougm protocol) != NULL) { 49144653Sdougm ret = SMF_EXIT_OK; 49154653Sdougm } 49163034Sdougm } 49174653Sdougm if (state != NULL) 49184653Sdougm sa_free_attr_string(state); 49193034Sdougm } 49203034Sdougm optind++; 49214653Sdougm } 49224653Sdougm } else { 49235331Samw for (group = sa_get_group(handle, NULL); 49245331Samw group != NULL; 49254653Sdougm group = sa_get_next_group(group)) { 49263034Sdougm state = sa_get_group_attr(group, "state"); 49273034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 49285331Samw worklist = add_list(worklist, group, 0, 49295331Samw protocol); 49303034Sdougm if (state != NULL) 49314653Sdougm sa_free_attr_string(state); 49323034Sdougm } 49333034Sdougm } 49344653Sdougm 49355331Samw (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE); 49364653Sdougm 49373034Sdougm if (worklist != NULL) 49384653Sdougm free_list(worklist); 49393034Sdougm return (ret); 49403034Sdougm } 49413034Sdougm 49423034Sdougm /* 49433034Sdougm * sa_stop_group(flags, argc, argv) 49443034Sdougm * 49453034Sdougm * Implements the stop command. 49463034Sdougm * This is similar to disable except it doesn't change the state 49473034Sdougm * of the group(s) and only disables shares if the group is already 49483034Sdougm * enabled. 49493034Sdougm */ 49503034Sdougm int 49513910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 49523034Sdougm { 49533034Sdougm int verbose = 0; 49543034Sdougm int all = 0; 49553034Sdougm int c; 49563034Sdougm int ret = SMF_EXIT_OK; 49573034Sdougm char *protocol = NULL; 49583034Sdougm char *state; 49593034Sdougm struct list *worklist = NULL; 49604653Sdougm sa_group_t group; 49615331Samw #ifdef lint 49625331Samw flags = flags; 49635331Samw #endif 49643034Sdougm 49653034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 49664653Sdougm switch (c) { 49674653Sdougm case 'a': 49684653Sdougm all = 1; 49694653Sdougm break; 49704653Sdougm case 'P': 49715331Samw if (protocol != NULL) { 49725331Samw (void) printf(gettext( 49735331Samw "Specifying multiple protocols " 49745331Samw "not supported: %s\n"), protocol); 49755331Samw return (SA_SYNTAX_ERR); 49765331Samw } 49774653Sdougm protocol = optarg; 49784653Sdougm if (!sa_valid_protocol(protocol)) { 49794653Sdougm (void) printf(gettext( 49804653Sdougm "Invalid protocol specified: %s\n"), 49814653Sdougm protocol); 49824653Sdougm return (SA_INVALID_PROTOCOL); 49834653Sdougm } 49844653Sdougm break; 49854653Sdougm case 'v': 49864653Sdougm verbose++; 49874653Sdougm break; 4988*6019Sdougm case 'h': 4989*6019Sdougm /* optopt on valid arg isn't defined */ 4990*6019Sdougm optopt = c; 4991*6019Sdougm /*FALLTHROUGH*/ 4992*6019Sdougm case '?': 49934653Sdougm default: 4994*6019Sdougm /* 4995*6019Sdougm * Since a bad option gets to here, sort it 4996*6019Sdougm * out and return a syntax error return value 4997*6019Sdougm * if necessary. 4998*6019Sdougm */ 4999*6019Sdougm ret = SA_OK; 5000*6019Sdougm switch (optopt) { 5001*6019Sdougm default: 5002*6019Sdougm ret = SA_SYNTAX_ERR; 5003*6019Sdougm break; 5004*6019Sdougm case 'h': 5005*6019Sdougm case '?': 5006*6019Sdougm break; 5007*6019Sdougm } 50084653Sdougm (void) printf(gettext("usage: %s\n"), 50094653Sdougm sa_get_usage(USAGE_STOP)); 5010*6019Sdougm return (ret); 50113034Sdougm } 50123034Sdougm } 50133034Sdougm 50143034Sdougm if (optind == argc && !all) { 50154653Sdougm (void) printf(gettext("usage: %s\n"), 50164653Sdougm sa_get_usage(USAGE_STOP)); 50174653Sdougm return (SMF_EXIT_ERR_FATAL); 50184653Sdougm } else if (!all) { 50194653Sdougm while (optind < argc) { 50203910Sdougm group = sa_get_group(handle, argv[optind]); 50213034Sdougm if (group != NULL) { 50224653Sdougm state = sa_get_group_attr(group, "state"); 50234653Sdougm if (state == NULL || 50244653Sdougm strcmp(state, "enabled") == 0) { 50255331Samw worklist = add_list(worklist, group, 0, 50265331Samw protocol); 50274653Sdougm if (verbose) 50284653Sdougm (void) printf(gettext( 50294653Sdougm "Stopping group \"%s\"\n"), 50304653Sdougm argv[optind]); 50314653Sdougm } else { 50324653Sdougm ret = SMF_EXIT_OK; 50334653Sdougm } 50344653Sdougm if (state != NULL) 50354653Sdougm sa_free_attr_string(state); 50363034Sdougm } 50373034Sdougm optind++; 50384653Sdougm } 50394653Sdougm } else { 50405331Samw for (group = sa_get_group(handle, NULL); 50415331Samw group != NULL; 50424653Sdougm group = sa_get_next_group(group)) { 50433034Sdougm state = sa_get_group_attr(group, "state"); 50443034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 50455331Samw worklist = add_list(worklist, group, 0, 50465331Samw protocol); 50473034Sdougm if (state != NULL) 50484653Sdougm sa_free_attr_string(state); 50493034Sdougm } 50503034Sdougm } 50514653Sdougm (void) disable_all_groups(handle, worklist, 0); 50524653Sdougm ret = sa_update_config(handle); 50534653Sdougm 50543034Sdougm if (worklist != NULL) 50554653Sdougm free_list(worklist); 50563034Sdougm return (ret); 50573034Sdougm } 50583034Sdougm 50593034Sdougm /* 50603034Sdougm * remove_all_options(share, proto) 50613034Sdougm * 50623034Sdougm * Removes all options on a share. 50633034Sdougm */ 50643034Sdougm 50653034Sdougm static void 50663034Sdougm remove_all_options(sa_share_t share, char *proto) 50673034Sdougm { 50683034Sdougm sa_optionset_t optionset; 50693034Sdougm sa_security_t security; 50703034Sdougm sa_security_t prevsec = NULL; 50713034Sdougm 50723034Sdougm optionset = sa_get_optionset(share, proto); 50733034Sdougm if (optionset != NULL) 50744653Sdougm (void) sa_destroy_optionset(optionset); 50753034Sdougm for (security = sa_get_security(share, NULL, NULL); 50763034Sdougm security != NULL; 50773034Sdougm security = sa_get_next_security(security)) { 50784653Sdougm char *type; 50793034Sdougm /* 50804653Sdougm * We walk through the list. prevsec keeps the 50813034Sdougm * previous security so we can delete it without 50823034Sdougm * destroying the list. 50833034Sdougm */ 50844653Sdougm if (prevsec != NULL) { 50854653Sdougm /* remove the previously seen security */ 50864653Sdougm (void) sa_destroy_security(prevsec); 50874653Sdougm /* set to NULL so we don't try multiple times */ 50884653Sdougm prevsec = NULL; 50894653Sdougm } 50904653Sdougm type = sa_get_security_attr(security, "type"); 50914653Sdougm if (type != NULL) { 50924653Sdougm /* 50934653Sdougm * if the security matches the specified protocol, we 50944653Sdougm * want to remove it. prevsec holds it until either 50954653Sdougm * the next pass or we fall out of the loop. 50964653Sdougm */ 50974653Sdougm if (strcmp(type, proto) == 0) 50984653Sdougm prevsec = security; 50994653Sdougm sa_free_attr_string(type); 51004653Sdougm } 51013034Sdougm } 51023034Sdougm /* in case there is one left */ 51033034Sdougm if (prevsec != NULL) 51044653Sdougm (void) sa_destroy_security(prevsec); 51053034Sdougm } 51063034Sdougm 51073034Sdougm 51083034Sdougm /* 51093034Sdougm * for legacy support, we need to handle the old syntax. This is what 51103034Sdougm * we get if sharemgr is called with the name "share" rather than 51113034Sdougm * sharemgr. 51123034Sdougm */ 51133034Sdougm 51143034Sdougm static int 51153034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 51163034Sdougm { 51173034Sdougm int err; 51183034Sdougm 51193034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 51203034Sdougm if (err > buffsize) 51214653Sdougm return (-1); 51223034Sdougm return (0); 51233034Sdougm } 51243034Sdougm 51253034Sdougm 51263034Sdougm /* 51273034Sdougm * check_legacy_cmd(proto, cmd) 51283034Sdougm * 51293034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 51303034Sdougm * executable. 51313034Sdougm */ 51323034Sdougm 51333034Sdougm static int 51343034Sdougm check_legacy_cmd(char *path) 51353034Sdougm { 51363034Sdougm struct stat st; 51373034Sdougm int ret = 0; 51383034Sdougm 51393034Sdougm if (stat(path, &st) == 0) { 51404653Sdougm if (S_ISREG(st.st_mode) && 51414653Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 51424653Sdougm ret = 1; 51433034Sdougm } 51443034Sdougm return (ret); 51453034Sdougm } 51463034Sdougm 51473034Sdougm /* 51483034Sdougm * run_legacy_command(proto, cmd, argv) 51493034Sdougm * 51504653Sdougm * We know the command exists, so attempt to execute it with all the 51513034Sdougm * arguments. This implements full legacy share support for those 51523034Sdougm * protocols that don't have plugin providers. 51533034Sdougm */ 51543034Sdougm 51553034Sdougm static int 51563034Sdougm run_legacy_command(char *path, char *argv[]) 51573034Sdougm { 51583034Sdougm int ret; 51593034Sdougm 51603034Sdougm ret = execv(path, argv); 51613034Sdougm if (ret < 0) { 51624653Sdougm switch (errno) { 51634653Sdougm case EACCES: 51644653Sdougm ret = SA_NO_PERMISSION; 51654653Sdougm break; 51664653Sdougm default: 51674653Sdougm ret = SA_SYSTEM_ERR; 51684653Sdougm break; 51694653Sdougm } 51703034Sdougm } 51713034Sdougm return (ret); 51723034Sdougm } 51733034Sdougm 51743034Sdougm /* 51753348Sdougm * out_share(out, group, proto) 51763034Sdougm * 51773034Sdougm * Display the share information in the format that the "share" 51783034Sdougm * command has traditionally used. 51793034Sdougm */ 51803034Sdougm 51813034Sdougm static void 51823348Sdougm out_share(FILE *out, sa_group_t group, char *proto) 51833034Sdougm { 51843034Sdougm sa_share_t share; 51853034Sdougm char resfmt[128]; 51865331Samw char *defprop; 51875331Samw 51885331Samw /* 51895331Samw * The original share command defaulted to displaying NFS 51905331Samw * shares or allowed a protocol to be specified. We want to 51915331Samw * skip those shares that are not the specified protocol. 51925331Samw */ 51935331Samw if (proto != NULL && sa_get_optionset(group, proto) == NULL) 51945331Samw return; 51955331Samw 51965331Samw if (proto == NULL) 51975331Samw proto = "nfs"; 51985331Samw 51995331Samw /* 52005331Samw * get the default property string. NFS uses "rw" but 52015331Samw * everything else will use "". 52025331Samw */ 52035331Samw if (proto != NULL && strcmp(proto, "nfs") != 0) 52045331Samw defprop = "\"\""; 52055331Samw else 52065331Samw defprop = "rw"; 52073034Sdougm 52084653Sdougm for (share = sa_get_share(group, NULL); 52094653Sdougm share != NULL; 52104653Sdougm share = sa_get_next_share(share)) { 52114653Sdougm char *path; 52124653Sdougm char *type; 52134653Sdougm char *resource; 52144653Sdougm char *description; 52154653Sdougm char *groupname; 52164653Sdougm char *sharedstate; 52174653Sdougm int shared = 1; 52184653Sdougm char *soptions; 52195331Samw char shareopts[MAXNAMLEN]; 52204653Sdougm 52214653Sdougm sharedstate = sa_get_share_attr(share, "shared"); 52224653Sdougm path = sa_get_share_attr(share, "path"); 52234653Sdougm type = sa_get_share_attr(share, "type"); 52245331Samw resource = get_resource(share); 52254653Sdougm groupname = sa_get_group_attr(group, "name"); 52264653Sdougm 52274653Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 52284653Sdougm sa_free_attr_string(groupname); 52294653Sdougm groupname = NULL; 52304653Sdougm } 52314653Sdougm description = sa_get_share_description(share); 52324653Sdougm 52335331Samw /* 52345331Samw * Want the sharetab version if it exists, defaulting 52355331Samw * to NFS if no protocol specified. 52365331Samw */ 52375331Samw (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto); 52385331Samw soptions = sa_get_share_attr(share, shareopts); 52394653Sdougm 52404653Sdougm if (sharedstate == NULL) 52414653Sdougm shared = 0; 52424653Sdougm 52434653Sdougm if (soptions == NULL) 52444653Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 52454653Sdougm 52464653Sdougm if (shared) { 52474653Sdougm /* only active shares go here */ 52484653Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 52494653Sdougm resource != NULL ? resource : "-", 52504653Sdougm groupname != NULL ? "@" : "", 52514653Sdougm groupname != NULL ? groupname : ""); 52524653Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 52534653Sdougm resfmt, path, 52544653Sdougm (soptions != NULL && strlen(soptions) > 0) ? 52555331Samw soptions : defprop, 52564653Sdougm (description != NULL) ? description : ""); 52574653Sdougm } 52584653Sdougm 52594653Sdougm if (path != NULL) 52604653Sdougm sa_free_attr_string(path); 52614653Sdougm if (type != NULL) 52624653Sdougm sa_free_attr_string(type); 52634653Sdougm if (resource != NULL) 52644653Sdougm sa_free_attr_string(resource); 52654653Sdougm if (groupname != NULL) 52664653Sdougm sa_free_attr_string(groupname); 52674653Sdougm if (description != NULL) 52684653Sdougm sa_free_share_description(description); 52694653Sdougm if (sharedstate != NULL) 52704653Sdougm sa_free_attr_string(sharedstate); 52714653Sdougm if (soptions != NULL) 52724653Sdougm sa_format_free(soptions); 52733034Sdougm } 52743034Sdougm } 52753034Sdougm 52763034Sdougm /* 52773034Sdougm * output_legacy_file(out, proto) 52783034Sdougm * 52793034Sdougm * Walk all of the groups for the specified protocol and call 52803034Sdougm * out_share() to format and write in the format displayed by the 52813034Sdougm * "share" command with no arguments. 52823034Sdougm */ 52833034Sdougm 52843034Sdougm static void 52853910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 52863034Sdougm { 52873034Sdougm sa_group_t group; 52883034Sdougm 52895331Samw for (group = sa_get_group(handle, NULL); 52905331Samw group != NULL; 52914653Sdougm group = sa_get_next_group(group)) { 52924653Sdougm char *zfs; 52933034Sdougm 52943034Sdougm /* 52955331Samw * Go through all the groups and ZFS 52965331Samw * sub-groups. out_share() will format the shares in 52975331Samw * the group appropriately. 52983034Sdougm */ 52993034Sdougm 53004653Sdougm zfs = sa_get_group_attr(group, "zfs"); 53014653Sdougm if (zfs != NULL) { 53024653Sdougm sa_group_t zgroup; 53034653Sdougm sa_free_attr_string(zfs); 53044653Sdougm for (zgroup = sa_get_sub_group(group); 53054653Sdougm zgroup != NULL; 53064653Sdougm zgroup = sa_get_next_group(zgroup)) { 53074653Sdougm 53084653Sdougm /* got a group, so display it */ 53094653Sdougm out_share(out, zgroup, proto); 53104653Sdougm } 53114653Sdougm } else { 53124653Sdougm out_share(out, group, proto); 53133034Sdougm } 53143034Sdougm } 53153034Sdougm } 53163034Sdougm 53173034Sdougm int 53183910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 53193034Sdougm { 53203034Sdougm char *protocol = "nfs"; 53213034Sdougm char *options = NULL; 53223034Sdougm char *description = NULL; 53233034Sdougm char *groupname = NULL; 53243034Sdougm char *sharepath = NULL; 53253034Sdougm char *resource = NULL; 53263034Sdougm char *groupstatus = NULL; 53273034Sdougm int persist = SA_SHARE_TRANSIENT; 53283034Sdougm int argsused = 0; 53293034Sdougm int c; 53303034Sdougm int ret = SA_OK; 53313034Sdougm int zfs = 0; 53323034Sdougm int true_legacy = 0; 53333034Sdougm int curtype = SA_SHARE_TRANSIENT; 53343034Sdougm char cmd[MAXPATHLEN]; 53354653Sdougm sa_group_t group = NULL; 53365331Samw sa_resource_t rsrc = NULL; 53374653Sdougm sa_share_t share; 53384653Sdougm char dir[MAXPATHLEN]; 53395331Samw uint64_t features; 53405331Samw #ifdef lint 53415331Samw flags = flags; 53425331Samw #endif 53433034Sdougm 53443034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 53454653Sdougm switch (c) { 53464653Sdougm case 'd': 53474653Sdougm description = optarg; 53484653Sdougm argsused++; 53494653Sdougm break; 53504653Sdougm case 'F': 53514653Sdougm protocol = optarg; 53524653Sdougm if (!sa_valid_protocol(protocol)) { 53534653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 53544653Sdougm protocol, "share") == 0 && 53554653Sdougm check_legacy_cmd(cmd)) { 53564653Sdougm true_legacy++; 53574653Sdougm } else { 53584653Sdougm (void) fprintf(stderr, gettext( 53594653Sdougm "Invalid protocol specified: " 53604653Sdougm "%s\n"), protocol); 53614653Sdougm return (SA_INVALID_PROTOCOL); 53624653Sdougm } 53634653Sdougm } 53644653Sdougm break; 53654653Sdougm case 'o': 53664653Sdougm options = optarg; 53674653Sdougm argsused++; 53684653Sdougm break; 53694653Sdougm case 'p': 53704653Sdougm persist = SA_SHARE_PERMANENT; 53714653Sdougm argsused++; 53724653Sdougm break; 53734653Sdougm case 'h': 5374*6019Sdougm /* optopt on valid arg isn't defined */ 5375*6019Sdougm optopt = c; 5376*6019Sdougm /*FALLTHROUGH*/ 53774653Sdougm case '?': 53784653Sdougm default: 5379*6019Sdougm /* 5380*6019Sdougm * Since a bad option gets to here, sort it 5381*6019Sdougm * out and return a syntax error return value 5382*6019Sdougm * if necessary. 5383*6019Sdougm */ 5384*6019Sdougm switch (optopt) { 5385*6019Sdougm default: 5386*6019Sdougm ret = SA_LEGACY_ERR; 5387*6019Sdougm break; 5388*6019Sdougm case 'h': 5389*6019Sdougm case '?': 5390*6019Sdougm break; 5391*6019Sdougm } 53924653Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 53934653Sdougm sa_get_usage(USAGE_SHARE)); 5394*6019Sdougm return (ret); 53953034Sdougm } 53964653Sdougm } 53974653Sdougm 53984653Sdougm /* Have the info so construct what is needed */ 53994653Sdougm if (!argsused && optind == argc) { 54004653Sdougm /* display current info in share format */ 54015331Samw (void) output_legacy_file(stdout, protocol, handle); 54024653Sdougm return (ret); 54033034Sdougm } 54043034Sdougm 54054653Sdougm /* We are modifying the configuration */ 54064653Sdougm if (optind == argc) { 54073034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 54084653Sdougm sa_get_usage(USAGE_SHARE)); 54093034Sdougm return (SA_LEGACY_ERR); 54104653Sdougm } 54114653Sdougm if (true_legacy) { 54124653Sdougm /* If still using legacy share/unshare, exec it */ 54133034Sdougm ret = run_legacy_command(cmd, argv); 54143034Sdougm return (ret); 54154653Sdougm } 54164653Sdougm 54174653Sdougm sharepath = argv[optind++]; 54184653Sdougm if (optind < argc) { 54193034Sdougm resource = argv[optind]; 54203034Sdougm groupname = strchr(resource, '@'); 54213034Sdougm if (groupname != NULL) 54224653Sdougm *groupname++ = '\0'; 54234653Sdougm } 54244653Sdougm if (realpath(sharepath, dir) == NULL) 54253034Sdougm ret = SA_BAD_PATH; 54264653Sdougm else 54273034Sdougm sharepath = dir; 54284653Sdougm if (ret == SA_OK) 54293910Sdougm share = sa_find_share(handle, sharepath); 54304653Sdougm else 54313034Sdougm share = NULL; 54324653Sdougm 54335331Samw features = sa_proto_get_featureset(protocol); 54345331Samw 54354653Sdougm if (groupname != NULL) { 54364653Sdougm ret = SA_NOT_ALLOWED; 54374653Sdougm } else if (ret == SA_OK) { 54385331Samw char *legacygroup; 54393034Sdougm /* 54404653Sdougm * The legacy group is always present and zfs groups 54413034Sdougm * come and go. zfs shares may be in sub-groups and 54423034Sdougm * the zfs share will already be in that group so it 54435331Samw * isn't an error. If the protocol is "smb", the group 54445331Samw * "smb" is used when "default" would otherwise be 54455331Samw * used. "default" is NFS only and "smb" is SMB only. 54463034Sdougm */ 54475331Samw if (strcmp(protocol, "smb") == 0) 54485331Samw legacygroup = "smb"; 54495331Samw else 54505331Samw legacygroup = "default"; 54515331Samw 54523034Sdougm /* 54534653Sdougm * If the share exists (not NULL), then make sure it 54544653Sdougm * is one we want to handle by getting the parent 54554653Sdougm * group. 54563034Sdougm */ 54575331Samw if (share != NULL) { 54584653Sdougm group = sa_get_parent_group(share); 54595331Samw } else { 54604653Sdougm group = sa_get_group(handle, legacygroup); 54615331Samw if (group == NULL && strcmp(legacygroup, "smb") == 0) { 54625331Samw /* 54635331Samw * This group may not exist, so create 54645331Samw * as necessary. It only contains the 54655331Samw * "smb" protocol. 54665331Samw */ 54675331Samw group = sa_create_group(handle, legacygroup, 54685331Samw &ret); 54695331Samw if (group != NULL) 54705331Samw (void) sa_create_optionset(group, 54715331Samw protocol); 54725331Samw } 54735331Samw } 54745331Samw 54755331Samw if (group == NULL) { 54765331Samw ret = SA_SYSTEM_ERR; 54775331Samw goto err; 54785331Samw } 54795331Samw 54805331Samw groupstatus = group_status(group); 54815331Samw if (share == NULL) { 54825331Samw share = sa_add_share(group, sharepath, 54835331Samw persist, &ret); 54845331Samw if (share == NULL && 54855331Samw ret == SA_DUPLICATE_NAME) { 54865331Samw /* 54875331Samw * Could be a ZFS path being started 54885331Samw */ 54895331Samw if (sa_zfs_is_shared(handle, 54905331Samw sharepath)) { 54915331Samw ret = SA_OK; 54925331Samw group = sa_get_group(handle, 54935331Samw "zfs"); 54945331Samw if (group == NULL) { 54955331Samw /* 54965331Samw * This shouldn't 54975331Samw * happen. 54985331Samw */ 54995331Samw ret = SA_CONFIG_ERR; 55005331Samw } else { 55015331Samw share = sa_add_share( 55025331Samw group, sharepath, 55035331Samw persist, &ret); 55044653Sdougm } 55053034Sdougm } 55065331Samw } 55075331Samw } else { 55085331Samw char *type; 55095331Samw /* 55105331Samw * May want to change persist state, but the 55115331Samw * important thing is to change options. We 55125331Samw * need to change them regardless of the 55135331Samw * source. 55145331Samw */ 55155331Samw 55165331Samw if (sa_zfs_is_shared(handle, sharepath)) { 55175331Samw zfs = 1; 55185331Samw } 55195331Samw remove_all_options(share, protocol); 55205331Samw type = sa_get_share_attr(share, "type"); 55215331Samw if (type != NULL && 55225331Samw strcmp(type, "transient") != 0) { 55235331Samw curtype = SA_SHARE_PERMANENT; 55245331Samw } 55255331Samw if (type != NULL) 55265331Samw sa_free_attr_string(type); 55275331Samw if (curtype != persist) { 55285331Samw (void) sa_set_share_attr(share, "type", 55295331Samw persist == SA_SHARE_PERMANENT ? 55305331Samw "persist" : "transient"); 55315331Samw } 55325331Samw } 55335331Samw 55345331Samw /* 55355331Samw * If there is a resource name, we may 55365331Samw * actually care about it if this is share for 55375331Samw * a protocol that uses resource level sharing 55385331Samw * (SMB). We need to find the resource and, if 55395331Samw * it exists, make sure it belongs to the 55405331Samw * current share. If it doesn't exist, attempt 55415331Samw * to create it. 55425331Samw */ 55435331Samw 55445331Samw if (ret == SA_OK && resource != NULL) { 55455331Samw rsrc = sa_find_resource(handle, resource); 55465331Samw if (rsrc != NULL) { 55475331Samw if (share != sa_get_resource_parent(rsrc)) 55485331Samw ret = SA_DUPLICATE_NAME; 55495331Samw } else { 55505331Samw rsrc = sa_add_resource(share, resource, 55515331Samw persist, &ret); 55523034Sdougm } 55535331Samw if (features & SA_FEATURE_RESOURCE) 55545331Samw share = rsrc; 55553108Sdougm } 55565331Samw 55574653Sdougm /* Have a group to hold this share path */ 55584653Sdougm if (ret == SA_OK && options != NULL && 55594653Sdougm strlen(options) > 0) { 55604653Sdougm ret = sa_parse_legacy_options(share, 55614653Sdougm options, 55624653Sdougm protocol); 55633034Sdougm } 55644653Sdougm if (!zfs) { 55654653Sdougm /* 55665331Samw * ZFS shares never have a description 55675331Samw * and we can't store the values so 55685331Samw * don't try. 55694653Sdougm */ 55704653Sdougm if (ret == SA_OK && description != NULL) 55714653Sdougm ret = sa_set_share_description(share, 55724653Sdougm description); 55733034Sdougm } 55745331Samw if (ret == SA_OK && 55755331Samw strcmp(groupstatus, "enabled") == 0) { 55765331Samw if (rsrc != share) 55774653Sdougm ret = sa_enable_share(share, protocol); 55785331Samw else 55795331Samw ret = sa_enable_resource(rsrc, 55805331Samw protocol); 55814653Sdougm if (ret == SA_OK && 55824653Sdougm persist == SA_SHARE_PERMANENT) { 55834653Sdougm (void) sa_update_legacy(share, 55844653Sdougm protocol); 55854653Sdougm } 55864653Sdougm if (ret == SA_OK) 55874653Sdougm ret = sa_update_config(handle); 55884653Sdougm } 55893034Sdougm } 55905331Samw err: 55913034Sdougm if (ret != SA_OK) { 55924653Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 55934653Sdougm sharepath, sa_errorstr(ret)); 55944653Sdougm ret = SA_LEGACY_ERR; 55953034Sdougm } 55963034Sdougm return (ret); 55973034Sdougm } 55983034Sdougm 55993034Sdougm /* 56003034Sdougm * sa_legacy_unshare(flags, argc, argv) 56013034Sdougm * 56023034Sdougm * Implements the original unshare command. 56033034Sdougm */ 56043034Sdougm int 56053910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 56063034Sdougm { 56073034Sdougm char *protocol = "nfs"; /* for now */ 56083034Sdougm char *options = NULL; 56093034Sdougm char *sharepath = NULL; 56103034Sdougm int persist = SA_SHARE_TRANSIENT; 56113034Sdougm int argsused = 0; 56123034Sdougm int c; 56133034Sdougm int ret = SA_OK; 56143034Sdougm int true_legacy = 0; 56155331Samw uint64_t features = 0; 56165331Samw sa_resource_t resource = NULL; 56173034Sdougm char cmd[MAXPATHLEN]; 56185331Samw #ifdef lint 56195331Samw flags = flags; 56205331Samw options = options; 56215331Samw #endif 56223034Sdougm 56233034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 56244653Sdougm switch (c) { 56254653Sdougm case 'F': 56264653Sdougm protocol = optarg; 56274653Sdougm if (!sa_valid_protocol(protocol)) { 56284653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 56294653Sdougm protocol, "unshare") == 0 && 56304653Sdougm check_legacy_cmd(cmd)) { 56314653Sdougm true_legacy++; 56324653Sdougm } else { 56334653Sdougm (void) printf(gettext( 56344653Sdougm "Invalid file system name\n")); 56354653Sdougm return (SA_INVALID_PROTOCOL); 56364653Sdougm } 56374653Sdougm } 56384653Sdougm break; 56394653Sdougm case 'o': 56404653Sdougm options = optarg; 56414653Sdougm argsused++; 56424653Sdougm break; 56434653Sdougm case 'p': 56444653Sdougm persist = SA_SHARE_PERMANENT; 56454653Sdougm argsused++; 56464653Sdougm break; 5647*6019Sdougm case 'h': 5648*6019Sdougm /* optopt on valid arg isn't defined */ 5649*6019Sdougm optopt = c; 5650*6019Sdougm /*FALLTHROUGH*/ 5651*6019Sdougm case '?': 56524653Sdougm default: 5653*6019Sdougm /* 5654*6019Sdougm * Since a bad option gets to here, sort it 5655*6019Sdougm * out and return a syntax error return value 5656*6019Sdougm * if necessary. 5657*6019Sdougm */ 5658*6019Sdougm switch (optopt) { 5659*6019Sdougm default: 5660*6019Sdougm ret = SA_LEGACY_ERR; 5661*6019Sdougm break; 5662*6019Sdougm case 'h': 5663*6019Sdougm case '?': 5664*6019Sdougm break; 5665*6019Sdougm } 56664653Sdougm (void) printf(gettext("usage: %s\n"), 56674653Sdougm sa_get_usage(USAGE_UNSHARE)); 5668*6019Sdougm return (ret); 56693034Sdougm } 56703034Sdougm } 56713034Sdougm 56724653Sdougm /* Have the info so construct what is needed */ 56734653Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 56744653Sdougm ret = SA_SYNTAX_ERR; 56753034Sdougm } else { 56764653Sdougm sa_share_t share; 56774653Sdougm char dir[MAXPATHLEN]; 56784653Sdougm if (true_legacy) { 56794653Sdougm /* if still using legacy share/unshare, exec it */ 56804653Sdougm ret = run_legacy_command(cmd, argv); 56814653Sdougm return (ret); 56824653Sdougm } 56833663Sdougm /* 56843663Sdougm * Find the path in the internal configuration. If it 56853663Sdougm * isn't found, attempt to resolve the path via 56863663Sdougm * realpath() and try again. 56873663Sdougm */ 56884653Sdougm sharepath = argv[optind++]; 56894653Sdougm share = sa_find_share(handle, sharepath); 56904653Sdougm if (share == NULL) { 56914653Sdougm if (realpath(sharepath, dir) == NULL) { 56924653Sdougm ret = SA_NO_SUCH_PATH; 56934653Sdougm } else { 56944653Sdougm share = sa_find_share(handle, dir); 56954653Sdougm } 56963663Sdougm } 56975331Samw if (share == NULL) { 56985331Samw /* Could be a resource name so check that next */ 56995331Samw features = sa_proto_get_featureset(protocol); 57005331Samw resource = sa_find_resource(handle, sharepath); 57015331Samw if (resource != NULL) { 57025331Samw share = sa_get_resource_parent(resource); 57035331Samw if (features & SA_FEATURE_RESOURCE) 57045331Samw (void) sa_disable_resource(resource, 57055331Samw protocol); 57065331Samw if (persist == SA_SHARE_PERMANENT) { 57075331Samw ret = sa_remove_resource(resource); 57085331Samw if (ret == SA_OK) 57095331Samw ret = sa_update_config(handle); 57105331Samw } 57115331Samw /* 57125331Samw * If we still have a resource on the 57135331Samw * share, we don't disable the share 57145331Samw * itself. IF there aren't anymore, we 57155331Samw * need to remove the share. The 57165331Samw * removal will be done in the next 57175331Samw * section if appropriate. 57185331Samw */ 57195331Samw resource = sa_get_share_resource(share, NULL); 57205331Samw if (resource != NULL) 57215331Samw share = NULL; 57225331Samw } else if (ret == SA_OK) { 57235331Samw /* Didn't find path and no resource */ 57245331Samw ret = SA_BAD_PATH; 57255331Samw } 57265331Samw } 57275331Samw if (share != NULL && resource == NULL) { 57284653Sdougm ret = sa_disable_share(share, protocol); 57294653Sdougm /* 57304653Sdougm * Errors are ok and removal should still occur. The 57314653Sdougm * legacy unshare is more forgiving of errors than the 57324653Sdougm * remove-share subcommand which may need the force 57334653Sdougm * flag set for some error conditions. That is, the 57344653Sdougm * "unshare" command will always unshare if it can 57354653Sdougm * while "remove-share" might require the force option. 57364653Sdougm */ 57374653Sdougm if (persist == SA_SHARE_PERMANENT) { 57384653Sdougm ret = sa_remove_share(share); 57394653Sdougm if (ret == SA_OK) 57404653Sdougm ret = sa_update_config(handle); 57414653Sdougm } 57425331Samw } else if (ret == SA_OK && share == NULL && resource == NULL) { 57435331Samw /* 57445331Samw * If both share and resource are NULL, then 57455331Samw * share not found. If one or the other was 57465331Samw * found or there was an earlier error, we 57475331Samw * assume it was handled earlier. 57485331Samw */ 57494653Sdougm ret = SA_NOT_SHARED; 57503663Sdougm } 57513034Sdougm } 57523034Sdougm switch (ret) { 57533034Sdougm default: 57544653Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 57554653Sdougm ret = SA_LEGACY_ERR; 57564653Sdougm break; 57573034Sdougm case SA_SYNTAX_ERR: 57584653Sdougm (void) printf(gettext("usage: %s\n"), 57594653Sdougm sa_get_usage(USAGE_UNSHARE)); 57604653Sdougm break; 57613034Sdougm case SA_OK: 57624653Sdougm break; 57633034Sdougm } 57643034Sdougm return (ret); 57653034Sdougm } 57663034Sdougm 57673034Sdougm /* 57684653Sdougm * Common commands that implement the sub-commands used by all 57695331Samw * protocols. The entries are found via the lookup command 57703034Sdougm */ 57713034Sdougm 57723034Sdougm static sa_command_t commands[] = { 57733034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 57743034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 57753034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 57763034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 57773034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 57783034Sdougm {"list", 0, sa_list, USAGE_LIST}, 57793034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 57803034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 57813034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 57823034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 57833034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 57843034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 57853034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 57865331Samw SVC_SET|SVC_ACTION}, 57873034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 57883034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 57893034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 57903034Sdougm {NULL, 0, NULL, NULL} 57913034Sdougm }; 57923034Sdougm 57933034Sdougm static char * 57943034Sdougm sa_get_usage(sa_usage_t index) 57953034Sdougm { 57963034Sdougm char *ret = NULL; 57973034Sdougm switch (index) { 57983034Sdougm case USAGE_ADD_SHARE: 57994653Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 58004653Sdougm "[-d \"description text\"] -s sharepath group"); 58014653Sdougm break; 58023034Sdougm case USAGE_CREATE: 58034653Sdougm ret = gettext( 58044653Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 58054653Sdougm break; 58063034Sdougm case USAGE_DELETE: 58074653Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 58084653Sdougm break; 58093034Sdougm case USAGE_DISABLE: 58104653Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 58114653Sdougm break; 58123034Sdougm case USAGE_ENABLE: 58134653Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 58144653Sdougm break; 58153034Sdougm case USAGE_LIST: 58164653Sdougm ret = gettext("list [-vh] [-P proto]"); 58174653Sdougm break; 58183034Sdougm case USAGE_MOVE_SHARE: 58194653Sdougm ret = gettext( 58204653Sdougm "move-share [-nvh] -s sharepath destination-group"); 58214653Sdougm break; 58223034Sdougm case USAGE_REMOVE_SHARE: 58235331Samw ret = gettext( 58245331Samw "remove-share [-fnvh] {-s sharepath | -r resource} " 58255331Samw "group"); 58264653Sdougm break; 58273034Sdougm case USAGE_SET: 58284653Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 58295331Samw "[-p property=value]* [-s sharepath] [-r resource]] " 58305331Samw "group"); 58314653Sdougm break; 58323034Sdougm case USAGE_SET_SECURITY: 58334653Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 58344653Sdougm "[-p property=value]* group"); 58354653Sdougm break; 58363034Sdougm case USAGE_SET_SHARE: 58374653Sdougm ret = gettext("set-share [-nh] [-r resource] " 58384653Sdougm "[-d \"description text\"] -s sharepath group"); 58394653Sdougm break; 58403034Sdougm case USAGE_SHOW: 58414653Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 58424653Sdougm break; 58433034Sdougm case USAGE_SHARE: 58444653Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 58454653Sdougm "[-d description] [pathname [resourcename]]"); 58464653Sdougm break; 58473034Sdougm case USAGE_START: 58484653Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 58494653Sdougm break; 58503034Sdougm case USAGE_STOP: 58514653Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 58524653Sdougm break; 58533034Sdougm case USAGE_UNSET: 58544653Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 58554653Sdougm "[-p property]* group"); 58564653Sdougm break; 58573034Sdougm case USAGE_UNSET_SECURITY: 58585331Samw ret = gettext("unset-security [-nvh] -P proto " 58595331Samw "-S security-type [-p property]* group"); 58604653Sdougm break; 58613034Sdougm case USAGE_UNSHARE: 58624653Sdougm ret = gettext( 58635331Samw "unshare [-F fstype] [-p] [-o optionlist] sharepath"); 58644653Sdougm break; 58653034Sdougm } 58663034Sdougm return (ret); 58673034Sdougm } 58683034Sdougm 58693034Sdougm /* 58703034Sdougm * sa_lookup(cmd, proto) 58713034Sdougm * 58723034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 58733034Sdougm * eventually provide a way to provide protocol specific sub-commands. 58743034Sdougm */ 58753034Sdougm sa_command_t * 58763034Sdougm sa_lookup(char *cmd, char *proto) 58773034Sdougm { 58783034Sdougm int i; 58793034Sdougm size_t len; 58805331Samw #ifdef lint 58815331Samw proto = proto; 58825331Samw #endif 58833034Sdougm 58843034Sdougm len = strlen(cmd); 58853034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 58864653Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 58874653Sdougm return (&commands[i]); 58883034Sdougm } 58893034Sdougm return (NULL); 58903034Sdougm } 58913034Sdougm 58923034Sdougm void 58933034Sdougm sub_command_help(char *proto) 58943034Sdougm { 58953034Sdougm int i; 58965331Samw #ifdef lint 58975331Samw proto = proto; 58985331Samw #endif 58993034Sdougm 59003034Sdougm (void) printf(gettext("\tsub-commands:\n")); 59013034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 59024653Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 59034653Sdougm (void) printf("\t%s\n", 59044653Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 59053034Sdougm } 59063034Sdougm } 5907