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 /* 1044*6088Sdougm * check_valid_group(group, protocol) 1045*6088Sdougm * 1046*6088Sdougm * Check to see that the group should have the protocol added (if 1047*6088Sdougm * there is one specified). 1048*6088Sdougm */ 1049*6088Sdougm 1050*6088Sdougm static int 1051*6088Sdougm check_valid_group(sa_group_t group, char *groupname, char *protocol) 1052*6088Sdougm { 1053*6088Sdougm 1054*6088Sdougm if (protocol != NULL) { 1055*6088Sdougm if (has_protocol(group, protocol)) { 1056*6088Sdougm (void) printf(gettext( 1057*6088Sdougm "Group \"%s\" already exists" 1058*6088Sdougm " with protocol %s\n"), groupname, 1059*6088Sdougm protocol); 1060*6088Sdougm return (SA_DUPLICATE_NAME); 1061*6088Sdougm } else if (strcmp(groupname, "default") == 0 && 1062*6088Sdougm strcmp(protocol, "nfs") != 0) { 1063*6088Sdougm (void) printf(gettext( 1064*6088Sdougm "Group \"%s\" only allows protocol " 1065*6088Sdougm "\"%s\"\n"), groupname, "nfs"); 1066*6088Sdougm return (SA_INVALID_PROTOCOL); 1067*6088Sdougm } 1068*6088Sdougm } else { 1069*6088Sdougm /* must add new protocol */ 1070*6088Sdougm (void) printf(gettext( 1071*6088Sdougm "Group already exists and no protocol " 1072*6088Sdougm "specified.\n")); 1073*6088Sdougm return (SA_DUPLICATE_NAME); 1074*6088Sdougm } 1075*6088Sdougm return (SA_OK); 1076*6088Sdougm } 1077*6088Sdougm 1078*6088Sdougm /* 1079*6088Sdougm * enforce_featureset(group, protocol, dryrun, force) 1080*6088Sdougm * 1081*6088Sdougm * Check the protocol featureset against the group and enforce any 1082*6088Sdougm * rules that might be imposed. 1083*6088Sdougm */ 1084*6088Sdougm 1085*6088Sdougm static int 1086*6088Sdougm enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun, 1087*6088Sdougm boolean_t force) 1088*6088Sdougm { 1089*6088Sdougm uint64_t features; 1090*6088Sdougm 1091*6088Sdougm if (protocol == NULL) 1092*6088Sdougm return (SA_OK); 1093*6088Sdougm 1094*6088Sdougm /* 1095*6088Sdougm * First check to see if specified protocol is one we want to 1096*6088Sdougm * allow on a group. Only server protocols are allowed here. 1097*6088Sdougm */ 1098*6088Sdougm features = sa_proto_get_featureset(protocol); 1099*6088Sdougm if (!(features & SA_FEATURE_SERVER)) { 1100*6088Sdougm (void) printf( 1101*6088Sdougm gettext("Protocol \"%s\" not supported.\n"), protocol); 1102*6088Sdougm return (SA_INVALID_PROTOCOL); 1103*6088Sdougm } 1104*6088Sdougm 1105*6088Sdougm /* 1106*6088Sdougm * Check to see if the new protocol is one that requires 1107*6088Sdougm * resource names and make sure we are compliant before 1108*6088Sdougm * proceeding. 1109*6088Sdougm */ 1110*6088Sdougm if ((features & SA_FEATURE_RESOURCE) && 1111*6088Sdougm !resource_compliant(group)) { 1112*6088Sdougm if (force && !dryrun) { 1113*6088Sdougm make_resources(group); 1114*6088Sdougm } else { 1115*6088Sdougm (void) printf( 1116*6088Sdougm gettext("Protocol requires resource names to be " 1117*6088Sdougm "set: %s\n"), protocol); 1118*6088Sdougm return (SA_RESOURCE_REQUIRED); 1119*6088Sdougm } 1120*6088Sdougm } 1121*6088Sdougm return (SA_OK); 1122*6088Sdougm } 1123*6088Sdougm 1124*6088Sdougm /* 1125*6088Sdougm * set_all_protocols(group) 1126*6088Sdougm * 1127*6088Sdougm * Get the list of all protocols and add all server protocols to the 1128*6088Sdougm * group. 1129*6088Sdougm */ 1130*6088Sdougm 1131*6088Sdougm static int 1132*6088Sdougm set_all_protocols(sa_group_t group) 1133*6088Sdougm { 1134*6088Sdougm char **protolist; 1135*6088Sdougm int numprotos, i; 1136*6088Sdougm uint64_t features; 1137*6088Sdougm sa_optionset_t optionset; 1138*6088Sdougm int ret = SA_OK; 1139*6088Sdougm 1140*6088Sdougm /* 1141*6088Sdougm * Now make sure we really want to put this protocol on a 1142*6088Sdougm * group. Only server protocols can go here. 1143*6088Sdougm */ 1144*6088Sdougm numprotos = sa_get_protocols(&protolist); 1145*6088Sdougm for (i = 0; i < numprotos; i++) { 1146*6088Sdougm features = sa_proto_get_featureset(protolist[i]); 1147*6088Sdougm if (features & SA_FEATURE_SERVER) { 1148*6088Sdougm optionset = sa_create_optionset(group, protolist[i]); 1149*6088Sdougm if (optionset == NULL) { 1150*6088Sdougm ret = SA_NO_MEMORY; 1151*6088Sdougm break; 1152*6088Sdougm } 1153*6088Sdougm } 1154*6088Sdougm } 1155*6088Sdougm 1156*6088Sdougm if (protolist != NULL) 1157*6088Sdougm free(protolist); 1158*6088Sdougm 1159*6088Sdougm return (ret); 1160*6088Sdougm } 1161*6088Sdougm 1162*6088Sdougm /* 11633034Sdougm * sa_create(flags, argc, argv) 11643034Sdougm * create a new group 11653034Sdougm * this may or may not have a protocol associated with it. 11663034Sdougm * No protocol means "all" protocols in this case. 11673034Sdougm */ 11683034Sdougm static int 11693910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[]) 11703034Sdougm { 11713034Sdougm char *groupname; 11723034Sdougm 11733034Sdougm sa_group_t group; 1174*6088Sdougm boolean_t force = B_FALSE; 1175*6088Sdougm boolean_t verbose = B_FALSE; 1176*6088Sdougm boolean_t dryrun = B_FALSE; 11773034Sdougm int c; 11783034Sdougm char *protocol = NULL; 11793034Sdougm int ret = SA_OK; 11803034Sdougm struct options *optlist = NULL; 11816019Sdougm int err = SA_OK; 11823034Sdougm int auth; 1183*6088Sdougm boolean_t created = B_FALSE; 11843034Sdougm 11855331Samw while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) { 11864653Sdougm switch (c) { 11875331Samw case 'f': 1188*6088Sdougm force = B_TRUE; 11895331Samw break; 11904653Sdougm case 'v': 1191*6088Sdougm verbose = B_TRUE; 11924653Sdougm break; 11934653Sdougm case 'n': 1194*6088Sdougm dryrun = B_TRUE; 11954653Sdougm break; 11964653Sdougm case 'P': 11975331Samw if (protocol != NULL) { 11985331Samw (void) printf(gettext("Specifying " 11995331Samw "multiple protocols " 12005331Samw "not supported: %s\n"), protocol); 12015331Samw return (SA_SYNTAX_ERR); 12025331Samw } 12034653Sdougm protocol = optarg; 12044653Sdougm if (sa_valid_protocol(protocol)) 12054653Sdougm break; 12064653Sdougm (void) printf(gettext( 12074653Sdougm "Invalid protocol specified: %s\n"), protocol); 12084653Sdougm return (SA_INVALID_PROTOCOL); 12094653Sdougm break; 12104653Sdougm case 'p': 12114653Sdougm ret = add_opt(&optlist, optarg, 0); 12124653Sdougm switch (ret) { 12134653Sdougm case OPT_ADD_SYNTAX: 12144653Sdougm (void) printf(gettext( 12154653Sdougm "Property syntax error for property: %s\n"), 12164653Sdougm optarg); 12174653Sdougm return (SA_SYNTAX_ERR); 12184653Sdougm case OPT_ADD_SECURITY: 12194653Sdougm (void) printf(gettext( 12204653Sdougm "Security properties need " 12214653Sdougm "to be set with set-security: %s\n"), 12224653Sdougm optarg); 12234653Sdougm return (SA_SYNTAX_ERR); 12244653Sdougm default: 12254653Sdougm break; 12264653Sdougm } 12274653Sdougm break; 12286019Sdougm case 'h': 12296019Sdougm /* optopt on valid arg isn't defined */ 12306019Sdougm optopt = c; 12316019Sdougm /*FALLTHROUGH*/ 12326019Sdougm case '?': 12334653Sdougm default: 12346019Sdougm /* 12356019Sdougm * Since a bad option gets to here, sort it 12366019Sdougm * out and return a syntax error return value 12376019Sdougm * if necessary. 12386019Sdougm */ 12396019Sdougm switch (optopt) { 12406019Sdougm default: 12416019Sdougm err = SA_SYNTAX_ERR; 12426019Sdougm break; 12436019Sdougm case 'h': 12446019Sdougm case '?': 12456019Sdougm break; 12466019Sdougm } 12474653Sdougm (void) printf(gettext("usage: %s\n"), 12484653Sdougm sa_get_usage(USAGE_CREATE)); 12496019Sdougm return (err); 12503034Sdougm } 12513034Sdougm } 12523034Sdougm 12533034Sdougm if (optind >= argc) { 12544653Sdougm (void) printf(gettext("usage: %s\n"), 12554653Sdougm sa_get_usage(USAGE_CREATE)); 12564653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 12574653Sdougm return (SA_BAD_PATH); 12583034Sdougm } 12593034Sdougm 12603034Sdougm if ((optind + 1) < argc) { 12614653Sdougm (void) printf(gettext("usage: %s\n"), 12624653Sdougm sa_get_usage(USAGE_CREATE)); 12634653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 12644653Sdougm return (SA_SYNTAX_ERR); 12653034Sdougm } 12663034Sdougm 12673034Sdougm if (protocol == NULL && optlist != NULL) { 12684653Sdougm /* lookup default protocol */ 12694653Sdougm (void) printf(gettext("usage: %s\n"), 12704653Sdougm sa_get_usage(USAGE_CREATE)); 12714653Sdougm (void) printf(gettext("\tprotocol must be specified " 12724653Sdougm "with properties\n")); 12734653Sdougm return (SA_INVALID_PROTOCOL); 12743034Sdougm } 12753034Sdougm 12763034Sdougm if (optlist != NULL) 12774653Sdougm ret = chk_opt(optlist, 0, protocol); 12783034Sdougm if (ret == OPT_ADD_SECURITY) { 12794653Sdougm (void) printf(gettext("Security properties not " 12804653Sdougm "supported with create\n")); 12814653Sdougm return (SA_SYNTAX_ERR); 12823034Sdougm } 12833034Sdougm 12843034Sdougm /* 12854653Sdougm * If a group already exists, we can only add a new protocol 12863034Sdougm * to it and not create a new one or add the same protocol 12873034Sdougm * again. 12883034Sdougm */ 12893034Sdougm 12903034Sdougm groupname = argv[optind]; 12913034Sdougm 12923034Sdougm auth = check_authorizations(groupname, flags); 12933034Sdougm 12943910Sdougm group = sa_get_group(handle, groupname); 12953034Sdougm if (group != NULL) { 12964653Sdougm /* group exists so must be a protocol add */ 1297*6088Sdougm ret = check_valid_group(group, groupname, protocol); 12983034Sdougm } else { 12993034Sdougm /* 13003034Sdougm * is it a valid name? Must comply with SMF instance 13013034Sdougm * name restrictions. 13023034Sdougm */ 13034653Sdougm if (!sa_valid_group_name(groupname)) { 13044653Sdougm ret = SA_INVALID_NAME; 13054653Sdougm (void) printf(gettext("Invalid group name: %s\n"), 13064653Sdougm groupname); 13074653Sdougm } 13083034Sdougm } 13093034Sdougm if (ret == SA_OK) { 13104653Sdougm /* check protocol vs optlist */ 13114653Sdougm if (optlist != NULL) { 13124653Sdougm /* check options, if any, for validity */ 13134653Sdougm ret = valid_options(optlist, protocol, group, NULL); 13144653Sdougm } 13153034Sdougm } 13163034Sdougm if (ret == SA_OK && !dryrun) { 13174653Sdougm if (group == NULL) { 13184653Sdougm group = sa_create_group(handle, (char *)groupname, 13194653Sdougm &err); 1320*6088Sdougm created = B_TRUE; 13213034Sdougm } 13224653Sdougm if (group != NULL) { 13234653Sdougm sa_optionset_t optionset; 1324*6088Sdougm 13255331Samw /* 1326*6088Sdougm * Check group and protocol against featureset 1327*6088Sdougm * requirements. 13285331Samw */ 1329*6088Sdougm ret = enforce_featureset(group, protocol, 1330*6088Sdougm dryrun, force); 1331*6088Sdougm if (ret != SA_OK) 1332*6088Sdougm goto err; 1333*6088Sdougm 1334*6088Sdougm /* 1335*6088Sdougm * So far so good. Now add the required 1336*6088Sdougm * optionset(s) to the group. 1337*6088Sdougm */ 13384653Sdougm if (optlist != NULL) { 13394653Sdougm (void) add_optionset(group, optlist, protocol, 13404653Sdougm &ret); 13414653Sdougm } else if (protocol != NULL) { 13424653Sdougm optionset = sa_create_optionset(group, 13434653Sdougm protocol); 13444653Sdougm if (optionset == NULL) 13454653Sdougm ret = SA_NO_MEMORY; 13464653Sdougm } else if (protocol == NULL) { 1347*6088Sdougm /* default group create so add all protocols */ 1348*6088Sdougm ret = set_all_protocols(group); 13494653Sdougm } 13503034Sdougm /* 13514653Sdougm * We have a group and legal additions 13523034Sdougm */ 13534653Sdougm if (ret == SA_OK) { 13544653Sdougm /* 13554653Sdougm * Commit to configuration for protocols that 13564653Sdougm * need to do block updates. For NFS, this 13574653Sdougm * doesn't do anything but it will be run for 13584653Sdougm * all protocols that implement the 13594653Sdougm * appropriate plugin. 13604653Sdougm */ 13614653Sdougm ret = sa_update_config(handle); 13624653Sdougm } else { 13634653Sdougm if (group != NULL) 13644653Sdougm (void) sa_remove_group(group); 13654653Sdougm } 13663034Sdougm } else { 13674653Sdougm ret = err; 13684653Sdougm (void) printf(gettext("Could not create group: %s\n"), 13694653Sdougm sa_errorstr(ret)); 13703034Sdougm } 13713034Sdougm } 13723034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 13734653Sdougm (void) printf(gettext("Command would fail: %s\n"), 13744653Sdougm sa_errorstr(SA_NO_PERMISSION)); 13754653Sdougm ret = SA_NO_PERMISSION; 13763034Sdougm } 13775331Samw err: 1378*6088Sdougm if (ret != SA_OK && created) 1379*6088Sdougm ret = sa_remove_group(group); 1380*6088Sdougm 13813034Sdougm free_opt(optlist); 13823034Sdougm return (ret); 13833034Sdougm } 13843034Sdougm 13853034Sdougm /* 13863034Sdougm * group_status(group) 13873034Sdougm * 13883034Sdougm * return the current status (enabled/disabled) of the group. 13893034Sdougm */ 13903034Sdougm 13913034Sdougm static char * 13923034Sdougm group_status(sa_group_t group) 13933034Sdougm { 13943034Sdougm char *state; 13953034Sdougm int enabled = 0; 13963034Sdougm 13973034Sdougm state = sa_get_group_attr(group, "state"); 13983034Sdougm if (state != NULL) { 13994653Sdougm if (strcmp(state, "enabled") == 0) { 14004653Sdougm enabled = 1; 14014653Sdougm } 14024653Sdougm sa_free_attr_string(state); 14033034Sdougm } 14044255Sdougm return (enabled ? "enabled" : "disabled"); 14053034Sdougm } 14063034Sdougm 14073034Sdougm /* 14083034Sdougm * sa_delete(flags, argc, argv) 14093034Sdougm * 14103034Sdougm * Delete a group. 14113034Sdougm */ 14123034Sdougm 14133034Sdougm static int 14143910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[]) 14153034Sdougm { 14163034Sdougm char *groupname; 14173034Sdougm sa_group_t group; 14183034Sdougm sa_share_t share; 14193034Sdougm int verbose = 0; 14203034Sdougm int dryrun = 0; 14213034Sdougm int force = 0; 14223034Sdougm int c; 14233034Sdougm char *protocol = NULL; 14243034Sdougm char *sectype = NULL; 14253034Sdougm int ret = SA_OK; 14263034Sdougm int auth; 14273034Sdougm 14283034Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 14294653Sdougm switch (c) { 14304653Sdougm case 'v': 14314653Sdougm verbose++; 14324653Sdougm break; 14334653Sdougm case 'n': 14344653Sdougm dryrun++; 14354653Sdougm break; 14364653Sdougm case 'P': 14375331Samw if (protocol != NULL) { 14385331Samw (void) printf(gettext("Specifying " 14395331Samw "multiple protocols " 14405331Samw "not supported: %s\n"), protocol); 14415331Samw return (SA_SYNTAX_ERR); 14425331Samw } 14434653Sdougm protocol = optarg; 14444653Sdougm if (!sa_valid_protocol(protocol)) { 14454653Sdougm (void) printf(gettext("Invalid protocol " 14465331Samw "specified: %s\n"), protocol); 14474653Sdougm return (SA_INVALID_PROTOCOL); 14484653Sdougm } 14494653Sdougm break; 14504653Sdougm case 'S': 14515331Samw if (sectype != NULL) { 14525331Samw (void) printf(gettext("Specifying " 14535331Samw "multiple property " 14545331Samw "spaces not supported: %s\n"), sectype); 14555331Samw return (SA_SYNTAX_ERR); 14565331Samw } 14574653Sdougm sectype = optarg; 14584653Sdougm break; 14594653Sdougm case 'f': 14604653Sdougm force++; 14614653Sdougm break; 14626019Sdougm case 'h': 14636019Sdougm /* optopt on valid arg isn't defined */ 14646019Sdougm optopt = c; 14656019Sdougm /*FALLTHROUGH*/ 14666019Sdougm case '?': 14674653Sdougm default: 14686019Sdougm /* 14696019Sdougm * Since a bad option gets to here, sort it 14706019Sdougm * out and return a syntax error return value 14716019Sdougm * if necessary. 14726019Sdougm */ 14736019Sdougm switch (optopt) { 14746019Sdougm default: 14756019Sdougm ret = SA_SYNTAX_ERR; 14766019Sdougm break; 14776019Sdougm case 'h': 14786019Sdougm case '?': 14796019Sdougm break; 14806019Sdougm } 14814653Sdougm (void) printf(gettext("usage: %s\n"), 14824653Sdougm sa_get_usage(USAGE_DELETE)); 14836019Sdougm return (ret); 14843034Sdougm } 14853034Sdougm } 14863034Sdougm 14873034Sdougm if (optind >= argc) { 14884653Sdougm (void) printf(gettext("usage: %s\n"), 14894653Sdougm sa_get_usage(USAGE_DELETE)); 14904653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 14914653Sdougm return (SA_SYNTAX_ERR); 14923034Sdougm } 14933034Sdougm 14943034Sdougm if ((optind + 1) < argc) { 14954653Sdougm (void) printf(gettext("usage: %s\n"), 14964653Sdougm sa_get_usage(USAGE_DELETE)); 14974653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 14984653Sdougm return (SA_SYNTAX_ERR); 14993034Sdougm } 15003034Sdougm 15013034Sdougm if (sectype != NULL && protocol == NULL) { 15024653Sdougm (void) printf(gettext("usage: %s\n"), 15034653Sdougm sa_get_usage(USAGE_DELETE)); 15044653Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 15054653Sdougm "specified.\n")); 15064653Sdougm return (SA_SYNTAX_ERR); 15073034Sdougm } 15083034Sdougm 15093034Sdougm /* 15103034Sdougm * Determine if the group already exists since it must in 15113034Sdougm * order to be removed. 15123034Sdougm * 15133034Sdougm * We can delete when: 15143034Sdougm * 15153034Sdougm * - group is empty 15163034Sdougm * - force flag is set 15173034Sdougm * - if protocol specified, only delete the protocol 15183034Sdougm */ 15193034Sdougm 15203034Sdougm groupname = argv[optind]; 15213910Sdougm group = sa_get_group(handle, groupname); 15223034Sdougm if (group == NULL) { 15233034Sdougm ret = SA_NO_SUCH_GROUP; 15244653Sdougm goto done; 15254653Sdougm } 15264653Sdougm auth = check_authorizations(groupname, flags); 15274653Sdougm if (protocol == NULL) { 15283034Sdougm share = sa_get_share(group, NULL); 15293034Sdougm if (share != NULL) 15304653Sdougm ret = SA_BUSY; 15313034Sdougm if (share == NULL || (share != NULL && force == 1)) { 15324653Sdougm ret = SA_OK; 15334653Sdougm if (!dryrun) { 15344653Sdougm while (share != NULL) { 15354653Sdougm sa_share_t next_share; 15364653Sdougm next_share = sa_get_next_share(share); 15374653Sdougm /* 15384653Sdougm * need to do the disable of 15394653Sdougm * each share, but don't 15404653Sdougm * actually do anything on a 15414653Sdougm * dryrun. 15424653Sdougm */ 15434653Sdougm ret = sa_disable_share(share, NULL); 15444653Sdougm ret = sa_remove_share(share); 15454653Sdougm share = next_share; 15464653Sdougm } 15474653Sdougm ret = sa_remove_group(group); 15483034Sdougm } 15493034Sdougm } 15504653Sdougm /* Commit to configuration if not a dryrun */ 15513034Sdougm if (!dryrun && ret == SA_OK) { 15524653Sdougm ret = sa_update_config(handle); 15533034Sdougm } 15544653Sdougm } else { 15553034Sdougm /* a protocol delete */ 15563034Sdougm sa_optionset_t optionset; 15573034Sdougm sa_security_t security; 15585331Samw if (sectype != NULL) { 15594653Sdougm /* only delete specified security */ 15604653Sdougm security = sa_get_security(group, sectype, protocol); 15614653Sdougm if (security != NULL && !dryrun) 15624653Sdougm ret = sa_destroy_security(security); 15634653Sdougm else 15644653Sdougm ret = SA_INVALID_PROTOCOL; 15653034Sdougm } else { 15664653Sdougm optionset = sa_get_optionset(group, protocol); 15674653Sdougm if (optionset != NULL && !dryrun) { 15684653Sdougm /* 15694653Sdougm * have an optionset with 15704653Sdougm * protocol to delete 15714653Sdougm */ 15724653Sdougm ret = sa_destroy_optionset(optionset); 15734653Sdougm /* 15744653Sdougm * Now find all security sets 15754653Sdougm * for the protocol and remove 15764653Sdougm * them. Don't remove other 15774653Sdougm * protocols. 15784653Sdougm */ 15794653Sdougm for (security = 15804653Sdougm sa_get_security(group, NULL, NULL); 15814653Sdougm ret == SA_OK && security != NULL; 15824653Sdougm security = sa_get_next_security(security)) { 15834653Sdougm char *secprot; 15844653Sdougm secprot = sa_get_security_attr(security, 15854653Sdougm "type"); 15864653Sdougm if (secprot != NULL && 15874653Sdougm strcmp(secprot, protocol) == 0) 15884653Sdougm ret = sa_destroy_security( 15894653Sdougm security); 15904653Sdougm if (secprot != NULL) 15914653Sdougm sa_free_attr_string(secprot); 15924653Sdougm } 15934653Sdougm } else { 15944653Sdougm if (!dryrun) 15954653Sdougm ret = SA_INVALID_PROTOCOL; 15963034Sdougm } 15973034Sdougm } 15985331Samw /* 15995331Samw * With the protocol items removed, make sure that all 16005331Samw * the shares are updated in the legacy files, if 16015331Samw * necessary. 16025331Samw */ 16035331Samw for (share = sa_get_share(group, NULL); 16045331Samw share != NULL; 16055331Samw share = sa_get_next_share(share)) { 16065331Samw (void) sa_delete_legacy(share, protocol); 16075331Samw } 16083034Sdougm } 16094653Sdougm 16104653Sdougm done: 16113034Sdougm if (ret != SA_OK) { 16124653Sdougm (void) printf(gettext("Could not delete group: %s\n"), 16134653Sdougm sa_errorstr(ret)); 16143034Sdougm } else if (dryrun && !auth && verbose) { 16154653Sdougm (void) printf(gettext("Command would fail: %s\n"), 16164653Sdougm sa_errorstr(SA_NO_PERMISSION)); 16173034Sdougm } 16183034Sdougm return (ret); 16193034Sdougm } 16203034Sdougm 16213034Sdougm /* 16223034Sdougm * strndupr(*buff, str, buffsize) 16233034Sdougm * 16243034Sdougm * used with small strings to duplicate and possibly increase the 16253034Sdougm * buffer size of a string. 16263034Sdougm */ 16273034Sdougm static char * 16283034Sdougm strndupr(char *buff, char *str, int *buffsize) 16293034Sdougm { 16303034Sdougm int limit; 16313034Sdougm char *orig_buff = buff; 16323034Sdougm 16333034Sdougm if (buff == NULL) { 16344653Sdougm buff = (char *)malloc(64); 16354653Sdougm if (buff == NULL) 16364653Sdougm return (NULL); 16374653Sdougm *buffsize = 64; 16384653Sdougm buff[0] = '\0'; 16393034Sdougm } 16403034Sdougm limit = strlen(buff) + strlen(str) + 1; 16413034Sdougm if (limit > *buffsize) { 16424653Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 16434653Sdougm buff = realloc(buff, limit); 16443034Sdougm } 16453034Sdougm if (buff != NULL) { 16464653Sdougm (void) strcat(buff, str); 16473034Sdougm } else { 16484653Sdougm /* if it fails, fail it hard */ 16494653Sdougm if (orig_buff != NULL) 16504653Sdougm free(orig_buff); 16513034Sdougm } 16523034Sdougm return (buff); 16533034Sdougm } 16543034Sdougm 16553034Sdougm /* 16563034Sdougm * group_proto(group) 16573034Sdougm * 16583034Sdougm * return a string of all the protocols (space separated) associated 16593034Sdougm * with this group. 16603034Sdougm */ 16613034Sdougm 16623034Sdougm static char * 16633034Sdougm group_proto(sa_group_t group) 16643034Sdougm { 16653034Sdougm sa_optionset_t optionset; 16663034Sdougm char *proto; 16673034Sdougm char *buff = NULL; 16683034Sdougm int buffsize = 0; 16693034Sdougm int addspace = 0; 16703034Sdougm /* 16713034Sdougm * get the protocol list by finding the optionsets on this 16723034Sdougm * group and extracting the type value. The initial call to 16733034Sdougm * strndupr() initailizes buff. 16743034Sdougm */ 16753034Sdougm buff = strndupr(buff, "", &buffsize); 16763034Sdougm if (buff != NULL) { 16774653Sdougm for (optionset = sa_get_optionset(group, NULL); 16784653Sdougm optionset != NULL && buff != NULL; 16794653Sdougm optionset = sa_get_next_optionset(optionset)) { 16804653Sdougm /* 16814653Sdougm * extract out the protocol type from this optionset 16824653Sdougm * and append it to the buffer "buff". strndupr() will 16834653Sdougm * reallocate space as necessay. 16844653Sdougm */ 16854653Sdougm proto = sa_get_optionset_attr(optionset, "type"); 16864653Sdougm if (proto != NULL) { 16874653Sdougm if (addspace++) 16884653Sdougm buff = strndupr(buff, " ", &buffsize); 16894653Sdougm buff = strndupr(buff, proto, &buffsize); 16904653Sdougm sa_free_attr_string(proto); 16914653Sdougm } 16923034Sdougm } 16933034Sdougm } 16943034Sdougm return (buff); 16953034Sdougm } 16963034Sdougm 16973034Sdougm /* 16983034Sdougm * sa_list(flags, argc, argv) 16993034Sdougm * 17003034Sdougm * implements the "list" subcommand to list groups and optionally 17013034Sdougm * their state and protocols. 17023034Sdougm */ 17033034Sdougm 17043034Sdougm static int 17053910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[]) 17063034Sdougm { 17073034Sdougm sa_group_t group; 17083034Sdougm int verbose = 0; 17093034Sdougm int c; 17103034Sdougm char *protocol = NULL; 17116019Sdougm int ret = SA_OK; 17125331Samw #ifdef lint 17135331Samw flags = flags; 17145331Samw #endif 17153034Sdougm 17163034Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 17174653Sdougm switch (c) { 17184653Sdougm case 'v': 17194653Sdougm verbose++; 17204653Sdougm break; 17214653Sdougm case 'P': 17225331Samw if (protocol != NULL) { 17235331Samw (void) printf(gettext( 17245331Samw "Specifying multiple protocols " 17255331Samw "not supported: %s\n"), 17265331Samw protocol); 17275331Samw return (SA_SYNTAX_ERR); 17285331Samw } 17294653Sdougm protocol = optarg; 17304653Sdougm if (!sa_valid_protocol(protocol)) { 17314653Sdougm (void) printf(gettext( 17324653Sdougm "Invalid protocol specified: %s\n"), 17334653Sdougm protocol); 17344653Sdougm return (SA_INVALID_PROTOCOL); 17354653Sdougm } 17364653Sdougm break; 17376019Sdougm case 'h': 17386019Sdougm /* optopt on valid arg isn't defined */ 17396019Sdougm optopt = c; 17406019Sdougm /*FALLTHROUGH*/ 17416019Sdougm case '?': 17424653Sdougm default: 17436019Sdougm /* 17446019Sdougm * Since a bad option gets to here, sort it 17456019Sdougm * out and return a syntax error return value 17466019Sdougm * if necessary. 17476019Sdougm */ 17486019Sdougm switch (optopt) { 17496019Sdougm default: 17506019Sdougm ret = SA_SYNTAX_ERR; 17516019Sdougm break; 17526019Sdougm case 'h': 17536019Sdougm case '?': 17546019Sdougm break; 17556019Sdougm } 17564653Sdougm (void) printf(gettext("usage: %s\n"), 17574653Sdougm sa_get_usage(USAGE_LIST)); 17586019Sdougm return (ret); 17593034Sdougm } 17603034Sdougm } 17613034Sdougm 17625885Sdougm if (optind != argc) { 17635885Sdougm (void) printf(gettext("usage: %s\n"), 17645885Sdougm sa_get_usage(USAGE_LIST)); 17655885Sdougm return (SA_SYNTAX_ERR); 17665885Sdougm } 17675885Sdougm 17684653Sdougm for (group = sa_get_group(handle, NULL); 17694653Sdougm group != NULL; 17703034Sdougm group = sa_get_next_group(group)) { 17714653Sdougm char *name; 17724653Sdougm char *proto; 17734653Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 17744653Sdougm name = sa_get_group_attr(group, "name"); 17754653Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 17764653Sdougm (void) printf("%s", (char *)name); 17774653Sdougm if (verbose) { 17784653Sdougm /* 17794653Sdougm * Need the list of protocols 17804653Sdougm * and current status once 17814653Sdougm * available. We do want to 17824653Sdougm * translate the 17834653Sdougm * enabled/disabled text here. 17844653Sdougm */ 17854653Sdougm (void) printf("\t%s", isenabled(group) ? 17864653Sdougm gettext("enabled") : 17874653Sdougm gettext("disabled")); 17884653Sdougm proto = group_proto(group); 17894653Sdougm if (proto != NULL) { 17904653Sdougm (void) printf("\t%s", 17914653Sdougm (char *)proto); 17924653Sdougm free(proto); 17934653Sdougm } 17944653Sdougm } 17954653Sdougm (void) printf("\n"); 17963034Sdougm } 17974653Sdougm if (name != NULL) 17984653Sdougm sa_free_attr_string(name); 17993034Sdougm } 18003034Sdougm } 18013034Sdougm return (0); 18023034Sdougm } 18033034Sdougm 18043034Sdougm /* 18053034Sdougm * out_properties(optionset, proto, sec) 18063034Sdougm * 18073034Sdougm * Format the properties and encode the protocol and optional named 18083034Sdougm * optionset into the string. 18093034Sdougm * 18103034Sdougm * format is protocol[:name]=(property-list) 18113034Sdougm */ 18123034Sdougm 18133034Sdougm static void 18143034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 18153034Sdougm { 18163034Sdougm char *type; 18173034Sdougm char *value; 18183034Sdougm int spacer; 18193034Sdougm sa_property_t prop; 18203034Sdougm 18214653Sdougm if (sec == NULL) 18224653Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 18234653Sdougm else 18244653Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 18253034Sdougm 18263034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 18274653Sdougm prop != NULL; 18284653Sdougm prop = sa_get_next_property(prop)) { 18293034Sdougm 18303034Sdougm /* 18313034Sdougm * extract the property name/value and output with 18323034Sdougm * appropriate spacing. I.e. no prefixed space the 18333034Sdougm * first time through but a space on subsequent 18343034Sdougm * properties. 18353034Sdougm */ 18364653Sdougm type = sa_get_property_attr(prop, "type"); 18374653Sdougm value = sa_get_property_attr(prop, "value"); 18384653Sdougm if (type != NULL) { 18394653Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 18404653Sdougm spacer = 1; 18414653Sdougm if (value != NULL) 18424653Sdougm (void) printf("\"%s\"", value); 18434653Sdougm else 18444653Sdougm (void) printf("\"\""); 18454653Sdougm } 18464653Sdougm if (type != NULL) 18474653Sdougm sa_free_attr_string(type); 18483034Sdougm if (value != NULL) 18494653Sdougm sa_free_attr_string(value); 18503034Sdougm } 18513034Sdougm (void) printf(")"); 18523034Sdougm } 18533034Sdougm 18543034Sdougm /* 18553034Sdougm * show_properties(group, protocol, prefix) 18563034Sdougm * 18573034Sdougm * print the properties for a group. If protocol is NULL, do all 18583034Sdougm * protocols otherwise only the specified protocol. All security 18593034Sdougm * (named groups specific to the protocol) are included. 18603034Sdougm * 18613034Sdougm * The "prefix" is always applied. The caller knows whether it wants 18623034Sdougm * some type of prefix string (white space) or not. Once the prefix 18633034Sdougm * has been output, it is reduced to the zero length string for the 18643034Sdougm * remainder of the property output. 18653034Sdougm */ 18663034Sdougm 18673034Sdougm static void 18683034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 18693034Sdougm { 18703034Sdougm sa_optionset_t optionset; 18713034Sdougm sa_security_t security; 18723034Sdougm char *value; 18733034Sdougm char *secvalue; 18743034Sdougm 18753034Sdougm if (protocol != NULL) { 18764653Sdougm optionset = sa_get_optionset(group, protocol); 18774653Sdougm if (optionset != NULL) { 18784653Sdougm (void) printf("%s", prefix); 18794653Sdougm prefix = ""; 18804653Sdougm out_properties(optionset, protocol, NULL); 18814653Sdougm } 18824653Sdougm security = sa_get_security(group, protocol, NULL); 18834653Sdougm if (security != NULL) { 18844653Sdougm (void) printf("%s", prefix); 18854653Sdougm prefix = ""; 18864653Sdougm out_properties(security, protocol, NULL); 18874653Sdougm } 18883034Sdougm } else { 18894653Sdougm for (optionset = sa_get_optionset(group, protocol); 18904653Sdougm optionset != NULL; 18914653Sdougm optionset = sa_get_next_optionset(optionset)) { 18924653Sdougm 18934653Sdougm value = sa_get_optionset_attr(optionset, "type"); 18944653Sdougm (void) printf("%s", prefix); 18954653Sdougm prefix = ""; 18964653Sdougm out_properties(optionset, value, 0); 18974653Sdougm if (value != NULL) 18984653Sdougm sa_free_attr_string(value); 18994653Sdougm } 19004653Sdougm for (security = sa_get_security(group, NULL, protocol); 19014653Sdougm security != NULL; 19024653Sdougm security = sa_get_next_security(security)) { 19034653Sdougm 19044653Sdougm value = sa_get_security_attr(security, "type"); 19054653Sdougm secvalue = sa_get_security_attr(security, "sectype"); 19064653Sdougm (void) printf("%s", prefix); 19074653Sdougm prefix = ""; 19084653Sdougm out_properties(security, value, secvalue); 19094653Sdougm if (value != NULL) 19104653Sdougm sa_free_attr_string(value); 19114653Sdougm if (secvalue != NULL) 19124653Sdougm sa_free_attr_string(secvalue); 19134653Sdougm } 19143034Sdougm } 19153034Sdougm } 19163034Sdougm 19173034Sdougm /* 19185331Samw * get_resource(share) 19195331Samw * 19205331Samw * Get the first resource name, if any, and fix string to be in 19215331Samw * current locale and have quotes if it has embedded spaces. Return 19225331Samw * an attr string that must be freed. 19235331Samw */ 19245331Samw 19255331Samw static char * 19265331Samw get_resource(sa_share_t share) 19275331Samw { 19285331Samw sa_resource_t resource; 19295331Samw char *resstring = NULL; 19305331Samw char *retstring; 19315331Samw 19325331Samw if ((resource = sa_get_share_resource(share, NULL)) != NULL) { 19335331Samw resstring = sa_get_resource_attr(resource, "name"); 19345331Samw if (resstring != NULL) { 19355331Samw char *cp; 19365331Samw int len; 19375331Samw 19385331Samw retstring = conv_from_utf8(resstring); 19395331Samw if (retstring != resstring) { 19405331Samw sa_free_attr_string(resstring); 19415331Samw resstring = retstring; 19425331Samw } 19435331Samw if (strpbrk(resstring, " ") != NULL) { 19445331Samw /* account for quotes */ 19455331Samw len = strlen(resstring) + 3; 19465331Samw cp = calloc(len, sizeof (char)); 19475331Samw if (cp != NULL) { 19485331Samw (void) snprintf(cp, len, 19495331Samw "\"%s\"", resstring); 19505331Samw sa_free_attr_string(resstring); 19515331Samw resstring = cp; 19525331Samw } else { 19535331Samw sa_free_attr_string(resstring); 19545331Samw resstring = NULL; 19555331Samw } 19565331Samw } 19575331Samw } 19585331Samw } 19595331Samw return (resstring); 19605331Samw } 19615331Samw 19625331Samw /* 19635331Samw * has_resource_with_opt(share) 19645331Samw * 19655331Samw * Check to see if the share has any resource names with optionsets 19665331Samw * set. Also indicate if multiple resource names since the syntax 19675331Samw * would be about the same. 19685331Samw */ 19695331Samw static int 19705331Samw has_resource_with_opt(sa_share_t share) 19715331Samw { 19725331Samw sa_resource_t resource; 19735331Samw int ret = B_FALSE; 19745331Samw 19755331Samw for (resource = sa_get_share_resource(share, NULL); 19765331Samw resource != NULL; 19775331Samw resource = sa_get_next_resource(resource)) { 19785331Samw 19795331Samw if (sa_get_optionset(resource, NULL) != NULL) { 19805331Samw ret = B_TRUE; 19815331Samw break; 19825331Samw } 19835331Samw } 19845331Samw return (ret); 19855331Samw } 19865331Samw 19875331Samw /* 19885331Samw * has_multiple_resource(share) 19895331Samw * 19905885Sdougm * Check to see if the share has multiple resource names since 19915885Sdougm * the syntax would be about the same. 19925331Samw */ 19935885Sdougm static boolean_t 19945331Samw has_multiple_resource(sa_share_t share) 19955331Samw { 19965331Samw sa_resource_t resource; 19975331Samw int num; 19985331Samw 19995331Samw for (num = 0, resource = sa_get_share_resource(share, NULL); 20005331Samw resource != NULL; 20015331Samw resource = sa_get_next_resource(resource)) { 20025331Samw num++; 20035331Samw if (num > 1) 20045331Samw return (B_TRUE); 20055331Samw } 20065331Samw return (B_FALSE); 20075331Samw } 20085331Samw 20095331Samw /* 20105331Samw * show_share(share, verbose, properties, proto, iszfs, sharepath) 20115331Samw * 20125331Samw * print out the share information. With the addition of resource as a 20135331Samw * full object that can have multiple instances below the share, we 20145331Samw * need to display that as well. 20155331Samw */ 20165331Samw 20175331Samw static void 20185331Samw show_share(sa_share_t share, int verbose, int properties, char *proto, 20195331Samw int iszfs, char *sharepath) 20205331Samw { 20215331Samw char *drive; 20225331Samw char *exclude; 20235331Samw sa_resource_t resource = NULL; 20245331Samw char *description; 20255331Samw char *rsrcname; 20265331Samw int rsrcwithopt; 20275885Sdougm boolean_t multiple; 20285331Samw char *type; 20295331Samw 20305331Samw rsrcwithopt = has_resource_with_opt(share); 20315331Samw 20325331Samw if (verbose || (properties && rsrcwithopt)) { 20335331Samw /* First, indicate if transient */ 20345331Samw type = sa_get_share_attr(share, "type"); 20355331Samw if (type != NULL && !iszfs && verbose && 20365331Samw strcmp(type, "transient") == 0) 20375331Samw (void) printf("\t* "); 20385331Samw else 20395331Samw (void) printf("\t "); 20405331Samw 20415331Samw if (type != NULL) 20425331Samw sa_free_attr_string(type); 20435331Samw 20445331Samw /* 20455331Samw * If we came in with verbose, we want to handle the case of 20465331Samw * multiple resources as though they had properties set. 20475331Samw */ 20485331Samw multiple = has_multiple_resource(share); 20495331Samw 20505885Sdougm /* 20515885Sdougm * if there is a description on the share and there 20525885Sdougm * are resources, treat as multiple resources in order 20535885Sdougm * to get all descriptions displayed. 20545885Sdougm */ 20555885Sdougm description = sa_get_share_description(share); 20565885Sdougm resource = sa_get_share_resource(share, NULL); 20575885Sdougm 20585885Sdougm if (description != NULL && resource != NULL) 20595885Sdougm multiple = B_TRUE; 20605885Sdougm 20615331Samw /* Next, if not multiple follow old model */ 20625331Samw if (!multiple && !rsrcwithopt) { 20635331Samw rsrcname = get_resource(share); 20645331Samw if (rsrcname != NULL && strlen(rsrcname) > 0) { 20655331Samw (void) printf("%s=%s", rsrcname, sharepath); 20665331Samw } else { 20675331Samw (void) printf("%s", sharepath); 20685331Samw } 20695331Samw if (rsrcname != NULL) 20705331Samw sa_free_attr_string(rsrcname); 20715885Sdougm /* Print the description string if there is one. */ 20725885Sdougm print_rsrc_desc(resource, description); 20735331Samw } else { 20745331Samw /* Treat as simple and then resources come later */ 20755331Samw (void) printf("%s", sharepath); 20765331Samw } 20775331Samw drive = sa_get_share_attr(share, "drive-letter"); 20785331Samw if (drive != NULL) { 20795331Samw if (strlen(drive) > 0) 20805331Samw (void) printf(gettext("\tdrive-letter=\"%s:\""), 20815331Samw drive); 20825331Samw sa_free_attr_string(drive); 20835331Samw } 20845331Samw if (properties) 20855331Samw show_properties(share, proto, "\t"); 20865331Samw exclude = sa_get_share_attr(share, "exclude"); 20875331Samw if (exclude != NULL) { 20885331Samw (void) printf(gettext("\tnot-shared-with=[%s]"), 20895331Samw exclude); 20905331Samw sa_free_attr_string(exclude); 20915331Samw } 20925885Sdougm 20935331Samw if (description != NULL) { 20945885Sdougm print_rsrc_desc((sa_resource_t)share, description); 20955331Samw } 20965331Samw /* 20975331Samw * If there are resource names with options, show them 20985331Samw * here, with one line per resource. Resource specific 20995331Samw * options are at the end of the line followed by 21005331Samw * description, if any. 21015331Samw */ 21025331Samw if (rsrcwithopt || multiple) { 21035331Samw for (resource = sa_get_share_resource(share, NULL); 21045331Samw resource != NULL; 21055331Samw resource = sa_get_next_resource(resource)) { 21065331Samw int has_space; 21075331Samw char *rsrc; 21085331Samw 21095331Samw (void) printf("\n\t\t "); 21105331Samw rsrcname = sa_get_resource_attr(resource, 21115331Samw "name"); 21125331Samw if (rsrcname == NULL) 21135331Samw continue; 21145331Samw 21155331Samw rsrc = conv_from_utf8(rsrcname); 21165331Samw has_space = strpbrk(rsrc, " ") != NULL; 21175331Samw 21185331Samw if (has_space) 21195331Samw (void) printf("\"%s\"=%s", rsrc, 21205331Samw sharepath); 21215331Samw else 21225331Samw (void) printf("%s=%s", rsrc, 21235331Samw sharepath); 21245331Samw if (rsrc != rsrcname) 21255331Samw sa_free_attr_string(rsrc); 21265331Samw sa_free_attr_string(rsrcname); 21275331Samw if (properties || rsrcwithopt) 21285331Samw show_properties(resource, proto, "\t"); 21295331Samw 21305331Samw /* Get description string if any */ 21315885Sdougm print_rsrc_desc(resource, description); 21325331Samw } 21335331Samw } 21345885Sdougm if (description != NULL) 21355885Sdougm sa_free_share_description(description); 21365331Samw } else { 21375331Samw (void) printf("\t %s", sharepath); 21385331Samw if (properties) 21395331Samw show_properties(share, proto, "\t"); 21405331Samw } 21415331Samw (void) printf("\n"); 21425331Samw } 21435331Samw 21445331Samw /* 21453034Sdougm * show_group(group, verbose, properties, proto, subgroup) 21463034Sdougm * 21473034Sdougm * helper function to show the contents of a group. 21483034Sdougm */ 21493034Sdougm 21503034Sdougm static void 21513034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 21525331Samw char *subgroup) 21533034Sdougm { 21543034Sdougm sa_share_t share; 21553034Sdougm char *groupname; 21563034Sdougm char *zfs = NULL; 21573034Sdougm int iszfs = 0; 21585331Samw char *sharepath; 21593034Sdougm 21603034Sdougm groupname = sa_get_group_attr(group, "name"); 21613034Sdougm if (groupname != NULL) { 21624653Sdougm if (proto != NULL && !has_protocol(group, proto)) { 21634653Sdougm sa_free_attr_string(groupname); 21644653Sdougm return; 21654653Sdougm } 21663034Sdougm /* 21673034Sdougm * check to see if the group is managed by ZFS. If 21683034Sdougm * there is an attribute, then it is. A non-NULL zfs 21693034Sdougm * variable will trigger the different way to display 21703034Sdougm * and will remove the transient property indicator 21713034Sdougm * from the output. 21723034Sdougm */ 21734653Sdougm zfs = sa_get_group_attr(group, "zfs"); 21744653Sdougm if (zfs != NULL) { 21754653Sdougm iszfs = 1; 21764653Sdougm sa_free_attr_string(zfs); 21773034Sdougm } 21784653Sdougm share = sa_get_share(group, NULL); 21794653Sdougm if (subgroup == NULL) 21804653Sdougm (void) printf("%s", groupname); 21814653Sdougm else 21824653Sdougm (void) printf(" %s/%s", subgroup, groupname); 21834653Sdougm if (properties) 21844653Sdougm show_properties(group, proto, ""); 21854653Sdougm (void) printf("\n"); 21864653Sdougm if (strcmp(groupname, "zfs") == 0) { 21874653Sdougm sa_group_t zgroup; 21884653Sdougm 21894653Sdougm for (zgroup = sa_get_sub_group(group); 21904653Sdougm zgroup != NULL; 21914653Sdougm zgroup = sa_get_next_group(zgroup)) { 21924653Sdougm show_group(zgroup, verbose, properties, proto, 21934653Sdougm "zfs"); 21944653Sdougm } 21954653Sdougm sa_free_attr_string(groupname); 21964653Sdougm return; 21974653Sdougm } 21983034Sdougm /* 21994653Sdougm * Have a group, so list the contents. Resource and 22003034Sdougm * description are only listed if verbose is set. 22013034Sdougm */ 22024653Sdougm for (share = sa_get_share(group, NULL); 22034653Sdougm share != NULL; 22044653Sdougm share = sa_get_next_share(share)) { 22054653Sdougm sharepath = sa_get_share_attr(share, "path"); 22064653Sdougm if (sharepath != NULL) { 22075331Samw show_share(share, verbose, properties, proto, 22085331Samw iszfs, sharepath); 22094653Sdougm sa_free_attr_string(sharepath); 22103034Sdougm } 22113034Sdougm } 22123034Sdougm } 22133034Sdougm if (groupname != NULL) { 22143034Sdougm sa_free_attr_string(groupname); 22153034Sdougm } 22163034Sdougm } 22173034Sdougm 22183034Sdougm /* 22193034Sdougm * show_group_xml_init() 22203034Sdougm * 22213034Sdougm * Create an XML document that will be used to display config info via 22223034Sdougm * XML format. 22233034Sdougm */ 22243034Sdougm 22253034Sdougm xmlDocPtr 22263034Sdougm show_group_xml_init() 22273034Sdougm { 22283034Sdougm xmlDocPtr doc; 22293034Sdougm xmlNodePtr root; 22303034Sdougm 22313034Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 22323034Sdougm if (doc != NULL) { 22334653Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 22344653Sdougm if (root != NULL) 22354653Sdougm xmlDocSetRootElement(doc, root); 22363034Sdougm } 22373034Sdougm return (doc); 22383034Sdougm } 22393034Sdougm 22403034Sdougm /* 22413034Sdougm * show_group_xml(doc, group) 22423034Sdougm * 22433034Sdougm * Copy the group info into the XML doc. 22443034Sdougm */ 22453034Sdougm 22463034Sdougm static void 22473034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 22483034Sdougm { 22493034Sdougm xmlNodePtr node; 22503034Sdougm xmlNodePtr root; 22513034Sdougm 22523034Sdougm root = xmlDocGetRootElement(doc); 22533034Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 22543034Sdougm if (node != NULL && root != NULL) { 22554653Sdougm xmlAddChild(root, node); 22563034Sdougm /* 22573034Sdougm * In the future, we may have interally used tags that 22583034Sdougm * should not appear in the XML output. Remove 22593034Sdougm * anything we don't want to show here. 22603034Sdougm */ 22613034Sdougm } 22623034Sdougm } 22633034Sdougm 22643034Sdougm /* 22653034Sdougm * sa_show(flags, argc, argv) 22663034Sdougm * 22673034Sdougm * Implements the show subcommand. 22683034Sdougm */ 22693034Sdougm 22703034Sdougm int 22713910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[]) 22723034Sdougm { 22733034Sdougm sa_group_t group; 22743034Sdougm int verbose = 0; 22753034Sdougm int properties = 0; 22763034Sdougm int c; 22773034Sdougm int ret = SA_OK; 22783034Sdougm char *protocol = NULL; 22793034Sdougm int xml = 0; 22803034Sdougm xmlDocPtr doc; 22815331Samw #ifdef lint 22825331Samw flags = flags; 22835331Samw #endif 22843034Sdougm 22853034Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 22864653Sdougm switch (c) { 22874653Sdougm case 'v': 22884653Sdougm verbose++; 22894653Sdougm break; 22904653Sdougm case 'p': 22914653Sdougm properties++; 22924653Sdougm break; 22934653Sdougm case 'P': 22945331Samw if (protocol != NULL) { 22955331Samw (void) printf(gettext( 22965331Samw "Specifying multiple protocols " 22975331Samw "not supported: %s\n"), 22985331Samw protocol); 22995331Samw return (SA_SYNTAX_ERR); 23005331Samw } 23014653Sdougm protocol = optarg; 23024653Sdougm if (!sa_valid_protocol(protocol)) { 23034653Sdougm (void) printf(gettext( 23044653Sdougm "Invalid protocol specified: %s\n"), 23054653Sdougm protocol); 23064653Sdougm return (SA_INVALID_PROTOCOL); 23074653Sdougm } 23084653Sdougm break; 23094653Sdougm case 'x': 23104653Sdougm xml++; 23114653Sdougm break; 23126019Sdougm case 'h': 23136019Sdougm /* optopt on valid arg isn't defined */ 23146019Sdougm optopt = c; 23156019Sdougm /*FALLTHROUGH*/ 23166019Sdougm case '?': 23174653Sdougm default: 23186019Sdougm /* 23196019Sdougm * Since a bad option gets to here, sort it 23206019Sdougm * out and return a syntax error return value 23216019Sdougm * if necessary. 23226019Sdougm */ 23236019Sdougm switch (optopt) { 23246019Sdougm default: 23256019Sdougm ret = SA_SYNTAX_ERR; 23266019Sdougm break; 23276019Sdougm case 'h': 23286019Sdougm case '?': 23296019Sdougm break; 23306019Sdougm } 23314653Sdougm (void) printf(gettext("usage: %s\n"), 23324653Sdougm sa_get_usage(USAGE_SHOW)); 23336019Sdougm return (ret); 23343034Sdougm } 23353034Sdougm } 23363034Sdougm 23373034Sdougm if (xml) { 23384653Sdougm doc = show_group_xml_init(); 23394653Sdougm if (doc == NULL) 23404653Sdougm ret = SA_NO_MEMORY; 23413034Sdougm } 23423034Sdougm 23433034Sdougm if (optind == argc) { 23444653Sdougm /* No group specified so go through them all */ 23454653Sdougm for (group = sa_get_group(handle, NULL); 23464653Sdougm group != NULL; 23474653Sdougm group = sa_get_next_group(group)) { 23484653Sdougm /* 23494653Sdougm * Have a group so check if one we want and then list 23504653Sdougm * contents with appropriate options. 23514653Sdougm */ 23524653Sdougm if (xml) 23534653Sdougm show_group_xml(doc, group); 23544653Sdougm else 23554653Sdougm show_group(group, verbose, properties, protocol, 23564653Sdougm NULL); 23574653Sdougm } 23583034Sdougm } else { 23594653Sdougm /* Have a specified list of groups */ 23604653Sdougm for (; optind < argc; optind++) { 23614653Sdougm group = sa_get_group(handle, argv[optind]); 23624653Sdougm if (group != NULL) { 23634653Sdougm if (xml) 23644653Sdougm show_group_xml(doc, group); 23654653Sdougm else 23664653Sdougm show_group(group, verbose, properties, 23674653Sdougm protocol, NULL); 23684653Sdougm } else { 23694653Sdougm (void) printf(gettext("%s: not found\n"), 23704653Sdougm argv[optind]); 23714653Sdougm ret = SA_NO_SUCH_GROUP; 23724653Sdougm } 23733034Sdougm } 23743034Sdougm } 23753034Sdougm if (xml && ret == SA_OK) { 23764653Sdougm xmlDocFormatDump(stdout, doc, 1); 23774653Sdougm xmlFreeDoc(doc); 23783034Sdougm } 23793034Sdougm return (ret); 23803034Sdougm 23813034Sdougm } 23823034Sdougm 23833034Sdougm /* 23843034Sdougm * enable_share(group, share, update_legacy) 23853034Sdougm * 23863034Sdougm * helper function to enable a share if the group is enabled. 23873034Sdougm */ 23883034Sdougm 23893034Sdougm static int 23903910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 23915331Samw int update_legacy) 23923034Sdougm { 23933034Sdougm char *value; 23943034Sdougm int enabled; 23953034Sdougm sa_optionset_t optionset; 23965331Samw int err; 23973034Sdougm int ret = SA_OK; 23983034Sdougm char *zfs = NULL; 23993034Sdougm int iszfs = 0; 24005331Samw int isshare; 24013034Sdougm 24023034Sdougm /* 24033034Sdougm * need to enable this share if the group is enabled but not 24043034Sdougm * otherwise. The enable is also done on each protocol 24053034Sdougm * represented in the group. 24063034Sdougm */ 24073034Sdougm value = sa_get_group_attr(group, "state"); 24083034Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 24093034Sdougm if (value != NULL) 24104653Sdougm sa_free_attr_string(value); 24113034Sdougm /* remove legacy config if necessary */ 24123034Sdougm if (update_legacy) 24135331Samw ret = sa_delete_legacy(share, NULL); 24143034Sdougm zfs = sa_get_group_attr(group, "zfs"); 24153034Sdougm if (zfs != NULL) { 24164653Sdougm iszfs++; 24174653Sdougm sa_free_attr_string(zfs); 24183034Sdougm } 24193034Sdougm 24203034Sdougm /* 24213034Sdougm * Step through each optionset at the group level and 24223034Sdougm * enable the share based on the protocol type. This 24233034Sdougm * works because protocols must be set on the group 24243034Sdougm * for the protocol to be enabled. 24253034Sdougm */ 24265331Samw isshare = sa_is_share(share); 24273034Sdougm for (optionset = sa_get_optionset(group, NULL); 24283034Sdougm optionset != NULL && ret == SA_OK; 24293034Sdougm optionset = sa_get_next_optionset(optionset)) { 24304653Sdougm value = sa_get_optionset_attr(optionset, "type"); 24314653Sdougm if (value != NULL) { 24325331Samw if (enabled) { 24335331Samw if (isshare) { 24345331Samw err = sa_enable_share(share, value); 24355331Samw } else { 24365331Samw err = sa_enable_resource(share, value); 24375331Samw if (err == SA_NOT_SUPPORTED) { 24385331Samw sa_share_t parent; 24395331Samw parent = sa_get_resource_parent( 24405331Samw share); 24415331Samw if (parent != NULL) 24425331Samw err = sa_enable_share( 24435331Samw parent, value); 24445331Samw } 24455331Samw } 24465331Samw if (err != SA_OK) { 24475331Samw ret = err; 24485331Samw (void) printf(gettext( 24495331Samw "Failed to enable share for " 24505331Samw "\"%s\": %s\n"), 24515331Samw value, sa_errorstr(ret)); 24525331Samw } 24535331Samw } 24545331Samw /* 24555331Samw * If we want to update the legacy, use a copy of 24565331Samw * share so we can avoid breaking the loop we are in 24575331Samw * since we might also need to go up the tree to the 24585331Samw * parent. 24595331Samw */ 24605331Samw if (update_legacy && !iszfs) { 24615331Samw sa_share_t update = share; 24625331Samw if (!sa_is_share(share)) { 24635331Samw update = sa_get_resource_parent(share); 24645331Samw } 24655331Samw (void) sa_update_legacy(update, value); 24665331Samw } 24674653Sdougm sa_free_attr_string(value); 24684653Sdougm } 24693034Sdougm } 24703034Sdougm if (ret == SA_OK) 24714653Sdougm (void) sa_update_config(handle); 24723034Sdougm return (ret); 24733034Sdougm } 24743034Sdougm 24753034Sdougm /* 24765331Samw * sa_require_resource(group) 24775331Samw * 24785331Samw * if any of the defined protocols on the group require resource 24795331Samw * names, then all shares must have them. 24805331Samw */ 24815331Samw 24825331Samw static int 24835331Samw sa_require_resource(sa_group_t group) 24845331Samw { 24855331Samw sa_optionset_t optionset; 24865331Samw 24875331Samw for (optionset = sa_get_optionset(group, NULL); 24885331Samw optionset != NULL; 24895331Samw optionset = sa_get_next_optionset(optionset)) { 24905331Samw char *proto; 24915331Samw 24925331Samw proto = sa_get_optionset_attr(optionset, "type"); 24935331Samw if (proto != NULL) { 24945331Samw uint64_t features; 24955331Samw 24965331Samw features = sa_proto_get_featureset(proto); 24975331Samw if (features & SA_FEATURE_RESOURCE) { 24985331Samw sa_free_attr_string(proto); 24995331Samw return (B_TRUE); 25005331Samw } 25015331Samw sa_free_attr_string(proto); 25025331Samw } 25035331Samw } 25045331Samw return (B_FALSE); 25055331Samw } 25065331Samw 25075331Samw /* 25083034Sdougm * sa_addshare(flags, argc, argv) 25093034Sdougm * 25103034Sdougm * implements add-share subcommand. 25113034Sdougm */ 25123034Sdougm 25135331Samw static int 25143910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 25153034Sdougm { 25163034Sdougm int verbose = 0; 25173034Sdougm int dryrun = 0; 25183034Sdougm int c; 25193034Sdougm int ret = SA_OK; 25203034Sdougm sa_group_t group; 25213034Sdougm sa_share_t share; 25225331Samw sa_resource_t resource = NULL; 25233034Sdougm char *sharepath = NULL; 25243034Sdougm char *description = NULL; 25255331Samw char *rsrcname = NULL; 25265331Samw char *rsrc = NULL; 25273034Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 25283034Sdougm int auth; 25293034Sdougm char dir[MAXPATHLEN]; 25303034Sdougm 25313034Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 25324653Sdougm switch (c) { 25334653Sdougm case 'n': 25344653Sdougm dryrun++; 25354653Sdougm break; 25364653Sdougm case 'v': 25374653Sdougm verbose++; 25384653Sdougm break; 25394653Sdougm case 'd': 25404653Sdougm description = optarg; 25414653Sdougm break; 25424653Sdougm case 'r': 25435331Samw if (rsrcname != NULL) { 25445331Samw (void) printf(gettext("Adding multiple " 25455331Samw "resource names not" 25465331Samw " supported\n")); 25475331Samw return (SA_SYNTAX_ERR); 25485331Samw } 25495331Samw rsrcname = optarg; 25504653Sdougm break; 25514653Sdougm case 's': 25524653Sdougm /* 25534653Sdougm * Save share path into group. Currently limit 25544653Sdougm * to one share per command. 25554653Sdougm */ 25564653Sdougm if (sharepath != NULL) { 25574653Sdougm (void) printf(gettext( 25584653Sdougm "Adding multiple shares not supported\n")); 25595331Samw return (SA_SYNTAX_ERR); 25604653Sdougm } 25614653Sdougm sharepath = optarg; 25624653Sdougm break; 25634653Sdougm case 't': 25644653Sdougm persist = SA_SHARE_TRANSIENT; 25654653Sdougm break; 25666019Sdougm case 'h': 25676019Sdougm /* optopt on valid arg isn't defined */ 25686019Sdougm optopt = c; 25696019Sdougm /*FALLTHROUGH*/ 25706019Sdougm case '?': 25714653Sdougm default: 25726019Sdougm /* 25736019Sdougm * Since a bad option gets to here, sort it 25746019Sdougm * out and return a syntax error return value 25756019Sdougm * if necessary. 25766019Sdougm */ 25776019Sdougm switch (optopt) { 25786019Sdougm default: 25796019Sdougm ret = SA_SYNTAX_ERR; 25806019Sdougm break; 25816019Sdougm case 'h': 25826019Sdougm case '?': 25836019Sdougm break; 25846019Sdougm } 25854653Sdougm (void) printf(gettext("usage: %s\n"), 25864653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 25876019Sdougm return (ret); 25883034Sdougm } 25893034Sdougm } 25903034Sdougm 25913034Sdougm if (optind >= argc) { 25924653Sdougm (void) printf(gettext("usage: %s\n"), 25934653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 25944653Sdougm if (dryrun || sharepath != NULL || description != NULL || 25955331Samw rsrcname != NULL || verbose || persist) { 25964653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 25974653Sdougm ret = SA_NO_SUCH_GROUP; 25984653Sdougm } else { 25994653Sdougm ret = SA_OK; 26004653Sdougm } 26013034Sdougm } else { 26024653Sdougm if (sharepath == NULL) { 26034653Sdougm (void) printf(gettext("usage: %s\n"), 26044653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 26054653Sdougm (void) printf(gettext( 26064653Sdougm "\t-s sharepath must be specified\n")); 26075331Samw ret = SA_BAD_PATH; 26084653Sdougm } 26095331Samw if (ret == SA_OK) { 26105331Samw if (realpath(sharepath, dir) == NULL) { 26115331Samw ret = SA_BAD_PATH; 26125331Samw (void) printf(gettext("Path " 26135331Samw "is not valid: %s\n"), 26145331Samw sharepath); 26155331Samw } else { 26165331Samw sharepath = dir; 26175331Samw } 26183034Sdougm } 26195331Samw if (ret == SA_OK && rsrcname != NULL) { 26205331Samw /* check for valid syntax */ 26215331Samw if (validresource(rsrcname)) { 26225331Samw rsrc = conv_to_utf8(rsrcname); 26235331Samw resource = sa_find_resource(handle, rsrc); 26245331Samw if (resource != NULL) { 26255331Samw /* 26265331Samw * Resource names must be 26275331Samw * unique in the system 26285331Samw */ 26295331Samw ret = SA_DUPLICATE_NAME; 26305331Samw (void) printf(gettext("usage: %s\n"), 26315331Samw sa_get_usage(USAGE_ADD_SHARE)); 26325331Samw (void) printf(gettext( 26335331Samw "\tresource names must be unique " 26345331Samw "in the system\n")); 26355331Samw } 26365331Samw } else { 26375331Samw (void) printf(gettext("usage: %s\n"), 26385331Samw sa_get_usage(USAGE_ADD_SHARE)); 26395331Samw (void) printf(gettext( 26405331Samw "\tresource names use restricted " 26415331Samw "character set\n")); 26425331Samw ret = SA_INVALID_NAME; 26435331Samw } 26443034Sdougm } 26455331Samw 26465331Samw if (ret != SA_OK) { 26475331Samw if (rsrc != NULL && rsrcname != rsrc) 26485331Samw sa_free_attr_string(rsrc); 26495331Samw return (ret); 26504653Sdougm } 26515331Samw 26524653Sdougm share = sa_find_share(handle, sharepath); 26534653Sdougm if (share != NULL) { 26545331Samw if (rsrcname == NULL) { 26555331Samw /* 26565331Samw * Can only have a duplicate share if a new 26575331Samw * resource name is being added. 26585331Samw */ 26595331Samw ret = SA_DUPLICATE_NAME; 26605331Samw (void) printf(gettext("Share path already " 26615331Samw "shared: %s\n"), sharepath); 26625331Samw } 26635331Samw } 26645331Samw if (ret != SA_OK) 26655331Samw return (ret); 26665331Samw 26675331Samw group = sa_get_group(handle, argv[optind]); 26685331Samw if (group != NULL) { 26695331Samw if (sa_require_resource(group) == B_TRUE && 26705331Samw rsrcname == NULL) { 26715331Samw (void) printf(gettext( 26725331Samw "Resource name is required " 26735331Samw "by at least one enabled protocol " 26745331Samw "in group\n")); 26755331Samw return (SA_RESOURCE_REQUIRED); 26765331Samw } 26775331Samw if (share == NULL && ret == SA_OK) { 26785331Samw if (dryrun) 26795331Samw ret = sa_check_path(group, sharepath, 26805331Samw SA_CHECK_NORMAL); 26815331Samw else 26825331Samw share = sa_add_share(group, sharepath, 26835331Samw persist, &ret); 26845331Samw } 26855331Samw /* 26865331Samw * Make sure this isn't an attempt to put a resourced 26875331Samw * share into a different group than it already is in. 26885331Samw */ 26895331Samw if (share != NULL) { 26905331Samw sa_group_t parent; 26915331Samw parent = sa_get_parent_group(share); 26925331Samw if (parent != group) { 26935331Samw ret = SA_DUPLICATE_NAME; 26944653Sdougm (void) printf(gettext( 26954653Sdougm "Share path already " 26965331Samw "shared: %s\n"), sharepath); 26974653Sdougm } 26983034Sdougm } 26993034Sdougm if (!dryrun && share == NULL) { 27004653Sdougm (void) printf(gettext( 27014653Sdougm "Could not add share: %s\n"), 27024653Sdougm sa_errorstr(ret)); 27033034Sdougm } else { 27045331Samw auth = check_authorizations(argv[optind], 27055331Samw flags); 27064653Sdougm if (!dryrun && ret == SA_OK) { 27075331Samw if (rsrcname != NULL) { 27085331Samw resource = sa_add_resource( 27095331Samw share, 27105331Samw rsrc, 27115331Samw SA_SHARE_PERMANENT, 27125331Samw &ret); 27134653Sdougm } 27144653Sdougm if (ret == SA_OK && 27154653Sdougm description != NULL) { 27165885Sdougm if (resource != NULL) 27175885Sdougm ret = 27185885Sdougm set_resource_desc( 27195885Sdougm resource, 27205885Sdougm description); 27215885Sdougm else 27225331Samw ret = 27235331Samw set_share_desc( 27245331Samw share, 27255331Samw description); 27264653Sdougm } 27274653Sdougm if (ret == SA_OK) { 27285331Samw /* now enable the share(s) */ 27295331Samw if (resource != NULL) { 27305331Samw ret = enable_share( 27315331Samw handle, 27325331Samw group, 27335331Samw resource, 27345331Samw 1); 27355331Samw } else { 27365331Samw ret = enable_share( 27375331Samw handle, 27385331Samw group, 27395331Samw share, 27405331Samw 1); 27415331Samw } 27424653Sdougm ret = sa_update_config(handle); 27434653Sdougm } 27444653Sdougm switch (ret) { 27454653Sdougm case SA_DUPLICATE_NAME: 27464653Sdougm (void) printf(gettext( 27474653Sdougm "Resource name in" 27485331Samw "use: %s\n"), 27495331Samw rsrcname); 27504653Sdougm break; 27514653Sdougm default: 27525331Samw (void) printf(gettext( 27535331Samw "Could not set " 27544653Sdougm "attribute: %s\n"), 27554653Sdougm sa_errorstr(ret)); 27564653Sdougm break; 27574653Sdougm case SA_OK: 27584653Sdougm break; 27594653Sdougm } 27605331Samw } else if (dryrun && ret == SA_OK && 27615331Samw !auth && verbose) { 27624653Sdougm (void) printf(gettext( 27634653Sdougm "Command would fail: %s\n"), 27644653Sdougm sa_errorstr(SA_NO_PERMISSION)); 27654653Sdougm ret = SA_NO_PERMISSION; 27663034Sdougm } 27673034Sdougm } 27685331Samw } else { 27695331Samw switch (ret) { 27705331Samw default: 27715331Samw (void) printf(gettext( 27725331Samw "Group \"%s\" not found\n"), argv[optind]); 27735331Samw ret = SA_NO_SUCH_GROUP; 27745331Samw break; 27755331Samw case SA_BAD_PATH: 27765331Samw case SA_DUPLICATE_NAME: 27775331Samw break; 27785331Samw } 27793034Sdougm } 27803034Sdougm } 27813034Sdougm return (ret); 27823034Sdougm } 27833034Sdougm 27843034Sdougm /* 27853034Sdougm * sa_moveshare(flags, argc, argv) 27863034Sdougm * 27873034Sdougm * implements move-share subcommand. 27883034Sdougm */ 27893034Sdougm 27903034Sdougm int 27913910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 27923034Sdougm { 27933034Sdougm int verbose = 0; 27943034Sdougm int dryrun = 0; 27953034Sdougm int c; 27963034Sdougm int ret = SA_OK; 27973034Sdougm sa_group_t group; 27983034Sdougm sa_share_t share; 27995331Samw char *rsrcname = NULL; 28003034Sdougm char *sharepath = NULL; 28013034Sdougm int authsrc = 0, authdst = 0; 28025885Sdougm char dir[MAXPATHLEN]; 28033034Sdougm 28045331Samw while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) { 28054653Sdougm switch (c) { 28064653Sdougm case 'n': 28074653Sdougm dryrun++; 28084653Sdougm break; 28094653Sdougm case 'v': 28104653Sdougm verbose++; 28114653Sdougm break; 28125331Samw case 'r': 28135331Samw if (rsrcname != NULL) { 28145331Samw (void) printf(gettext( 28155331Samw "Moving multiple resource names not" 28165331Samw " supported\n")); 28175331Samw return (SA_SYNTAX_ERR); 28185331Samw } 28195331Samw rsrcname = optarg; 28205331Samw break; 28214653Sdougm case 's': 28224653Sdougm /* 28234653Sdougm * Remove share path from group. Currently limit 28244653Sdougm * to one share per command. 28254653Sdougm */ 28264653Sdougm if (sharepath != NULL) { 28274653Sdougm (void) printf(gettext("Moving multiple shares" 28285331Samw " not supported\n")); 28295331Samw return (SA_SYNTAX_ERR); 28304653Sdougm } 28314653Sdougm sharepath = optarg; 28324653Sdougm break; 28336019Sdougm case 'h': 28346019Sdougm /* optopt on valid arg isn't defined */ 28356019Sdougm optopt = c; 28366019Sdougm /*FALLTHROUGH*/ 28376019Sdougm case '?': 28384653Sdougm default: 28396019Sdougm /* 28406019Sdougm * Since a bad option gets to here, sort it 28416019Sdougm * out and return a syntax error return value 28426019Sdougm * if necessary. 28436019Sdougm */ 28446019Sdougm switch (optopt) { 28456019Sdougm default: 28466019Sdougm ret = SA_SYNTAX_ERR; 28476019Sdougm break; 28486019Sdougm case 'h': 28496019Sdougm case '?': 28506019Sdougm break; 28516019Sdougm } 28524653Sdougm (void) printf(gettext("usage: %s\n"), 28534653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 28546019Sdougm return (ret); 28553034Sdougm } 28563034Sdougm } 28573034Sdougm 28583034Sdougm if (optind >= argc || sharepath == NULL) { 28595331Samw (void) printf(gettext("usage: %s\n"), 28605331Samw sa_get_usage(USAGE_MOVE_SHARE)); 28615331Samw if (dryrun || verbose || sharepath != NULL) { 28625331Samw (void) printf(gettext("\tgroup must be specified\n")); 28635331Samw ret = SA_NO_SUCH_GROUP; 28645331Samw } else { 28655331Samw if (sharepath == NULL) { 28665331Samw ret = SA_SYNTAX_ERR; 28674653Sdougm (void) printf(gettext( 28685331Samw "\tsharepath must be specified\n")); 28694653Sdougm } else { 28705331Samw ret = SA_OK; 28714653Sdougm } 28725331Samw } 28734653Sdougm } else { 28744653Sdougm sa_group_t parent; 28754653Sdougm char *zfsold; 28764653Sdougm char *zfsnew; 28774653Sdougm 28783034Sdougm if (sharepath == NULL) { 28794653Sdougm (void) printf(gettext( 28804653Sdougm "sharepath must be specified with the -s " 28814653Sdougm "option\n")); 28824653Sdougm return (SA_BAD_PATH); 28834653Sdougm } 28843910Sdougm group = sa_get_group(handle, argv[optind]); 28854653Sdougm if (group == NULL) { 28864653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 28874653Sdougm argv[optind]); 28884653Sdougm return (SA_NO_SUCH_GROUP); 28894653Sdougm } 28904653Sdougm share = sa_find_share(handle, sharepath); 28915885Sdougm /* 28925885Sdougm * If a share wasn't found, it may have been a symlink 28935885Sdougm * or has a trailing '/'. Try again after resolving 28945885Sdougm * with realpath(). 28955885Sdougm */ 28965885Sdougm if (share == NULL) { 28975885Sdougm if (realpath(sharepath, dir) == NULL) { 28985885Sdougm (void) printf(gettext("Path " 28995885Sdougm "is not valid: %s\n"), 29005885Sdougm sharepath); 29015885Sdougm return (SA_BAD_PATH); 29025885Sdougm } 29035885Sdougm sharepath = dir; 29045885Sdougm share = sa_find_share(handle, sharepath); 29055885Sdougm } 29064653Sdougm if (share == NULL) { 29073034Sdougm (void) printf(gettext("Share not found: %s\n"), 29084653Sdougm sharepath); 29094653Sdougm return (SA_NO_SUCH_PATH); 29104653Sdougm } 29115885Sdougm authdst = check_authorizations(argv[optind], flags); 29124653Sdougm 29134653Sdougm parent = sa_get_parent_group(share); 29144653Sdougm if (parent != NULL) { 29154653Sdougm char *pname; 29164653Sdougm pname = sa_get_group_attr(parent, "name"); 29174653Sdougm if (pname != NULL) { 29183034Sdougm authsrc = check_authorizations(pname, flags); 29193034Sdougm sa_free_attr_string(pname); 29204653Sdougm } 29214653Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 29224653Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 29234653Sdougm if ((zfsold != NULL && zfsnew == NULL) || 29244653Sdougm (zfsold == NULL && zfsnew != NULL)) { 29253034Sdougm ret = SA_NOT_ALLOWED; 29263034Sdougm } 29274653Sdougm if (zfsold != NULL) 29284653Sdougm sa_free_attr_string(zfsold); 29294653Sdougm if (zfsnew != NULL) 29304653Sdougm sa_free_attr_string(zfsnew); 29314653Sdougm } 29324653Sdougm 29334653Sdougm if (ret == SA_OK && parent != group && !dryrun) { 29344653Sdougm char *oldstate; 29354653Sdougm /* 29364653Sdougm * Note that the share may need to be 29375331Samw * "unshared" if the new group is disabled and 29385331Samw * the old was enabled or it may need to be 29395331Samw * share to update if the new group is 29405331Samw * enabled. We disable before the move and 29415331Samw * will have to enable after the move in order 29425331Samw * to cleanup entries for protocols that 29435331Samw * aren't in the new group. 29444653Sdougm */ 29454653Sdougm oldstate = sa_get_group_attr(parent, "state"); 29464653Sdougm 29474653Sdougm /* enable_share determines what to do */ 29485331Samw if (strcmp(oldstate, "enabled") == 0) 29493034Sdougm (void) sa_disable_share(share, NULL); 29505331Samw 29514653Sdougm if (oldstate != NULL) 29523034Sdougm sa_free_attr_string(oldstate); 29533034Sdougm } 29544653Sdougm 29555331Samw if (!dryrun && ret == SA_OK) 29565331Samw ret = sa_move_share(group, share); 29575331Samw 29585331Samw /* 29595331Samw * Reenable and update any config information. 29605331Samw */ 29615331Samw if (ret == SA_OK && parent != group && !dryrun) { 29625331Samw ret = sa_update_config(handle); 29635331Samw 29645331Samw (void) enable_share(handle, group, share, 1); 29655331Samw } 29665331Samw 29674653Sdougm if (ret != SA_OK) 29684653Sdougm (void) printf(gettext("Could not move share: %s\n"), 29694653Sdougm sa_errorstr(ret)); 29704653Sdougm 29714653Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 29724653Sdougm verbose) { 29734653Sdougm (void) printf(gettext("Command would fail: %s\n"), 29744653Sdougm sa_errorstr(SA_NO_PERMISSION)); 29754653Sdougm } 29763034Sdougm } 29773034Sdougm return (ret); 29783034Sdougm } 29793034Sdougm 29803034Sdougm /* 29813034Sdougm * sa_removeshare(flags, argc, argv) 29823034Sdougm * 29833034Sdougm * implements remove-share subcommand. 29843034Sdougm */ 29853034Sdougm 29863034Sdougm int 29873910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 29883034Sdougm { 29893034Sdougm int verbose = 0; 29903034Sdougm int dryrun = 0; 29913034Sdougm int force = 0; 29923034Sdougm int c; 29933034Sdougm int ret = SA_OK; 29943034Sdougm sa_group_t group; 29955331Samw sa_resource_t resource = NULL; 29965331Samw sa_share_t share = NULL; 29975331Samw char *rsrcname = NULL; 29983034Sdougm char *sharepath = NULL; 29993034Sdougm char dir[MAXPATHLEN]; 30003034Sdougm int auth; 30013034Sdougm 30025331Samw while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) { 30034653Sdougm switch (c) { 30044653Sdougm case 'n': 30054653Sdougm dryrun++; 30064653Sdougm break; 30074653Sdougm case 'v': 30084653Sdougm verbose++; 30094653Sdougm break; 30104653Sdougm case 'f': 30114653Sdougm force++; 30124653Sdougm break; 30134653Sdougm case 's': 30144653Sdougm /* 30154653Sdougm * Remove share path from group. Currently limit 30164653Sdougm * to one share per command. 30174653Sdougm */ 30184653Sdougm if (sharepath != NULL) { 30194653Sdougm (void) printf(gettext( 30204653Sdougm "Removing multiple shares not " 30213034Sdougm "supported\n")); 30224653Sdougm return (SA_SYNTAX_ERR); 30234653Sdougm } 30244653Sdougm sharepath = optarg; 30254653Sdougm break; 30265331Samw case 'r': 30275331Samw /* 30285331Samw * Remove share from group if last resource or remove 30295331Samw * resource from share if multiple resources. 30305331Samw */ 30315331Samw if (rsrcname != NULL) { 30325331Samw (void) printf(gettext( 30335331Samw "Removing multiple resource names not " 30345331Samw "supported\n")); 30355331Samw return (SA_SYNTAX_ERR); 30365331Samw } 30375331Samw rsrcname = optarg; 30385331Samw break; 30396019Sdougm case 'h': 30406019Sdougm /* optopt on valid arg isn't defined */ 30416019Sdougm optopt = c; 30426019Sdougm /*FALLTHROUGH*/ 30436019Sdougm case '?': 30444653Sdougm default: 30456019Sdougm /* 30466019Sdougm * Since a bad option gets to here, sort it 30476019Sdougm * out and return a syntax error return value 30486019Sdougm * if necessary. 30496019Sdougm */ 30506019Sdougm switch (optopt) { 30516019Sdougm default: 30526019Sdougm ret = SA_SYNTAX_ERR; 30536019Sdougm break; 30546019Sdougm case 'h': 30556019Sdougm case '?': 30566019Sdougm break; 30576019Sdougm } 30584653Sdougm (void) printf(gettext("usage: %s\n"), 30594653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 30606019Sdougm return (ret); 30613034Sdougm } 30623034Sdougm } 30633034Sdougm 30645331Samw if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) { 30655331Samw if (sharepath == NULL && rsrcname == NULL) { 30663034Sdougm (void) printf(gettext("usage: %s\n"), 30674653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 30685331Samw (void) printf(gettext("\t-s sharepath or -r resource" 30695331Samw " must be specified\n")); 30704653Sdougm ret = SA_BAD_PATH; 30714653Sdougm } else { 30724653Sdougm ret = SA_OK; 30734653Sdougm } 30743034Sdougm } 30754653Sdougm if (ret != SA_OK) { 30764653Sdougm return (ret); 30774653Sdougm } 30784653Sdougm 30794653Sdougm if (optind < argc) { 30803034Sdougm if ((optind + 1) < argc) { 30814653Sdougm (void) printf(gettext("Extraneous group(s) at end of " 30824653Sdougm "command\n")); 30834653Sdougm ret = SA_SYNTAX_ERR; 30843034Sdougm } else { 30854653Sdougm group = sa_get_group(handle, argv[optind]); 30864653Sdougm if (group == NULL) { 30874653Sdougm (void) printf(gettext( 30884653Sdougm "Group \"%s\" not found\n"), argv[optind]); 30894653Sdougm ret = SA_NO_SUCH_GROUP; 30904653Sdougm } 30913034Sdougm } 30924653Sdougm } else { 30933034Sdougm group = NULL; 30944653Sdougm } 30954653Sdougm 30965331Samw if (rsrcname != NULL) { 30975331Samw resource = sa_find_resource(handle, rsrcname); 30985331Samw if (resource == NULL) { 30995331Samw ret = SA_NO_SUCH_RESOURCE; 31005331Samw (void) printf(gettext( 31015331Samw "Resource name not found for share: %s\n"), 31025331Samw rsrcname); 31035331Samw } 31045331Samw } 31055331Samw 31064653Sdougm /* 31074653Sdougm * Lookup the path in the internal configuration. Care 31084653Sdougm * must be taken to handle the case where the 31094653Sdougm * underlying path has been removed since we need to 31104653Sdougm * be able to deal with that as well. 31114653Sdougm */ 31124653Sdougm if (ret == SA_OK) { 31135331Samw if (sharepath != NULL) { 31145331Samw if (group != NULL) 31155331Samw share = sa_get_share(group, sharepath); 31165331Samw else 31175331Samw share = sa_find_share(handle, sharepath); 31185331Samw } 31195331Samw 31205331Samw if (resource != NULL) { 31215331Samw sa_share_t rsrcshare; 31225331Samw rsrcshare = sa_get_resource_parent(resource); 31235331Samw if (share == NULL) 31245331Samw share = rsrcshare; 31255331Samw else if (share != rsrcshare) { 31265331Samw ret = SA_NO_SUCH_RESOURCE; 31275331Samw (void) printf(gettext( 31285331Samw "Bad resource name for share: %s\n"), 31295331Samw rsrcname); 31305331Samw share = NULL; 31315331Samw } 31325331Samw } 31335331Samw 31343663Sdougm /* 31353663Sdougm * If we didn't find the share with the provided path, 31363663Sdougm * it may be a symlink so attempt to resolve it using 31373663Sdougm * realpath and try again. Realpath will resolve any 31383663Sdougm * symlinks and place them in "dir". Note that 31393663Sdougm * sharepath is only used for the lookup the first 31403663Sdougm * time and later for error messages. dir will be used 31413663Sdougm * on the second attempt. Once a share is found, all 31423663Sdougm * operations are based off of the share variable. 31433663Sdougm */ 31443663Sdougm if (share == NULL) { 31454653Sdougm if (realpath(sharepath, dir) == NULL) { 31464653Sdougm ret = SA_BAD_PATH; 31474653Sdougm (void) printf(gettext( 31484653Sdougm "Path is not valid: %s\n"), sharepath); 31494653Sdougm } else { 31504653Sdougm if (group != NULL) 31514653Sdougm share = sa_get_share(group, dir); 31524653Sdougm else 31534653Sdougm share = sa_find_share(handle, dir); 31544653Sdougm } 31553663Sdougm } 31564653Sdougm } 31574653Sdougm 31584653Sdougm /* 31594653Sdougm * If there hasn't been an error, there was likely a 31604653Sdougm * path found. If not, give the appropriate error 31614653Sdougm * message and set the return error. If it was found, 31624653Sdougm * then disable the share and then remove it from the 31634653Sdougm * configuration. 31644653Sdougm */ 31654653Sdougm if (ret != SA_OK) { 31664653Sdougm return (ret); 31674653Sdougm } 31684653Sdougm if (share == NULL) { 31694653Sdougm if (group != NULL) 31703034Sdougm (void) printf(gettext("Share not found in group %s:" 31714653Sdougm " %s\n"), argv[optind], sharepath); 31724653Sdougm else 31733034Sdougm (void) printf(gettext("Share not found: %s\n"), 31744653Sdougm sharepath); 31755331Samw ret = SA_NO_SUCH_PATH; 31764653Sdougm } else { 31774653Sdougm if (group == NULL) 31783034Sdougm group = sa_get_parent_group(share); 31794653Sdougm if (!dryrun) { 31803034Sdougm if (ret == SA_OK) { 31815331Samw if (resource != NULL) 31825331Samw ret = sa_disable_resource(resource, 31835331Samw NULL); 31845331Samw else 31855331Samw ret = sa_disable_share(share, NULL); 31863034Sdougm /* 31874653Sdougm * We don't care if it fails since it 31883663Sdougm * could be disabled already. Some 31893663Sdougm * unexpected errors could occur that 31903663Sdougm * prevent removal, so also check for 31913663Sdougm * force being set. 31923034Sdougm */ 31935331Samw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 31945331Samw ret == SA_NOT_SUPPORTED || 31955331Samw ret == SA_SYSTEM_ERR || force) && 31965331Samw resource == NULL) 31975331Samw ret = sa_remove_share(share); 31985331Samw 31995331Samw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 32004653Sdougm ret == SA_NOT_SUPPORTED || 32015331Samw ret == SA_SYSTEM_ERR || force) && 32025331Samw resource != NULL) { 32035331Samw ret = sa_remove_resource(resource); 32045331Samw if (ret == SA_OK) { 32055331Samw /* 32065331Samw * If this was the 32075331Samw * last one, remove 32085331Samw * the share as well. 32095331Samw */ 32105331Samw resource = 32115331Samw sa_get_share_resource( 32125331Samw share, NULL); 32135331Samw if (resource == NULL) 32145331Samw ret = sa_remove_share( 32155331Samw share); 32165331Samw } 32174653Sdougm } 32184653Sdougm if (ret == SA_OK) 32194653Sdougm ret = sa_update_config(handle); 32203034Sdougm } 32214653Sdougm if (ret != SA_OK) 32225331Samw (void) printf(gettext("Could not remove share:" 32235331Samw " %s\n"), sa_errorstr(ret)); 32244653Sdougm } else if (ret == SA_OK) { 32253034Sdougm char *pname; 32263034Sdougm pname = sa_get_group_attr(group, "name"); 32273034Sdougm if (pname != NULL) { 32284653Sdougm auth = check_authorizations(pname, flags); 32294653Sdougm sa_free_attr_string(pname); 32303034Sdougm } 32313034Sdougm if (!auth && verbose) { 32324653Sdougm (void) printf(gettext( 32334653Sdougm "Command would fail: %s\n"), 32344653Sdougm sa_errorstr(SA_NO_PERMISSION)); 32353034Sdougm } 32363034Sdougm } 32373034Sdougm } 32383034Sdougm return (ret); 32393034Sdougm } 32403034Sdougm 32413034Sdougm /* 32423034Sdougm * sa_set_share(flags, argc, argv) 32433034Sdougm * 32443034Sdougm * implements set-share subcommand. 32453034Sdougm */ 32463034Sdougm 32473034Sdougm int 32483910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 32493034Sdougm { 32503034Sdougm int dryrun = 0; 32513034Sdougm int c; 32523034Sdougm int ret = SA_OK; 32533034Sdougm sa_group_t group, sharegroup; 32545772Sas200622 sa_share_t share = NULL; 32555331Samw sa_resource_t resource = NULL; 32563034Sdougm char *sharepath = NULL; 32573034Sdougm char *description = NULL; 32585331Samw char *rsrcname = NULL; 32595331Samw char *rsrc = NULL; 32605331Samw char *newname = NULL; 32615331Samw char *newrsrc; 32625331Samw char *groupname = NULL; 32633034Sdougm int auth; 32643034Sdougm int verbose = 0; 32653034Sdougm 32663034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 32674653Sdougm switch (c) { 32684653Sdougm case 'n': 32694653Sdougm dryrun++; 32704653Sdougm break; 32714653Sdougm case 'd': 32724653Sdougm description = optarg; 32734653Sdougm break; 32744653Sdougm case 'v': 32754653Sdougm verbose++; 32764653Sdougm break; 32775331Samw case 'r': 32785331Samw /* 32795331Samw * Update share by resource name 32805331Samw */ 32815331Samw if (rsrcname != NULL) { 32825331Samw (void) printf(gettext( 32835331Samw "Updating multiple resource names not " 32845331Samw "supported\n")); 32855331Samw return (SA_SYNTAX_ERR); 32865331Samw } 32875331Samw rsrcname = optarg; 32885331Samw break; 32894653Sdougm case 's': 32904653Sdougm /* 32914653Sdougm * Save share path into group. Currently limit 32924653Sdougm * to one share per command. 32934653Sdougm */ 32944653Sdougm if (sharepath != NULL) { 32954653Sdougm (void) printf(gettext( 32964653Sdougm "Updating multiple shares not " 32973034Sdougm "supported\n")); 32985331Samw return (SA_SYNTAX_ERR); 32994653Sdougm } 33004653Sdougm sharepath = optarg; 33014653Sdougm break; 33026019Sdougm case 'h': 33036019Sdougm /* optopt on valid arg isn't defined */ 33046019Sdougm optopt = c; 33056019Sdougm /*FALLTHROUGH*/ 33066019Sdougm case '?': 33074653Sdougm default: 33086019Sdougm /* 33096019Sdougm * Since a bad option gets to here, sort it 33106019Sdougm * out and return a syntax error return value 33116019Sdougm * if necessary. 33126019Sdougm */ 33136019Sdougm switch (optopt) { 33146019Sdougm default: 33156019Sdougm ret = SA_SYNTAX_ERR; 33166019Sdougm break; 33176019Sdougm case 'h': 33186019Sdougm case '?': 33196019Sdougm break; 33206019Sdougm } 33214653Sdougm (void) printf(gettext("usage: %s\n"), 33224653Sdougm sa_get_usage(USAGE_SET_SHARE)); 33236019Sdougm return (ret); 33243034Sdougm } 33253034Sdougm } 33264653Sdougm 33275331Samw if (optind >= argc && sharepath == NULL && rsrcname == NULL) { 33284653Sdougm if (sharepath == NULL) { 33294653Sdougm (void) printf(gettext("usage: %s\n"), 33304653Sdougm sa_get_usage(USAGE_SET_SHARE)); 33314653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 33324653Sdougm ret = SA_BAD_PATH; 33334653Sdougm } else { 33344653Sdougm ret = SA_OK; 33354653Sdougm } 33363034Sdougm } 33373034Sdougm if ((optind + 1) < argc) { 33384653Sdougm (void) printf(gettext("usage: %s\n"), 33394653Sdougm sa_get_usage(USAGE_SET_SHARE)); 33404653Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 33414653Sdougm ret = SA_SYNTAX_ERR; 33423034Sdougm } 33434653Sdougm 33445331Samw /* 33455331Samw * Must have at least one of sharepath and rsrcrname. 33465331Samw * It is a syntax error to be missing both. 33475331Samw */ 33485331Samw if (sharepath == NULL && rsrcname == NULL) { 33495331Samw (void) printf(gettext("usage: %s\n"), 33505331Samw sa_get_usage(USAGE_SET_SHARE)); 33515331Samw ret = SA_SYNTAX_ERR; 33525331Samw } 33535331Samw 33544653Sdougm if (ret != SA_OK) 33554653Sdougm return (ret); 33564653Sdougm 33574653Sdougm if (optind < argc) { 33583034Sdougm groupname = argv[optind]; 33593910Sdougm group = sa_get_group(handle, groupname); 33604653Sdougm } else { 33613034Sdougm group = NULL; 33623034Sdougm groupname = NULL; 33634653Sdougm } 33645331Samw if (rsrcname != NULL) { 33655331Samw /* 33665331Samw * If rsrcname exists, split rename syntax and then 33675331Samw * convert to utf 8 if no errors. 33685331Samw */ 33695331Samw newname = strchr(rsrcname, '='); 33705331Samw if (newname != NULL) { 33715331Samw *newname++ = '\0'; 33725331Samw } 33735331Samw if (!validresource(rsrcname)) { 33745331Samw ret = SA_INVALID_NAME; 33755331Samw (void) printf(gettext("Invalid resource name: " 33765331Samw "\"%s\"\n"), rsrcname); 33775331Samw } else { 33785331Samw rsrc = conv_to_utf8(rsrcname); 33795331Samw } 33805331Samw if (newname != NULL) { 33815331Samw if (!validresource(newname)) { 33825331Samw ret = SA_INVALID_NAME; 33835331Samw (void) printf(gettext("Invalid resource name: " 33845331Samw "%s\n"), newname); 33855331Samw } else { 33865331Samw newrsrc = conv_to_utf8(newname); 33875331Samw } 33885331Samw } 33895331Samw } 33905331Samw 33915331Samw if (ret != SA_OK) { 33925331Samw if (rsrcname != NULL && rsrcname != rsrc) 33935331Samw sa_free_attr_string(rsrc); 33945331Samw if (newname != NULL && newname != newrsrc) 33955331Samw sa_free_attr_string(newrsrc); 33965331Samw return (ret); 33975331Samw } 33985331Samw 33995331Samw if (sharepath != NULL) { 34005331Samw share = sa_find_share(handle, sharepath); 34015331Samw } else if (rsrcname != NULL) { 34025331Samw resource = sa_find_resource(handle, rsrc); 34035772Sas200622 if (resource != NULL) 34045331Samw share = sa_get_resource_parent(resource); 34055772Sas200622 else 34065772Sas200622 ret = SA_NO_SUCH_RESOURCE; 34075331Samw } 34085331Samw if (share != NULL) { 34095331Samw sharegroup = sa_get_parent_group(share); 34105331Samw if (group != NULL && group != sharegroup) { 34115331Samw (void) printf(gettext("Group \"%s\" does not contain " 34125331Samw "share %s\n"), 34135331Samw argv[optind], sharepath); 34145331Samw ret = SA_BAD_PATH; 34155331Samw } else { 34165331Samw int delgroupname = 0; 34175331Samw if (groupname == NULL) { 34185331Samw groupname = sa_get_group_attr(sharegroup, 34195331Samw "name"); 34205331Samw delgroupname = 1; 34215331Samw } 34225331Samw if (groupname != NULL) { 34235331Samw auth = check_authorizations(groupname, flags); 34245331Samw if (delgroupname) { 34255331Samw sa_free_attr_string(groupname); 34265331Samw groupname = NULL; 34275331Samw } 34285331Samw } else { 34295331Samw ret = SA_NO_MEMORY; 34305331Samw } 34315331Samw if (rsrcname != NULL) { 34325331Samw resource = sa_find_resource(handle, rsrc); 34335331Samw if (!dryrun) { 34345331Samw if (newname != NULL && 34355331Samw resource != NULL) 34365331Samw ret = sa_rename_resource( 34375331Samw resource, newrsrc); 34385331Samw else if (newname != NULL) 34395331Samw ret = SA_NO_SUCH_RESOURCE; 34405331Samw if (newname != NULL && 34415331Samw newname != newrsrc) 34425331Samw sa_free_attr_string(newrsrc); 34435331Samw } 34445331Samw if (rsrc != rsrcname) 34455331Samw sa_free_attr_string(rsrc); 34465331Samw } 34475331Samw 34485331Samw /* 34495331Samw * If the user has set a description, it will be 34505331Samw * on the resource if -r was used otherwise it 34515331Samw * must be on the share. 34525331Samw */ 34535967Scp160787 if (!dryrun && ret == SA_OK && description != NULL) { 34545967Scp160787 char *desc; 34555967Scp160787 desc = conv_to_utf8(description); 34565331Samw if (resource != NULL) 34575967Scp160787 ret = sa_set_resource_description( 34585967Scp160787 resource, desc); 34595331Samw else 34605967Scp160787 ret = sa_set_share_description(share, 34615967Scp160787 desc); 34625967Scp160787 if (desc != description) 34635967Scp160787 sa_free_share_description(desc); 34645331Samw } 34655331Samw } 34665331Samw if (!dryrun && ret == SA_OK) { 34675331Samw if (resource != NULL) 34685331Samw (void) sa_enable_resource(resource, NULL); 34695331Samw ret = sa_update_config(handle); 34705331Samw } 34715331Samw switch (ret) { 34725331Samw case SA_DUPLICATE_NAME: 34735331Samw (void) printf(gettext("Resource name in use: %s\n"), 34745331Samw rsrcname); 34755331Samw break; 34765331Samw default: 34775331Samw (void) printf(gettext("Could not set: %s\n"), 34785331Samw sa_errorstr(ret)); 34795331Samw break; 34805331Samw case SA_OK: 34815331Samw if (dryrun && !auth && verbose) { 34825331Samw (void) printf(gettext( 34835331Samw "Command would fail: %s\n"), 34845331Samw sa_errorstr(SA_NO_PERMISSION)); 34855331Samw } 34865331Samw break; 34875331Samw } 34885331Samw } else { 34895772Sas200622 switch (ret) { 34905772Sas200622 case SA_NO_SUCH_RESOURCE: 34915772Sas200622 (void) printf(gettext("Resource \"%s\" not found\n"), 34925772Sas200622 rsrcname); 34935772Sas200622 break; 34945772Sas200622 default: 34955772Sas200622 if (sharepath != NULL) { 34965772Sas200622 (void) printf( 34975772Sas200622 gettext("Share path \"%s\" not found\n"), 34985772Sas200622 sharepath); 34995772Sas200622 ret = SA_NO_SUCH_PATH; 35005772Sas200622 } else { 35015772Sas200622 (void) printf(gettext("Set failed: %s\n"), 35025772Sas200622 sa_errorstr(ret)); 35035772Sas200622 } 35045772Sas200622 } 35053034Sdougm } 35064653Sdougm 35073034Sdougm return (ret); 35083034Sdougm } 35093034Sdougm 35103034Sdougm /* 35113034Sdougm * add_security(group, sectype, optlist, proto, *err) 35123034Sdougm * 35133034Sdougm * Helper function to add a security option (named optionset) to the 35143034Sdougm * group. 35153034Sdougm */ 35163034Sdougm 35173034Sdougm static int 35183034Sdougm add_security(sa_group_t group, char *sectype, 35195331Samw struct options *optlist, char *proto, int *err) 35203034Sdougm { 35213034Sdougm sa_security_t security; 35223034Sdougm int ret = SA_OK; 35233034Sdougm int result = 0; 35243034Sdougm 35253034Sdougm sectype = sa_proto_space_alias(proto, sectype); 35263034Sdougm security = sa_get_security(group, sectype, proto); 35274653Sdougm if (security == NULL) 35284653Sdougm security = sa_create_security(group, sectype, proto); 35294653Sdougm 35303034Sdougm if (sectype != NULL) 35314653Sdougm sa_free_attr_string(sectype); 35324653Sdougm 35334653Sdougm if (security == NULL) 35344653Sdougm return (ret); 35354653Sdougm 35364653Sdougm while (optlist != NULL) { 35373034Sdougm sa_property_t prop; 35383034Sdougm prop = sa_get_property(security, optlist->optname); 35393034Sdougm if (prop == NULL) { 35403034Sdougm /* 35414653Sdougm * Add the property, but only if it is 35423034Sdougm * a non-NULL or non-zero length value 35433034Sdougm */ 35444653Sdougm if (optlist->optvalue != NULL) { 35454653Sdougm prop = sa_create_property(optlist->optname, 35464653Sdougm optlist->optvalue); 35474653Sdougm if (prop != NULL) { 35485331Samw ret = sa_valid_property(security, 35495331Samw proto, prop); 35504653Sdougm if (ret != SA_OK) { 35514653Sdougm (void) sa_remove_property(prop); 35524653Sdougm (void) printf(gettext( 35534653Sdougm "Could not add " 35544653Sdougm "property %s: %s\n"), 35554653Sdougm optlist->optname, 35564653Sdougm sa_errorstr(ret)); 35574653Sdougm } 35584653Sdougm if (ret == SA_OK) { 35594653Sdougm ret = sa_add_property(security, 35604653Sdougm prop); 35614653Sdougm if (ret != SA_OK) { 35624653Sdougm (void) printf(gettext( 35634653Sdougm "Could not add " 35645331Samw "property (%s=%s):" 35655331Samw " %s\n"), 35664653Sdougm optlist->optname, 35674653Sdougm optlist->optvalue, 35684653Sdougm sa_errorstr(ret)); 35694653Sdougm } else { 35704653Sdougm result = 1; 35714653Sdougm } 35724653Sdougm } 35733034Sdougm } 35743034Sdougm } 35753034Sdougm } else { 35764653Sdougm ret = sa_update_property(prop, optlist->optvalue); 35774653Sdougm result = 1; /* should check if really changed */ 35783034Sdougm } 35793034Sdougm optlist = optlist->next; 35804653Sdougm } 35814653Sdougm /* 35824653Sdougm * When done, properties may have all been removed but 35834653Sdougm * we need to keep the security type itself until 35844653Sdougm * explicitly removed. 35854653Sdougm */ 35864653Sdougm if (result) 35873034Sdougm ret = sa_commit_properties(security, 0); 35883034Sdougm *err = ret; 35893034Sdougm return (result); 35903034Sdougm } 35913034Sdougm 35923034Sdougm /* 35935089Sdougm * zfscheck(group, share) 35945089Sdougm * 35955089Sdougm * For the special case where a share was provided, make sure it is a 35965089Sdougm * compatible path for a ZFS property change. The only path 35975089Sdougm * acceptable is the path that defines the zfs sub-group (dataset with 35985089Sdougm * the sharenfs property set) and not one of the paths that inherited 35995089Sdougm * the NFS properties. Returns SA_OK if it is usable and 36005089Sdougm * SA_NOT_ALLOWED if it isn't. 36015089Sdougm * 36025089Sdougm * If group is not a ZFS group/subgroup, we assume OK since the check 36035089Sdougm * on return will catch errors for those cases. What we are looking 36045089Sdougm * for here is that the group is ZFS and the share is not the defining 36055089Sdougm * share. All else is SA_OK. 36065089Sdougm */ 36075089Sdougm 36085089Sdougm static int 36095089Sdougm zfscheck(sa_group_t group, sa_share_t share) 36105089Sdougm { 36115089Sdougm int ret = SA_OK; 36125089Sdougm char *attr; 36135089Sdougm 36145089Sdougm if (sa_group_is_zfs(group)) { 36155089Sdougm /* 36165089Sdougm * The group is a ZFS group. Does the share represent 36175089Sdougm * the dataset that defined the group? It is only OK 36185089Sdougm * if the attribute "subgroup" exists on the share and 36195089Sdougm * has a value of "true". 36205089Sdougm */ 36215089Sdougm 36225089Sdougm ret = SA_NOT_ALLOWED; 36235089Sdougm attr = sa_get_share_attr(share, "subgroup"); 36245089Sdougm if (attr != NULL) { 36255089Sdougm if (strcmp(attr, "true") == 0) 36265089Sdougm ret = SA_OK; 36275089Sdougm sa_free_attr_string(attr); 36285089Sdougm } 36295089Sdougm } 36305089Sdougm return (ret); 36315089Sdougm } 36325089Sdougm 36335089Sdougm /* 36345331Samw * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 36353034Sdougm * 36363034Sdougm * This function implements "set" when a name space (-S) is not 36373034Sdougm * specified. It is a basic set. Options and other CLI parsing has 36383034Sdougm * already been done. 36395331Samw * 36405331Samw * "rsrcname" is a "resource name". If it is non-NULL, it must match 36415331Samw * the sharepath if present or group if present, otherwise it is used 36425331Samw * to set options. 36435331Samw * 36445331Samw * Resource names may take options if the protocol supports it. If the 36455331Samw * protocol doesn't support resource level options, rsrcname is just 36465331Samw * an alias for the share. 36473034Sdougm */ 36483034Sdougm 36493034Sdougm static int 36503910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 36515331Samw char *protocol, char *sharepath, char *rsrcname, int dryrun) 36523034Sdougm { 36533034Sdougm sa_group_t group; 36543034Sdougm int ret = SA_OK; 36553034Sdougm int change = 0; 36563034Sdougm struct list *worklist = NULL; 36573034Sdougm 36583910Sdougm group = sa_get_group(handle, groupname); 36593034Sdougm if (group != NULL) { 36604653Sdougm sa_share_t share = NULL; 36615331Samw sa_resource_t resource = NULL; 36625331Samw 36635331Samw /* 36645331Samw * If there is a sharepath, make sure it belongs to 36655331Samw * the group. 36665331Samw */ 36674653Sdougm if (sharepath != NULL) { 36684653Sdougm share = sa_get_share(group, sharepath); 36694653Sdougm if (share == NULL) { 36704653Sdougm (void) printf(gettext( 36714653Sdougm "Share does not exist in group %s\n"), 36724653Sdougm groupname, sharepath); 36734653Sdougm ret = SA_NO_SUCH_PATH; 36745089Sdougm } else { 36755089Sdougm /* if ZFS and OK, then only group */ 36765089Sdougm ret = zfscheck(group, share); 36775089Sdougm if (ret == SA_OK && 36785089Sdougm sa_group_is_zfs(group)) 36795089Sdougm share = NULL; 36805089Sdougm if (ret == SA_NOT_ALLOWED) 36815089Sdougm (void) printf(gettext( 36825089Sdougm "Properties on ZFS group shares " 36835089Sdougm "not supported: %s\n"), sharepath); 36844653Sdougm } 36853034Sdougm } 36865331Samw 36875331Samw /* 36885331Samw * If a resource name exists, make sure it belongs to 36895331Samw * the share if present else it belongs to the 36905331Samw * group. Also check the protocol to see if it 36915331Samw * supports resource level properties or not. If not, 36925331Samw * use share only. 36935331Samw */ 36945331Samw if (rsrcname != NULL) { 36955331Samw if (share != NULL) { 36965331Samw resource = sa_get_share_resource(share, 36975331Samw rsrcname); 36985331Samw if (resource == NULL) 36995331Samw ret = SA_NO_SUCH_RESOURCE; 37005331Samw } else { 37015331Samw resource = sa_get_resource(group, rsrcname); 37025331Samw if (resource != NULL) 37035331Samw share = sa_get_resource_parent( 37045331Samw resource); 37055331Samw else 37065331Samw ret = SA_NO_SUCH_RESOURCE; 37075331Samw } 37085331Samw if (ret == SA_OK && resource != NULL) { 37095331Samw uint64_t features; 37105331Samw /* 37115331Samw * Check to see if the resource can take 37125331Samw * properties. If so, stick the resource into 37135331Samw * "share" so it will all just work. 37145331Samw */ 37155331Samw features = sa_proto_get_featureset(protocol); 37165331Samw if (features & SA_FEATURE_RESOURCE) 37175331Samw share = (sa_share_t)resource; 37185331Samw } 37195331Samw } 37205331Samw 37214653Sdougm if (ret == SA_OK) { 37224653Sdougm /* group must exist */ 37234653Sdougm ret = valid_options(optlist, protocol, 37244653Sdougm share == NULL ? group : share, NULL); 37254653Sdougm if (ret == SA_OK && !dryrun) { 37264653Sdougm if (share != NULL) 37274653Sdougm change |= add_optionset(share, optlist, 37284653Sdougm protocol, &ret); 37294653Sdougm else 37304653Sdougm change |= add_optionset(group, optlist, 37314653Sdougm protocol, &ret); 37324653Sdougm if (ret == SA_OK && change) 37334653Sdougm worklist = add_list(worklist, group, 37345331Samw share, protocol); 37354653Sdougm } 37363034Sdougm } 37374653Sdougm free_opt(optlist); 37383034Sdougm } else { 37393034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 37403034Sdougm ret = SA_NO_SUCH_GROUP; 37413034Sdougm } 37423034Sdougm /* 37433034Sdougm * we have a group and potentially legal additions 37443034Sdougm */ 37453034Sdougm 37464653Sdougm /* 37474653Sdougm * Commit to configuration if not a dryrunp and properties 37484653Sdougm * have changed. 37494653Sdougm */ 37504653Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 37513034Sdougm /* properties changed, so update all shares */ 37525331Samw (void) enable_all_groups(handle, worklist, 0, 0, protocol, 37535331Samw B_TRUE); 37544653Sdougm 37553034Sdougm if (worklist != NULL) 37564653Sdougm free_list(worklist); 37573034Sdougm return (ret); 37583034Sdougm } 37593034Sdougm 37603034Sdougm /* 37613034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 37623034Sdougm * 37633034Sdougm * This function implements "set" when a name space (-S) is 37643034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 37653034Sdougm * already been done. 37663034Sdougm */ 37673034Sdougm 37683034Sdougm static int 37693910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 37705331Samw char *protocol, char *sharepath, int dryrun, char *sectype) 37713034Sdougm { 37723034Sdougm sa_group_t group; 37733034Sdougm int ret = SA_OK; 37743034Sdougm int change = 0; 37753034Sdougm struct list *worklist = NULL; 37763034Sdougm 37773034Sdougm /* 37783034Sdougm * make sure protcol and sectype are valid 37793034Sdougm */ 37803034Sdougm 37813034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 37824653Sdougm (void) printf(gettext("Option space \"%s\" not valid " 37834653Sdougm "for protocol.\n"), sectype); 37844653Sdougm return (SA_INVALID_SECURITY); 37853034Sdougm } 37863034Sdougm 37873910Sdougm group = sa_get_group(handle, groupname); 37883034Sdougm if (group != NULL) { 37894653Sdougm sa_share_t share = NULL; 37904653Sdougm if (sharepath != NULL) { 37914653Sdougm share = sa_get_share(group, sharepath); 37924653Sdougm if (share == NULL) { 37934653Sdougm (void) printf(gettext( 37944653Sdougm "Share does not exist in group %s\n"), 37954653Sdougm groupname, sharepath); 37964653Sdougm ret = SA_NO_SUCH_PATH; 37975089Sdougm } else { 37985089Sdougm /* if ZFS and OK, then only group */ 37995089Sdougm ret = zfscheck(group, share); 38005089Sdougm if (ret == SA_OK && 38015089Sdougm sa_group_is_zfs(group)) 38025089Sdougm share = NULL; 38035089Sdougm if (ret == SA_NOT_ALLOWED) 38045089Sdougm (void) printf(gettext( 38055089Sdougm "Properties on ZFS group shares " 38065089Sdougm "not supported: %s\n"), sharepath); 38074653Sdougm } 38083034Sdougm } 38094653Sdougm if (ret == SA_OK) { 38104653Sdougm /* group must exist */ 38114653Sdougm ret = valid_options(optlist, protocol, 38124653Sdougm share == NULL ? group : share, sectype); 38134653Sdougm if (ret == SA_OK && !dryrun) { 38144653Sdougm if (share != NULL) 38154653Sdougm change = add_security(share, sectype, 38164653Sdougm optlist, protocol, &ret); 38174653Sdougm else 38184653Sdougm change = add_security(group, sectype, 38194653Sdougm optlist, protocol, &ret); 38204653Sdougm if (ret != SA_OK) 38214653Sdougm (void) printf(gettext( 38224653Sdougm "Could not set property: %s\n"), 38234653Sdougm sa_errorstr(ret)); 38244653Sdougm } 38254653Sdougm if (ret == SA_OK && change) 38265331Samw worklist = add_list(worklist, group, share, 38275331Samw protocol); 38283034Sdougm } 38294653Sdougm free_opt(optlist); 38303034Sdougm } else { 38313034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 38323034Sdougm ret = SA_NO_SUCH_GROUP; 38333034Sdougm } 38345331Samw 38353034Sdougm /* 38365331Samw * We have a group and potentially legal additions. 38373034Sdougm */ 38383034Sdougm 38394653Sdougm /* Commit to configuration if not a dryrun */ 38403034Sdougm if (!dryrun && ret == 0) { 38414653Sdougm if (change && worklist != NULL) { 38424653Sdougm /* properties changed, so update all shares */ 38434653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 38445331Samw protocol, B_TRUE); 38454653Sdougm } 38464653Sdougm ret = sa_update_config(handle); 38473034Sdougm } 38483034Sdougm if (worklist != NULL) 38494653Sdougm free_list(worklist); 38503034Sdougm return (ret); 38513034Sdougm } 38523034Sdougm 38533034Sdougm /* 38543034Sdougm * sa_set(flags, argc, argv) 38553034Sdougm * 38563034Sdougm * Implements the set subcommand. It keys off of -S to determine which 38573034Sdougm * set of operations to actually do. 38583034Sdougm */ 38593034Sdougm 38603034Sdougm int 38613910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 38623034Sdougm { 38633034Sdougm char *groupname; 38643034Sdougm int verbose = 0; 38653034Sdougm int dryrun = 0; 38663034Sdougm int c; 38673034Sdougm char *protocol = NULL; 38683034Sdougm int ret = SA_OK; 38693034Sdougm struct options *optlist = NULL; 38705331Samw char *rsrcname = NULL; 38713034Sdougm char *sharepath = NULL; 38723034Sdougm char *optset = NULL; 38733034Sdougm int auth; 38743034Sdougm 38755331Samw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 38764653Sdougm switch (c) { 38774653Sdougm case 'v': 38784653Sdougm verbose++; 38794653Sdougm break; 38804653Sdougm case 'n': 38814653Sdougm dryrun++; 38824653Sdougm break; 38834653Sdougm case 'P': 38845331Samw if (protocol != NULL) { 38855331Samw (void) printf(gettext( 38865331Samw "Specifying multiple protocols " 38875331Samw "not supported: %s\n"), protocol); 38885331Samw return (SA_SYNTAX_ERR); 38895331Samw } 38904653Sdougm protocol = optarg; 38914653Sdougm if (!sa_valid_protocol(protocol)) { 38924653Sdougm (void) printf(gettext( 38934653Sdougm "Invalid protocol specified: %s\n"), 38944653Sdougm protocol); 38954653Sdougm return (SA_INVALID_PROTOCOL); 38964653Sdougm } 38974653Sdougm break; 38984653Sdougm case 'p': 38994653Sdougm ret = add_opt(&optlist, optarg, 0); 39004653Sdougm switch (ret) { 39014653Sdougm case OPT_ADD_SYNTAX: 39024653Sdougm (void) printf(gettext("Property syntax error:" 39034653Sdougm " %s\n"), optarg); 39044653Sdougm return (SA_SYNTAX_ERR); 39054653Sdougm case OPT_ADD_MEMORY: 39064653Sdougm (void) printf(gettext("No memory to set " 39074653Sdougm "property: %s\n"), optarg); 39084653Sdougm return (SA_NO_MEMORY); 39094653Sdougm default: 39104653Sdougm break; 39114653Sdougm } 39124653Sdougm break; 39135331Samw case 'r': 39145331Samw if (rsrcname != NULL) { 39155331Samw (void) printf(gettext( 39165331Samw "Setting multiple resource names not" 39175331Samw " supported\n")); 39185331Samw return (SA_SYNTAX_ERR); 39195331Samw } 39205331Samw rsrcname = optarg; 39215331Samw break; 39224653Sdougm case 's': 39235331Samw if (sharepath != NULL) { 39245331Samw (void) printf(gettext( 39255331Samw "Setting multiple shares not supported\n")); 39265331Samw return (SA_SYNTAX_ERR); 39275331Samw } 39284653Sdougm sharepath = optarg; 39294653Sdougm break; 39304653Sdougm case 'S': 39315331Samw if (optset != NULL) { 39325331Samw (void) printf(gettext( 39335331Samw "Specifying multiple property " 39345331Samw "spaces not supported: %s\n"), optset); 39355331Samw return (SA_SYNTAX_ERR); 39365331Samw } 39374653Sdougm optset = optarg; 39384653Sdougm break; 39396019Sdougm case 'h': 39406019Sdougm /* optopt on valid arg isn't defined */ 39416019Sdougm optopt = c; 39426019Sdougm /*FALLTHROUGH*/ 39436019Sdougm case '?': 39444653Sdougm default: 39456019Sdougm /* 39466019Sdougm * Since a bad option gets to here, sort it 39476019Sdougm * out and return a syntax error return value 39486019Sdougm * if necessary. 39496019Sdougm */ 39506019Sdougm switch (optopt) { 39516019Sdougm default: 39526019Sdougm ret = SA_SYNTAX_ERR; 39536019Sdougm break; 39546019Sdougm case 'h': 39556019Sdougm case '?': 39566019Sdougm break; 39576019Sdougm } 39584653Sdougm (void) printf(gettext("usage: %s\n"), 39594653Sdougm sa_get_usage(USAGE_SET)); 39606019Sdougm return (ret); 39613034Sdougm } 39623034Sdougm } 39633034Sdougm 39643034Sdougm if (optlist != NULL) 39654653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 39663034Sdougm 39673034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 39684653Sdougm protocol == NULL || ret != OPT_ADD_OK) { 39694653Sdougm char *sep = "\t"; 39704653Sdougm 39714653Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 39724653Sdougm if (optind >= argc) { 39734653Sdougm (void) printf(gettext("%sgroup must be specified"), 39744653Sdougm sep); 39754653Sdougm sep = ", "; 39764653Sdougm } 39774653Sdougm if (optlist == NULL) { 39784653Sdougm (void) printf(gettext("%sat least one property must be" 39794653Sdougm " specified"), sep); 39804653Sdougm sep = ", "; 39814653Sdougm } 39824653Sdougm if (protocol == NULL) { 39834653Sdougm (void) printf(gettext("%sprotocol must be specified"), 39844653Sdougm sep); 39854653Sdougm sep = ", "; 39864653Sdougm } 39874653Sdougm (void) printf("\n"); 39884653Sdougm ret = SA_SYNTAX_ERR; 39893034Sdougm } else { 39903034Sdougm /* 39915089Sdougm * Group already exists so we can proceed after a few 39925089Sdougm * additional checks related to ZFS handling. 39933034Sdougm */ 39943034Sdougm 39954653Sdougm groupname = argv[optind]; 39965089Sdougm if (strcmp(groupname, "zfs") == 0) { 39975089Sdougm (void) printf(gettext("Changing properties for group " 39985089Sdougm "\"zfs\" not allowed\n")); 39995089Sdougm return (SA_NOT_ALLOWED); 40005089Sdougm } 40015089Sdougm 40024653Sdougm auth = check_authorizations(groupname, flags); 40034653Sdougm if (optset == NULL) 40044653Sdougm ret = basic_set(handle, groupname, optlist, protocol, 40055331Samw sharepath, rsrcname, dryrun); 40064653Sdougm else 40074653Sdougm ret = space_set(handle, groupname, optlist, protocol, 40084653Sdougm sharepath, dryrun, optset); 40094653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 40104653Sdougm (void) printf(gettext("Command would fail: %s\n"), 40114653Sdougm sa_errorstr(SA_NO_PERMISSION)); 40124653Sdougm } 40133034Sdougm } 40143034Sdougm return (ret); 40153034Sdougm } 40163034Sdougm 40173034Sdougm /* 40183034Sdougm * remove_options(group, optlist, proto, *err) 40193034Sdougm * 40204653Sdougm * Helper function to actually remove options from a group after all 40213034Sdougm * preprocessing is done. 40223034Sdougm */ 40233034Sdougm 40243034Sdougm static int 40253034Sdougm remove_options(sa_group_t group, struct options *optlist, 40265331Samw char *proto, int *err) 40273034Sdougm { 40283034Sdougm struct options *cur; 40293034Sdougm sa_optionset_t optionset; 40303034Sdougm sa_property_t prop; 40313034Sdougm int change = 0; 40323034Sdougm int ret = SA_OK; 40333034Sdougm 40343034Sdougm optionset = sa_get_optionset(group, proto); 40353034Sdougm if (optionset != NULL) { 40364653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 40374653Sdougm prop = sa_get_property(optionset, cur->optname); 40384653Sdougm if (prop != NULL) { 40394653Sdougm ret = sa_remove_property(prop); 40404653Sdougm if (ret != SA_OK) 40414653Sdougm break; 40424653Sdougm change = 1; 40434653Sdougm } 40443034Sdougm } 40453034Sdougm } 40463034Sdougm if (ret == SA_OK && change) 40474653Sdougm ret = sa_commit_properties(optionset, 0); 40483034Sdougm 40493034Sdougm if (err != NULL) 40504653Sdougm *err = ret; 40513034Sdougm return (change); 40523034Sdougm } 40533034Sdougm 40543034Sdougm /* 40553034Sdougm * valid_unset(group, optlist, proto) 40563034Sdougm * 40573034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 40583034Sdougm * error if a property doesn't exist. 40593034Sdougm */ 40603034Sdougm 40613034Sdougm static int 40623034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 40633034Sdougm { 40643034Sdougm struct options *cur; 40653034Sdougm sa_optionset_t optionset; 40663034Sdougm sa_property_t prop; 40673034Sdougm int ret = SA_OK; 40683034Sdougm 40693034Sdougm optionset = sa_get_optionset(group, proto); 40703034Sdougm if (optionset != NULL) { 40714653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 40724653Sdougm prop = sa_get_property(optionset, cur->optname); 40734653Sdougm if (prop == NULL) { 40744653Sdougm (void) printf(gettext( 40754653Sdougm "Could not unset property %s: not set\n"), 40764653Sdougm cur->optname); 40774653Sdougm ret = SA_NO_SUCH_PROP; 40784653Sdougm } 40793034Sdougm } 40803034Sdougm } 40813034Sdougm return (ret); 40823034Sdougm } 40833034Sdougm 40843034Sdougm /* 40853034Sdougm * valid_unset_security(group, optlist, proto) 40863034Sdougm * 40873034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 40883034Sdougm * error if a property doesn't exist. 40893034Sdougm */ 40903034Sdougm 40913034Sdougm static int 40923034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 40935331Samw char *sectype) 40943034Sdougm { 40953034Sdougm struct options *cur; 40963034Sdougm sa_security_t security; 40973034Sdougm sa_property_t prop; 40983034Sdougm int ret = SA_OK; 40993034Sdougm char *sec; 41003034Sdougm 41013034Sdougm sec = sa_proto_space_alias(proto, sectype); 41023034Sdougm security = sa_get_security(group, sec, proto); 41033034Sdougm if (security != NULL) { 41044653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 41054653Sdougm prop = sa_get_property(security, cur->optname); 41064653Sdougm if (prop == NULL) { 41074653Sdougm (void) printf(gettext( 41084653Sdougm "Could not unset property %s: not set\n"), 41094653Sdougm cur->optname); 41104653Sdougm ret = SA_NO_SUCH_PROP; 41114653Sdougm } 41123034Sdougm } 41133034Sdougm } else { 41144653Sdougm (void) printf(gettext( 41154653Sdougm "Could not unset %s: space not defined\n"), sectype); 41164653Sdougm ret = SA_NO_SUCH_SECURITY; 41173034Sdougm } 41183034Sdougm if (sec != NULL) 41194653Sdougm sa_free_attr_string(sec); 41203034Sdougm return (ret); 41213034Sdougm } 41223034Sdougm 41233034Sdougm /* 41243034Sdougm * remove_security(group, optlist, proto) 41253034Sdougm * 41263034Sdougm * Remove the properties since they were checked as valid. 41273034Sdougm */ 41283034Sdougm 41293034Sdougm static int 41303034Sdougm remove_security(sa_group_t group, char *sectype, 41315331Samw struct options *optlist, char *proto, int *err) 41323034Sdougm { 41333034Sdougm sa_security_t security; 41343034Sdougm int ret = SA_OK; 41353034Sdougm int change = 0; 41363034Sdougm 41373034Sdougm sectype = sa_proto_space_alias(proto, sectype); 41383034Sdougm security = sa_get_security(group, sectype, proto); 41393034Sdougm if (sectype != NULL) 41404653Sdougm sa_free_attr_string(sectype); 41413034Sdougm 41423034Sdougm if (security != NULL) { 41434653Sdougm while (optlist != NULL) { 41444653Sdougm sa_property_t prop; 41454653Sdougm prop = sa_get_property(security, optlist->optname); 41464653Sdougm if (prop != NULL) { 41474653Sdougm ret = sa_remove_property(prop); 41484653Sdougm if (ret != SA_OK) 41494653Sdougm break; 41504653Sdougm change = 1; 41514653Sdougm } 41524653Sdougm optlist = optlist->next; 41533034Sdougm } 41543034Sdougm /* 41553034Sdougm * when done, properties may have all been removed but 41563034Sdougm * we need to keep the security type itself until 41573034Sdougm * explicitly removed. 41583034Sdougm */ 41594653Sdougm if (ret == SA_OK && change) 41604653Sdougm ret = sa_commit_properties(security, 0); 41613034Sdougm } else { 41624653Sdougm ret = SA_NO_SUCH_PROP; 41633034Sdougm } 41643034Sdougm if (err != NULL) 41654653Sdougm *err = ret; 41663034Sdougm return (change); 41673034Sdougm } 41683034Sdougm 41693034Sdougm /* 41705331Samw * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 41713034Sdougm * 41724653Sdougm * Unset non-named optionset properties. 41733034Sdougm */ 41743034Sdougm 41753034Sdougm static int 41763910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 41775331Samw char *protocol, char *sharepath, char *rsrcname, int dryrun) 41783034Sdougm { 41793034Sdougm sa_group_t group; 41803034Sdougm int ret = SA_OK; 41813034Sdougm int change = 0; 41823034Sdougm struct list *worklist = NULL; 41834653Sdougm sa_share_t share = NULL; 41845331Samw sa_resource_t resource = NULL; 41853034Sdougm 41863910Sdougm group = sa_get_group(handle, groupname); 41874653Sdougm if (group == NULL) 41884653Sdougm return (ret); 41894653Sdougm 41905331Samw /* 41915331Samw * If there is a sharepath, make sure it belongs to 41925331Samw * the group. 41935331Samw */ 41944653Sdougm if (sharepath != NULL) { 41953034Sdougm share = sa_get_share(group, sharepath); 41963034Sdougm if (share == NULL) { 41974653Sdougm (void) printf(gettext( 41984653Sdougm "Share does not exist in group %s\n"), 41994653Sdougm groupname, sharepath); 42004653Sdougm ret = SA_NO_SUCH_PATH; 42013034Sdougm } 42024653Sdougm } 42035331Samw /* 42045331Samw * If a resource name exists, make sure it belongs to 42055331Samw * the share if present else it belongs to the 42065331Samw * group. Also check the protocol to see if it 42075331Samw * supports resource level properties or not. If not, 42085331Samw * use share only. 42095331Samw */ 42105331Samw if (rsrcname != NULL) { 42115331Samw if (share != NULL) { 42125331Samw resource = sa_get_share_resource(share, rsrcname); 42135331Samw if (resource == NULL) 42145331Samw ret = SA_NO_SUCH_RESOURCE; 42155331Samw } else { 42165331Samw resource = sa_get_resource(group, rsrcname); 42175331Samw if (resource != NULL) { 42185331Samw share = sa_get_resource_parent(resource); 42195331Samw } else { 42205331Samw ret = SA_NO_SUCH_RESOURCE; 42215331Samw } 42225331Samw } 42235331Samw if (ret == SA_OK && resource != NULL) { 42245331Samw uint64_t features; 42255331Samw /* 42265331Samw * Check to see if the resource can take 42275331Samw * properties. If so, stick the resource into 42285331Samw * "share" so it will all just work. 42295331Samw */ 42305331Samw features = sa_proto_get_featureset(protocol); 42315331Samw if (features & SA_FEATURE_RESOURCE) 42325331Samw share = (sa_share_t)resource; 42335331Samw } 42345331Samw } 42355331Samw 42364653Sdougm if (ret == SA_OK) { 42373034Sdougm /* group must exist */ 42383034Sdougm ret = valid_unset(share != NULL ? share : group, 42394653Sdougm optlist, protocol); 42403034Sdougm if (ret == SA_OK && !dryrun) { 42414653Sdougm if (share != NULL) { 42424653Sdougm sa_optionset_t optionset; 42434653Sdougm sa_property_t prop; 42444653Sdougm change |= remove_options(share, optlist, 42454653Sdougm protocol, &ret); 42464653Sdougm /* 42474653Sdougm * If a share optionset is 42484653Sdougm * empty, remove it. 42494653Sdougm */ 42504653Sdougm optionset = sa_get_optionset((sa_share_t)share, 42514653Sdougm protocol); 42524653Sdougm if (optionset != NULL) { 42534653Sdougm prop = sa_get_property(optionset, NULL); 42544653Sdougm if (prop == NULL) 42554653Sdougm (void) sa_destroy_optionset( 42564653Sdougm optionset); 42574653Sdougm } 42584653Sdougm } else { 42594653Sdougm change |= remove_options(group, 42604653Sdougm optlist, protocol, &ret); 42613034Sdougm } 42624653Sdougm if (ret == SA_OK && change) 42635331Samw worklist = add_list(worklist, group, share, 42645331Samw protocol); 42654653Sdougm if (ret != SA_OK) 42664653Sdougm (void) printf(gettext( 42674653Sdougm "Could not remove properties: " 42684653Sdougm "%s\n"), sa_errorstr(ret)); 42693034Sdougm } 42704653Sdougm } else { 42715331Samw (void) printf(gettext("Group \"%s\" not found\n"), groupname); 42723034Sdougm ret = SA_NO_SUCH_GROUP; 42733034Sdougm } 42744653Sdougm free_opt(optlist); 42753034Sdougm 42763034Sdougm /* 42774653Sdougm * We have a group and potentially legal additions 42784653Sdougm * 42794653Sdougm * Commit to configuration if not a dryrun 42803034Sdougm */ 42813034Sdougm if (!dryrun && ret == SA_OK) { 42824653Sdougm if (change && worklist != NULL) { 42834653Sdougm /* properties changed, so update all shares */ 42844653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 42855331Samw protocol, B_TRUE); 42864653Sdougm } 42873034Sdougm } 42883034Sdougm if (worklist != NULL) 42894653Sdougm free_list(worklist); 42903034Sdougm return (ret); 42913034Sdougm } 42923034Sdougm 42933034Sdougm /* 42943034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 42953034Sdougm * 42964653Sdougm * Unset named optionset properties. 42973034Sdougm */ 42983034Sdougm static int 42993910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 43005331Samw char *protocol, char *sharepath, int dryrun, char *sectype) 43013034Sdougm { 43023034Sdougm sa_group_t group; 43033034Sdougm int ret = SA_OK; 43043034Sdougm int change = 0; 43053034Sdougm struct list *worklist = NULL; 43064653Sdougm sa_share_t share = NULL; 43073034Sdougm 43083910Sdougm group = sa_get_group(handle, groupname); 43094653Sdougm if (group == NULL) { 43104653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 43114653Sdougm return (SA_NO_SUCH_GROUP); 43124653Sdougm } 43134653Sdougm if (sharepath != NULL) { 43143034Sdougm share = sa_get_share(group, sharepath); 43153034Sdougm if (share == NULL) { 43164653Sdougm (void) printf(gettext( 43174653Sdougm "Share does not exist in group %s\n"), 43184653Sdougm groupname, sharepath); 43194653Sdougm return (SA_NO_SUCH_PATH); 43203034Sdougm } 43214653Sdougm } 43225331Samw ret = valid_unset_security(share != NULL ? share : group, 43235331Samw optlist, protocol, sectype); 43244653Sdougm 43254653Sdougm if (ret == SA_OK && !dryrun) { 43264653Sdougm if (optlist != NULL) { 43273034Sdougm if (share != NULL) { 43284653Sdougm sa_security_t optionset; 43294653Sdougm sa_property_t prop; 43304653Sdougm change = remove_security(share, 43314653Sdougm sectype, optlist, protocol, &ret); 43324653Sdougm 43334653Sdougm /* If a share security is empty, remove it */ 43344653Sdougm optionset = sa_get_security((sa_group_t)share, 43354653Sdougm sectype, protocol); 43364653Sdougm if (optionset != NULL) { 43374653Sdougm prop = sa_get_property(optionset, 43384653Sdougm NULL); 43394653Sdougm if (prop == NULL) 43404653Sdougm ret = sa_destroy_security( 43414653Sdougm optionset); 43424653Sdougm } 43433034Sdougm } else { 43444653Sdougm change = remove_security(group, sectype, 43454653Sdougm optlist, protocol, &ret); 43463034Sdougm } 43474653Sdougm } else { 43483034Sdougm sa_security_t security; 43493034Sdougm char *sec; 43503034Sdougm sec = sa_proto_space_alias(protocol, sectype); 43513034Sdougm security = sa_get_security(group, sec, protocol); 43523034Sdougm if (sec != NULL) 43534653Sdougm sa_free_attr_string(sec); 43543034Sdougm if (security != NULL) { 43554653Sdougm ret = sa_destroy_security(security); 43564653Sdougm if (ret == SA_OK) 43574653Sdougm change = 1; 43583034Sdougm } else { 43594653Sdougm ret = SA_NO_SUCH_PROP; 43603034Sdougm } 43614653Sdougm } 43624653Sdougm if (ret != SA_OK) 43633034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 43644653Sdougm sa_errorstr(ret)); 43653034Sdougm } 43664653Sdougm 43674653Sdougm if (ret == SA_OK && change) 43685331Samw worklist = add_list(worklist, group, 0, protocol); 43694653Sdougm 43703034Sdougm free_opt(optlist); 43713034Sdougm /* 43724653Sdougm * We have a group and potentially legal additions 43733034Sdougm */ 43743034Sdougm 43754653Sdougm /* Commit to configuration if not a dryrun */ 43763034Sdougm if (!dryrun && ret == 0) { 43773034Sdougm /* properties changed, so update all shares */ 43784653Sdougm if (change && worklist != NULL) 43794653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 43805331Samw protocol, B_TRUE); 43814653Sdougm ret = sa_update_config(handle); 43823034Sdougm } 43833034Sdougm if (worklist != NULL) 43844653Sdougm free_list(worklist); 43853034Sdougm return (ret); 43863034Sdougm } 43873034Sdougm 43883034Sdougm /* 43893034Sdougm * sa_unset(flags, argc, argv) 43903034Sdougm * 43914653Sdougm * Implements the unset subcommand. Parsing done here and then basic 43923034Sdougm * or space versions of the real code are called. 43933034Sdougm */ 43943034Sdougm 43953034Sdougm int 43963910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 43973034Sdougm { 43983034Sdougm char *groupname; 43993034Sdougm int verbose = 0; 44003034Sdougm int dryrun = 0; 44013034Sdougm int c; 44023034Sdougm char *protocol = NULL; 44033034Sdougm int ret = SA_OK; 44043034Sdougm struct options *optlist = NULL; 44055331Samw char *rsrcname = NULL; 44063034Sdougm char *sharepath = NULL; 44073034Sdougm char *optset = NULL; 44083034Sdougm int auth; 44093034Sdougm 44105331Samw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 44114653Sdougm switch (c) { 44124653Sdougm case 'v': 44134653Sdougm verbose++; 44144653Sdougm break; 44154653Sdougm case 'n': 44164653Sdougm dryrun++; 44174653Sdougm break; 44184653Sdougm case 'P': 44195331Samw if (protocol != NULL) { 44205331Samw (void) printf(gettext( 44215331Samw "Specifying multiple protocols " 44225331Samw "not supported: %s\n"), protocol); 44235331Samw return (SA_SYNTAX_ERR); 44245331Samw } 44254653Sdougm protocol = optarg; 44264653Sdougm if (!sa_valid_protocol(protocol)) { 44274653Sdougm (void) printf(gettext( 44284653Sdougm "Invalid protocol specified: %s\n"), 44294653Sdougm protocol); 44304653Sdougm return (SA_INVALID_PROTOCOL); 44314653Sdougm } 44324653Sdougm break; 44334653Sdougm case 'p': 44344653Sdougm ret = add_opt(&optlist, optarg, 1); 44354653Sdougm switch (ret) { 44364653Sdougm case OPT_ADD_SYNTAX: 44374653Sdougm (void) printf(gettext("Property syntax error " 44384653Sdougm "for property %s\n"), optarg); 44394653Sdougm return (SA_SYNTAX_ERR); 44404653Sdougm 44414653Sdougm case OPT_ADD_PROPERTY: 44424653Sdougm (void) printf(gettext("Properties need to be " 44434653Sdougm "set with set command: %s\n"), optarg); 44444653Sdougm return (SA_SYNTAX_ERR); 44454653Sdougm 44464653Sdougm default: 44474653Sdougm break; 44484653Sdougm } 44494653Sdougm break; 44505331Samw case 'r': 44515331Samw /* 44525331Samw * Unset properties on resource if applicable or on 44535331Samw * share if resource for this protocol doesn't use 44545331Samw * resources. 44555331Samw */ 44565331Samw if (rsrcname != NULL) { 44575331Samw (void) printf(gettext( 44585331Samw "Unsetting multiple resource " 44595331Samw "names not supported\n")); 44605331Samw return (SA_SYNTAX_ERR); 44615331Samw } 44625331Samw rsrcname = optarg; 44635331Samw break; 44644653Sdougm case 's': 44655331Samw if (sharepath != NULL) { 44665331Samw (void) printf(gettext( 44675331Samw "Adding multiple shares not supported\n")); 44685331Samw return (SA_SYNTAX_ERR); 44695331Samw } 44704653Sdougm sharepath = optarg; 44714653Sdougm break; 44724653Sdougm case 'S': 44735331Samw if (optset != NULL) { 44745331Samw (void) printf(gettext( 44755331Samw "Specifying multiple property " 44765331Samw "spaces not supported: %s\n"), optset); 44775331Samw return (SA_SYNTAX_ERR); 44785331Samw } 44794653Sdougm optset = optarg; 44804653Sdougm break; 44816019Sdougm case 'h': 44826019Sdougm /* optopt on valid arg isn't defined */ 44836019Sdougm optopt = c; 44846019Sdougm /*FALLTHROUGH*/ 44856019Sdougm case '?': 44864653Sdougm default: 44876019Sdougm /* 44886019Sdougm * Since a bad option gets to here, sort it 44896019Sdougm * out and return a syntax error return value 44906019Sdougm * if necessary. 44916019Sdougm */ 44926019Sdougm switch (optopt) { 44936019Sdougm default: 44946019Sdougm ret = SA_SYNTAX_ERR; 44956019Sdougm break; 44966019Sdougm case 'h': 44976019Sdougm case '?': 44986019Sdougm break; 44996019Sdougm } 45004653Sdougm (void) printf(gettext("usage: %s\n"), 45014653Sdougm sa_get_usage(USAGE_UNSET)); 45026019Sdougm return (ret); 45033034Sdougm } 45043034Sdougm } 45053034Sdougm 45063034Sdougm if (optlist != NULL) 45074653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 45083034Sdougm 45093034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 45103034Sdougm protocol == NULL) { 45114653Sdougm char *sep = "\t"; 45124653Sdougm (void) printf(gettext("usage: %s\n"), 45134653Sdougm sa_get_usage(USAGE_UNSET)); 45144653Sdougm if (optind >= argc) { 45154653Sdougm (void) printf(gettext("%sgroup must be specified"), 45164653Sdougm sep); 45174653Sdougm sep = ", "; 45184653Sdougm } 45194653Sdougm if (optlist == NULL) { 45204653Sdougm (void) printf(gettext("%sat least one property must " 45214653Sdougm "be specified"), sep); 45224653Sdougm sep = ", "; 45234653Sdougm } 45244653Sdougm if (protocol == NULL) { 45254653Sdougm (void) printf(gettext("%sprotocol must be specified"), 45264653Sdougm sep); 45274653Sdougm sep = ", "; 45284653Sdougm } 45294653Sdougm (void) printf("\n"); 45304653Sdougm ret = SA_SYNTAX_ERR; 45313034Sdougm } else { 45323034Sdougm 45333034Sdougm /* 45344653Sdougm * If a group already exists, we can only add a new 45353034Sdougm * protocol to it and not create a new one or add the 45363034Sdougm * same protocol again. 45373034Sdougm */ 45383034Sdougm 45394653Sdougm groupname = argv[optind]; 45404653Sdougm auth = check_authorizations(groupname, flags); 45414653Sdougm if (optset == NULL) 45424653Sdougm ret = basic_unset(handle, groupname, optlist, protocol, 45435331Samw sharepath, rsrcname, dryrun); 45444653Sdougm else 45454653Sdougm ret = space_unset(handle, groupname, optlist, protocol, 45464653Sdougm sharepath, dryrun, optset); 45474653Sdougm 45484653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 45494653Sdougm (void) printf(gettext("Command would fail: %s\n"), 45504653Sdougm sa_errorstr(SA_NO_PERMISSION)); 45513034Sdougm } 45523034Sdougm return (ret); 45533034Sdougm } 45543034Sdougm 45553034Sdougm /* 45563034Sdougm * sa_enable_group(flags, argc, argv) 45573034Sdougm * 45583034Sdougm * Implements the enable subcommand 45593034Sdougm */ 45603034Sdougm 45613034Sdougm int 45623910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 45633034Sdougm { 45643034Sdougm int verbose = 0; 45653034Sdougm int dryrun = 0; 45663034Sdougm int all = 0; 45673034Sdougm int c; 45683034Sdougm int ret = SA_OK; 45693034Sdougm char *protocol = NULL; 45703034Sdougm char *state; 45713034Sdougm struct list *worklist = NULL; 45723034Sdougm int auth = 1; 45734653Sdougm sa_group_t group; 45743034Sdougm 45753034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 45764653Sdougm switch (c) { 45774653Sdougm case 'a': 45784653Sdougm all = 1; 45794653Sdougm break; 45804653Sdougm case 'n': 45814653Sdougm dryrun++; 45824653Sdougm break; 45834653Sdougm case 'P': 45845331Samw if (protocol != NULL) { 45855331Samw (void) printf(gettext( 45865331Samw "Specifying multiple protocols " 45875331Samw "not supported: %s\n"), protocol); 45885331Samw return (SA_SYNTAX_ERR); 45895331Samw } 45904653Sdougm protocol = optarg; 45914653Sdougm if (!sa_valid_protocol(protocol)) { 45924653Sdougm (void) printf(gettext( 45934653Sdougm "Invalid protocol specified: %s\n"), 45943034Sdougm protocol); 45954653Sdougm return (SA_INVALID_PROTOCOL); 45964653Sdougm } 45974653Sdougm break; 45984653Sdougm case 'v': 45994653Sdougm verbose++; 46004653Sdougm break; 46014653Sdougm case 'h': 46026019Sdougm /* optopt on valid arg isn't defined */ 46036019Sdougm optopt = c; 46046019Sdougm /*FALLTHROUGH*/ 46054653Sdougm case '?': 46066019Sdougm default: 46076019Sdougm /* 46086019Sdougm * Since a bad option gets to here, sort it 46096019Sdougm * out and return a syntax error return value 46106019Sdougm * if necessary. 46116019Sdougm */ 46126019Sdougm switch (optopt) { 46136019Sdougm default: 46146019Sdougm ret = SA_SYNTAX_ERR; 46156019Sdougm break; 46166019Sdougm case 'h': 46176019Sdougm case '?': 46186019Sdougm (void) printf(gettext("usage: %s\n"), 46196019Sdougm sa_get_usage(USAGE_ENABLE)); 46206019Sdougm return (ret); 46216019Sdougm } 46223034Sdougm } 46233034Sdougm } 46243034Sdougm 46253034Sdougm if (optind == argc && !all) { 46264653Sdougm (void) printf(gettext("usage: %s\n"), 46274653Sdougm sa_get_usage(USAGE_ENABLE)); 46284653Sdougm (void) printf(gettext("\tmust specify group\n")); 46294653Sdougm return (SA_NO_SUCH_PATH); 46304653Sdougm } 46314653Sdougm if (!all) { 46323034Sdougm while (optind < argc) { 46334653Sdougm group = sa_get_group(handle, argv[optind]); 46344653Sdougm if (group != NULL) { 46354653Sdougm auth &= check_authorizations(argv[optind], 46364653Sdougm flags); 46374653Sdougm state = sa_get_group_attr(group, "state"); 46384653Sdougm if (state != NULL && 46394653Sdougm strcmp(state, "enabled") == 0) { 46404653Sdougm /* already enabled */ 46414653Sdougm if (verbose) 46424653Sdougm (void) printf(gettext( 46434653Sdougm "Group \"%s\" is already " 46444653Sdougm "enabled\n"), 46454653Sdougm argv[optind]); 46464653Sdougm ret = SA_BUSY; /* already enabled */ 46474653Sdougm } else { 46484653Sdougm worklist = add_list(worklist, group, 46495331Samw 0, protocol); 46504653Sdougm if (verbose) 46514653Sdougm (void) printf(gettext( 46524653Sdougm "Enabling group \"%s\"\n"), 46534653Sdougm argv[optind]); 46544653Sdougm } 46554653Sdougm if (state != NULL) 46564653Sdougm sa_free_attr_string(state); 46573034Sdougm } else { 46584653Sdougm ret = SA_NO_SUCH_GROUP; 46593034Sdougm } 46604653Sdougm optind++; 46613034Sdougm } 46624653Sdougm } else { 46634653Sdougm for (group = sa_get_group(handle, NULL); 46644653Sdougm group != NULL; 46653034Sdougm group = sa_get_next_group(group)) { 46665331Samw worklist = add_list(worklist, group, 0, protocol); 46673034Sdougm } 46684653Sdougm } 46694653Sdougm if (!dryrun && ret == SA_OK) 46705331Samw ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE); 46714653Sdougm 46724653Sdougm if (ret != SA_OK && ret != SA_BUSY) 46733034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 46744653Sdougm sa_errorstr(ret)); 46754653Sdougm if (ret == SA_BUSY) 46763034Sdougm ret = SA_OK; 46774653Sdougm 46783034Sdougm if (worklist != NULL) 46794653Sdougm free_list(worklist); 46803034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 46814653Sdougm (void) printf(gettext("Command would fail: %s\n"), 46824653Sdougm sa_errorstr(SA_NO_PERMISSION)); 46833034Sdougm } 46843034Sdougm return (ret); 46853034Sdougm } 46863034Sdougm 46873034Sdougm /* 46885331Samw * disable_group(group, proto) 46893034Sdougm * 46905331Samw * Disable all the shares in the specified group.. This is a helper 46915331Samw * for disable_all_groups in order to simplify regular and subgroup 46925331Samw * (zfs) disabling. Group has already been checked for non-NULL. 46933034Sdougm */ 46943034Sdougm 46953034Sdougm static int 46965331Samw disable_group(sa_group_t group, char *proto) 46973034Sdougm { 46983034Sdougm sa_share_t share; 46993034Sdougm int ret = SA_OK; 47003034Sdougm 47015331Samw /* 47025331Samw * If the protocol isn't enabled, skip it and treat as 47035331Samw * successful. 47045331Samw */ 47055331Samw if (!has_protocol(group, proto)) 47065331Samw return (ret); 47075331Samw 47083034Sdougm for (share = sa_get_share(group, NULL); 47093034Sdougm share != NULL && ret == SA_OK; 47103034Sdougm share = sa_get_next_share(share)) { 47115331Samw ret = sa_disable_share(share, proto); 47124653Sdougm if (ret == SA_NO_SUCH_PATH) { 47134653Sdougm /* 47144653Sdougm * this is OK since the path is gone. we can't 47154653Sdougm * re-share it anyway so no error. 47164653Sdougm */ 47174653Sdougm ret = SA_OK; 47184653Sdougm } 47193034Sdougm } 47203034Sdougm return (ret); 47213034Sdougm } 47223034Sdougm 47233034Sdougm /* 47243034Sdougm * disable_all_groups(work, setstate) 47253034Sdougm * 47263034Sdougm * helper function that disables the shares in the list of groups 47273034Sdougm * provided. It optionally marks the group as disabled. Used by both 47283034Sdougm * enable and start subcommands. 47293034Sdougm */ 47303034Sdougm 47313034Sdougm static int 47323910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 47333034Sdougm { 47343034Sdougm int ret = SA_OK; 47353034Sdougm sa_group_t subgroup, group; 47363034Sdougm 47373034Sdougm while (work != NULL && ret == SA_OK) { 47384653Sdougm group = (sa_group_t)work->item; 47394653Sdougm if (setstate) 47404653Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 47414653Sdougm if (ret == SA_OK) { 47424653Sdougm char *name; 47434653Sdougm name = sa_get_group_attr(group, "name"); 47444653Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 47454653Sdougm /* need to get the sub-groups for stopping */ 47464653Sdougm for (subgroup = sa_get_sub_group(group); 47474653Sdougm subgroup != NULL; 47484653Sdougm subgroup = sa_get_next_group(subgroup)) { 47495331Samw ret = disable_group(subgroup, 47505331Samw work->proto); 47514653Sdougm } 47524653Sdougm } else { 47535331Samw ret = disable_group(group, work->proto); 47544653Sdougm } 47554653Sdougm /* 47564653Sdougm * We don't want to "disable" since it won't come 47574653Sdougm * up after a reboot. The SMF framework should do 47584653Sdougm * the right thing. On enable we do want to do 47594653Sdougm * something. 47604653Sdougm */ 47613034Sdougm } 47624653Sdougm work = work->next; 47633034Sdougm } 47643034Sdougm if (ret == SA_OK) 47654653Sdougm ret = sa_update_config(handle); 47663034Sdougm return (ret); 47673034Sdougm } 47683034Sdougm 47693034Sdougm /* 47703034Sdougm * sa_disable_group(flags, argc, argv) 47713034Sdougm * 47723034Sdougm * Implements the disable subcommand 47733034Sdougm */ 47743034Sdougm 47753034Sdougm int 47763910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 47773034Sdougm { 47783034Sdougm int verbose = 0; 47793034Sdougm int dryrun = 0; 47803034Sdougm int all = 0; 47813034Sdougm int c; 47823034Sdougm int ret = SA_OK; 47835331Samw char *protocol = NULL; 47843034Sdougm char *state; 47853034Sdougm struct list *worklist = NULL; 47864653Sdougm sa_group_t group; 47873034Sdougm int auth = 1; 47883034Sdougm 47893034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 47904653Sdougm switch (c) { 47914653Sdougm case 'a': 47924653Sdougm all = 1; 47934653Sdougm break; 47944653Sdougm case 'n': 47954653Sdougm dryrun++; 47964653Sdougm break; 47974653Sdougm case 'P': 47985331Samw if (protocol != NULL) { 47995331Samw (void) printf(gettext( 48005331Samw "Specifying multiple protocols " 48015331Samw "not supported: %s\n"), protocol); 48025331Samw return (SA_SYNTAX_ERR); 48035331Samw } 48044653Sdougm protocol = optarg; 48054653Sdougm if (!sa_valid_protocol(protocol)) { 48064653Sdougm (void) printf(gettext( 48074653Sdougm "Invalid protocol specified: %s\n"), 48084653Sdougm protocol); 48094653Sdougm return (SA_INVALID_PROTOCOL); 48104653Sdougm } 48114653Sdougm break; 48124653Sdougm case 'v': 48134653Sdougm verbose++; 48144653Sdougm break; 48156019Sdougm case 'h': 48166019Sdougm /* optopt on valid arg isn't defined */ 48176019Sdougm optopt = c; 48186019Sdougm /*FALLTHROUGH*/ 48196019Sdougm case '?': 48204653Sdougm default: 48216019Sdougm /* 48226019Sdougm * Since a bad option gets to here, sort it 48236019Sdougm * out and return a syntax error return value 48246019Sdougm * if necessary. 48256019Sdougm */ 48266019Sdougm switch (optopt) { 48276019Sdougm default: 48286019Sdougm ret = SA_SYNTAX_ERR; 48296019Sdougm break; 48306019Sdougm case 'h': 48316019Sdougm case '?': 48326019Sdougm break; 48336019Sdougm } 48344653Sdougm (void) printf(gettext("usage: %s\n"), 48354653Sdougm sa_get_usage(USAGE_DISABLE)); 48366019Sdougm return (ret); 48373034Sdougm } 48383034Sdougm } 48393034Sdougm 48403034Sdougm if (optind == argc && !all) { 48413034Sdougm (void) printf(gettext("usage: %s\n"), 48424653Sdougm sa_get_usage(USAGE_DISABLE)); 48433034Sdougm (void) printf(gettext("\tmust specify group\n")); 48444653Sdougm return (SA_NO_SUCH_PATH); 48454653Sdougm } 48464653Sdougm if (!all) { 48474653Sdougm while (optind < argc) { 48483910Sdougm group = sa_get_group(handle, argv[optind]); 48493034Sdougm if (group != NULL) { 48504653Sdougm auth &= check_authorizations(argv[optind], 48514653Sdougm flags); 48524653Sdougm state = sa_get_group_attr(group, "state"); 48534653Sdougm if (state == NULL || 48544653Sdougm strcmp(state, "disabled") == 0) { 48554653Sdougm /* already disabled */ 48564653Sdougm if (verbose) 48574653Sdougm (void) printf(gettext( 48584653Sdougm "Group \"%s\" is " 48594653Sdougm "already disabled\n"), 48604653Sdougm argv[optind]); 48615331Samw ret = SA_BUSY; /* already disabled */ 48624653Sdougm } else { 48635331Samw worklist = add_list(worklist, group, 0, 48645331Samw protocol); 48654653Sdougm if (verbose) 48664653Sdougm (void) printf(gettext( 48674653Sdougm "Disabling group " 48684653Sdougm "\"%s\"\n"), argv[optind]); 48694653Sdougm } 48704653Sdougm if (state != NULL) 48714653Sdougm sa_free_attr_string(state); 48723034Sdougm } else { 48734653Sdougm ret = SA_NO_SUCH_GROUP; 48743034Sdougm } 48753034Sdougm optind++; 48764653Sdougm } 48774653Sdougm } else { 48784653Sdougm for (group = sa_get_group(handle, NULL); 48794653Sdougm group != NULL; 48804653Sdougm group = sa_get_next_group(group)) 48815331Samw worklist = add_list(worklist, group, 0, protocol); 48823034Sdougm } 48834653Sdougm 48844653Sdougm if (ret == SA_OK && !dryrun) 48854653Sdougm ret = disable_all_groups(handle, worklist, 1); 48864653Sdougm if (ret != SA_OK && ret != SA_BUSY) 48874653Sdougm (void) printf(gettext("Could not disable group: %s\n"), 48884653Sdougm sa_errorstr(ret)); 48894653Sdougm if (ret == SA_BUSY) 48904653Sdougm ret = SA_OK; 48913034Sdougm if (worklist != NULL) 48924653Sdougm free_list(worklist); 48934653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 48944653Sdougm (void) printf(gettext("Command would fail: %s\n"), 48954653Sdougm sa_errorstr(SA_NO_PERMISSION)); 48963034Sdougm return (ret); 48973034Sdougm } 48983034Sdougm 48993034Sdougm /* 49003034Sdougm * sa_start_group(flags, argc, argv) 49013034Sdougm * 49023034Sdougm * Implements the start command. 49033034Sdougm * This is similar to enable except it doesn't change the state 49043034Sdougm * of the group(s) and only enables shares if the group is already 49053034Sdougm * enabled. 49063034Sdougm */ 49075331Samw 49083034Sdougm int 49093910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 49103034Sdougm { 49113034Sdougm int verbose = 0; 49123034Sdougm int all = 0; 49133034Sdougm int c; 49143034Sdougm int ret = SMF_EXIT_OK; 49153034Sdougm char *protocol = NULL; 49163034Sdougm char *state; 49173034Sdougm struct list *worklist = NULL; 49184653Sdougm sa_group_t group; 49195331Samw #ifdef lint 49205331Samw flags = flags; 49215331Samw #endif 49223034Sdougm 49233034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 49244653Sdougm switch (c) { 49254653Sdougm case 'a': 49264653Sdougm all = 1; 49274653Sdougm break; 49284653Sdougm case 'P': 49295331Samw if (protocol != NULL) { 49305331Samw (void) printf(gettext( 49315331Samw "Specifying multiple protocols " 49325331Samw "not supported: %s\n"), protocol); 49335331Samw return (SA_SYNTAX_ERR); 49345331Samw } 49354653Sdougm protocol = optarg; 49364653Sdougm if (!sa_valid_protocol(protocol)) { 49374653Sdougm (void) printf(gettext( 49384653Sdougm "Invalid protocol specified: %s\n"), 49393034Sdougm protocol); 49404653Sdougm return (SA_INVALID_PROTOCOL); 49414653Sdougm } 49424653Sdougm break; 49434653Sdougm case 'v': 49444653Sdougm verbose++; 49454653Sdougm break; 49466019Sdougm case 'h': 49476019Sdougm /* optopt on valid arg isn't defined */ 49486019Sdougm optopt = c; 49496019Sdougm /*FALLTHROUGH*/ 49506019Sdougm case '?': 49514653Sdougm default: 49526019Sdougm /* 49536019Sdougm * Since a bad option gets to here, sort it 49546019Sdougm * out and return a syntax error return value 49556019Sdougm * if necessary. 49566019Sdougm */ 49576019Sdougm ret = SA_OK; 49586019Sdougm switch (optopt) { 49596019Sdougm default: 49606019Sdougm ret = SA_SYNTAX_ERR; 49616019Sdougm break; 49626019Sdougm case 'h': 49636019Sdougm case '?': 49646019Sdougm break; 49656019Sdougm } 49664653Sdougm (void) printf(gettext("usage: %s\n"), 49674653Sdougm sa_get_usage(USAGE_START)); 49686019Sdougm return (ret); 49693034Sdougm } 49703034Sdougm } 49713034Sdougm 49723034Sdougm if (optind == argc && !all) { 49733034Sdougm (void) printf(gettext("usage: %s\n"), 49744653Sdougm sa_get_usage(USAGE_START)); 49754653Sdougm return (SMF_EXIT_ERR_FATAL); 49764653Sdougm } 49774653Sdougm 49784653Sdougm if (!all) { 49794653Sdougm while (optind < argc) { 49803910Sdougm group = sa_get_group(handle, argv[optind]); 49813034Sdougm if (group != NULL) { 49824653Sdougm state = sa_get_group_attr(group, "state"); 49834653Sdougm if (state == NULL || 49844653Sdougm strcmp(state, "enabled") == 0) { 49855331Samw worklist = add_list(worklist, group, 0, 49865331Samw protocol); 49874653Sdougm if (verbose) 49884653Sdougm (void) printf(gettext( 49894653Sdougm "Starting group \"%s\"\n"), 49904653Sdougm argv[optind]); 49914653Sdougm } else { 49924653Sdougm /* 49934653Sdougm * Determine if there are any 49945331Samw * protocols. If there aren't any, 49954653Sdougm * then there isn't anything to do in 49964653Sdougm * any case so no error. 49974653Sdougm */ 49984653Sdougm if (sa_get_optionset(group, 49994653Sdougm protocol) != NULL) { 50004653Sdougm ret = SMF_EXIT_OK; 50014653Sdougm } 50023034Sdougm } 50034653Sdougm if (state != NULL) 50044653Sdougm sa_free_attr_string(state); 50053034Sdougm } 50063034Sdougm optind++; 50074653Sdougm } 50084653Sdougm } else { 50095331Samw for (group = sa_get_group(handle, NULL); 50105331Samw group != NULL; 50114653Sdougm group = sa_get_next_group(group)) { 50123034Sdougm state = sa_get_group_attr(group, "state"); 50133034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 50145331Samw worklist = add_list(worklist, group, 0, 50155331Samw protocol); 50163034Sdougm if (state != NULL) 50174653Sdougm sa_free_attr_string(state); 50183034Sdougm } 50193034Sdougm } 50204653Sdougm 50215331Samw (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE); 50224653Sdougm 50233034Sdougm if (worklist != NULL) 50244653Sdougm free_list(worklist); 50253034Sdougm return (ret); 50263034Sdougm } 50273034Sdougm 50283034Sdougm /* 50293034Sdougm * sa_stop_group(flags, argc, argv) 50303034Sdougm * 50313034Sdougm * Implements the stop command. 50323034Sdougm * This is similar to disable except it doesn't change the state 50333034Sdougm * of the group(s) and only disables shares if the group is already 50343034Sdougm * enabled. 50353034Sdougm */ 50363034Sdougm int 50373910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 50383034Sdougm { 50393034Sdougm int verbose = 0; 50403034Sdougm int all = 0; 50413034Sdougm int c; 50423034Sdougm int ret = SMF_EXIT_OK; 50433034Sdougm char *protocol = NULL; 50443034Sdougm char *state; 50453034Sdougm struct list *worklist = NULL; 50464653Sdougm sa_group_t group; 50475331Samw #ifdef lint 50485331Samw flags = flags; 50495331Samw #endif 50503034Sdougm 50513034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 50524653Sdougm switch (c) { 50534653Sdougm case 'a': 50544653Sdougm all = 1; 50554653Sdougm break; 50564653Sdougm case 'P': 50575331Samw if (protocol != NULL) { 50585331Samw (void) printf(gettext( 50595331Samw "Specifying multiple protocols " 50605331Samw "not supported: %s\n"), protocol); 50615331Samw return (SA_SYNTAX_ERR); 50625331Samw } 50634653Sdougm protocol = optarg; 50644653Sdougm if (!sa_valid_protocol(protocol)) { 50654653Sdougm (void) printf(gettext( 50664653Sdougm "Invalid protocol specified: %s\n"), 50674653Sdougm protocol); 50684653Sdougm return (SA_INVALID_PROTOCOL); 50694653Sdougm } 50704653Sdougm break; 50714653Sdougm case 'v': 50724653Sdougm verbose++; 50734653Sdougm break; 50746019Sdougm case 'h': 50756019Sdougm /* optopt on valid arg isn't defined */ 50766019Sdougm optopt = c; 50776019Sdougm /*FALLTHROUGH*/ 50786019Sdougm case '?': 50794653Sdougm default: 50806019Sdougm /* 50816019Sdougm * Since a bad option gets to here, sort it 50826019Sdougm * out and return a syntax error return value 50836019Sdougm * if necessary. 50846019Sdougm */ 50856019Sdougm ret = SA_OK; 50866019Sdougm switch (optopt) { 50876019Sdougm default: 50886019Sdougm ret = SA_SYNTAX_ERR; 50896019Sdougm break; 50906019Sdougm case 'h': 50916019Sdougm case '?': 50926019Sdougm break; 50936019Sdougm } 50944653Sdougm (void) printf(gettext("usage: %s\n"), 50954653Sdougm sa_get_usage(USAGE_STOP)); 50966019Sdougm return (ret); 50973034Sdougm } 50983034Sdougm } 50993034Sdougm 51003034Sdougm if (optind == argc && !all) { 51014653Sdougm (void) printf(gettext("usage: %s\n"), 51024653Sdougm sa_get_usage(USAGE_STOP)); 51034653Sdougm return (SMF_EXIT_ERR_FATAL); 51044653Sdougm } else if (!all) { 51054653Sdougm while (optind < argc) { 51063910Sdougm group = sa_get_group(handle, argv[optind]); 51073034Sdougm if (group != NULL) { 51084653Sdougm state = sa_get_group_attr(group, "state"); 51094653Sdougm if (state == NULL || 51104653Sdougm strcmp(state, "enabled") == 0) { 51115331Samw worklist = add_list(worklist, group, 0, 51125331Samw protocol); 51134653Sdougm if (verbose) 51144653Sdougm (void) printf(gettext( 51154653Sdougm "Stopping group \"%s\"\n"), 51164653Sdougm argv[optind]); 51174653Sdougm } else { 51184653Sdougm ret = SMF_EXIT_OK; 51194653Sdougm } 51204653Sdougm if (state != NULL) 51214653Sdougm sa_free_attr_string(state); 51223034Sdougm } 51233034Sdougm optind++; 51244653Sdougm } 51254653Sdougm } else { 51265331Samw for (group = sa_get_group(handle, NULL); 51275331Samw group != NULL; 51284653Sdougm group = sa_get_next_group(group)) { 51293034Sdougm state = sa_get_group_attr(group, "state"); 51303034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 51315331Samw worklist = add_list(worklist, group, 0, 51325331Samw protocol); 51333034Sdougm if (state != NULL) 51344653Sdougm sa_free_attr_string(state); 51353034Sdougm } 51363034Sdougm } 51374653Sdougm (void) disable_all_groups(handle, worklist, 0); 51384653Sdougm ret = sa_update_config(handle); 51394653Sdougm 51403034Sdougm if (worklist != NULL) 51414653Sdougm free_list(worklist); 51423034Sdougm return (ret); 51433034Sdougm } 51443034Sdougm 51453034Sdougm /* 51463034Sdougm * remove_all_options(share, proto) 51473034Sdougm * 51483034Sdougm * Removes all options on a share. 51493034Sdougm */ 51503034Sdougm 51513034Sdougm static void 51523034Sdougm remove_all_options(sa_share_t share, char *proto) 51533034Sdougm { 51543034Sdougm sa_optionset_t optionset; 51553034Sdougm sa_security_t security; 51563034Sdougm sa_security_t prevsec = NULL; 51573034Sdougm 51583034Sdougm optionset = sa_get_optionset(share, proto); 51593034Sdougm if (optionset != NULL) 51604653Sdougm (void) sa_destroy_optionset(optionset); 51613034Sdougm for (security = sa_get_security(share, NULL, NULL); 51623034Sdougm security != NULL; 51633034Sdougm security = sa_get_next_security(security)) { 51644653Sdougm char *type; 51653034Sdougm /* 51664653Sdougm * We walk through the list. prevsec keeps the 51673034Sdougm * previous security so we can delete it without 51683034Sdougm * destroying the list. 51693034Sdougm */ 51704653Sdougm if (prevsec != NULL) { 51714653Sdougm /* remove the previously seen security */ 51724653Sdougm (void) sa_destroy_security(prevsec); 51734653Sdougm /* set to NULL so we don't try multiple times */ 51744653Sdougm prevsec = NULL; 51754653Sdougm } 51764653Sdougm type = sa_get_security_attr(security, "type"); 51774653Sdougm if (type != NULL) { 51784653Sdougm /* 51794653Sdougm * if the security matches the specified protocol, we 51804653Sdougm * want to remove it. prevsec holds it until either 51814653Sdougm * the next pass or we fall out of the loop. 51824653Sdougm */ 51834653Sdougm if (strcmp(type, proto) == 0) 51844653Sdougm prevsec = security; 51854653Sdougm sa_free_attr_string(type); 51864653Sdougm } 51873034Sdougm } 51883034Sdougm /* in case there is one left */ 51893034Sdougm if (prevsec != NULL) 51904653Sdougm (void) sa_destroy_security(prevsec); 51913034Sdougm } 51923034Sdougm 51933034Sdougm 51943034Sdougm /* 51953034Sdougm * for legacy support, we need to handle the old syntax. This is what 51963034Sdougm * we get if sharemgr is called with the name "share" rather than 51973034Sdougm * sharemgr. 51983034Sdougm */ 51993034Sdougm 52003034Sdougm static int 52013034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 52023034Sdougm { 52033034Sdougm int err; 52043034Sdougm 52053034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 52063034Sdougm if (err > buffsize) 52074653Sdougm return (-1); 52083034Sdougm return (0); 52093034Sdougm } 52103034Sdougm 52113034Sdougm 52123034Sdougm /* 52133034Sdougm * check_legacy_cmd(proto, cmd) 52143034Sdougm * 52153034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 52163034Sdougm * executable. 52173034Sdougm */ 52183034Sdougm 52193034Sdougm static int 52203034Sdougm check_legacy_cmd(char *path) 52213034Sdougm { 52223034Sdougm struct stat st; 52233034Sdougm int ret = 0; 52243034Sdougm 52253034Sdougm if (stat(path, &st) == 0) { 52264653Sdougm if (S_ISREG(st.st_mode) && 52274653Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 52284653Sdougm ret = 1; 52293034Sdougm } 52303034Sdougm return (ret); 52313034Sdougm } 52323034Sdougm 52333034Sdougm /* 52343034Sdougm * run_legacy_command(proto, cmd, argv) 52353034Sdougm * 52364653Sdougm * We know the command exists, so attempt to execute it with all the 52373034Sdougm * arguments. This implements full legacy share support for those 52383034Sdougm * protocols that don't have plugin providers. 52393034Sdougm */ 52403034Sdougm 52413034Sdougm static int 52423034Sdougm run_legacy_command(char *path, char *argv[]) 52433034Sdougm { 52443034Sdougm int ret; 52453034Sdougm 52463034Sdougm ret = execv(path, argv); 52473034Sdougm if (ret < 0) { 52484653Sdougm switch (errno) { 52494653Sdougm case EACCES: 52504653Sdougm ret = SA_NO_PERMISSION; 52514653Sdougm break; 52524653Sdougm default: 52534653Sdougm ret = SA_SYSTEM_ERR; 52544653Sdougm break; 52554653Sdougm } 52563034Sdougm } 52573034Sdougm return (ret); 52583034Sdougm } 52593034Sdougm 52603034Sdougm /* 52613348Sdougm * out_share(out, group, proto) 52623034Sdougm * 52633034Sdougm * Display the share information in the format that the "share" 52643034Sdougm * command has traditionally used. 52653034Sdougm */ 52663034Sdougm 52673034Sdougm static void 52683348Sdougm out_share(FILE *out, sa_group_t group, char *proto) 52693034Sdougm { 52703034Sdougm sa_share_t share; 52713034Sdougm char resfmt[128]; 52725331Samw char *defprop; 52735331Samw 52745331Samw /* 52755331Samw * The original share command defaulted to displaying NFS 52765331Samw * shares or allowed a protocol to be specified. We want to 52775331Samw * skip those shares that are not the specified protocol. 52785331Samw */ 52795331Samw if (proto != NULL && sa_get_optionset(group, proto) == NULL) 52805331Samw return; 52815331Samw 52825331Samw if (proto == NULL) 52835331Samw proto = "nfs"; 52845331Samw 52855331Samw /* 52865331Samw * get the default property string. NFS uses "rw" but 52875331Samw * everything else will use "". 52885331Samw */ 52895331Samw if (proto != NULL && strcmp(proto, "nfs") != 0) 52905331Samw defprop = "\"\""; 52915331Samw else 52925331Samw defprop = "rw"; 52933034Sdougm 52944653Sdougm for (share = sa_get_share(group, NULL); 52954653Sdougm share != NULL; 52964653Sdougm share = sa_get_next_share(share)) { 52974653Sdougm char *path; 52984653Sdougm char *type; 52994653Sdougm char *resource; 53004653Sdougm char *description; 53014653Sdougm char *groupname; 53024653Sdougm char *sharedstate; 53034653Sdougm int shared = 1; 53044653Sdougm char *soptions; 53055331Samw char shareopts[MAXNAMLEN]; 53064653Sdougm 53074653Sdougm sharedstate = sa_get_share_attr(share, "shared"); 53084653Sdougm path = sa_get_share_attr(share, "path"); 53094653Sdougm type = sa_get_share_attr(share, "type"); 53105331Samw resource = get_resource(share); 53114653Sdougm groupname = sa_get_group_attr(group, "name"); 53124653Sdougm 53134653Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 53144653Sdougm sa_free_attr_string(groupname); 53154653Sdougm groupname = NULL; 53164653Sdougm } 53174653Sdougm description = sa_get_share_description(share); 53184653Sdougm 53195331Samw /* 53205331Samw * Want the sharetab version if it exists, defaulting 53215331Samw * to NFS if no protocol specified. 53225331Samw */ 53235331Samw (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto); 53245331Samw soptions = sa_get_share_attr(share, shareopts); 53254653Sdougm 53264653Sdougm if (sharedstate == NULL) 53274653Sdougm shared = 0; 53284653Sdougm 53294653Sdougm if (soptions == NULL) 53304653Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 53314653Sdougm 53324653Sdougm if (shared) { 53334653Sdougm /* only active shares go here */ 53344653Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 53354653Sdougm resource != NULL ? resource : "-", 53364653Sdougm groupname != NULL ? "@" : "", 53374653Sdougm groupname != NULL ? groupname : ""); 53384653Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 53394653Sdougm resfmt, path, 53404653Sdougm (soptions != NULL && strlen(soptions) > 0) ? 53415331Samw soptions : defprop, 53424653Sdougm (description != NULL) ? description : ""); 53434653Sdougm } 53444653Sdougm 53454653Sdougm if (path != NULL) 53464653Sdougm sa_free_attr_string(path); 53474653Sdougm if (type != NULL) 53484653Sdougm sa_free_attr_string(type); 53494653Sdougm if (resource != NULL) 53504653Sdougm sa_free_attr_string(resource); 53514653Sdougm if (groupname != NULL) 53524653Sdougm sa_free_attr_string(groupname); 53534653Sdougm if (description != NULL) 53544653Sdougm sa_free_share_description(description); 53554653Sdougm if (sharedstate != NULL) 53564653Sdougm sa_free_attr_string(sharedstate); 53574653Sdougm if (soptions != NULL) 53584653Sdougm sa_format_free(soptions); 53593034Sdougm } 53603034Sdougm } 53613034Sdougm 53623034Sdougm /* 53633034Sdougm * output_legacy_file(out, proto) 53643034Sdougm * 53653034Sdougm * Walk all of the groups for the specified protocol and call 53663034Sdougm * out_share() to format and write in the format displayed by the 53673034Sdougm * "share" command with no arguments. 53683034Sdougm */ 53693034Sdougm 53703034Sdougm static void 53713910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 53723034Sdougm { 53733034Sdougm sa_group_t group; 53743034Sdougm 53755331Samw for (group = sa_get_group(handle, NULL); 53765331Samw group != NULL; 53774653Sdougm group = sa_get_next_group(group)) { 53784653Sdougm char *zfs; 53793034Sdougm 53803034Sdougm /* 53815331Samw * Go through all the groups and ZFS 53825331Samw * sub-groups. out_share() will format the shares in 53835331Samw * the group appropriately. 53843034Sdougm */ 53853034Sdougm 53864653Sdougm zfs = sa_get_group_attr(group, "zfs"); 53874653Sdougm if (zfs != NULL) { 53884653Sdougm sa_group_t zgroup; 53894653Sdougm sa_free_attr_string(zfs); 53904653Sdougm for (zgroup = sa_get_sub_group(group); 53914653Sdougm zgroup != NULL; 53924653Sdougm zgroup = sa_get_next_group(zgroup)) { 53934653Sdougm 53944653Sdougm /* got a group, so display it */ 53954653Sdougm out_share(out, zgroup, proto); 53964653Sdougm } 53974653Sdougm } else { 53984653Sdougm out_share(out, group, proto); 53993034Sdougm } 54003034Sdougm } 54013034Sdougm } 54023034Sdougm 54033034Sdougm int 54043910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 54053034Sdougm { 54063034Sdougm char *protocol = "nfs"; 54073034Sdougm char *options = NULL; 54083034Sdougm char *description = NULL; 54093034Sdougm char *groupname = NULL; 54103034Sdougm char *sharepath = NULL; 54113034Sdougm char *resource = NULL; 54123034Sdougm char *groupstatus = NULL; 54133034Sdougm int persist = SA_SHARE_TRANSIENT; 54143034Sdougm int argsused = 0; 54153034Sdougm int c; 54163034Sdougm int ret = SA_OK; 54173034Sdougm int zfs = 0; 54183034Sdougm int true_legacy = 0; 54193034Sdougm int curtype = SA_SHARE_TRANSIENT; 54203034Sdougm char cmd[MAXPATHLEN]; 54214653Sdougm sa_group_t group = NULL; 54225331Samw sa_resource_t rsrc = NULL; 54234653Sdougm sa_share_t share; 54244653Sdougm char dir[MAXPATHLEN]; 54255331Samw uint64_t features; 54265331Samw #ifdef lint 54275331Samw flags = flags; 54285331Samw #endif 54293034Sdougm 54303034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 54314653Sdougm switch (c) { 54324653Sdougm case 'd': 54334653Sdougm description = optarg; 54344653Sdougm argsused++; 54354653Sdougm break; 54364653Sdougm case 'F': 54374653Sdougm protocol = optarg; 54384653Sdougm if (!sa_valid_protocol(protocol)) { 54394653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 54404653Sdougm protocol, "share") == 0 && 54414653Sdougm check_legacy_cmd(cmd)) { 54424653Sdougm true_legacy++; 54434653Sdougm } else { 54444653Sdougm (void) fprintf(stderr, gettext( 54454653Sdougm "Invalid protocol specified: " 54464653Sdougm "%s\n"), protocol); 54474653Sdougm return (SA_INVALID_PROTOCOL); 54484653Sdougm } 54494653Sdougm } 54504653Sdougm break; 54514653Sdougm case 'o': 54524653Sdougm options = optarg; 54534653Sdougm argsused++; 54544653Sdougm break; 54554653Sdougm case 'p': 54564653Sdougm persist = SA_SHARE_PERMANENT; 54574653Sdougm argsused++; 54584653Sdougm break; 54594653Sdougm case 'h': 54606019Sdougm /* optopt on valid arg isn't defined */ 54616019Sdougm optopt = c; 54626019Sdougm /*FALLTHROUGH*/ 54634653Sdougm case '?': 54644653Sdougm default: 54656019Sdougm /* 54666019Sdougm * Since a bad option gets to here, sort it 54676019Sdougm * out and return a syntax error return value 54686019Sdougm * if necessary. 54696019Sdougm */ 54706019Sdougm switch (optopt) { 54716019Sdougm default: 54726019Sdougm ret = SA_LEGACY_ERR; 54736019Sdougm break; 54746019Sdougm case 'h': 54756019Sdougm case '?': 54766019Sdougm break; 54776019Sdougm } 54784653Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 54794653Sdougm sa_get_usage(USAGE_SHARE)); 54806019Sdougm return (ret); 54813034Sdougm } 54824653Sdougm } 54834653Sdougm 54844653Sdougm /* Have the info so construct what is needed */ 54854653Sdougm if (!argsused && optind == argc) { 54864653Sdougm /* display current info in share format */ 54875331Samw (void) output_legacy_file(stdout, protocol, handle); 54884653Sdougm return (ret); 54893034Sdougm } 54903034Sdougm 54914653Sdougm /* We are modifying the configuration */ 54924653Sdougm if (optind == argc) { 54933034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 54944653Sdougm sa_get_usage(USAGE_SHARE)); 54953034Sdougm return (SA_LEGACY_ERR); 54964653Sdougm } 54974653Sdougm if (true_legacy) { 54984653Sdougm /* If still using legacy share/unshare, exec it */ 54993034Sdougm ret = run_legacy_command(cmd, argv); 55003034Sdougm return (ret); 55014653Sdougm } 55024653Sdougm 55034653Sdougm sharepath = argv[optind++]; 55044653Sdougm if (optind < argc) { 55053034Sdougm resource = argv[optind]; 55063034Sdougm groupname = strchr(resource, '@'); 55073034Sdougm if (groupname != NULL) 55084653Sdougm *groupname++ = '\0'; 55094653Sdougm } 55104653Sdougm if (realpath(sharepath, dir) == NULL) 55113034Sdougm ret = SA_BAD_PATH; 55124653Sdougm else 55133034Sdougm sharepath = dir; 55144653Sdougm if (ret == SA_OK) 55153910Sdougm share = sa_find_share(handle, sharepath); 55164653Sdougm else 55173034Sdougm share = NULL; 55184653Sdougm 55195331Samw features = sa_proto_get_featureset(protocol); 55205331Samw 55214653Sdougm if (groupname != NULL) { 55224653Sdougm ret = SA_NOT_ALLOWED; 55234653Sdougm } else if (ret == SA_OK) { 55245331Samw char *legacygroup; 55253034Sdougm /* 55264653Sdougm * The legacy group is always present and zfs groups 55273034Sdougm * come and go. zfs shares may be in sub-groups and 55283034Sdougm * the zfs share will already be in that group so it 55295331Samw * isn't an error. If the protocol is "smb", the group 55305331Samw * "smb" is used when "default" would otherwise be 55315331Samw * used. "default" is NFS only and "smb" is SMB only. 55323034Sdougm */ 55335331Samw if (strcmp(protocol, "smb") == 0) 55345331Samw legacygroup = "smb"; 55355331Samw else 55365331Samw legacygroup = "default"; 55375331Samw 55383034Sdougm /* 55394653Sdougm * If the share exists (not NULL), then make sure it 55404653Sdougm * is one we want to handle by getting the parent 55414653Sdougm * group. 55423034Sdougm */ 55435331Samw if (share != NULL) { 55444653Sdougm group = sa_get_parent_group(share); 55455331Samw } else { 55464653Sdougm group = sa_get_group(handle, legacygroup); 55475331Samw if (group == NULL && strcmp(legacygroup, "smb") == 0) { 55485331Samw /* 55495331Samw * This group may not exist, so create 55505331Samw * as necessary. It only contains the 55515331Samw * "smb" protocol. 55525331Samw */ 55535331Samw group = sa_create_group(handle, legacygroup, 55545331Samw &ret); 55555331Samw if (group != NULL) 55565331Samw (void) sa_create_optionset(group, 55575331Samw protocol); 55585331Samw } 55595331Samw } 55605331Samw 55615331Samw if (group == NULL) { 55625331Samw ret = SA_SYSTEM_ERR; 55635331Samw goto err; 55645331Samw } 55655331Samw 55665331Samw groupstatus = group_status(group); 55675331Samw if (share == NULL) { 55685331Samw share = sa_add_share(group, sharepath, 55695331Samw persist, &ret); 55705331Samw if (share == NULL && 55715331Samw ret == SA_DUPLICATE_NAME) { 55725331Samw /* 55735331Samw * Could be a ZFS path being started 55745331Samw */ 55755331Samw if (sa_zfs_is_shared(handle, 55765331Samw sharepath)) { 55775331Samw ret = SA_OK; 55785331Samw group = sa_get_group(handle, 55795331Samw "zfs"); 55805331Samw if (group == NULL) { 55815331Samw /* 55825331Samw * This shouldn't 55835331Samw * happen. 55845331Samw */ 55855331Samw ret = SA_CONFIG_ERR; 55865331Samw } else { 55875331Samw share = sa_add_share( 55885331Samw group, sharepath, 55895331Samw persist, &ret); 55904653Sdougm } 55913034Sdougm } 55925331Samw } 55935331Samw } else { 55945331Samw char *type; 55955331Samw /* 55965331Samw * May want to change persist state, but the 55975331Samw * important thing is to change options. We 55985331Samw * need to change them regardless of the 55995331Samw * source. 56005331Samw */ 56015331Samw 56025331Samw if (sa_zfs_is_shared(handle, sharepath)) { 56035331Samw zfs = 1; 56045331Samw } 56055331Samw remove_all_options(share, protocol); 56065331Samw type = sa_get_share_attr(share, "type"); 56075331Samw if (type != NULL && 56085331Samw strcmp(type, "transient") != 0) { 56095331Samw curtype = SA_SHARE_PERMANENT; 56105331Samw } 56115331Samw if (type != NULL) 56125331Samw sa_free_attr_string(type); 56135331Samw if (curtype != persist) { 56145331Samw (void) sa_set_share_attr(share, "type", 56155331Samw persist == SA_SHARE_PERMANENT ? 56165331Samw "persist" : "transient"); 56175331Samw } 56185331Samw } 56195331Samw 56205331Samw /* 56215331Samw * If there is a resource name, we may 56225331Samw * actually care about it if this is share for 56235331Samw * a protocol that uses resource level sharing 56245331Samw * (SMB). We need to find the resource and, if 56255331Samw * it exists, make sure it belongs to the 56265331Samw * current share. If it doesn't exist, attempt 56275331Samw * to create it. 56285331Samw */ 56295331Samw 56305331Samw if (ret == SA_OK && resource != NULL) { 56315331Samw rsrc = sa_find_resource(handle, resource); 56325331Samw if (rsrc != NULL) { 56335331Samw if (share != sa_get_resource_parent(rsrc)) 56345331Samw ret = SA_DUPLICATE_NAME; 56355331Samw } else { 56365331Samw rsrc = sa_add_resource(share, resource, 56375331Samw persist, &ret); 56383034Sdougm } 56395331Samw if (features & SA_FEATURE_RESOURCE) 56405331Samw share = rsrc; 56413108Sdougm } 56425331Samw 56434653Sdougm /* Have a group to hold this share path */ 56444653Sdougm if (ret == SA_OK && options != NULL && 56454653Sdougm strlen(options) > 0) { 56464653Sdougm ret = sa_parse_legacy_options(share, 56474653Sdougm options, 56484653Sdougm protocol); 56493034Sdougm } 56504653Sdougm if (!zfs) { 56514653Sdougm /* 56525331Samw * ZFS shares never have a description 56535331Samw * and we can't store the values so 56545331Samw * don't try. 56554653Sdougm */ 56564653Sdougm if (ret == SA_OK && description != NULL) 56574653Sdougm ret = sa_set_share_description(share, 56584653Sdougm description); 56593034Sdougm } 56605331Samw if (ret == SA_OK && 56615331Samw strcmp(groupstatus, "enabled") == 0) { 56625331Samw if (rsrc != share) 56634653Sdougm ret = sa_enable_share(share, protocol); 56645331Samw else 56655331Samw ret = sa_enable_resource(rsrc, 56665331Samw protocol); 56674653Sdougm if (ret == SA_OK && 56684653Sdougm persist == SA_SHARE_PERMANENT) { 56694653Sdougm (void) sa_update_legacy(share, 56704653Sdougm protocol); 56714653Sdougm } 56724653Sdougm if (ret == SA_OK) 56734653Sdougm ret = sa_update_config(handle); 56744653Sdougm } 56753034Sdougm } 56765331Samw err: 56773034Sdougm if (ret != SA_OK) { 56784653Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 56794653Sdougm sharepath, sa_errorstr(ret)); 56804653Sdougm ret = SA_LEGACY_ERR; 56813034Sdougm } 56823034Sdougm return (ret); 56833034Sdougm } 56843034Sdougm 56853034Sdougm /* 56863034Sdougm * sa_legacy_unshare(flags, argc, argv) 56873034Sdougm * 56883034Sdougm * Implements the original unshare command. 56893034Sdougm */ 56903034Sdougm int 56913910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 56923034Sdougm { 56933034Sdougm char *protocol = "nfs"; /* for now */ 56943034Sdougm char *options = NULL; 56953034Sdougm char *sharepath = NULL; 56963034Sdougm int persist = SA_SHARE_TRANSIENT; 56973034Sdougm int argsused = 0; 56983034Sdougm int c; 56993034Sdougm int ret = SA_OK; 57003034Sdougm int true_legacy = 0; 57015331Samw uint64_t features = 0; 57025331Samw sa_resource_t resource = NULL; 57033034Sdougm char cmd[MAXPATHLEN]; 57045331Samw #ifdef lint 57055331Samw flags = flags; 57065331Samw options = options; 57075331Samw #endif 57083034Sdougm 57093034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 57104653Sdougm switch (c) { 57114653Sdougm case 'F': 57124653Sdougm protocol = optarg; 57134653Sdougm if (!sa_valid_protocol(protocol)) { 57144653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 57154653Sdougm protocol, "unshare") == 0 && 57164653Sdougm check_legacy_cmd(cmd)) { 57174653Sdougm true_legacy++; 57184653Sdougm } else { 57194653Sdougm (void) printf(gettext( 57204653Sdougm "Invalid file system name\n")); 57214653Sdougm return (SA_INVALID_PROTOCOL); 57224653Sdougm } 57234653Sdougm } 57244653Sdougm break; 57254653Sdougm case 'o': 57264653Sdougm options = optarg; 57274653Sdougm argsused++; 57284653Sdougm break; 57294653Sdougm case 'p': 57304653Sdougm persist = SA_SHARE_PERMANENT; 57314653Sdougm argsused++; 57324653Sdougm break; 57336019Sdougm case 'h': 57346019Sdougm /* optopt on valid arg isn't defined */ 57356019Sdougm optopt = c; 57366019Sdougm /*FALLTHROUGH*/ 57376019Sdougm case '?': 57384653Sdougm default: 57396019Sdougm /* 57406019Sdougm * Since a bad option gets to here, sort it 57416019Sdougm * out and return a syntax error return value 57426019Sdougm * if necessary. 57436019Sdougm */ 57446019Sdougm switch (optopt) { 57456019Sdougm default: 57466019Sdougm ret = SA_LEGACY_ERR; 57476019Sdougm break; 57486019Sdougm case 'h': 57496019Sdougm case '?': 57506019Sdougm break; 57516019Sdougm } 57524653Sdougm (void) printf(gettext("usage: %s\n"), 57534653Sdougm sa_get_usage(USAGE_UNSHARE)); 57546019Sdougm return (ret); 57553034Sdougm } 57563034Sdougm } 57573034Sdougm 57584653Sdougm /* Have the info so construct what is needed */ 57594653Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 57604653Sdougm ret = SA_SYNTAX_ERR; 57613034Sdougm } else { 57624653Sdougm sa_share_t share; 57634653Sdougm char dir[MAXPATHLEN]; 57644653Sdougm if (true_legacy) { 57654653Sdougm /* if still using legacy share/unshare, exec it */ 57664653Sdougm ret = run_legacy_command(cmd, argv); 57674653Sdougm return (ret); 57684653Sdougm } 57693663Sdougm /* 57703663Sdougm * Find the path in the internal configuration. If it 57713663Sdougm * isn't found, attempt to resolve the path via 57723663Sdougm * realpath() and try again. 57733663Sdougm */ 57744653Sdougm sharepath = argv[optind++]; 57754653Sdougm share = sa_find_share(handle, sharepath); 57764653Sdougm if (share == NULL) { 57774653Sdougm if (realpath(sharepath, dir) == NULL) { 57784653Sdougm ret = SA_NO_SUCH_PATH; 57794653Sdougm } else { 57804653Sdougm share = sa_find_share(handle, dir); 57814653Sdougm } 57823663Sdougm } 57835331Samw if (share == NULL) { 57845331Samw /* Could be a resource name so check that next */ 57855331Samw features = sa_proto_get_featureset(protocol); 57865331Samw resource = sa_find_resource(handle, sharepath); 57875331Samw if (resource != NULL) { 57885331Samw share = sa_get_resource_parent(resource); 57895331Samw if (features & SA_FEATURE_RESOURCE) 57905331Samw (void) sa_disable_resource(resource, 57915331Samw protocol); 57925331Samw if (persist == SA_SHARE_PERMANENT) { 57935331Samw ret = sa_remove_resource(resource); 57945331Samw if (ret == SA_OK) 57955331Samw ret = sa_update_config(handle); 57965331Samw } 57975331Samw /* 57985331Samw * If we still have a resource on the 57995331Samw * share, we don't disable the share 58005331Samw * itself. IF there aren't anymore, we 58015331Samw * need to remove the share. The 58025331Samw * removal will be done in the next 58035331Samw * section if appropriate. 58045331Samw */ 58055331Samw resource = sa_get_share_resource(share, NULL); 58065331Samw if (resource != NULL) 58075331Samw share = NULL; 58085331Samw } else if (ret == SA_OK) { 58095331Samw /* Didn't find path and no resource */ 58105331Samw ret = SA_BAD_PATH; 58115331Samw } 58125331Samw } 58135331Samw if (share != NULL && resource == NULL) { 58144653Sdougm ret = sa_disable_share(share, protocol); 58154653Sdougm /* 58164653Sdougm * Errors are ok and removal should still occur. The 58174653Sdougm * legacy unshare is more forgiving of errors than the 58184653Sdougm * remove-share subcommand which may need the force 58194653Sdougm * flag set for some error conditions. That is, the 58204653Sdougm * "unshare" command will always unshare if it can 58214653Sdougm * while "remove-share" might require the force option. 58224653Sdougm */ 58234653Sdougm if (persist == SA_SHARE_PERMANENT) { 58244653Sdougm ret = sa_remove_share(share); 58254653Sdougm if (ret == SA_OK) 58264653Sdougm ret = sa_update_config(handle); 58274653Sdougm } 58285331Samw } else if (ret == SA_OK && share == NULL && resource == NULL) { 58295331Samw /* 58305331Samw * If both share and resource are NULL, then 58315331Samw * share not found. If one or the other was 58325331Samw * found or there was an earlier error, we 58335331Samw * assume it was handled earlier. 58345331Samw */ 58354653Sdougm ret = SA_NOT_SHARED; 58363663Sdougm } 58373034Sdougm } 58383034Sdougm switch (ret) { 58393034Sdougm default: 58404653Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 58414653Sdougm ret = SA_LEGACY_ERR; 58424653Sdougm break; 58433034Sdougm case SA_SYNTAX_ERR: 58444653Sdougm (void) printf(gettext("usage: %s\n"), 58454653Sdougm sa_get_usage(USAGE_UNSHARE)); 58464653Sdougm break; 58473034Sdougm case SA_OK: 58484653Sdougm break; 58493034Sdougm } 58503034Sdougm return (ret); 58513034Sdougm } 58523034Sdougm 58533034Sdougm /* 58544653Sdougm * Common commands that implement the sub-commands used by all 58555331Samw * protocols. The entries are found via the lookup command 58563034Sdougm */ 58573034Sdougm 58583034Sdougm static sa_command_t commands[] = { 58593034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 58603034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 58613034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 58623034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 58633034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 58643034Sdougm {"list", 0, sa_list, USAGE_LIST}, 58653034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 58663034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 58673034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 58683034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 58693034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 58703034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 58713034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 58725331Samw SVC_SET|SVC_ACTION}, 58733034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 58743034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 58753034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 58763034Sdougm {NULL, 0, NULL, NULL} 58773034Sdougm }; 58783034Sdougm 58793034Sdougm static char * 58803034Sdougm sa_get_usage(sa_usage_t index) 58813034Sdougm { 58823034Sdougm char *ret = NULL; 58833034Sdougm switch (index) { 58843034Sdougm case USAGE_ADD_SHARE: 58854653Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 58864653Sdougm "[-d \"description text\"] -s sharepath group"); 58874653Sdougm break; 58883034Sdougm case USAGE_CREATE: 58894653Sdougm ret = gettext( 58904653Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 58914653Sdougm break; 58923034Sdougm case USAGE_DELETE: 58934653Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 58944653Sdougm break; 58953034Sdougm case USAGE_DISABLE: 58964653Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 58974653Sdougm break; 58983034Sdougm case USAGE_ENABLE: 58994653Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 59004653Sdougm break; 59013034Sdougm case USAGE_LIST: 59024653Sdougm ret = gettext("list [-vh] [-P proto]"); 59034653Sdougm break; 59043034Sdougm case USAGE_MOVE_SHARE: 59054653Sdougm ret = gettext( 59064653Sdougm "move-share [-nvh] -s sharepath destination-group"); 59074653Sdougm break; 59083034Sdougm case USAGE_REMOVE_SHARE: 59095331Samw ret = gettext( 59105331Samw "remove-share [-fnvh] {-s sharepath | -r resource} " 59115331Samw "group"); 59124653Sdougm break; 59133034Sdougm case USAGE_SET: 59144653Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 59155331Samw "[-p property=value]* [-s sharepath] [-r resource]] " 59165331Samw "group"); 59174653Sdougm break; 59183034Sdougm case USAGE_SET_SECURITY: 59194653Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 59204653Sdougm "[-p property=value]* group"); 59214653Sdougm break; 59223034Sdougm case USAGE_SET_SHARE: 59234653Sdougm ret = gettext("set-share [-nh] [-r resource] " 59244653Sdougm "[-d \"description text\"] -s sharepath group"); 59254653Sdougm break; 59263034Sdougm case USAGE_SHOW: 59274653Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 59284653Sdougm break; 59293034Sdougm case USAGE_SHARE: 59304653Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 59314653Sdougm "[-d description] [pathname [resourcename]]"); 59324653Sdougm break; 59333034Sdougm case USAGE_START: 59344653Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 59354653Sdougm break; 59363034Sdougm case USAGE_STOP: 59374653Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 59384653Sdougm break; 59393034Sdougm case USAGE_UNSET: 59404653Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 59414653Sdougm "[-p property]* group"); 59424653Sdougm break; 59433034Sdougm case USAGE_UNSET_SECURITY: 59445331Samw ret = gettext("unset-security [-nvh] -P proto " 59455331Samw "-S security-type [-p property]* group"); 59464653Sdougm break; 59473034Sdougm case USAGE_UNSHARE: 59484653Sdougm ret = gettext( 59495331Samw "unshare [-F fstype] [-p] [-o optionlist] sharepath"); 59504653Sdougm break; 59513034Sdougm } 59523034Sdougm return (ret); 59533034Sdougm } 59543034Sdougm 59553034Sdougm /* 59563034Sdougm * sa_lookup(cmd, proto) 59573034Sdougm * 59583034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 59593034Sdougm * eventually provide a way to provide protocol specific sub-commands. 59603034Sdougm */ 59613034Sdougm sa_command_t * 59623034Sdougm sa_lookup(char *cmd, char *proto) 59633034Sdougm { 59643034Sdougm int i; 59653034Sdougm size_t len; 59665331Samw #ifdef lint 59675331Samw proto = proto; 59685331Samw #endif 59693034Sdougm 59703034Sdougm len = strlen(cmd); 59713034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 59724653Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 59734653Sdougm return (&commands[i]); 59743034Sdougm } 59753034Sdougm return (NULL); 59763034Sdougm } 59773034Sdougm 59783034Sdougm void 59793034Sdougm sub_command_help(char *proto) 59803034Sdougm { 59813034Sdougm int i; 59825331Samw #ifdef lint 59835331Samw proto = proto; 59845331Samw #endif 59853034Sdougm 59863034Sdougm (void) printf(gettext("\tsub-commands:\n")); 59873034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 59884653Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 59894653Sdougm (void) printf("\t%s\n", 59904653Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 59913034Sdougm } 59923034Sdougm } 5993