16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 230b4fd3b1SSurya Prakki * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 2533f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 26*a8cc26d6SJohn Levon * Copyright 2019, Joyent, Inc. 276185db85Sdougm */ 286185db85Sdougm 296185db85Sdougm #include <sys/types.h> 306185db85Sdougm #include <sys/stat.h> 316185db85Sdougm #include <fcntl.h> 326185db85Sdougm #include <stdlib.h> 336185db85Sdougm #include <stdio.h> 346185db85Sdougm #include <string.h> 356185db85Sdougm #include <ctype.h> 366185db85Sdougm #include <unistd.h> 376185db85Sdougm #include <getopt.h> 386185db85Sdougm #include <utmpx.h> 396185db85Sdougm #include <pwd.h> 406185db85Sdougm #include <auth_attr.h> 416185db85Sdougm #include <secdb.h> 426185db85Sdougm #include <sys/param.h> 436185db85Sdougm #include <sys/stat.h> 446185db85Sdougm #include <errno.h> 456185db85Sdougm 466185db85Sdougm #include <libshare.h> 476185db85Sdougm #include "sharemgr.h" 486185db85Sdougm #include <libscf.h> 496185db85Sdougm #include <libxml/tree.h> 506185db85Sdougm #include <libintl.h> 51da6c28aaSamw #include <assert.h> 52da6c28aaSamw #include <iconv.h> 53da6c28aaSamw #include <langinfo.h> 54da6c28aaSamw #include <dirent.h> 556185db85Sdougm 566185db85Sdougm static char *sa_get_usage(sa_usage_t); 576185db85Sdougm 586185db85Sdougm /* 596185db85Sdougm * Implementation of the common sub-commands supported by sharemgr. 606185db85Sdougm * A number of helper functions are also included. 616185db85Sdougm */ 626185db85Sdougm 636185db85Sdougm /* 646185db85Sdougm * has_protocol(group, proto) 656185db85Sdougm * If the group has an optionset with the specified protocol, 666185db85Sdougm * return true (1) otherwise false (0). 676185db85Sdougm */ 686185db85Sdougm static int 696185db85Sdougm has_protocol(sa_group_t group, char *protocol) 706185db85Sdougm { 716185db85Sdougm sa_optionset_t optionset; 726185db85Sdougm int result = 0; 736185db85Sdougm 746185db85Sdougm optionset = sa_get_optionset(group, protocol); 756185db85Sdougm if (optionset != NULL) { 7625a68471Sdougm result++; 776185db85Sdougm } 786185db85Sdougm return (result); 796185db85Sdougm } 806185db85Sdougm 816185db85Sdougm /* 82da6c28aaSamw * validresource(name) 83da6c28aaSamw * 84da6c28aaSamw * Check that name only has valid characters in it. The current valid 85da6c28aaSamw * set are the printable characters but not including: 86da6c28aaSamw * " / \ [ ] : | < > + ; , ? * = \t 87da6c28aaSamw * Note that space is included and there is a maximum length. 88da6c28aaSamw */ 89da6c28aaSamw static int 90da6c28aaSamw validresource(const char *name) 91da6c28aaSamw { 92da6c28aaSamw const char *cp; 93da6c28aaSamw size_t len; 94da6c28aaSamw 95da6c28aaSamw if (name == NULL) 96da6c28aaSamw return (B_FALSE); 97da6c28aaSamw 98da6c28aaSamw len = strlen(name); 99da6c28aaSamw if (len == 0 || len > SA_MAX_RESOURCE_NAME) 100da6c28aaSamw return (B_FALSE); 101da6c28aaSamw 102da6c28aaSamw if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) { 103da6c28aaSamw return (B_FALSE); 104da6c28aaSamw } 105da6c28aaSamw 106da6c28aaSamw for (cp = name; *cp != '\0'; cp++) 107da6c28aaSamw if (iscntrl(*cp)) 108da6c28aaSamw return (B_FALSE); 109da6c28aaSamw 110da6c28aaSamw return (B_TRUE); 111da6c28aaSamw } 112da6c28aaSamw 113da6c28aaSamw /* 114da6c28aaSamw * conv_to_utf8(input) 115da6c28aaSamw * 116da6c28aaSamw * Convert the input string to utf8 from the current locale. If the 117da6c28aaSamw * conversion fails, use the current locale, it is likely close 118da6c28aaSamw * enough. For example, the "C" locale is a subset of utf-8. The 119da6c28aaSamw * return value may be a new string or the original input string. 120da6c28aaSamw */ 121da6c28aaSamw 122da6c28aaSamw static char * 123da6c28aaSamw conv_to_utf8(char *input) 124da6c28aaSamw { 125da6c28aaSamw iconv_t cd; 12655bf511dSas char *inval = input; 127da6c28aaSamw char *output = input; 128da6c28aaSamw char *outleft; 129da6c28aaSamw char *curlocale; 130da6c28aaSamw size_t bytesleft; 131da6c28aaSamw size_t size; 132da6c28aaSamw size_t osize; 133da6c28aaSamw static int warned = 0; 134da6c28aaSamw 135da6c28aaSamw curlocale = nl_langinfo(CODESET); 136da6c28aaSamw if (curlocale == NULL) 137da6c28aaSamw curlocale = "C"; 138da6c28aaSamw cd = iconv_open("UTF-8", curlocale); 139da6c28aaSamw if (cd != NULL && cd != (iconv_t)-1) { 140da6c28aaSamw size = strlen(input); 141da6c28aaSamw /* Assume worst case of characters expanding to 4 bytes. */ 142da6c28aaSamw bytesleft = size * 4; 143da6c28aaSamw output = calloc(bytesleft, 1); 144da6c28aaSamw if (output != NULL) { 145da6c28aaSamw outleft = output; 14655bf511dSas /* inval can be modified on return */ 14755bf511dSas osize = iconv(cd, (const char **)&inval, &size, 148da6c28aaSamw &outleft, &bytesleft); 149da6c28aaSamw if (osize == (size_t)-1 || size != 0) { 150da6c28aaSamw free(output); 151da6c28aaSamw output = input; 152da6c28aaSamw } 15355bf511dSas } else { 15455bf511dSas /* Need to return something. */ 15555bf511dSas output = input; 156da6c28aaSamw } 157da6c28aaSamw (void) iconv_close(cd); 158da6c28aaSamw } else { 159da6c28aaSamw if (!warned) 160da6c28aaSamw (void) fprintf(stderr, 161da6c28aaSamw gettext("Cannot convert to UTF-8 from %s\n"), 162da6c28aaSamw curlocale ? curlocale : gettext("unknown")); 163da6c28aaSamw warned = 1; 164da6c28aaSamw } 165da6c28aaSamw return (output); 166da6c28aaSamw } 167da6c28aaSamw 168da6c28aaSamw /* 169da6c28aaSamw * conv_from(input) 170da6c28aaSamw * 171da6c28aaSamw * Convert the input string from utf8 to current locale. If the 172da6c28aaSamw * conversion isn't supported, just use as is. The return value may be 173da6c28aaSamw * a new string or the original input string. 174da6c28aaSamw */ 175da6c28aaSamw 176da6c28aaSamw static char * 177da6c28aaSamw conv_from_utf8(char *input) 178da6c28aaSamw { 179da6c28aaSamw iconv_t cd; 180da6c28aaSamw char *output = input; 18155bf511dSas char *inval = input; 182da6c28aaSamw char *outleft; 183da6c28aaSamw char *curlocale; 184da6c28aaSamw size_t bytesleft; 185da6c28aaSamw size_t size; 186da6c28aaSamw size_t osize; 187da6c28aaSamw static int warned = 0; 188da6c28aaSamw 189da6c28aaSamw curlocale = nl_langinfo(CODESET); 190da6c28aaSamw if (curlocale == NULL) 191da6c28aaSamw curlocale = "C"; 192da6c28aaSamw cd = iconv_open(curlocale, "UTF-8"); 193da6c28aaSamw if (cd != NULL && cd != (iconv_t)-1) { 194da6c28aaSamw size = strlen(input); 195da6c28aaSamw /* Assume worst case of characters expanding to 4 bytes. */ 196da6c28aaSamw bytesleft = size * 4; 197da6c28aaSamw output = calloc(bytesleft, 1); 198da6c28aaSamw if (output != NULL) { 199da6c28aaSamw outleft = output; 20055bf511dSas osize = iconv(cd, (const char **)&inval, &size, 201da6c28aaSamw &outleft, &bytesleft); 20255bf511dSas if (osize == (size_t)-1 || size != 0) 203da6c28aaSamw output = input; 20455bf511dSas } else { 20555bf511dSas /* Need to return something. */ 20655bf511dSas output = input; 207da6c28aaSamw } 208da6c28aaSamw (void) iconv_close(cd); 209da6c28aaSamw } else { 210da6c28aaSamw if (!warned) 211da6c28aaSamw (void) fprintf(stderr, 212da6c28aaSamw gettext("Cannot convert to %s from UTF-8\n"), 213da6c28aaSamw curlocale ? curlocale : gettext("unknown")); 214da6c28aaSamw warned = 1; 215da6c28aaSamw } 216da6c28aaSamw return (output); 217da6c28aaSamw } 218da6c28aaSamw 219573b0c00Sdougm /* 220573b0c00Sdougm * print_rsrc_desc(resource, sharedesc) 221573b0c00Sdougm * 222573b0c00Sdougm * Print the resource description string after converting from UTF8 to 223573b0c00Sdougm * the current locale. If sharedesc is not NULL and there is no 224573b0c00Sdougm * description on the resource, use sharedesc. sharedesc will already 225573b0c00Sdougm * be converted to UTF8. 226573b0c00Sdougm */ 227573b0c00Sdougm 228da6c28aaSamw static void 229573b0c00Sdougm print_rsrc_desc(sa_resource_t resource, char *sharedesc) 230da6c28aaSamw { 231da6c28aaSamw char *description; 232da6c28aaSamw char *desc; 233da6c28aaSamw 234573b0c00Sdougm if (resource == NULL) 235573b0c00Sdougm return; 236573b0c00Sdougm 237da6c28aaSamw description = sa_get_resource_description(resource); 238da6c28aaSamw if (description != NULL) { 239da6c28aaSamw desc = conv_from_utf8(description); 240da6c28aaSamw if (desc != description) { 241da6c28aaSamw sa_free_share_description(description); 242da6c28aaSamw description = desc; 243da6c28aaSamw } 244573b0c00Sdougm } else if (sharedesc != NULL) { 245573b0c00Sdougm description = strdup(sharedesc); 246573b0c00Sdougm } 247573b0c00Sdougm if (description != NULL) { 248da6c28aaSamw (void) printf("\t\"%s\"", description); 249da6c28aaSamw sa_free_share_description(description); 250da6c28aaSamw } 251da6c28aaSamw } 252da6c28aaSamw 253573b0c00Sdougm /* 254573b0c00Sdougm * set_resource_desc(share, description) 255573b0c00Sdougm * 256573b0c00Sdougm * Set the share description value after converting the description 257573b0c00Sdougm * string to UTF8 from the current locale. 258573b0c00Sdougm */ 259573b0c00Sdougm 260573b0c00Sdougm static int 261573b0c00Sdougm set_resource_desc(sa_share_t share, char *description) 262573b0c00Sdougm { 263573b0c00Sdougm char *desc; 264573b0c00Sdougm int ret; 265573b0c00Sdougm 266573b0c00Sdougm desc = conv_to_utf8(description); 267573b0c00Sdougm ret = sa_set_resource_description(share, desc); 268573b0c00Sdougm if (description != desc) 269573b0c00Sdougm sa_free_share_description(desc); 270573b0c00Sdougm return (ret); 271573b0c00Sdougm } 272573b0c00Sdougm 273573b0c00Sdougm /* 274573b0c00Sdougm * set_share_desc(share, description) 275573b0c00Sdougm * 276573b0c00Sdougm * Set the resource description value after converting the description 277573b0c00Sdougm * string to UTF8 from the current locale. 278573b0c00Sdougm */ 279573b0c00Sdougm 280da6c28aaSamw static int 281da6c28aaSamw set_share_desc(sa_share_t share, char *description) 282da6c28aaSamw { 283da6c28aaSamw char *desc; 284da6c28aaSamw int ret; 285da6c28aaSamw 286da6c28aaSamw desc = conv_to_utf8(description); 287da6c28aaSamw ret = sa_set_share_description(share, desc); 288da6c28aaSamw if (description != desc) 289da6c28aaSamw sa_free_share_description(desc); 290da6c28aaSamw return (ret); 291da6c28aaSamw } 292da6c28aaSamw 293da6c28aaSamw /* 294da6c28aaSamw * add_list(list, item, data, proto) 295da6c28aaSamw * Adds a new list member that points holds item in the list. 2966185db85Sdougm * If list is NULL, it starts a new list. The function returns 2976185db85Sdougm * the first member of the list. 2986185db85Sdougm */ 2996185db85Sdougm struct list * 300da6c28aaSamw add_list(struct list *listp, void *item, void *data, char *proto) 3016185db85Sdougm { 3026185db85Sdougm struct list *new, *tmp; 3036185db85Sdougm 3046185db85Sdougm new = malloc(sizeof (struct list)); 3056185db85Sdougm if (new != NULL) { 30625a68471Sdougm new->next = NULL; 30725a68471Sdougm new->item = item; 30825a68471Sdougm new->itemdata = data; 309da6c28aaSamw new->proto = proto; 3106185db85Sdougm } else { 31125a68471Sdougm return (listp); 3126185db85Sdougm } 3136185db85Sdougm 3146185db85Sdougm if (listp == NULL) 31525a68471Sdougm return (new); 3166185db85Sdougm 3176185db85Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 3186185db85Sdougm /* get to end of list */ 3196185db85Sdougm } 3206185db85Sdougm tmp->next = new; 3216185db85Sdougm return (listp); 3226185db85Sdougm } 3236185db85Sdougm 3246185db85Sdougm /* 3256185db85Sdougm * free_list(list) 3266185db85Sdougm * Given a list, free all the members of the list; 3276185db85Sdougm */ 3286185db85Sdougm static void 3296185db85Sdougm free_list(struct list *listp) 3306185db85Sdougm { 3316185db85Sdougm struct list *tmp; 3326185db85Sdougm while (listp != NULL) { 33325a68471Sdougm tmp = listp; 33425a68471Sdougm listp = listp->next; 33525a68471Sdougm free(tmp); 3366185db85Sdougm } 3376185db85Sdougm } 3386185db85Sdougm 3396185db85Sdougm /* 3406185db85Sdougm * check_authorization(instname, which) 3416185db85Sdougm * 3426185db85Sdougm * Checks to see if the specific type of authorization in which is 3436185db85Sdougm * enabled for the user in this SMF service instance. 3446185db85Sdougm */ 3456185db85Sdougm 3466185db85Sdougm static int 3476185db85Sdougm check_authorization(char *instname, int which) 3486185db85Sdougm { 3496185db85Sdougm scf_handle_t *handle = NULL; 3506185db85Sdougm scf_simple_prop_t *prop = NULL; 3516185db85Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 3526185db85Sdougm char *authstr = NULL; 3536185db85Sdougm ssize_t numauths; 35425a68471Sdougm int ret = B_TRUE; 3556185db85Sdougm uid_t uid; 3566185db85Sdougm struct passwd *pw = NULL; 3576185db85Sdougm 3586185db85Sdougm uid = getuid(); 3596185db85Sdougm pw = getpwuid(uid); 36025a68471Sdougm if (pw == NULL) { 36125a68471Sdougm ret = B_FALSE; 36225a68471Sdougm } else { 36325a68471Sdougm /* 36425a68471Sdougm * Since names are restricted to SA_MAX_NAME_LEN won't 36525a68471Sdougm * overflow. 36625a68471Sdougm */ 36725a68471Sdougm (void) snprintf(svcstring, sizeof (svcstring), "%s:%s", 36825a68471Sdougm SA_SVC_FMRI_BASE, instname); 36925a68471Sdougm handle = scf_handle_create(SCF_VERSION); 37025a68471Sdougm if (handle != NULL) { 37125a68471Sdougm if (scf_handle_bind(handle) == 0) { 37225a68471Sdougm switch (which) { 37325a68471Sdougm case SVC_SET: 37425a68471Sdougm prop = scf_simple_prop_get(handle, 37525a68471Sdougm svcstring, "general", 37625a68471Sdougm SVC_AUTH_VALUE); 37725a68471Sdougm break; 37825a68471Sdougm case SVC_ACTION: 37925a68471Sdougm prop = scf_simple_prop_get(handle, 38025a68471Sdougm svcstring, "general", 38125a68471Sdougm SVC_AUTH_ACTION); 38225a68471Sdougm break; 38325a68471Sdougm } 38425a68471Sdougm } 38525a68471Sdougm } 3866185db85Sdougm } 3876185db85Sdougm /* make sure we have an authorization string property */ 3886185db85Sdougm if (prop != NULL) { 38925a68471Sdougm int i; 39025a68471Sdougm numauths = scf_simple_prop_numvalues(prop); 39125a68471Sdougm for (ret = 0, i = 0; i < numauths; i++) { 39225a68471Sdougm authstr = scf_simple_prop_next_astring(prop); 39325a68471Sdougm if (authstr != NULL) { 39425a68471Sdougm /* check if this user has one of the strings */ 39525a68471Sdougm if (chkauthattr(authstr, pw->pw_name)) { 39625a68471Sdougm ret = 1; 39725a68471Sdougm break; 39825a68471Sdougm } 39925a68471Sdougm } 4006185db85Sdougm } 40125a68471Sdougm endauthattr(); 40225a68471Sdougm scf_simple_prop_free(prop); 4036185db85Sdougm } else { 40425a68471Sdougm /* no authorization string defined */ 40525a68471Sdougm ret = 0; 4066185db85Sdougm } 4076185db85Sdougm if (handle != NULL) 40825a68471Sdougm scf_handle_destroy(handle); 4096185db85Sdougm return (ret); 4106185db85Sdougm } 4116185db85Sdougm 4126185db85Sdougm /* 4136185db85Sdougm * check_authorizations(instname, flags) 4146185db85Sdougm * 4156185db85Sdougm * check all the needed authorizations for the user in this service 4166185db85Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 4176185db85Sdougm * there are authorizations for the user or not. 4186185db85Sdougm */ 4196185db85Sdougm 4206185db85Sdougm static int 4216185db85Sdougm check_authorizations(char *instname, int flags) 4226185db85Sdougm { 4236185db85Sdougm int ret1 = 0; 4246185db85Sdougm int ret2 = 0; 4256185db85Sdougm int ret; 4266185db85Sdougm 4276185db85Sdougm if (flags & SVC_SET) 42825a68471Sdougm ret1 = check_authorization(instname, SVC_SET); 4296185db85Sdougm if (flags & SVC_ACTION) 43025a68471Sdougm ret2 = check_authorization(instname, SVC_ACTION); 4316185db85Sdougm switch (flags) { 4326185db85Sdougm case SVC_ACTION: 43325a68471Sdougm ret = ret2; 43425a68471Sdougm break; 4356185db85Sdougm case SVC_SET: 43625a68471Sdougm ret = ret1; 43725a68471Sdougm break; 4386185db85Sdougm case SVC_ACTION|SVC_SET: 43925a68471Sdougm ret = ret1 & ret2; 44025a68471Sdougm break; 4416185db85Sdougm default: 44225a68471Sdougm /* if not flags set, we assume we don't need authorizations */ 44325a68471Sdougm ret = 1; 4446185db85Sdougm } 4456185db85Sdougm return (ret); 4466185db85Sdougm } 4476185db85Sdougm 4486185db85Sdougm /* 449da6c28aaSamw * notify_or_enable_share(share, protocol) 450da6c28aaSamw * 451da6c28aaSamw * Since some protocols don't want an "enable" when properties change, 452da6c28aaSamw * this function will use the protocol specific notify function 453da6c28aaSamw * first. If that fails, it will then attempt to use the 454da6c28aaSamw * sa_enable_share(). "protocol" is the protocol that was specified 455da6c28aaSamw * on the command line. 456da6c28aaSamw */ 457da6c28aaSamw static void 458da6c28aaSamw notify_or_enable_share(sa_share_t share, char *protocol) 459da6c28aaSamw { 460da6c28aaSamw sa_group_t group; 461da6c28aaSamw sa_optionset_t opt; 462da6c28aaSamw int ret = SA_OK; 463da6c28aaSamw char *path; 464da6c28aaSamw char *groupproto; 465da6c28aaSamw sa_share_t parent = share; 466da6c28aaSamw 467da6c28aaSamw /* If really a resource, get parent share */ 468da6c28aaSamw if (!sa_is_share(share)) { 469da6c28aaSamw parent = sa_get_resource_parent((sa_resource_t)share); 470da6c28aaSamw } 471da6c28aaSamw 472da6c28aaSamw /* 473da6c28aaSamw * Now that we've got a share in "parent", make sure it has a path. 474da6c28aaSamw */ 475da6c28aaSamw path = sa_get_share_attr(parent, "path"); 476da6c28aaSamw if (path == NULL) 477da6c28aaSamw return; 478da6c28aaSamw 479da6c28aaSamw group = sa_get_parent_group(parent); 480da6c28aaSamw 481da6c28aaSamw if (group == NULL) { 482da6c28aaSamw sa_free_attr_string(path); 483da6c28aaSamw return; 484da6c28aaSamw } 485da6c28aaSamw for (opt = sa_get_optionset(group, NULL); 486da6c28aaSamw opt != NULL; 487da6c28aaSamw opt = sa_get_next_optionset(opt)) { 488da6c28aaSamw groupproto = sa_get_optionset_attr(opt, "type"); 489da6c28aaSamw if (groupproto == NULL || 490da6c28aaSamw (protocol != NULL && strcmp(groupproto, protocol) != 0)) { 491fe1c642dSBill Krier if (groupproto != NULL) 492fe1c642dSBill Krier sa_free_attr_string(groupproto); 493da6c28aaSamw continue; 494da6c28aaSamw } 495da6c28aaSamw if (sa_is_share(share)) { 496da6c28aaSamw if ((ret = sa_proto_change_notify(share, 497da6c28aaSamw groupproto)) != SA_OK) { 498da6c28aaSamw ret = sa_enable_share(share, groupproto); 499da6c28aaSamw if (ret != SA_OK) { 500da6c28aaSamw (void) printf( 501da6c28aaSamw gettext("Could not reenable" 502da6c28aaSamw " share %s: %s\n"), 503da6c28aaSamw path, sa_errorstr(ret)); 504da6c28aaSamw } 505da6c28aaSamw } 506da6c28aaSamw } else { 507da6c28aaSamw /* Must be a resource */ 508da6c28aaSamw if ((ret = sa_proto_notify_resource(share, 509da6c28aaSamw groupproto)) != SA_OK) { 510da6c28aaSamw ret = sa_enable_resource(share, groupproto); 511da6c28aaSamw if (ret != SA_OK) { 512da6c28aaSamw (void) printf( 513da6c28aaSamw gettext("Could not " 514da6c28aaSamw "reenable resource %s: " 515da6c28aaSamw "%s\n"), path, 516da6c28aaSamw sa_errorstr(ret)); 517da6c28aaSamw } 518da6c28aaSamw } 519da6c28aaSamw } 520da6c28aaSamw sa_free_attr_string(groupproto); 521da6c28aaSamw } 522da6c28aaSamw sa_free_attr_string(path); 523da6c28aaSamw } 524da6c28aaSamw 525da6c28aaSamw /* 526da6c28aaSamw * enable_group(group, updateproto, notify, proto) 5277d968cb8Sdougm * 5287d968cb8Sdougm * enable all the shares in the specified group. This is a helper for 5297d968cb8Sdougm * enable_all_groups in order to simplify regular and subgroup (zfs) 530da6c28aaSamw * enabling. Group has already been checked for non-NULL. If notify 531da6c28aaSamw * is non-zero, attempt to use the notify interface rather than 532da6c28aaSamw * enable. 5336185db85Sdougm */ 5347d968cb8Sdougm static void 535da6c28aaSamw enable_group(sa_group_t group, char *updateproto, int notify, char *proto) 5366185db85Sdougm { 5376185db85Sdougm sa_share_t share; 5387d968cb8Sdougm 539e0a942cbSRichard Lowe /* If the protocol isn't enabled for this group skip it */ 540e0a942cbSRichard Lowe if (!has_protocol(group, proto)) 541e0a942cbSRichard Lowe return; 542e0a942cbSRichard Lowe 5437d968cb8Sdougm for (share = sa_get_share(group, NULL); 5447d968cb8Sdougm share != NULL; 5457d968cb8Sdougm share = sa_get_next_share(share)) { 54625a68471Sdougm if (updateproto != NULL) 54725a68471Sdougm (void) sa_update_legacy(share, updateproto); 548da6c28aaSamw if (notify) 549da6c28aaSamw notify_or_enable_share(share, proto); 550da6c28aaSamw else 551da6c28aaSamw (void) sa_enable_share(share, proto); 5527d968cb8Sdougm } 5537d968cb8Sdougm } 5547d968cb8Sdougm 555330ef417Sdougm /* 556330ef417Sdougm * isenabled(group) 557330ef417Sdougm * 558330ef417Sdougm * Returns B_TRUE if the group is enabled or B_FALSE if it isn't. 559330ef417Sdougm * Moved to separate function to reduce clutter in the code. 560330ef417Sdougm */ 561330ef417Sdougm 562330ef417Sdougm static int 563330ef417Sdougm isenabled(sa_group_t group) 564330ef417Sdougm { 565330ef417Sdougm char *state; 566330ef417Sdougm int ret = B_FALSE; 567330ef417Sdougm 568330ef417Sdougm if (group != NULL) { 56925a68471Sdougm state = sa_get_group_attr(group, "state"); 57025a68471Sdougm if (state != NULL) { 571da6c28aaSamw 57225a68471Sdougm if (strcmp(state, "enabled") == 0) 57325a68471Sdougm ret = B_TRUE; 57425a68471Sdougm sa_free_attr_string(state); 57525a68471Sdougm } 576330ef417Sdougm } 577330ef417Sdougm return (ret); 578330ef417Sdougm } 579330ef417Sdougm 5807d968cb8Sdougm /* 5817d968cb8Sdougm * enable_all_groups(list, setstate, online, updateproto) 582da6c28aaSamw * 583da6c28aaSamw * Given a list of groups, enable each one found. If updateproto is 584da6c28aaSamw * not NULL, then update all the shares for the protocol that was 585da6c28aaSamw * passed in. If enable is non-zero, tell enable_group to try the 586da6c28aaSamw * notify interface since this is a property change. 5877d968cb8Sdougm */ 5887d968cb8Sdougm static int 589549ec3ffSdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate, 590da6c28aaSamw int online, char *updateproto, int enable) 5917d968cb8Sdougm { 592330ef417Sdougm int ret; 5936185db85Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 5946185db85Sdougm char *state; 5956185db85Sdougm char *name; 5966185db85Sdougm char *zfs = NULL; 5976185db85Sdougm sa_group_t group; 5987d968cb8Sdougm sa_group_t subgroup; 5996185db85Sdougm 600330ef417Sdougm for (ret = SA_OK; work != NULL; work = work->next) { 60125a68471Sdougm group = (sa_group_t)work->item; 602330ef417Sdougm 603330ef417Sdougm /* 604330ef417Sdougm * If setstate == TRUE, then make sure to set 605330ef417Sdougm * enabled. This needs to be done here in order for 606330ef417Sdougm * the isenabled check to succeed on a newly enabled 607330ef417Sdougm * group. 608330ef417Sdougm */ 60925a68471Sdougm if (setstate == B_TRUE) { 61025a68471Sdougm ret = sa_set_group_attr(group, "state", "enabled"); 61125a68471Sdougm if (ret != SA_OK) 61225a68471Sdougm break; 61325a68471Sdougm } 614330ef417Sdougm 615330ef417Sdougm /* 616330ef417Sdougm * Check to see if group is enabled. If it isn't, skip 617330ef417Sdougm * the rest. We don't want shares starting if the 618330ef417Sdougm * group is disabled. The properties may have been 619330ef417Sdougm * updated, but there won't be a change until the 620330ef417Sdougm * group is enabled. 621330ef417Sdougm */ 62225a68471Sdougm if (!isenabled(group)) 62325a68471Sdougm continue; 624330ef417Sdougm 62525a68471Sdougm /* if itemdata != NULL then a single share */ 62625a68471Sdougm if (work->itemdata != NULL) { 627da6c28aaSamw if (enable) { 628da6c28aaSamw if (work->itemdata != NULL) 629da6c28aaSamw notify_or_enable_share(work->itemdata, 630da6c28aaSamw updateproto); 631da6c28aaSamw else 632da6c28aaSamw ret = SA_CONFIG_ERR; 633da6c28aaSamw } else { 634da6c28aaSamw if (sa_is_share(work->itemdata)) { 635da6c28aaSamw ret = sa_enable_share( 636da6c28aaSamw (sa_share_t)work->itemdata, 637da6c28aaSamw updateproto); 638da6c28aaSamw } else { 639da6c28aaSamw ret = sa_enable_resource( 640da6c28aaSamw (sa_resource_t)work->itemdata, 641da6c28aaSamw updateproto); 642da6c28aaSamw } 643da6c28aaSamw } 64425a68471Sdougm } 64525a68471Sdougm if (ret != SA_OK) 64625a68471Sdougm break; 64725a68471Sdougm 64825a68471Sdougm /* if itemdata == NULL then the whole group */ 64925a68471Sdougm if (work->itemdata == NULL) { 65025a68471Sdougm zfs = sa_get_group_attr(group, "zfs"); 65125a68471Sdougm /* 652da6c28aaSamw * If the share is managed by ZFS, don't 65325a68471Sdougm * update any of the protocols since ZFS is 654da6c28aaSamw * handling this. Updateproto will contain 65525a68471Sdougm * the name of the protocol that we want to 65625a68471Sdougm * update legacy files for. 65725a68471Sdougm */ 658da6c28aaSamw enable_group(group, zfs == NULL ? updateproto : NULL, 659da6c28aaSamw enable, work->proto); 660fe1c642dSBill Krier if (zfs != NULL) 661fe1c642dSBill Krier sa_free_attr_string(zfs); 662fe1c642dSBill Krier 66325a68471Sdougm for (subgroup = sa_get_sub_group(group); 66425a68471Sdougm subgroup != NULL; 66525a68471Sdougm subgroup = sa_get_next_group(subgroup)) { 66625a68471Sdougm /* never update legacy for ZFS subgroups */ 667da6c28aaSamw enable_group(subgroup, NULL, enable, 668da6c28aaSamw work->proto); 66925a68471Sdougm } 67025a68471Sdougm } 67125a68471Sdougm if (online) { 67225a68471Sdougm zfs = sa_get_group_attr(group, "zfs"); 67325a68471Sdougm name = sa_get_group_attr(group, "name"); 67425a68471Sdougm if (name != NULL) { 67525a68471Sdougm if (zfs == NULL) { 67625a68471Sdougm (void) snprintf(instance, 67725a68471Sdougm sizeof (instance), "%s:%s", 67825a68471Sdougm SA_SVC_FMRI_BASE, name); 67925a68471Sdougm state = smf_get_state(instance); 68025a68471Sdougm if (state == NULL || 68125a68471Sdougm strcmp(state, "online") != 0) { 68225a68471Sdougm (void) smf_enable_instance( 68325a68471Sdougm instance, 0); 68425a68471Sdougm free(state); 68525a68471Sdougm } 68625a68471Sdougm } else { 68725a68471Sdougm sa_free_attr_string(zfs); 68825a68471Sdougm zfs = NULL; 68925a68471Sdougm } 69025a68471Sdougm if (name != NULL) 69125a68471Sdougm sa_free_attr_string(name); 6926185db85Sdougm } 6936185db85Sdougm } 6946185db85Sdougm } 6956185db85Sdougm if (ret == SA_OK) { 69625a68471Sdougm ret = sa_update_config(handle); 6976185db85Sdougm } 6986185db85Sdougm return (ret); 6996185db85Sdougm } 7006185db85Sdougm 7016185db85Sdougm /* 7026185db85Sdougm * chk_opt(optlistp, security, proto) 7036185db85Sdougm * 7046185db85Sdougm * Do a sanity check on the optlist provided for the protocol. This 7056185db85Sdougm * is a syntax check and verification that the property is either a 7066185db85Sdougm * general or specific to a names optionset. 7076185db85Sdougm */ 7086185db85Sdougm 7096185db85Sdougm static int 7106185db85Sdougm chk_opt(struct options *optlistp, int security, char *proto) 7116185db85Sdougm { 7126185db85Sdougm struct options *optlist; 7136185db85Sdougm char *sep = ""; 7146185db85Sdougm int notfirst = 0; 7156185db85Sdougm int ret; 7166185db85Sdougm 7176185db85Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 71825a68471Sdougm char *optname; 71925a68471Sdougm 72025a68471Sdougm optname = optlist->optname; 72125a68471Sdougm ret = OPT_ADD_OK; 72225a68471Sdougm /* extract property/value pair */ 72325a68471Sdougm if (sa_is_security(optname, proto)) { 72425a68471Sdougm if (!security) 72525a68471Sdougm ret = OPT_ADD_SECURITY; 72625a68471Sdougm } else { 72725a68471Sdougm if (security) 72825a68471Sdougm ret = OPT_ADD_PROPERTY; 72925a68471Sdougm } 73025a68471Sdougm if (ret != OPT_ADD_OK) { 73125a68471Sdougm if (notfirst == 0) 73225a68471Sdougm (void) printf( 73325a68471Sdougm gettext("Property syntax error: ")); 73425a68471Sdougm switch (ret) { 73525a68471Sdougm case OPT_ADD_SYNTAX: 73625a68471Sdougm (void) printf(gettext("%ssyntax error: %s"), 7376185db85Sdougm sep, optname); 73825a68471Sdougm sep = ", "; 73925a68471Sdougm break; 74025a68471Sdougm case OPT_ADD_SECURITY: 74125a68471Sdougm (void) printf(gettext("%s%s requires -S"), 7426185db85Sdougm optname, sep); 74325a68471Sdougm sep = ", "; 74425a68471Sdougm break; 74525a68471Sdougm case OPT_ADD_PROPERTY: 74625a68471Sdougm (void) printf( 74725a68471Sdougm gettext("%s%s not supported with -S"), 7486185db85Sdougm optname, sep); 74925a68471Sdougm sep = ", "; 75025a68471Sdougm break; 75125a68471Sdougm } 75225a68471Sdougm notfirst++; 7536185db85Sdougm } 7546185db85Sdougm } 7556185db85Sdougm if (notfirst) { 75625a68471Sdougm (void) printf("\n"); 75725a68471Sdougm ret = SA_SYNTAX_ERR; 7586185db85Sdougm } 7596185db85Sdougm return (ret); 7606185db85Sdougm } 7616185db85Sdougm 7626185db85Sdougm /* 7636185db85Sdougm * free_opt(optlist) 7646185db85Sdougm * Free the specified option list. 7656185db85Sdougm */ 7666185db85Sdougm static void 7676185db85Sdougm free_opt(struct options *optlist) 7686185db85Sdougm { 7696185db85Sdougm struct options *nextopt; 7706185db85Sdougm while (optlist != NULL) { 7716185db85Sdougm nextopt = optlist->next; 7726185db85Sdougm free(optlist); 7736185db85Sdougm optlist = nextopt; 7746185db85Sdougm } 7756185db85Sdougm } 7766185db85Sdougm 7776185db85Sdougm /* 7786185db85Sdougm * check property list for valid properties 7796185db85Sdougm * A null value is a remove which is always valid. 7806185db85Sdougm */ 7816185db85Sdougm static int 782687915e9Sdougm valid_options(sa_handle_t handle, struct options *optlist, char *proto, 783687915e9Sdougm void *object, char *sec) 7846185db85Sdougm { 7856185db85Sdougm int ret = SA_OK; 7866185db85Sdougm struct options *cur; 7876185db85Sdougm sa_property_t prop; 7886185db85Sdougm sa_optionset_t parent = NULL; 7896185db85Sdougm 7906185db85Sdougm if (object != NULL) { 79125a68471Sdougm if (sec == NULL) 79225a68471Sdougm parent = sa_get_optionset(object, proto); 79325a68471Sdougm else 79425a68471Sdougm parent = sa_get_security(object, sec, proto); 7956185db85Sdougm } 7966185db85Sdougm 7976185db85Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 79825a68471Sdougm if (cur->optvalue == NULL) 79925a68471Sdougm continue; 8006185db85Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 8016185db85Sdougm if (prop == NULL) 80225a68471Sdougm ret = SA_NO_MEMORY; 8036185db85Sdougm if (ret != SA_OK || 804687915e9Sdougm (ret = sa_valid_property(handle, parent, proto, prop)) != 805687915e9Sdougm SA_OK) { 80625a68471Sdougm (void) printf( 80725a68471Sdougm gettext("Could not add property %s: %s\n"), 80825a68471Sdougm cur->optname, sa_errorstr(ret)); 8096185db85Sdougm } 8106185db85Sdougm (void) sa_remove_property(prop); 8116185db85Sdougm } 8126185db85Sdougm return (ret); 8136185db85Sdougm } 8146185db85Sdougm 8156185db85Sdougm /* 8166185db85Sdougm * add_optionset(group, optlist, protocol, *err) 8176185db85Sdougm * Add the options in optlist to an optionset and then add the optionset 8186185db85Sdougm * to the group. 8196185db85Sdougm * 8206185db85Sdougm * The return value indicates if there was a "change" while errors are 8216185db85Sdougm * returned via the *err parameters. 8226185db85Sdougm */ 8236185db85Sdougm static int 8246185db85Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 8256185db85Sdougm { 8266185db85Sdougm sa_optionset_t optionset; 8276185db85Sdougm int ret = SA_OK; 828da6c28aaSamw int result = B_FALSE; 829687915e9Sdougm sa_handle_t handle; 8306185db85Sdougm 8316185db85Sdougm optionset = sa_get_optionset(group, proto); 8326185db85Sdougm if (optionset == NULL) { 83325a68471Sdougm optionset = sa_create_optionset(group, proto); 834da6c28aaSamw if (optionset == NULL) 835da6c28aaSamw ret = SA_NO_MEMORY; 836da6c28aaSamw result = B_TRUE; /* adding a protocol is a change */ 8376185db85Sdougm } 83825a68471Sdougm if (optionset == NULL) { 83925a68471Sdougm ret = SA_NO_MEMORY; 84025a68471Sdougm goto out; 84125a68471Sdougm } 842687915e9Sdougm handle = sa_find_group_handle(group); 843687915e9Sdougm if (handle == NULL) { 844687915e9Sdougm ret = SA_CONFIG_ERR; 845687915e9Sdougm goto out; 846687915e9Sdougm } 84725a68471Sdougm while (optlist != NULL) { 8486185db85Sdougm sa_property_t prop; 8496185db85Sdougm prop = sa_get_property(optionset, optlist->optname); 8506185db85Sdougm if (prop == NULL) { 8516185db85Sdougm /* 8526185db85Sdougm * add the property, but only if it is 8536185db85Sdougm * a non-NULL or non-zero length value 8546185db85Sdougm */ 85525a68471Sdougm if (optlist->optvalue != NULL) { 85625a68471Sdougm prop = sa_create_property(optlist->optname, 85725a68471Sdougm optlist->optvalue); 85825a68471Sdougm if (prop != NULL) { 859687915e9Sdougm ret = sa_valid_property(handle, 860687915e9Sdougm optionset, proto, prop); 86125a68471Sdougm if (ret != SA_OK) { 86225a68471Sdougm (void) sa_remove_property(prop); 86325a68471Sdougm (void) printf(gettext("Could " 86425a68471Sdougm "not add property " 86525a68471Sdougm "%s: %s\n"), 86625a68471Sdougm optlist->optname, 86725a68471Sdougm sa_errorstr(ret)); 86825a68471Sdougm } 86925a68471Sdougm } 87025a68471Sdougm if (ret == SA_OK) { 87125a68471Sdougm ret = sa_add_property(optionset, prop); 87225a68471Sdougm if (ret != SA_OK) { 87325a68471Sdougm (void) printf(gettext( 87425a68471Sdougm "Could not add property " 87525a68471Sdougm "%s: %s\n"), 87625a68471Sdougm optlist->optname, 87725a68471Sdougm sa_errorstr(ret)); 87825a68471Sdougm } else { 87925a68471Sdougm /* there was a change */ 880da6c28aaSamw result = B_TRUE; 88125a68471Sdougm } 88225a68471Sdougm } 8836185db85Sdougm } 88425a68471Sdougm } else { 88525a68471Sdougm ret = sa_update_property(prop, optlist->optvalue); 88625a68471Sdougm /* should check to see if value changed */ 88725a68471Sdougm if (ret != SA_OK) { 88825a68471Sdougm (void) printf(gettext("Could not update " 88925a68471Sdougm "property %s: %s\n"), optlist->optname, 89025a68471Sdougm sa_errorstr(ret)); 89125a68471Sdougm } else { 892da6c28aaSamw result = B_TRUE; 8936185db85Sdougm } 8946185db85Sdougm } 8956185db85Sdougm optlist = optlist->next; 8966185db85Sdougm } 89725a68471Sdougm ret = sa_commit_properties(optionset, 0); 89825a68471Sdougm 89925a68471Sdougm out: 9006185db85Sdougm if (err != NULL) 90125a68471Sdougm *err = ret; 9026185db85Sdougm return (result); 9036185db85Sdougm } 9046185db85Sdougm 905da6c28aaSamw /* 906da6c28aaSamw * resource_compliant(group) 907da6c28aaSamw * 908da6c28aaSamw * Go through all the shares in the group. Assume compliant, but if 909da6c28aaSamw * any share doesn't have at least one resource name, it isn't 910da6c28aaSamw * compliant. 911da6c28aaSamw */ 912da6c28aaSamw static int 913da6c28aaSamw resource_compliant(sa_group_t group) 914da6c28aaSamw { 915da6c28aaSamw sa_share_t share; 916da6c28aaSamw 917da6c28aaSamw for (share = sa_get_share(group, NULL); share != NULL; 918da6c28aaSamw share = sa_get_next_share(share)) { 919da6c28aaSamw if (sa_get_share_resource(share, NULL) == NULL) { 920da6c28aaSamw return (B_FALSE); 921da6c28aaSamw } 922da6c28aaSamw } 923da6c28aaSamw return (B_TRUE); 924da6c28aaSamw } 925da6c28aaSamw 926da6c28aaSamw /* 927da6c28aaSamw * fix_path(path) 928da6c28aaSamw * 929da6c28aaSamw * change all illegal characters to something else. For now, all get 930da6c28aaSamw * converted to '_' and the leading '/' is stripped off. This is used 931da6c28aaSamw * to construct an resource name (SMB share name) that is valid. 932da6c28aaSamw * Caller must pass a valid path. 933da6c28aaSamw */ 934da6c28aaSamw static void 935da6c28aaSamw fix_path(char *path) 936da6c28aaSamw { 937da6c28aaSamw char *cp; 938da6c28aaSamw size_t len; 939da6c28aaSamw 940da6c28aaSamw assert(path != NULL); 941da6c28aaSamw 942da6c28aaSamw /* make sure we are appropriate length */ 943da6c28aaSamw cp = path + 1; /* skip leading slash */ 944da6c28aaSamw while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) { 945da6c28aaSamw cp = strchr(cp, '/'); 946da6c28aaSamw if (cp != NULL) 947da6c28aaSamw cp++; 948da6c28aaSamw } 949da6c28aaSamw /* two cases - cp == NULL and cp is substring of path */ 950da6c28aaSamw if (cp == NULL) { 951da6c28aaSamw /* just take last SA_MAX_RESOURCE_NAME chars */ 952da6c28aaSamw len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME; 953da6c28aaSamw (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME); 954da6c28aaSamw path[SA_MAX_RESOURCE_NAME] = '\0'; 955da6c28aaSamw } else { 956da6c28aaSamw len = strlen(cp) + 1; 957da6c28aaSamw (void) memmove(path, cp, len); 958da6c28aaSamw } 959da6c28aaSamw 960da6c28aaSamw /* 961da6c28aaSamw * Don't want any of the characters that are not allowed 962da6c28aaSamw * in and SMB share name. Replace them with '_'. 963da6c28aaSamw */ 964da6c28aaSamw while (*path) { 965da6c28aaSamw switch (*path) { 966da6c28aaSamw case '/': 967da6c28aaSamw case '"': 968da6c28aaSamw case '\\': 969da6c28aaSamw case '[': 970da6c28aaSamw case ']': 971da6c28aaSamw case ':': 972da6c28aaSamw case '|': 973da6c28aaSamw case '<': 974da6c28aaSamw case '>': 975da6c28aaSamw case '+': 976da6c28aaSamw case ';': 977da6c28aaSamw case ',': 978da6c28aaSamw case '?': 979da6c28aaSamw case '*': 980da6c28aaSamw case '=': 981da6c28aaSamw case '\t': 982da6c28aaSamw *path = '_'; 983da6c28aaSamw break; 984da6c28aaSamw } 985da6c28aaSamw path++; 986da6c28aaSamw } 987da6c28aaSamw } 988da6c28aaSamw 989da6c28aaSamw /* 990da6c28aaSamw * name_adjust(path, count) 991da6c28aaSamw * 992da6c28aaSamw * Add a ~<count> in place of last few characters. The total number of 993da6c28aaSamw * characters is dependent on count. 994da6c28aaSamw */ 995da6c28aaSamw #define MAX_MANGLE_NUMBER 10000 996da6c28aaSamw 997da6c28aaSamw static int 998da6c28aaSamw name_adjust(char *path, int count) 999da6c28aaSamw { 1000da6c28aaSamw size_t len; 1001da6c28aaSamw 1002da6c28aaSamw len = strlen(path) - 2; 1003da6c28aaSamw if (count > 10) 1004da6c28aaSamw len--; 1005da6c28aaSamw if (count > 100) 1006da6c28aaSamw len--; 1007da6c28aaSamw if (count > 1000) 1008da6c28aaSamw len--; 1009da6c28aaSamw if (len > 0) 1010da6c28aaSamw (void) sprintf(path + len, "~%d", count); 1011da6c28aaSamw else 1012da6c28aaSamw return (SA_BAD_VALUE); 1013da6c28aaSamw 1014da6c28aaSamw return (SA_OK); 1015da6c28aaSamw } 1016da6c28aaSamw 1017da6c28aaSamw /* 1018da6c28aaSamw * make_resources(group) 1019da6c28aaSamw * 1020da6c28aaSamw * Go through all the shares in the group and make them have resource 1021da6c28aaSamw * names. 1022da6c28aaSamw */ 1023da6c28aaSamw static void 1024da6c28aaSamw make_resources(sa_group_t group) 1025da6c28aaSamw { 1026da6c28aaSamw sa_share_t share; 1027da6c28aaSamw int count; 1028da6c28aaSamw int err = SA_OK; 1029da6c28aaSamw 1030da6c28aaSamw for (share = sa_get_share(group, NULL); share != NULL; 1031da6c28aaSamw share = sa_get_next_share(share)) { 1032da6c28aaSamw /* Skip those with resources */ 1033da6c28aaSamw if (sa_get_share_resource(share, NULL) == NULL) { 1034da6c28aaSamw char *path; 1035da6c28aaSamw path = sa_get_share_attr(share, "path"); 1036da6c28aaSamw if (path == NULL) 1037da6c28aaSamw continue; 1038da6c28aaSamw fix_path(path); 1039da6c28aaSamw count = 0; /* reset for next resource */ 1040da6c28aaSamw while (sa_add_resource(share, path, 1041da6c28aaSamw SA_SHARE_PERMANENT, &err) == NULL && 1042da6c28aaSamw err == SA_DUPLICATE_NAME) { 1043da6c28aaSamw int ret; 1044da6c28aaSamw ret = name_adjust(path, count); 1045da6c28aaSamw count++; 1046da6c28aaSamw if (ret != SA_OK || 1047da6c28aaSamw count >= MAX_MANGLE_NUMBER) { 1048da6c28aaSamw (void) printf(gettext( 1049da6c28aaSamw "Cannot create resource name for" 1050da6c28aaSamw " path: %s\n"), path); 1051da6c28aaSamw break; 1052da6c28aaSamw } 1053da6c28aaSamw } 1054da6c28aaSamw sa_free_attr_string(path); 1055da6c28aaSamw } 1056da6c28aaSamw } 1057da6c28aaSamw } 1058da6c28aaSamw 10599e5da854Sdougm /* 10609e5da854Sdougm * check_valid_group(group, protocol) 10619e5da854Sdougm * 10629e5da854Sdougm * Check to see that the group should have the protocol added (if 10639e5da854Sdougm * there is one specified). 10649e5da854Sdougm */ 10659e5da854Sdougm 10669e5da854Sdougm static int 10679e5da854Sdougm check_valid_group(sa_group_t group, char *groupname, char *protocol) 10689e5da854Sdougm { 10699e5da854Sdougm 10709e5da854Sdougm if (protocol != NULL) { 10719e5da854Sdougm if (has_protocol(group, protocol)) { 10729e5da854Sdougm (void) printf(gettext( 10739e5da854Sdougm "Group \"%s\" already exists" 10749e5da854Sdougm " with protocol %s\n"), groupname, 10759e5da854Sdougm protocol); 10769e5da854Sdougm return (SA_DUPLICATE_NAME); 10779e5da854Sdougm } else if (strcmp(groupname, "default") == 0 && 10789e5da854Sdougm strcmp(protocol, "nfs") != 0) { 10799e5da854Sdougm (void) printf(gettext( 10809e5da854Sdougm "Group \"%s\" only allows protocol " 10819e5da854Sdougm "\"%s\"\n"), groupname, "nfs"); 10829e5da854Sdougm return (SA_INVALID_PROTOCOL); 10839e5da854Sdougm } 10849e5da854Sdougm } else { 10859e5da854Sdougm /* must add new protocol */ 10869e5da854Sdougm (void) printf(gettext( 10879e5da854Sdougm "Group already exists and no protocol " 10889e5da854Sdougm "specified.\n")); 10899e5da854Sdougm return (SA_DUPLICATE_NAME); 10909e5da854Sdougm } 10919e5da854Sdougm return (SA_OK); 10929e5da854Sdougm } 10939e5da854Sdougm 10949e5da854Sdougm /* 10959e5da854Sdougm * enforce_featureset(group, protocol, dryrun, force) 10969e5da854Sdougm * 10979e5da854Sdougm * Check the protocol featureset against the group and enforce any 10989e5da854Sdougm * rules that might be imposed. 10999e5da854Sdougm */ 11009e5da854Sdougm 11019e5da854Sdougm static int 11029e5da854Sdougm enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun, 11039e5da854Sdougm boolean_t force) 11049e5da854Sdougm { 11059e5da854Sdougm uint64_t features; 11069e5da854Sdougm 11079e5da854Sdougm if (protocol == NULL) 11089e5da854Sdougm return (SA_OK); 11099e5da854Sdougm 11109e5da854Sdougm /* 11119e5da854Sdougm * First check to see if specified protocol is one we want to 11129e5da854Sdougm * allow on a group. Only server protocols are allowed here. 11139e5da854Sdougm */ 11149e5da854Sdougm features = sa_proto_get_featureset(protocol); 11159e5da854Sdougm if (!(features & SA_FEATURE_SERVER)) { 11169e5da854Sdougm (void) printf( 11179e5da854Sdougm gettext("Protocol \"%s\" not supported.\n"), protocol); 11189e5da854Sdougm return (SA_INVALID_PROTOCOL); 11199e5da854Sdougm } 11209e5da854Sdougm 11219e5da854Sdougm /* 11229e5da854Sdougm * Check to see if the new protocol is one that requires 11239e5da854Sdougm * resource names and make sure we are compliant before 11249e5da854Sdougm * proceeding. 11259e5da854Sdougm */ 11269e5da854Sdougm if ((features & SA_FEATURE_RESOURCE) && 11279e5da854Sdougm !resource_compliant(group)) { 11289e5da854Sdougm if (force && !dryrun) { 11299e5da854Sdougm make_resources(group); 11309e5da854Sdougm } else { 11319e5da854Sdougm (void) printf( 11329e5da854Sdougm gettext("Protocol requires resource names to be " 11339e5da854Sdougm "set: %s\n"), protocol); 11349e5da854Sdougm return (SA_RESOURCE_REQUIRED); 11359e5da854Sdougm } 11369e5da854Sdougm } 11379e5da854Sdougm return (SA_OK); 11389e5da854Sdougm } 11399e5da854Sdougm 11409e5da854Sdougm /* 11419e5da854Sdougm * set_all_protocols(group) 11429e5da854Sdougm * 11439e5da854Sdougm * Get the list of all protocols and add all server protocols to the 11449e5da854Sdougm * group. 11459e5da854Sdougm */ 11469e5da854Sdougm 11479e5da854Sdougm static int 11489e5da854Sdougm set_all_protocols(sa_group_t group) 11499e5da854Sdougm { 11509e5da854Sdougm char **protolist; 11519e5da854Sdougm int numprotos, i; 11529e5da854Sdougm uint64_t features; 11539e5da854Sdougm sa_optionset_t optionset; 11549e5da854Sdougm int ret = SA_OK; 11559e5da854Sdougm 11569e5da854Sdougm /* 11579e5da854Sdougm * Now make sure we really want to put this protocol on a 11589e5da854Sdougm * group. Only server protocols can go here. 11599e5da854Sdougm */ 11609e5da854Sdougm numprotos = sa_get_protocols(&protolist); 11619e5da854Sdougm for (i = 0; i < numprotos; i++) { 11629e5da854Sdougm features = sa_proto_get_featureset(protolist[i]); 11639e5da854Sdougm if (features & SA_FEATURE_SERVER) { 11649e5da854Sdougm optionset = sa_create_optionset(group, protolist[i]); 11659e5da854Sdougm if (optionset == NULL) { 11669e5da854Sdougm ret = SA_NO_MEMORY; 11679e5da854Sdougm break; 11689e5da854Sdougm } 11699e5da854Sdougm } 11709e5da854Sdougm } 11719e5da854Sdougm 11729e5da854Sdougm if (protolist != NULL) 11739e5da854Sdougm free(protolist); 11749e5da854Sdougm 11759e5da854Sdougm return (ret); 11769e5da854Sdougm } 11779e5da854Sdougm 11786185db85Sdougm /* 11796185db85Sdougm * sa_create(flags, argc, argv) 11806185db85Sdougm * create a new group 11816185db85Sdougm * this may or may not have a protocol associated with it. 11826185db85Sdougm * No protocol means "all" protocols in this case. 11836185db85Sdougm */ 11846185db85Sdougm static int 1185549ec3ffSdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[]) 11866185db85Sdougm { 11876185db85Sdougm char *groupname; 11886185db85Sdougm 11896185db85Sdougm sa_group_t group; 11909e5da854Sdougm boolean_t force = B_FALSE; 11919e5da854Sdougm boolean_t verbose = B_FALSE; 11929e5da854Sdougm boolean_t dryrun = B_FALSE; 11936185db85Sdougm int c; 11946185db85Sdougm char *protocol = NULL; 11956185db85Sdougm int ret = SA_OK; 11966185db85Sdougm struct options *optlist = NULL; 1197e7bab347Sdougm int err = SA_OK; 11986185db85Sdougm int auth; 11999e5da854Sdougm boolean_t created = B_FALSE; 12006185db85Sdougm 1201da6c28aaSamw while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) { 120225a68471Sdougm switch (c) { 1203da6c28aaSamw case 'f': 12049e5da854Sdougm force = B_TRUE; 1205da6c28aaSamw break; 120625a68471Sdougm case 'v': 12079e5da854Sdougm verbose = B_TRUE; 120825a68471Sdougm break; 120925a68471Sdougm case 'n': 12109e5da854Sdougm dryrun = B_TRUE; 121125a68471Sdougm break; 121225a68471Sdougm case 'P': 1213da6c28aaSamw if (protocol != NULL) { 1214da6c28aaSamw (void) printf(gettext("Specifying " 1215da6c28aaSamw "multiple protocols " 1216da6c28aaSamw "not supported: %s\n"), protocol); 1217da6c28aaSamw return (SA_SYNTAX_ERR); 1218da6c28aaSamw } 121925a68471Sdougm protocol = optarg; 122025a68471Sdougm if (sa_valid_protocol(protocol)) 122125a68471Sdougm break; 122225a68471Sdougm (void) printf(gettext( 122325a68471Sdougm "Invalid protocol specified: %s\n"), protocol); 122425a68471Sdougm return (SA_INVALID_PROTOCOL); 122525a68471Sdougm case 'p': 122625a68471Sdougm ret = add_opt(&optlist, optarg, 0); 122725a68471Sdougm switch (ret) { 122825a68471Sdougm case OPT_ADD_SYNTAX: 122925a68471Sdougm (void) printf(gettext( 123025a68471Sdougm "Property syntax error for property: %s\n"), 12316185db85Sdougm optarg); 123225a68471Sdougm return (SA_SYNTAX_ERR); 123325a68471Sdougm case OPT_ADD_SECURITY: 123425a68471Sdougm (void) printf(gettext( 123525a68471Sdougm "Security properties need " 123625a68471Sdougm "to be set with set-security: %s\n"), 12376185db85Sdougm optarg); 123825a68471Sdougm return (SA_SYNTAX_ERR); 123925a68471Sdougm default: 124025a68471Sdougm break; 124125a68471Sdougm } 124225a68471Sdougm break; 124325a68471Sdougm case 'h': 1244e7bab347Sdougm /* optopt on valid arg isn't defined */ 1245e7bab347Sdougm optopt = c; 1246e7bab347Sdougm /*FALLTHROUGH*/ 124725a68471Sdougm case '?': 1248e7bab347Sdougm default: 1249e7bab347Sdougm /* 1250e7bab347Sdougm * Since a bad option gets to here, sort it 1251e7bab347Sdougm * out and return a syntax error return value 1252e7bab347Sdougm * if necessary. 1253e7bab347Sdougm */ 1254e7bab347Sdougm switch (optopt) { 1255e7bab347Sdougm default: 1256e7bab347Sdougm err = SA_SYNTAX_ERR; 1257e7bab347Sdougm break; 1258e7bab347Sdougm case 'h': 1259e7bab347Sdougm case '?': 1260e7bab347Sdougm break; 1261e7bab347Sdougm } 126225a68471Sdougm (void) printf(gettext("usage: %s\n"), 126325a68471Sdougm sa_get_usage(USAGE_CREATE)); 1264e7bab347Sdougm return (err); 12656185db85Sdougm } 12666185db85Sdougm } 12676185db85Sdougm 12686185db85Sdougm if (optind >= argc) { 126925a68471Sdougm (void) printf(gettext("usage: %s\n"), 127025a68471Sdougm sa_get_usage(USAGE_CREATE)); 127125a68471Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 127225a68471Sdougm return (SA_BAD_PATH); 12736185db85Sdougm } 12746185db85Sdougm 12756185db85Sdougm if ((optind + 1) < argc) { 127625a68471Sdougm (void) printf(gettext("usage: %s\n"), 127725a68471Sdougm sa_get_usage(USAGE_CREATE)); 127825a68471Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 127925a68471Sdougm return (SA_SYNTAX_ERR); 12806185db85Sdougm } 12816185db85Sdougm 12826185db85Sdougm if (protocol == NULL && optlist != NULL) { 128325a68471Sdougm /* lookup default protocol */ 128425a68471Sdougm (void) printf(gettext("usage: %s\n"), 128525a68471Sdougm sa_get_usage(USAGE_CREATE)); 128625a68471Sdougm (void) printf(gettext("\tprotocol must be specified " 128725a68471Sdougm "with properties\n")); 128825a68471Sdougm return (SA_INVALID_PROTOCOL); 12896185db85Sdougm } 12906185db85Sdougm 12916185db85Sdougm if (optlist != NULL) 129225a68471Sdougm ret = chk_opt(optlist, 0, protocol); 12936185db85Sdougm if (ret == OPT_ADD_SECURITY) { 129425a68471Sdougm (void) printf(gettext("Security properties not " 129525a68471Sdougm "supported with create\n")); 129625a68471Sdougm return (SA_SYNTAX_ERR); 12976185db85Sdougm } 12986185db85Sdougm 12996185db85Sdougm /* 130025a68471Sdougm * If a group already exists, we can only add a new protocol 13016185db85Sdougm * to it and not create a new one or add the same protocol 13026185db85Sdougm * again. 13036185db85Sdougm */ 13046185db85Sdougm 13056185db85Sdougm groupname = argv[optind]; 13066185db85Sdougm 13076185db85Sdougm auth = check_authorizations(groupname, flags); 13086185db85Sdougm 1309549ec3ffSdougm group = sa_get_group(handle, groupname); 13106185db85Sdougm if (group != NULL) { 131125a68471Sdougm /* group exists so must be a protocol add */ 13129e5da854Sdougm ret = check_valid_group(group, groupname, protocol); 13136185db85Sdougm } else { 13146185db85Sdougm /* 13156185db85Sdougm * is it a valid name? Must comply with SMF instance 13166185db85Sdougm * name restrictions. 13176185db85Sdougm */ 131825a68471Sdougm if (!sa_valid_group_name(groupname)) { 131925a68471Sdougm ret = SA_INVALID_NAME; 132025a68471Sdougm (void) printf(gettext("Invalid group name: %s\n"), 132125a68471Sdougm groupname); 132225a68471Sdougm } 13236185db85Sdougm } 13246185db85Sdougm if (ret == SA_OK) { 132525a68471Sdougm /* check protocol vs optlist */ 132625a68471Sdougm if (optlist != NULL) { 132725a68471Sdougm /* check options, if any, for validity */ 1328687915e9Sdougm ret = valid_options(handle, optlist, protocol, 1329687915e9Sdougm group, NULL); 133025a68471Sdougm } 13316185db85Sdougm } 13326185db85Sdougm if (ret == SA_OK && !dryrun) { 133325a68471Sdougm if (group == NULL) { 133425a68471Sdougm group = sa_create_group(handle, (char *)groupname, 133525a68471Sdougm &err); 13369e5da854Sdougm created = B_TRUE; 13376185db85Sdougm } 133825a68471Sdougm if (group != NULL) { 133925a68471Sdougm sa_optionset_t optionset; 13409e5da854Sdougm 1341da6c28aaSamw /* 13429e5da854Sdougm * Check group and protocol against featureset 13439e5da854Sdougm * requirements. 1344da6c28aaSamw */ 13459e5da854Sdougm ret = enforce_featureset(group, protocol, 13469e5da854Sdougm dryrun, force); 13479e5da854Sdougm if (ret != SA_OK) 13489e5da854Sdougm goto err; 1349da6c28aaSamw 13509e5da854Sdougm /* 13519e5da854Sdougm * So far so good. Now add the required 13529e5da854Sdougm * optionset(s) to the group. 13539e5da854Sdougm */ 135425a68471Sdougm if (optlist != NULL) { 135525a68471Sdougm (void) add_optionset(group, optlist, protocol, 135625a68471Sdougm &ret); 135725a68471Sdougm } else if (protocol != NULL) { 135825a68471Sdougm optionset = sa_create_optionset(group, 135925a68471Sdougm protocol); 136025a68471Sdougm if (optionset == NULL) 136125a68471Sdougm ret = SA_NO_MEMORY; 136225a68471Sdougm } else if (protocol == NULL) { 13639e5da854Sdougm /* default group create so add all protocols */ 13649e5da854Sdougm ret = set_all_protocols(group); 136525a68471Sdougm } 13666185db85Sdougm /* 136725a68471Sdougm * We have a group and legal additions 13686185db85Sdougm */ 136925a68471Sdougm if (ret == SA_OK) { 137025a68471Sdougm /* 137125a68471Sdougm * Commit to configuration for protocols that 137225a68471Sdougm * need to do block updates. For NFS, this 137325a68471Sdougm * doesn't do anything but it will be run for 137425a68471Sdougm * all protocols that implement the 137525a68471Sdougm * appropriate plugin. 137625a68471Sdougm */ 137725a68471Sdougm ret = sa_update_config(handle); 137825a68471Sdougm } else { 137925a68471Sdougm if (group != NULL) 138025a68471Sdougm (void) sa_remove_group(group); 138125a68471Sdougm } 13826185db85Sdougm } else { 138325a68471Sdougm ret = err; 138425a68471Sdougm (void) printf(gettext("Could not create group: %s\n"), 138525a68471Sdougm sa_errorstr(ret)); 13866185db85Sdougm } 13876185db85Sdougm } 13886185db85Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 138925a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 139025a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 139125a68471Sdougm ret = SA_NO_PERMISSION; 13926185db85Sdougm } 1393da6c28aaSamw err: 13949e5da854Sdougm if (ret != SA_OK && created) 13959e5da854Sdougm ret = sa_remove_group(group); 13969e5da854Sdougm 13976185db85Sdougm free_opt(optlist); 13986185db85Sdougm return (ret); 13996185db85Sdougm } 14006185db85Sdougm 14016185db85Sdougm /* 14026185db85Sdougm * group_status(group) 14036185db85Sdougm * 14046185db85Sdougm * return the current status (enabled/disabled) of the group. 14056185db85Sdougm */ 14066185db85Sdougm 14076185db85Sdougm static char * 14086185db85Sdougm group_status(sa_group_t group) 14096185db85Sdougm { 14106185db85Sdougm char *state; 14116185db85Sdougm int enabled = 0; 14126185db85Sdougm 14136185db85Sdougm state = sa_get_group_attr(group, "state"); 14146185db85Sdougm if (state != NULL) { 141525a68471Sdougm if (strcmp(state, "enabled") == 0) { 141625a68471Sdougm enabled = 1; 141725a68471Sdougm } 141825a68471Sdougm sa_free_attr_string(state); 14196185db85Sdougm } 14204db300d5Sdougm return (enabled ? "enabled" : "disabled"); 14216185db85Sdougm } 14226185db85Sdougm 14236185db85Sdougm /* 14246185db85Sdougm * sa_delete(flags, argc, argv) 14256185db85Sdougm * 14266185db85Sdougm * Delete a group. 14276185db85Sdougm */ 14286185db85Sdougm 14296185db85Sdougm static int 1430549ec3ffSdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[]) 14316185db85Sdougm { 14326185db85Sdougm char *groupname; 14336185db85Sdougm sa_group_t group; 14346185db85Sdougm sa_share_t share; 14356185db85Sdougm int verbose = 0; 14366185db85Sdougm int dryrun = 0; 14376185db85Sdougm int force = 0; 14386185db85Sdougm int c; 14396185db85Sdougm char *protocol = NULL; 14406185db85Sdougm char *sectype = NULL; 14416185db85Sdougm int ret = SA_OK; 14426185db85Sdougm int auth; 14436185db85Sdougm 14446185db85Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 144525a68471Sdougm switch (c) { 144625a68471Sdougm case 'v': 144725a68471Sdougm verbose++; 144825a68471Sdougm break; 144925a68471Sdougm case 'n': 145025a68471Sdougm dryrun++; 145125a68471Sdougm break; 145225a68471Sdougm case 'P': 1453da6c28aaSamw if (protocol != NULL) { 1454da6c28aaSamw (void) printf(gettext("Specifying " 1455da6c28aaSamw "multiple protocols " 1456da6c28aaSamw "not supported: %s\n"), protocol); 1457da6c28aaSamw return (SA_SYNTAX_ERR); 1458da6c28aaSamw } 145925a68471Sdougm protocol = optarg; 146025a68471Sdougm if (!sa_valid_protocol(protocol)) { 146125a68471Sdougm (void) printf(gettext("Invalid protocol " 1462da6c28aaSamw "specified: %s\n"), protocol); 146325a68471Sdougm return (SA_INVALID_PROTOCOL); 146425a68471Sdougm } 146525a68471Sdougm break; 146625a68471Sdougm case 'S': 1467da6c28aaSamw if (sectype != NULL) { 1468da6c28aaSamw (void) printf(gettext("Specifying " 1469da6c28aaSamw "multiple property " 1470da6c28aaSamw "spaces not supported: %s\n"), sectype); 1471da6c28aaSamw return (SA_SYNTAX_ERR); 1472da6c28aaSamw } 147325a68471Sdougm sectype = optarg; 147425a68471Sdougm break; 147525a68471Sdougm case 'f': 147625a68471Sdougm force++; 147725a68471Sdougm break; 147825a68471Sdougm case 'h': 1479e7bab347Sdougm /* optopt on valid arg isn't defined */ 1480e7bab347Sdougm optopt = c; 1481e7bab347Sdougm /*FALLTHROUGH*/ 148225a68471Sdougm case '?': 1483e7bab347Sdougm default: 1484e7bab347Sdougm /* 1485e7bab347Sdougm * Since a bad option gets to here, sort it 1486e7bab347Sdougm * out and return a syntax error return value 1487e7bab347Sdougm * if necessary. 1488e7bab347Sdougm */ 1489e7bab347Sdougm switch (optopt) { 1490e7bab347Sdougm default: 1491e7bab347Sdougm ret = SA_SYNTAX_ERR; 1492e7bab347Sdougm break; 1493e7bab347Sdougm case 'h': 1494e7bab347Sdougm case '?': 1495e7bab347Sdougm break; 1496e7bab347Sdougm } 149725a68471Sdougm (void) printf(gettext("usage: %s\n"), 149825a68471Sdougm sa_get_usage(USAGE_DELETE)); 1499e7bab347Sdougm return (ret); 15006185db85Sdougm } 15016185db85Sdougm } 15026185db85Sdougm 15036185db85Sdougm if (optind >= argc) { 150425a68471Sdougm (void) printf(gettext("usage: %s\n"), 150525a68471Sdougm sa_get_usage(USAGE_DELETE)); 150625a68471Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 150725a68471Sdougm return (SA_SYNTAX_ERR); 15086185db85Sdougm } 15096185db85Sdougm 15106185db85Sdougm if ((optind + 1) < argc) { 151125a68471Sdougm (void) printf(gettext("usage: %s\n"), 151225a68471Sdougm sa_get_usage(USAGE_DELETE)); 151325a68471Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 151425a68471Sdougm return (SA_SYNTAX_ERR); 15156185db85Sdougm } 15166185db85Sdougm 15176185db85Sdougm if (sectype != NULL && protocol == NULL) { 151825a68471Sdougm (void) printf(gettext("usage: %s\n"), 151925a68471Sdougm sa_get_usage(USAGE_DELETE)); 152025a68471Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 152125a68471Sdougm "specified.\n")); 152225a68471Sdougm return (SA_SYNTAX_ERR); 15236185db85Sdougm } 15246185db85Sdougm 15256185db85Sdougm /* 15266185db85Sdougm * Determine if the group already exists since it must in 15276185db85Sdougm * order to be removed. 15286185db85Sdougm * 15296185db85Sdougm * We can delete when: 15306185db85Sdougm * 15316185db85Sdougm * - group is empty 15326185db85Sdougm * - force flag is set 15336185db85Sdougm * - if protocol specified, only delete the protocol 15346185db85Sdougm */ 15356185db85Sdougm 15366185db85Sdougm groupname = argv[optind]; 1537549ec3ffSdougm group = sa_get_group(handle, groupname); 15386185db85Sdougm if (group == NULL) { 15396185db85Sdougm ret = SA_NO_SUCH_GROUP; 154025a68471Sdougm goto done; 154125a68471Sdougm } 154225a68471Sdougm auth = check_authorizations(groupname, flags); 154325a68471Sdougm if (protocol == NULL) { 15446185db85Sdougm share = sa_get_share(group, NULL); 15456185db85Sdougm if (share != NULL) 154625a68471Sdougm ret = SA_BUSY; 15476185db85Sdougm if (share == NULL || (share != NULL && force == 1)) { 154825a68471Sdougm ret = SA_OK; 154925a68471Sdougm if (!dryrun) { 155025a68471Sdougm while (share != NULL) { 155125a68471Sdougm sa_share_t next_share; 155225a68471Sdougm next_share = sa_get_next_share(share); 155325a68471Sdougm /* 155425a68471Sdougm * need to do the disable of 155525a68471Sdougm * each share, but don't 155625a68471Sdougm * actually do anything on a 155725a68471Sdougm * dryrun. 155825a68471Sdougm */ 155925a68471Sdougm ret = sa_disable_share(share, NULL); 156025a68471Sdougm ret = sa_remove_share(share); 156125a68471Sdougm share = next_share; 156225a68471Sdougm } 156325a68471Sdougm ret = sa_remove_group(group); 15646185db85Sdougm } 15656185db85Sdougm } 156625a68471Sdougm /* Commit to configuration if not a dryrun */ 15676185db85Sdougm if (!dryrun && ret == SA_OK) { 156825a68471Sdougm ret = sa_update_config(handle); 15696185db85Sdougm } 157025a68471Sdougm } else { 15716185db85Sdougm /* a protocol delete */ 15726185db85Sdougm sa_optionset_t optionset; 15736185db85Sdougm sa_security_t security; 1574da6c28aaSamw if (sectype != NULL) { 157525a68471Sdougm /* only delete specified security */ 157625a68471Sdougm security = sa_get_security(group, sectype, protocol); 157725a68471Sdougm if (security != NULL && !dryrun) 15786185db85Sdougm ret = sa_destroy_security(security); 157925a68471Sdougm else 158025a68471Sdougm ret = SA_INVALID_PROTOCOL; 158125a68471Sdougm } else { 158225a68471Sdougm optionset = sa_get_optionset(group, protocol); 158325a68471Sdougm if (optionset != NULL && !dryrun) { 158425a68471Sdougm /* 158525a68471Sdougm * have an optionset with 158625a68471Sdougm * protocol to delete 158725a68471Sdougm */ 158825a68471Sdougm ret = sa_destroy_optionset(optionset); 158925a68471Sdougm /* 159025a68471Sdougm * Now find all security sets 159125a68471Sdougm * for the protocol and remove 159225a68471Sdougm * them. Don't remove other 159325a68471Sdougm * protocols. 159425a68471Sdougm */ 159525a68471Sdougm for (security = 159625a68471Sdougm sa_get_security(group, NULL, NULL); 159725a68471Sdougm ret == SA_OK && security != NULL; 159825a68471Sdougm security = sa_get_next_security(security)) { 159925a68471Sdougm char *secprot; 160025a68471Sdougm secprot = sa_get_security_attr(security, 160125a68471Sdougm "type"); 160225a68471Sdougm if (secprot != NULL && 160325a68471Sdougm strcmp(secprot, protocol) == 0) 160425a68471Sdougm ret = sa_destroy_security( 160525a68471Sdougm security); 160625a68471Sdougm if (secprot != NULL) 160725a68471Sdougm sa_free_attr_string(secprot); 160825a68471Sdougm } 160925a68471Sdougm } else { 161025a68471Sdougm if (!dryrun) 161125a68471Sdougm ret = SA_INVALID_PROTOCOL; 16126185db85Sdougm } 16136185db85Sdougm } 1614da6c28aaSamw /* 1615da6c28aaSamw * With the protocol items removed, make sure that all 1616da6c28aaSamw * the shares are updated in the legacy files, if 1617da6c28aaSamw * necessary. 1618da6c28aaSamw */ 1619da6c28aaSamw for (share = sa_get_share(group, NULL); 1620da6c28aaSamw share != NULL; 1621da6c28aaSamw share = sa_get_next_share(share)) { 1622da6c28aaSamw (void) sa_delete_legacy(share, protocol); 1623da6c28aaSamw } 16246185db85Sdougm } 162525a68471Sdougm 162625a68471Sdougm done: 16276185db85Sdougm if (ret != SA_OK) { 162825a68471Sdougm (void) printf(gettext("Could not delete group: %s\n"), 162925a68471Sdougm sa_errorstr(ret)); 16306185db85Sdougm } else if (dryrun && !auth && verbose) { 163125a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 163225a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 16336185db85Sdougm } 16346185db85Sdougm return (ret); 16356185db85Sdougm } 16366185db85Sdougm 16376185db85Sdougm /* 16386185db85Sdougm * strndupr(*buff, str, buffsize) 16396185db85Sdougm * 16406185db85Sdougm * used with small strings to duplicate and possibly increase the 16416185db85Sdougm * buffer size of a string. 16426185db85Sdougm */ 16436185db85Sdougm static char * 16446185db85Sdougm strndupr(char *buff, char *str, int *buffsize) 16456185db85Sdougm { 16466185db85Sdougm int limit; 16476185db85Sdougm char *orig_buff = buff; 16486185db85Sdougm 16496185db85Sdougm if (buff == NULL) { 165025a68471Sdougm buff = (char *)malloc(64); 165125a68471Sdougm if (buff == NULL) 165225a68471Sdougm return (NULL); 165325a68471Sdougm *buffsize = 64; 165425a68471Sdougm buff[0] = '\0'; 16556185db85Sdougm } 16566185db85Sdougm limit = strlen(buff) + strlen(str) + 1; 16576185db85Sdougm if (limit > *buffsize) { 165825a68471Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 165925a68471Sdougm buff = realloc(buff, limit); 16606185db85Sdougm } 16616185db85Sdougm if (buff != NULL) { 166225a68471Sdougm (void) strcat(buff, str); 16636185db85Sdougm } else { 166425a68471Sdougm /* if it fails, fail it hard */ 166525a68471Sdougm if (orig_buff != NULL) 166625a68471Sdougm free(orig_buff); 16676185db85Sdougm } 16686185db85Sdougm return (buff); 16696185db85Sdougm } 16706185db85Sdougm 16716185db85Sdougm /* 16726185db85Sdougm * group_proto(group) 16736185db85Sdougm * 16746185db85Sdougm * return a string of all the protocols (space separated) associated 16756185db85Sdougm * with this group. 16766185db85Sdougm */ 16776185db85Sdougm 16786185db85Sdougm static char * 16796185db85Sdougm group_proto(sa_group_t group) 16806185db85Sdougm { 16816185db85Sdougm sa_optionset_t optionset; 16826185db85Sdougm char *proto; 16836185db85Sdougm char *buff = NULL; 16846185db85Sdougm int buffsize = 0; 16856185db85Sdougm int addspace = 0; 16866185db85Sdougm /* 16876185db85Sdougm * get the protocol list by finding the optionsets on this 16886185db85Sdougm * group and extracting the type value. The initial call to 16896185db85Sdougm * strndupr() initailizes buff. 16906185db85Sdougm */ 16916185db85Sdougm buff = strndupr(buff, "", &buffsize); 16926185db85Sdougm if (buff != NULL) { 169325a68471Sdougm for (optionset = sa_get_optionset(group, NULL); 169425a68471Sdougm optionset != NULL && buff != NULL; 169525a68471Sdougm optionset = sa_get_next_optionset(optionset)) { 169625a68471Sdougm /* 169725a68471Sdougm * extract out the protocol type from this optionset 169825a68471Sdougm * and append it to the buffer "buff". strndupr() will 169925a68471Sdougm * reallocate space as necessay. 170025a68471Sdougm */ 170125a68471Sdougm proto = sa_get_optionset_attr(optionset, "type"); 170225a68471Sdougm if (proto != NULL) { 170325a68471Sdougm if (addspace++) 170425a68471Sdougm buff = strndupr(buff, " ", &buffsize); 170525a68471Sdougm buff = strndupr(buff, proto, &buffsize); 170625a68471Sdougm sa_free_attr_string(proto); 170725a68471Sdougm } 17086185db85Sdougm } 17096185db85Sdougm } 17106185db85Sdougm return (buff); 17116185db85Sdougm } 17126185db85Sdougm 17136185db85Sdougm /* 17146185db85Sdougm * sa_list(flags, argc, argv) 17156185db85Sdougm * 17166185db85Sdougm * implements the "list" subcommand to list groups and optionally 17176185db85Sdougm * their state and protocols. 17186185db85Sdougm */ 17196185db85Sdougm 17206185db85Sdougm static int 1721549ec3ffSdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[]) 17226185db85Sdougm { 17236185db85Sdougm sa_group_t group; 17246185db85Sdougm int verbose = 0; 17256185db85Sdougm int c; 17266185db85Sdougm char *protocol = NULL; 1727e7bab347Sdougm int ret = SA_OK; 1728da6c28aaSamw #ifdef lint 1729da6c28aaSamw flags = flags; 1730da6c28aaSamw #endif 17316185db85Sdougm 17326185db85Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 173325a68471Sdougm switch (c) { 173425a68471Sdougm case 'v': 173525a68471Sdougm verbose++; 173625a68471Sdougm break; 173725a68471Sdougm case 'P': 1738da6c28aaSamw if (protocol != NULL) { 1739da6c28aaSamw (void) printf(gettext( 1740da6c28aaSamw "Specifying multiple protocols " 1741da6c28aaSamw "not supported: %s\n"), 1742da6c28aaSamw protocol); 1743da6c28aaSamw return (SA_SYNTAX_ERR); 1744da6c28aaSamw } 174525a68471Sdougm protocol = optarg; 174625a68471Sdougm if (!sa_valid_protocol(protocol)) { 174725a68471Sdougm (void) printf(gettext( 174825a68471Sdougm "Invalid protocol specified: %s\n"), 174925a68471Sdougm protocol); 175025a68471Sdougm return (SA_INVALID_PROTOCOL); 175125a68471Sdougm } 175225a68471Sdougm break; 175325a68471Sdougm case 'h': 1754e7bab347Sdougm /* optopt on valid arg isn't defined */ 1755e7bab347Sdougm optopt = c; 1756e7bab347Sdougm /*FALLTHROUGH*/ 175725a68471Sdougm case '?': 1758e7bab347Sdougm default: 1759e7bab347Sdougm /* 1760e7bab347Sdougm * Since a bad option gets to here, sort it 1761e7bab347Sdougm * out and return a syntax error return value 1762e7bab347Sdougm * if necessary. 1763e7bab347Sdougm */ 1764e7bab347Sdougm switch (optopt) { 1765e7bab347Sdougm default: 1766e7bab347Sdougm ret = SA_SYNTAX_ERR; 1767e7bab347Sdougm break; 1768e7bab347Sdougm case 'h': 1769e7bab347Sdougm case '?': 1770e7bab347Sdougm break; 1771e7bab347Sdougm } 177225a68471Sdougm (void) printf(gettext("usage: %s\n"), 177325a68471Sdougm sa_get_usage(USAGE_LIST)); 1774*a8cc26d6SJohn Levon return (ret); 17756185db85Sdougm } 17766185db85Sdougm } 17776185db85Sdougm 1778573b0c00Sdougm if (optind != argc) { 1779573b0c00Sdougm (void) printf(gettext("usage: %s\n"), 1780573b0c00Sdougm sa_get_usage(USAGE_LIST)); 1781573b0c00Sdougm return (SA_SYNTAX_ERR); 1782573b0c00Sdougm } 1783573b0c00Sdougm 178425a68471Sdougm for (group = sa_get_group(handle, NULL); 178525a68471Sdougm group != NULL; 17866185db85Sdougm group = sa_get_next_group(group)) { 178725a68471Sdougm char *name; 178825a68471Sdougm char *proto; 178925a68471Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 179025a68471Sdougm name = sa_get_group_attr(group, "name"); 179125a68471Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 179225a68471Sdougm (void) printf("%s", (char *)name); 179325a68471Sdougm if (verbose) { 179425a68471Sdougm /* 179525a68471Sdougm * Need the list of protocols 179625a68471Sdougm * and current status once 179725a68471Sdougm * available. We do want to 179825a68471Sdougm * translate the 179925a68471Sdougm * enabled/disabled text here. 180025a68471Sdougm */ 180125a68471Sdougm (void) printf("\t%s", isenabled(group) ? 180225a68471Sdougm gettext("enabled") : 180325a68471Sdougm gettext("disabled")); 180425a68471Sdougm proto = group_proto(group); 180525a68471Sdougm if (proto != NULL) { 180625a68471Sdougm (void) printf("\t%s", 180725a68471Sdougm (char *)proto); 180825a68471Sdougm free(proto); 180925a68471Sdougm } 181025a68471Sdougm } 181125a68471Sdougm (void) printf("\n"); 18126185db85Sdougm } 181325a68471Sdougm if (name != NULL) 181425a68471Sdougm sa_free_attr_string(name); 18156185db85Sdougm } 18166185db85Sdougm } 18176185db85Sdougm return (0); 18186185db85Sdougm } 18196185db85Sdougm 18206185db85Sdougm /* 18216185db85Sdougm * out_properties(optionset, proto, sec) 18226185db85Sdougm * 18236185db85Sdougm * Format the properties and encode the protocol and optional named 18246185db85Sdougm * optionset into the string. 18256185db85Sdougm * 18266185db85Sdougm * format is protocol[:name]=(property-list) 18276185db85Sdougm */ 18286185db85Sdougm 18296185db85Sdougm static void 18306185db85Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 18316185db85Sdougm { 18326185db85Sdougm char *type; 18336185db85Sdougm char *value; 18346185db85Sdougm int spacer; 18356185db85Sdougm sa_property_t prop; 18366185db85Sdougm 183725a68471Sdougm if (sec == NULL) 183825a68471Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 183925a68471Sdougm else 184025a68471Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 18416185db85Sdougm 18426185db85Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 184325a68471Sdougm prop != NULL; 184425a68471Sdougm prop = sa_get_next_property(prop)) { 18456185db85Sdougm 18466185db85Sdougm /* 18476185db85Sdougm * extract the property name/value and output with 18486185db85Sdougm * appropriate spacing. I.e. no prefixed space the 18496185db85Sdougm * first time through but a space on subsequent 18506185db85Sdougm * properties. 18516185db85Sdougm */ 185225a68471Sdougm type = sa_get_property_attr(prop, "type"); 185325a68471Sdougm value = sa_get_property_attr(prop, "value"); 185425a68471Sdougm if (type != NULL) { 185525a68471Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 185625a68471Sdougm spacer = 1; 185725a68471Sdougm if (value != NULL) 185825a68471Sdougm (void) printf("\"%s\"", value); 185925a68471Sdougm else 186025a68471Sdougm (void) printf("\"\""); 186125a68471Sdougm } 186225a68471Sdougm if (type != NULL) 186325a68471Sdougm sa_free_attr_string(type); 18646185db85Sdougm if (value != NULL) 186525a68471Sdougm sa_free_attr_string(value); 18666185db85Sdougm } 18676185db85Sdougm (void) printf(")"); 18686185db85Sdougm } 18696185db85Sdougm 18706185db85Sdougm /* 18716185db85Sdougm * show_properties(group, protocol, prefix) 18726185db85Sdougm * 18736185db85Sdougm * print the properties for a group. If protocol is NULL, do all 18746185db85Sdougm * protocols otherwise only the specified protocol. All security 18756185db85Sdougm * (named groups specific to the protocol) are included. 18766185db85Sdougm * 18776185db85Sdougm * The "prefix" is always applied. The caller knows whether it wants 18786185db85Sdougm * some type of prefix string (white space) or not. Once the prefix 18796185db85Sdougm * has been output, it is reduced to the zero length string for the 18806185db85Sdougm * remainder of the property output. 18816185db85Sdougm */ 18826185db85Sdougm 18836185db85Sdougm static void 18846185db85Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 18856185db85Sdougm { 18866185db85Sdougm sa_optionset_t optionset; 18876185db85Sdougm sa_security_t security; 18886185db85Sdougm char *value; 18896185db85Sdougm char *secvalue; 18906185db85Sdougm 18916185db85Sdougm if (protocol != NULL) { 189225a68471Sdougm optionset = sa_get_optionset(group, protocol); 189325a68471Sdougm if (optionset != NULL) { 189425a68471Sdougm (void) printf("%s", prefix); 189525a68471Sdougm prefix = ""; 189625a68471Sdougm out_properties(optionset, protocol, NULL); 189725a68471Sdougm } 189825a68471Sdougm security = sa_get_security(group, protocol, NULL); 189925a68471Sdougm if (security != NULL) { 190025a68471Sdougm (void) printf("%s", prefix); 190125a68471Sdougm prefix = ""; 190225a68471Sdougm out_properties(security, protocol, NULL); 190325a68471Sdougm } 19046185db85Sdougm } else { 190525a68471Sdougm for (optionset = sa_get_optionset(group, protocol); 190625a68471Sdougm optionset != NULL; 190725a68471Sdougm optionset = sa_get_next_optionset(optionset)) { 190825a68471Sdougm 190925a68471Sdougm value = sa_get_optionset_attr(optionset, "type"); 191025a68471Sdougm (void) printf("%s", prefix); 191125a68471Sdougm prefix = ""; 191225a68471Sdougm out_properties(optionset, value, 0); 191325a68471Sdougm if (value != NULL) 191425a68471Sdougm sa_free_attr_string(value); 191525a68471Sdougm } 191625a68471Sdougm for (security = sa_get_security(group, NULL, protocol); 191725a68471Sdougm security != NULL; 191825a68471Sdougm security = sa_get_next_security(security)) { 191925a68471Sdougm 192025a68471Sdougm value = sa_get_security_attr(security, "type"); 192125a68471Sdougm secvalue = sa_get_security_attr(security, "sectype"); 192225a68471Sdougm (void) printf("%s", prefix); 192325a68471Sdougm prefix = ""; 192425a68471Sdougm out_properties(security, value, secvalue); 192525a68471Sdougm if (value != NULL) 192625a68471Sdougm sa_free_attr_string(value); 192725a68471Sdougm if (secvalue != NULL) 192825a68471Sdougm sa_free_attr_string(secvalue); 192925a68471Sdougm } 19306185db85Sdougm } 19316185db85Sdougm } 19326185db85Sdougm 1933da6c28aaSamw /* 1934da6c28aaSamw * get_resource(share) 1935da6c28aaSamw * 1936da6c28aaSamw * Get the first resource name, if any, and fix string to be in 1937da6c28aaSamw * current locale and have quotes if it has embedded spaces. Return 1938da6c28aaSamw * an attr string that must be freed. 1939da6c28aaSamw */ 1940da6c28aaSamw 1941da6c28aaSamw static char * 1942da6c28aaSamw get_resource(sa_share_t share) 1943da6c28aaSamw { 1944da6c28aaSamw sa_resource_t resource; 1945da6c28aaSamw char *resstring = NULL; 1946da6c28aaSamw char *retstring; 1947da6c28aaSamw 1948da6c28aaSamw if ((resource = sa_get_share_resource(share, NULL)) != NULL) { 1949da6c28aaSamw resstring = sa_get_resource_attr(resource, "name"); 1950da6c28aaSamw if (resstring != NULL) { 1951da6c28aaSamw char *cp; 1952da6c28aaSamw int len; 1953da6c28aaSamw 1954da6c28aaSamw retstring = conv_from_utf8(resstring); 1955da6c28aaSamw if (retstring != resstring) { 1956da6c28aaSamw sa_free_attr_string(resstring); 1957da6c28aaSamw resstring = retstring; 1958da6c28aaSamw } 1959da6c28aaSamw if (strpbrk(resstring, " ") != NULL) { 1960da6c28aaSamw /* account for quotes */ 1961da6c28aaSamw len = strlen(resstring) + 3; 1962da6c28aaSamw cp = calloc(len, sizeof (char)); 1963da6c28aaSamw if (cp != NULL) { 1964da6c28aaSamw (void) snprintf(cp, len, 1965da6c28aaSamw "\"%s\"", resstring); 1966da6c28aaSamw sa_free_attr_string(resstring); 1967da6c28aaSamw resstring = cp; 1968da6c28aaSamw } else { 1969da6c28aaSamw sa_free_attr_string(resstring); 1970da6c28aaSamw resstring = NULL; 1971da6c28aaSamw } 1972da6c28aaSamw } 1973da6c28aaSamw } 1974da6c28aaSamw } 1975da6c28aaSamw return (resstring); 1976da6c28aaSamw } 1977da6c28aaSamw 1978da6c28aaSamw /* 1979da6c28aaSamw * has_resource_with_opt(share) 1980da6c28aaSamw * 1981da6c28aaSamw * Check to see if the share has any resource names with optionsets 1982da6c28aaSamw * set. Also indicate if multiple resource names since the syntax 1983da6c28aaSamw * would be about the same. 1984da6c28aaSamw */ 1985da6c28aaSamw static int 1986da6c28aaSamw has_resource_with_opt(sa_share_t share) 1987da6c28aaSamw { 1988da6c28aaSamw sa_resource_t resource; 1989da6c28aaSamw int ret = B_FALSE; 1990da6c28aaSamw 1991da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1992da6c28aaSamw resource != NULL; 1993da6c28aaSamw resource = sa_get_next_resource(resource)) { 1994da6c28aaSamw 1995da6c28aaSamw if (sa_get_optionset(resource, NULL) != NULL) { 1996da6c28aaSamw ret = B_TRUE; 1997da6c28aaSamw break; 1998da6c28aaSamw } 1999da6c28aaSamw } 2000da6c28aaSamw return (ret); 2001da6c28aaSamw } 2002da6c28aaSamw 2003da6c28aaSamw /* 2004da6c28aaSamw * has_multiple_resource(share) 2005da6c28aaSamw * 2006573b0c00Sdougm * Check to see if the share has multiple resource names since 2007573b0c00Sdougm * the syntax would be about the same. 2008da6c28aaSamw */ 2009573b0c00Sdougm static boolean_t 2010da6c28aaSamw has_multiple_resource(sa_share_t share) 2011da6c28aaSamw { 2012da6c28aaSamw sa_resource_t resource; 2013da6c28aaSamw int num; 2014da6c28aaSamw 2015da6c28aaSamw for (num = 0, resource = sa_get_share_resource(share, NULL); 2016da6c28aaSamw resource != NULL; 2017da6c28aaSamw resource = sa_get_next_resource(resource)) { 2018da6c28aaSamw num++; 2019da6c28aaSamw if (num > 1) 2020da6c28aaSamw return (B_TRUE); 2021da6c28aaSamw } 2022da6c28aaSamw return (B_FALSE); 2023da6c28aaSamw } 2024da6c28aaSamw 2025da6c28aaSamw /* 2026da6c28aaSamw * show_share(share, verbose, properties, proto, iszfs, sharepath) 2027da6c28aaSamw * 2028da6c28aaSamw * print out the share information. With the addition of resource as a 2029da6c28aaSamw * full object that can have multiple instances below the share, we 2030da6c28aaSamw * need to display that as well. 2031da6c28aaSamw */ 2032da6c28aaSamw 2033da6c28aaSamw static void 2034da6c28aaSamw show_share(sa_share_t share, int verbose, int properties, char *proto, 2035da6c28aaSamw int iszfs, char *sharepath) 2036da6c28aaSamw { 2037da6c28aaSamw char *drive; 2038da6c28aaSamw char *exclude; 2039da6c28aaSamw sa_resource_t resource = NULL; 2040da6c28aaSamw char *description; 2041da6c28aaSamw char *rsrcname; 2042da6c28aaSamw int rsrcwithopt; 2043573b0c00Sdougm boolean_t multiple; 2044da6c28aaSamw char *type; 2045da6c28aaSamw 2046da6c28aaSamw rsrcwithopt = has_resource_with_opt(share); 2047da6c28aaSamw 2048da6c28aaSamw if (verbose || (properties && rsrcwithopt)) { 2049da6c28aaSamw /* First, indicate if transient */ 2050da6c28aaSamw type = sa_get_share_attr(share, "type"); 2051da6c28aaSamw if (type != NULL && !iszfs && verbose && 2052da6c28aaSamw strcmp(type, "transient") == 0) 2053da6c28aaSamw (void) printf("\t* "); 2054da6c28aaSamw else 2055da6c28aaSamw (void) printf("\t "); 2056da6c28aaSamw 2057da6c28aaSamw if (type != NULL) 2058da6c28aaSamw sa_free_attr_string(type); 2059da6c28aaSamw 2060da6c28aaSamw /* 2061da6c28aaSamw * If we came in with verbose, we want to handle the case of 2062da6c28aaSamw * multiple resources as though they had properties set. 2063da6c28aaSamw */ 2064da6c28aaSamw multiple = has_multiple_resource(share); 2065da6c28aaSamw 2066573b0c00Sdougm /* 2067573b0c00Sdougm * if there is a description on the share and there 2068573b0c00Sdougm * are resources, treat as multiple resources in order 2069573b0c00Sdougm * to get all descriptions displayed. 2070573b0c00Sdougm */ 2071573b0c00Sdougm description = sa_get_share_description(share); 2072573b0c00Sdougm resource = sa_get_share_resource(share, NULL); 2073573b0c00Sdougm 2074573b0c00Sdougm if (description != NULL && resource != NULL) 2075573b0c00Sdougm multiple = B_TRUE; 2076573b0c00Sdougm 2077da6c28aaSamw /* Next, if not multiple follow old model */ 2078da6c28aaSamw if (!multiple && !rsrcwithopt) { 2079da6c28aaSamw rsrcname = get_resource(share); 2080da6c28aaSamw if (rsrcname != NULL && strlen(rsrcname) > 0) { 2081da6c28aaSamw (void) printf("%s=%s", rsrcname, sharepath); 2082da6c28aaSamw } else { 2083da6c28aaSamw (void) printf("%s", sharepath); 2084da6c28aaSamw } 2085da6c28aaSamw if (rsrcname != NULL) 2086da6c28aaSamw sa_free_attr_string(rsrcname); 2087573b0c00Sdougm /* Print the description string if there is one. */ 2088573b0c00Sdougm print_rsrc_desc(resource, description); 2089da6c28aaSamw } else { 2090da6c28aaSamw /* Treat as simple and then resources come later */ 2091da6c28aaSamw (void) printf("%s", sharepath); 2092da6c28aaSamw } 2093da6c28aaSamw drive = sa_get_share_attr(share, "drive-letter"); 2094da6c28aaSamw if (drive != NULL) { 2095da6c28aaSamw if (strlen(drive) > 0) 2096da6c28aaSamw (void) printf(gettext("\tdrive-letter=\"%s:\""), 2097da6c28aaSamw drive); 2098da6c28aaSamw sa_free_attr_string(drive); 2099da6c28aaSamw } 2100da6c28aaSamw if (properties) 2101da6c28aaSamw show_properties(share, proto, "\t"); 2102da6c28aaSamw exclude = sa_get_share_attr(share, "exclude"); 2103da6c28aaSamw if (exclude != NULL) { 2104da6c28aaSamw (void) printf(gettext("\tnot-shared-with=[%s]"), 2105da6c28aaSamw exclude); 2106da6c28aaSamw sa_free_attr_string(exclude); 2107da6c28aaSamw } 2108573b0c00Sdougm 2109da6c28aaSamw if (description != NULL) { 2110573b0c00Sdougm print_rsrc_desc((sa_resource_t)share, description); 2111da6c28aaSamw } 2112da6c28aaSamw /* 2113da6c28aaSamw * If there are resource names with options, show them 2114da6c28aaSamw * here, with one line per resource. Resource specific 2115da6c28aaSamw * options are at the end of the line followed by 2116da6c28aaSamw * description, if any. 2117da6c28aaSamw */ 2118da6c28aaSamw if (rsrcwithopt || multiple) { 2119da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 2120da6c28aaSamw resource != NULL; 2121da6c28aaSamw resource = sa_get_next_resource(resource)) { 2122da6c28aaSamw int has_space; 2123da6c28aaSamw char *rsrc; 2124da6c28aaSamw 2125da6c28aaSamw (void) printf("\n\t\t "); 2126da6c28aaSamw rsrcname = sa_get_resource_attr(resource, 2127da6c28aaSamw "name"); 2128da6c28aaSamw if (rsrcname == NULL) 2129da6c28aaSamw continue; 2130da6c28aaSamw 2131da6c28aaSamw rsrc = conv_from_utf8(rsrcname); 2132da6c28aaSamw has_space = strpbrk(rsrc, " ") != NULL; 2133da6c28aaSamw 2134da6c28aaSamw if (has_space) 2135da6c28aaSamw (void) printf("\"%s\"=%s", rsrc, 2136da6c28aaSamw sharepath); 2137da6c28aaSamw else 2138da6c28aaSamw (void) printf("%s=%s", rsrc, 2139da6c28aaSamw sharepath); 2140da6c28aaSamw if (rsrc != rsrcname) 2141da6c28aaSamw sa_free_attr_string(rsrc); 2142da6c28aaSamw sa_free_attr_string(rsrcname); 2143da6c28aaSamw if (properties || rsrcwithopt) 2144da6c28aaSamw show_properties(resource, proto, "\t"); 2145da6c28aaSamw 2146da6c28aaSamw /* Get description string if any */ 2147573b0c00Sdougm print_rsrc_desc(resource, description); 2148da6c28aaSamw } 2149da6c28aaSamw } 2150573b0c00Sdougm if (description != NULL) 2151573b0c00Sdougm sa_free_share_description(description); 2152da6c28aaSamw } else { 2153da6c28aaSamw (void) printf("\t %s", sharepath); 2154da6c28aaSamw if (properties) 2155da6c28aaSamw show_properties(share, proto, "\t"); 2156da6c28aaSamw } 2157da6c28aaSamw (void) printf("\n"); 2158da6c28aaSamw } 2159da6c28aaSamw 21606185db85Sdougm /* 21616185db85Sdougm * show_group(group, verbose, properties, proto, subgroup) 21626185db85Sdougm * 21636185db85Sdougm * helper function to show the contents of a group. 21646185db85Sdougm */ 21656185db85Sdougm 21666185db85Sdougm static void 21676185db85Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 2168da6c28aaSamw char *subgroup) 21696185db85Sdougm { 21706185db85Sdougm sa_share_t share; 21716185db85Sdougm char *groupname; 21726185db85Sdougm char *zfs = NULL; 21736185db85Sdougm int iszfs = 0; 2174da6c28aaSamw char *sharepath; 21756185db85Sdougm 21766185db85Sdougm groupname = sa_get_group_attr(group, "name"); 21776185db85Sdougm if (groupname != NULL) { 217825a68471Sdougm if (proto != NULL && !has_protocol(group, proto)) { 217925a68471Sdougm sa_free_attr_string(groupname); 218025a68471Sdougm return; 218125a68471Sdougm } 21826185db85Sdougm /* 21836185db85Sdougm * check to see if the group is managed by ZFS. If 21846185db85Sdougm * there is an attribute, then it is. A non-NULL zfs 21856185db85Sdougm * variable will trigger the different way to display 21866185db85Sdougm * and will remove the transient property indicator 21876185db85Sdougm * from the output. 21886185db85Sdougm */ 218925a68471Sdougm zfs = sa_get_group_attr(group, "zfs"); 219025a68471Sdougm if (zfs != NULL) { 219125a68471Sdougm iszfs = 1; 219225a68471Sdougm sa_free_attr_string(zfs); 219325a68471Sdougm } 219425a68471Sdougm share = sa_get_share(group, NULL); 219525a68471Sdougm if (subgroup == NULL) 219625a68471Sdougm (void) printf("%s", groupname); 219725a68471Sdougm else 219825a68471Sdougm (void) printf(" %s/%s", subgroup, groupname); 219925a68471Sdougm if (properties) 220025a68471Sdougm show_properties(group, proto, ""); 220125a68471Sdougm (void) printf("\n"); 220225a68471Sdougm if (strcmp(groupname, "zfs") == 0) { 220325a68471Sdougm sa_group_t zgroup; 220425a68471Sdougm 220525a68471Sdougm for (zgroup = sa_get_sub_group(group); 220625a68471Sdougm zgroup != NULL; 220725a68471Sdougm zgroup = sa_get_next_group(zgroup)) { 220825a68471Sdougm show_group(zgroup, verbose, properties, proto, 220925a68471Sdougm "zfs"); 221025a68471Sdougm } 221125a68471Sdougm sa_free_attr_string(groupname); 221225a68471Sdougm return; 22136185db85Sdougm } 22146185db85Sdougm /* 221525a68471Sdougm * Have a group, so list the contents. Resource and 22166185db85Sdougm * description are only listed if verbose is set. 22176185db85Sdougm */ 221825a68471Sdougm for (share = sa_get_share(group, NULL); 221925a68471Sdougm share != NULL; 222025a68471Sdougm share = sa_get_next_share(share)) { 222125a68471Sdougm sharepath = sa_get_share_attr(share, "path"); 222225a68471Sdougm if (sharepath != NULL) { 2223da6c28aaSamw show_share(share, verbose, properties, proto, 2224da6c28aaSamw iszfs, sharepath); 222525a68471Sdougm sa_free_attr_string(sharepath); 222625a68471Sdougm } 222725a68471Sdougm } 22286185db85Sdougm } 22296185db85Sdougm if (groupname != NULL) { 22306185db85Sdougm sa_free_attr_string(groupname); 22316185db85Sdougm } 22326185db85Sdougm } 22336185db85Sdougm 22346185db85Sdougm /* 22356185db85Sdougm * show_group_xml_init() 22366185db85Sdougm * 22376185db85Sdougm * Create an XML document that will be used to display config info via 22386185db85Sdougm * XML format. 22396185db85Sdougm */ 22406185db85Sdougm 22416185db85Sdougm xmlDocPtr 22426185db85Sdougm show_group_xml_init() 22436185db85Sdougm { 22446185db85Sdougm xmlDocPtr doc; 22456185db85Sdougm xmlNodePtr root; 22466185db85Sdougm 22476185db85Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 22486185db85Sdougm if (doc != NULL) { 224925a68471Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 225025a68471Sdougm if (root != NULL) 22510b4fd3b1SSurya Prakki (void) xmlDocSetRootElement(doc, root); 22526185db85Sdougm } 22536185db85Sdougm return (doc); 22546185db85Sdougm } 22556185db85Sdougm 22566185db85Sdougm /* 22576185db85Sdougm * show_group_xml(doc, group) 22586185db85Sdougm * 22596185db85Sdougm * Copy the group info into the XML doc. 22606185db85Sdougm */ 22616185db85Sdougm 22626185db85Sdougm static void 22636185db85Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 22646185db85Sdougm { 22656185db85Sdougm xmlNodePtr node; 22666185db85Sdougm xmlNodePtr root; 22676185db85Sdougm 22686185db85Sdougm root = xmlDocGetRootElement(doc); 22696185db85Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 22706185db85Sdougm if (node != NULL && root != NULL) { 22710b4fd3b1SSurya Prakki (void) xmlAddChild(root, node); 22726185db85Sdougm /* 22736185db85Sdougm * In the future, we may have interally used tags that 22746185db85Sdougm * should not appear in the XML output. Remove 22756185db85Sdougm * anything we don't want to show here. 22766185db85Sdougm */ 22776185db85Sdougm } 22786185db85Sdougm } 22796185db85Sdougm 22806185db85Sdougm /* 22816185db85Sdougm * sa_show(flags, argc, argv) 22826185db85Sdougm * 22836185db85Sdougm * Implements the show subcommand. 22846185db85Sdougm */ 22856185db85Sdougm 22866185db85Sdougm int 2287549ec3ffSdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[]) 22886185db85Sdougm { 22896185db85Sdougm sa_group_t group; 22906185db85Sdougm int verbose = 0; 22916185db85Sdougm int properties = 0; 22926185db85Sdougm int c; 22936185db85Sdougm int ret = SA_OK; 22946185db85Sdougm char *protocol = NULL; 22956185db85Sdougm int xml = 0; 22966185db85Sdougm xmlDocPtr doc; 2297da6c28aaSamw #ifdef lint 2298da6c28aaSamw flags = flags; 2299da6c28aaSamw #endif 23006185db85Sdougm 23016185db85Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 230225a68471Sdougm switch (c) { 230325a68471Sdougm case 'v': 230425a68471Sdougm verbose++; 230525a68471Sdougm break; 230625a68471Sdougm case 'p': 230725a68471Sdougm properties++; 230825a68471Sdougm break; 230925a68471Sdougm case 'P': 2310da6c28aaSamw if (protocol != NULL) { 2311da6c28aaSamw (void) printf(gettext( 2312da6c28aaSamw "Specifying multiple protocols " 2313da6c28aaSamw "not supported: %s\n"), 2314da6c28aaSamw protocol); 2315da6c28aaSamw return (SA_SYNTAX_ERR); 2316da6c28aaSamw } 231725a68471Sdougm protocol = optarg; 231825a68471Sdougm if (!sa_valid_protocol(protocol)) { 231925a68471Sdougm (void) printf(gettext( 232025a68471Sdougm "Invalid protocol specified: %s\n"), 232125a68471Sdougm protocol); 232225a68471Sdougm return (SA_INVALID_PROTOCOL); 232325a68471Sdougm } 232425a68471Sdougm break; 232525a68471Sdougm case 'x': 232625a68471Sdougm xml++; 232725a68471Sdougm break; 232825a68471Sdougm case 'h': 2329e7bab347Sdougm /* optopt on valid arg isn't defined */ 2330e7bab347Sdougm optopt = c; 2331e7bab347Sdougm /*FALLTHROUGH*/ 233225a68471Sdougm case '?': 2333e7bab347Sdougm default: 2334e7bab347Sdougm /* 2335e7bab347Sdougm * Since a bad option gets to here, sort it 2336e7bab347Sdougm * out and return a syntax error return value 2337e7bab347Sdougm * if necessary. 2338e7bab347Sdougm */ 2339e7bab347Sdougm switch (optopt) { 2340e7bab347Sdougm default: 2341e7bab347Sdougm ret = SA_SYNTAX_ERR; 2342e7bab347Sdougm break; 2343e7bab347Sdougm case 'h': 2344e7bab347Sdougm case '?': 2345e7bab347Sdougm break; 2346e7bab347Sdougm } 234725a68471Sdougm (void) printf(gettext("usage: %s\n"), 234825a68471Sdougm sa_get_usage(USAGE_SHOW)); 2349e7bab347Sdougm return (ret); 23506185db85Sdougm } 23516185db85Sdougm } 23526185db85Sdougm 23536185db85Sdougm if (xml) { 235425a68471Sdougm doc = show_group_xml_init(); 235525a68471Sdougm if (doc == NULL) 235625a68471Sdougm ret = SA_NO_MEMORY; 23576185db85Sdougm } 23586185db85Sdougm 23596185db85Sdougm if (optind == argc) { 236025a68471Sdougm /* No group specified so go through them all */ 236125a68471Sdougm for (group = sa_get_group(handle, NULL); 236225a68471Sdougm group != NULL; 236325a68471Sdougm group = sa_get_next_group(group)) { 236425a68471Sdougm /* 236525a68471Sdougm * Have a group so check if one we want and then list 236625a68471Sdougm * contents with appropriate options. 236725a68471Sdougm */ 236825a68471Sdougm if (xml) 236925a68471Sdougm show_group_xml(doc, group); 237025a68471Sdougm else 237125a68471Sdougm show_group(group, verbose, properties, protocol, 237225a68471Sdougm NULL); 237325a68471Sdougm } 23746185db85Sdougm } else { 237525a68471Sdougm /* Have a specified list of groups */ 237625a68471Sdougm for (; optind < argc; optind++) { 237725a68471Sdougm group = sa_get_group(handle, argv[optind]); 237825a68471Sdougm if (group != NULL) { 237925a68471Sdougm if (xml) 238025a68471Sdougm show_group_xml(doc, group); 238125a68471Sdougm else 238225a68471Sdougm show_group(group, verbose, properties, 238325a68471Sdougm protocol, NULL); 238425a68471Sdougm } else { 238525a68471Sdougm (void) printf(gettext("%s: not found\n"), 238625a68471Sdougm argv[optind]); 238725a68471Sdougm ret = SA_NO_SUCH_GROUP; 238825a68471Sdougm } 23896185db85Sdougm } 23906185db85Sdougm } 23916185db85Sdougm if (xml && ret == SA_OK) { 23920b4fd3b1SSurya Prakki (void) xmlDocFormatDump(stdout, doc, 1); 239325a68471Sdougm xmlFreeDoc(doc); 23946185db85Sdougm } 23956185db85Sdougm return (ret); 23966185db85Sdougm 23976185db85Sdougm } 23986185db85Sdougm 23996185db85Sdougm /* 24006185db85Sdougm * enable_share(group, share, update_legacy) 24016185db85Sdougm * 24026185db85Sdougm * helper function to enable a share if the group is enabled. 24036185db85Sdougm */ 24046185db85Sdougm 24056185db85Sdougm static int 2406549ec3ffSdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 2407da6c28aaSamw int update_legacy) 24086185db85Sdougm { 24096185db85Sdougm char *value; 24106185db85Sdougm int enabled; 24116185db85Sdougm sa_optionset_t optionset; 2412da6c28aaSamw int err; 24136185db85Sdougm int ret = SA_OK; 24146185db85Sdougm char *zfs = NULL; 24156185db85Sdougm int iszfs = 0; 2416da6c28aaSamw int isshare; 24176185db85Sdougm 24186185db85Sdougm /* 24196185db85Sdougm * need to enable this share if the group is enabled but not 24206185db85Sdougm * otherwise. The enable is also done on each protocol 24216185db85Sdougm * represented in the group. 24226185db85Sdougm */ 24236185db85Sdougm value = sa_get_group_attr(group, "state"); 24246185db85Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 24256185db85Sdougm if (value != NULL) 242625a68471Sdougm sa_free_attr_string(value); 24276185db85Sdougm /* remove legacy config if necessary */ 24286185db85Sdougm if (update_legacy) 2429da6c28aaSamw ret = sa_delete_legacy(share, NULL); 24306185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 24316185db85Sdougm if (zfs != NULL) { 243225a68471Sdougm iszfs++; 243325a68471Sdougm sa_free_attr_string(zfs); 24346185db85Sdougm } 24356185db85Sdougm 24366185db85Sdougm /* 24376185db85Sdougm * Step through each optionset at the group level and 24386185db85Sdougm * enable the share based on the protocol type. This 24396185db85Sdougm * works because protocols must be set on the group 24406185db85Sdougm * for the protocol to be enabled. 24416185db85Sdougm */ 2442da6c28aaSamw isshare = sa_is_share(share); 24436185db85Sdougm for (optionset = sa_get_optionset(group, NULL); 24446185db85Sdougm optionset != NULL && ret == SA_OK; 24456185db85Sdougm optionset = sa_get_next_optionset(optionset)) { 244625a68471Sdougm value = sa_get_optionset_attr(optionset, "type"); 244725a68471Sdougm if (value != NULL) { 2448da6c28aaSamw if (enabled) { 2449da6c28aaSamw if (isshare) { 2450da6c28aaSamw err = sa_enable_share(share, value); 2451da6c28aaSamw } else { 2452da6c28aaSamw err = sa_enable_resource(share, value); 2453da6c28aaSamw if (err == SA_NOT_SUPPORTED) { 2454da6c28aaSamw sa_share_t parent; 2455da6c28aaSamw parent = sa_get_resource_parent( 2456da6c28aaSamw share); 2457da6c28aaSamw if (parent != NULL) 2458da6c28aaSamw err = sa_enable_share( 2459da6c28aaSamw parent, value); 2460da6c28aaSamw } 2461da6c28aaSamw } 2462da6c28aaSamw if (err != SA_OK) { 2463da6c28aaSamw ret = err; 2464da6c28aaSamw (void) printf(gettext( 2465da6c28aaSamw "Failed to enable share for " 2466da6c28aaSamw "\"%s\": %s\n"), 2467da6c28aaSamw value, sa_errorstr(ret)); 2468da6c28aaSamw } 2469da6c28aaSamw } 2470da6c28aaSamw /* 2471da6c28aaSamw * If we want to update the legacy, use a copy of 2472da6c28aaSamw * share so we can avoid breaking the loop we are in 2473da6c28aaSamw * since we might also need to go up the tree to the 2474da6c28aaSamw * parent. 2475da6c28aaSamw */ 2476da6c28aaSamw if (update_legacy && !iszfs) { 2477da6c28aaSamw sa_share_t update = share; 2478da6c28aaSamw if (!sa_is_share(share)) { 2479da6c28aaSamw update = sa_get_resource_parent(share); 2480da6c28aaSamw } 2481da6c28aaSamw (void) sa_update_legacy(update, value); 2482da6c28aaSamw } 248325a68471Sdougm sa_free_attr_string(value); 248425a68471Sdougm } 24856185db85Sdougm } 24866185db85Sdougm if (ret == SA_OK) 248725a68471Sdougm (void) sa_update_config(handle); 24886185db85Sdougm return (ret); 24896185db85Sdougm } 24906185db85Sdougm 2491da6c28aaSamw /* 2492da6c28aaSamw * sa_require_resource(group) 2493da6c28aaSamw * 2494da6c28aaSamw * if any of the defined protocols on the group require resource 2495da6c28aaSamw * names, then all shares must have them. 2496da6c28aaSamw */ 2497da6c28aaSamw 2498da6c28aaSamw static int 2499da6c28aaSamw sa_require_resource(sa_group_t group) 2500da6c28aaSamw { 2501da6c28aaSamw sa_optionset_t optionset; 2502da6c28aaSamw 2503da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 2504da6c28aaSamw optionset != NULL; 2505da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 2506da6c28aaSamw char *proto; 2507da6c28aaSamw 2508da6c28aaSamw proto = sa_get_optionset_attr(optionset, "type"); 2509da6c28aaSamw if (proto != NULL) { 2510da6c28aaSamw uint64_t features; 2511da6c28aaSamw 2512da6c28aaSamw features = sa_proto_get_featureset(proto); 2513da6c28aaSamw if (features & SA_FEATURE_RESOURCE) { 2514da6c28aaSamw sa_free_attr_string(proto); 2515da6c28aaSamw return (B_TRUE); 2516da6c28aaSamw } 2517da6c28aaSamw sa_free_attr_string(proto); 2518da6c28aaSamw } 2519da6c28aaSamw } 2520da6c28aaSamw return (B_FALSE); 2521da6c28aaSamw } 2522da6c28aaSamw 25236185db85Sdougm /* 25246185db85Sdougm * sa_addshare(flags, argc, argv) 25256185db85Sdougm * 25266185db85Sdougm * implements add-share subcommand. 25276185db85Sdougm */ 25286185db85Sdougm 2529da6c28aaSamw static int 2530549ec3ffSdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 25316185db85Sdougm { 25326185db85Sdougm int verbose = 0; 25336185db85Sdougm int dryrun = 0; 25346185db85Sdougm int c; 25356185db85Sdougm int ret = SA_OK; 25366185db85Sdougm sa_group_t group; 25376185db85Sdougm sa_share_t share; 2538da6c28aaSamw sa_resource_t resource = NULL; 25396185db85Sdougm char *sharepath = NULL; 25406185db85Sdougm char *description = NULL; 2541da6c28aaSamw char *rsrcname = NULL; 2542da6c28aaSamw char *rsrc = NULL; 25436185db85Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 25446185db85Sdougm int auth; 25456185db85Sdougm char dir[MAXPATHLEN]; 25466185db85Sdougm 25476185db85Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 254825a68471Sdougm switch (c) { 254925a68471Sdougm case 'n': 255025a68471Sdougm dryrun++; 255125a68471Sdougm break; 255225a68471Sdougm case 'v': 255325a68471Sdougm verbose++; 255425a68471Sdougm break; 255525a68471Sdougm case 'd': 255625a68471Sdougm description = optarg; 255725a68471Sdougm break; 255825a68471Sdougm case 'r': 2559da6c28aaSamw if (rsrcname != NULL) { 2560da6c28aaSamw (void) printf(gettext("Adding multiple " 2561da6c28aaSamw "resource names not" 2562da6c28aaSamw " supported\n")); 2563da6c28aaSamw return (SA_SYNTAX_ERR); 2564da6c28aaSamw } 2565da6c28aaSamw rsrcname = optarg; 256625a68471Sdougm break; 256725a68471Sdougm case 's': 256825a68471Sdougm /* 256925a68471Sdougm * Save share path into group. Currently limit 257025a68471Sdougm * to one share per command. 257125a68471Sdougm */ 257225a68471Sdougm if (sharepath != NULL) { 257325a68471Sdougm (void) printf(gettext( 257425a68471Sdougm "Adding multiple shares not supported\n")); 2575da6c28aaSamw return (SA_SYNTAX_ERR); 257625a68471Sdougm } 257725a68471Sdougm sharepath = optarg; 257825a68471Sdougm break; 257925a68471Sdougm case 't': 258025a68471Sdougm persist = SA_SHARE_TRANSIENT; 258125a68471Sdougm break; 258225a68471Sdougm case 'h': 2583e7bab347Sdougm /* optopt on valid arg isn't defined */ 2584e7bab347Sdougm optopt = c; 2585e7bab347Sdougm /*FALLTHROUGH*/ 258625a68471Sdougm case '?': 2587e7bab347Sdougm default: 2588e7bab347Sdougm /* 2589e7bab347Sdougm * Since a bad option gets to here, sort it 2590e7bab347Sdougm * out and return a syntax error return value 2591e7bab347Sdougm * if necessary. 2592e7bab347Sdougm */ 2593e7bab347Sdougm switch (optopt) { 2594e7bab347Sdougm default: 2595e7bab347Sdougm ret = SA_SYNTAX_ERR; 2596e7bab347Sdougm break; 2597e7bab347Sdougm case 'h': 2598e7bab347Sdougm case '?': 2599e7bab347Sdougm break; 2600e7bab347Sdougm } 260125a68471Sdougm (void) printf(gettext("usage: %s\n"), 260225a68471Sdougm sa_get_usage(USAGE_ADD_SHARE)); 2603e7bab347Sdougm return (ret); 26046185db85Sdougm } 26056185db85Sdougm } 26066185db85Sdougm 26076185db85Sdougm if (optind >= argc) { 26086185db85Sdougm (void) printf(gettext("usage: %s\n"), 260925a68471Sdougm sa_get_usage(USAGE_ADD_SHARE)); 261025a68471Sdougm if (dryrun || sharepath != NULL || description != NULL || 2611da6c28aaSamw rsrcname != NULL || verbose || persist) { 261225a68471Sdougm (void) printf(gettext("\tgroup must be specified\n")); 261325a68471Sdougm ret = SA_NO_SUCH_GROUP; 261425a68471Sdougm } else { 261525a68471Sdougm ret = SA_OK; 261625a68471Sdougm } 261725a68471Sdougm } else { 261825a68471Sdougm if (sharepath == NULL) { 261925a68471Sdougm (void) printf(gettext("usage: %s\n"), 262025a68471Sdougm sa_get_usage(USAGE_ADD_SHARE)); 262125a68471Sdougm (void) printf(gettext( 262225a68471Sdougm "\t-s sharepath must be specified\n")); 2623da6c28aaSamw ret = SA_BAD_PATH; 262425a68471Sdougm } 2625da6c28aaSamw if (ret == SA_OK) { 2626da6c28aaSamw if (realpath(sharepath, dir) == NULL) { 2627da6c28aaSamw ret = SA_BAD_PATH; 2628da6c28aaSamw (void) printf(gettext("Path " 2629da6c28aaSamw "is not valid: %s\n"), 2630da6c28aaSamw sharepath); 2631da6c28aaSamw } else { 2632da6c28aaSamw sharepath = dir; 2633da6c28aaSamw } 263425a68471Sdougm } 2635da6c28aaSamw if (ret == SA_OK && rsrcname != NULL) { 2636da6c28aaSamw /* check for valid syntax */ 2637da6c28aaSamw if (validresource(rsrcname)) { 2638da6c28aaSamw rsrc = conv_to_utf8(rsrcname); 2639da6c28aaSamw resource = sa_find_resource(handle, rsrc); 2640da6c28aaSamw if (resource != NULL) { 2641da6c28aaSamw /* 2642da6c28aaSamw * Resource names must be 2643da6c28aaSamw * unique in the system 2644da6c28aaSamw */ 2645da6c28aaSamw ret = SA_DUPLICATE_NAME; 2646da6c28aaSamw (void) printf(gettext("usage: %s\n"), 2647da6c28aaSamw sa_get_usage(USAGE_ADD_SHARE)); 2648da6c28aaSamw (void) printf(gettext( 2649da6c28aaSamw "\tresource names must be unique " 2650da6c28aaSamw "in the system\n")); 2651da6c28aaSamw } 2652da6c28aaSamw } else { 2653da6c28aaSamw (void) printf(gettext("usage: %s\n"), 2654da6c28aaSamw sa_get_usage(USAGE_ADD_SHARE)); 2655da6c28aaSamw (void) printf(gettext( 2656da6c28aaSamw "\tresource names use restricted " 2657da6c28aaSamw "character set\n")); 2658da6c28aaSamw ret = SA_INVALID_NAME; 2659da6c28aaSamw } 266025a68471Sdougm } 2661da6c28aaSamw 2662da6c28aaSamw if (ret != SA_OK) { 2663da6c28aaSamw if (rsrc != NULL && rsrcname != rsrc) 2664da6c28aaSamw sa_free_attr_string(rsrc); 2665da6c28aaSamw return (ret); 266625a68471Sdougm } 2667da6c28aaSamw 266825a68471Sdougm share = sa_find_share(handle, sharepath); 266925a68471Sdougm if (share != NULL) { 2670da6c28aaSamw if (rsrcname == NULL) { 2671da6c28aaSamw /* 2672da6c28aaSamw * Can only have a duplicate share if a new 2673da6c28aaSamw * resource name is being added. 2674da6c28aaSamw */ 2675da6c28aaSamw ret = SA_DUPLICATE_NAME; 2676da6c28aaSamw (void) printf(gettext("Share path already " 2677da6c28aaSamw "shared: %s\n"), sharepath); 2678da6c28aaSamw } 2679da6c28aaSamw } 2680da6c28aaSamw if (ret != SA_OK) 2681da6c28aaSamw return (ret); 2682da6c28aaSamw 2683da6c28aaSamw group = sa_get_group(handle, argv[optind]); 2684da6c28aaSamw if (group != NULL) { 2685da6c28aaSamw if (sa_require_resource(group) == B_TRUE && 2686da6c28aaSamw rsrcname == NULL) { 268725a68471Sdougm (void) printf(gettext( 2688da6c28aaSamw "Resource name is required " 2689da6c28aaSamw "by at least one enabled protocol " 2690da6c28aaSamw "in group\n")); 2691da6c28aaSamw return (SA_RESOURCE_REQUIRED); 2692da6c28aaSamw } 2693da6c28aaSamw if (share == NULL && ret == SA_OK) { 2694da6c28aaSamw if (dryrun) 2695da6c28aaSamw ret = sa_check_path(group, sharepath, 2696da6c28aaSamw SA_CHECK_NORMAL); 2697da6c28aaSamw else 2698da6c28aaSamw share = sa_add_share(group, sharepath, 2699da6c28aaSamw persist, &ret); 27006185db85Sdougm } 27016185db85Sdougm /* 2702da6c28aaSamw * Make sure this isn't an attempt to put a resourced 2703da6c28aaSamw * share into a different group than it already is in. 27046185db85Sdougm */ 2705da6c28aaSamw if (share != NULL) { 2706da6c28aaSamw sa_group_t parent; 2707da6c28aaSamw parent = sa_get_parent_group(share); 2708da6c28aaSamw if (parent != group) { 2709da6c28aaSamw ret = SA_DUPLICATE_NAME; 2710da6c28aaSamw (void) printf(gettext( 2711da6c28aaSamw "Share path already " 2712da6c28aaSamw "shared: %s\n"), sharepath); 2713da6c28aaSamw } 2714da6c28aaSamw } 27156185db85Sdougm if (!dryrun && share == NULL) { 271625a68471Sdougm (void) printf(gettext( 271725a68471Sdougm "Could not add share: %s\n"), 271825a68471Sdougm sa_errorstr(ret)); 27196185db85Sdougm } else { 2720da6c28aaSamw auth = check_authorizations(argv[optind], 2721da6c28aaSamw flags); 272225a68471Sdougm if (!dryrun && ret == SA_OK) { 2723da6c28aaSamw if (rsrcname != NULL) { 2724da6c28aaSamw resource = sa_add_resource( 2725da6c28aaSamw share, 2726da6c28aaSamw rsrc, 2727da6c28aaSamw SA_SHARE_PERMANENT, 2728da6c28aaSamw &ret); 272925a68471Sdougm } 273025a68471Sdougm if (ret == SA_OK && 273125a68471Sdougm description != NULL) { 2732573b0c00Sdougm if (resource != NULL) 2733573b0c00Sdougm ret = 2734573b0c00Sdougm set_resource_desc( 2735573b0c00Sdougm resource, 2736573b0c00Sdougm description); 2737573b0c00Sdougm else 2738da6c28aaSamw ret = 2739da6c28aaSamw set_share_desc( 2740da6c28aaSamw share, 2741da6c28aaSamw description); 274225a68471Sdougm } 274325a68471Sdougm if (ret == SA_OK) { 2744da6c28aaSamw /* now enable the share(s) */ 2745da6c28aaSamw if (resource != NULL) { 2746da6c28aaSamw ret = enable_share( 2747da6c28aaSamw handle, 2748da6c28aaSamw group, 2749da6c28aaSamw resource, 2750da6c28aaSamw 1); 2751da6c28aaSamw } else { 2752da6c28aaSamw ret = enable_share( 2753da6c28aaSamw handle, 2754da6c28aaSamw group, 2755da6c28aaSamw share, 2756da6c28aaSamw 1); 2757da6c28aaSamw } 275825a68471Sdougm ret = sa_update_config(handle); 275925a68471Sdougm } 276025a68471Sdougm switch (ret) { 276125a68471Sdougm case SA_DUPLICATE_NAME: 276225a68471Sdougm (void) printf(gettext( 276325a68471Sdougm "Resource name in" 2764da6c28aaSamw "use: %s\n"), 2765da6c28aaSamw rsrcname); 276625a68471Sdougm break; 276725a68471Sdougm default: 2768da6c28aaSamw (void) printf(gettext( 2769da6c28aaSamw "Could not set " 27706185db85Sdougm "attribute: %s\n"), 277125a68471Sdougm sa_errorstr(ret)); 277225a68471Sdougm break; 277325a68471Sdougm case SA_OK: 277425a68471Sdougm break; 277525a68471Sdougm } 2776da6c28aaSamw } else if (dryrun && ret == SA_OK && 2777da6c28aaSamw !auth && verbose) { 277825a68471Sdougm (void) printf(gettext( 277925a68471Sdougm "Command would fail: %s\n"), 278025a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 278125a68471Sdougm ret = SA_NO_PERMISSION; 27826185db85Sdougm } 278325a68471Sdougm } 2784da6c28aaSamw } else { 2785da6c28aaSamw switch (ret) { 2786da6c28aaSamw default: 2787da6c28aaSamw (void) printf(gettext( 2788da6c28aaSamw "Group \"%s\" not found\n"), argv[optind]); 2789da6c28aaSamw ret = SA_NO_SUCH_GROUP; 2790da6c28aaSamw break; 2791da6c28aaSamw case SA_BAD_PATH: 2792da6c28aaSamw case SA_DUPLICATE_NAME: 2793da6c28aaSamw break; 2794da6c28aaSamw } 27956185db85Sdougm } 27966185db85Sdougm } 27976185db85Sdougm return (ret); 27986185db85Sdougm } 27996185db85Sdougm 28006185db85Sdougm /* 28016185db85Sdougm * sa_moveshare(flags, argc, argv) 28026185db85Sdougm * 28036185db85Sdougm * implements move-share subcommand. 28046185db85Sdougm */ 28056185db85Sdougm 28066185db85Sdougm int 2807549ec3ffSdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 28086185db85Sdougm { 28096185db85Sdougm int verbose = 0; 28106185db85Sdougm int dryrun = 0; 28116185db85Sdougm int c; 28126185db85Sdougm int ret = SA_OK; 28136185db85Sdougm sa_group_t group; 28146185db85Sdougm sa_share_t share; 2815da6c28aaSamw char *rsrcname = NULL; 28166185db85Sdougm char *sharepath = NULL; 28176185db85Sdougm int authsrc = 0, authdst = 0; 2818573b0c00Sdougm char dir[MAXPATHLEN]; 28196185db85Sdougm 2820da6c28aaSamw while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) { 282125a68471Sdougm switch (c) { 282225a68471Sdougm case 'n': 282325a68471Sdougm dryrun++; 282425a68471Sdougm break; 282525a68471Sdougm case 'v': 282625a68471Sdougm verbose++; 282725a68471Sdougm break; 2828da6c28aaSamw case 'r': 2829da6c28aaSamw if (rsrcname != NULL) { 2830da6c28aaSamw (void) printf(gettext( 2831da6c28aaSamw "Moving multiple resource names not" 2832da6c28aaSamw " supported\n")); 2833da6c28aaSamw return (SA_SYNTAX_ERR); 2834da6c28aaSamw } 2835da6c28aaSamw rsrcname = optarg; 2836da6c28aaSamw break; 283725a68471Sdougm case 's': 283825a68471Sdougm /* 283925a68471Sdougm * Remove share path from group. Currently limit 284025a68471Sdougm * to one share per command. 284125a68471Sdougm */ 284225a68471Sdougm if (sharepath != NULL) { 284325a68471Sdougm (void) printf(gettext("Moving multiple shares" 2844da6c28aaSamw " not supported\n")); 2845da6c28aaSamw return (SA_SYNTAX_ERR); 284625a68471Sdougm } 284725a68471Sdougm sharepath = optarg; 284825a68471Sdougm break; 284925a68471Sdougm case 'h': 2850e7bab347Sdougm /* optopt on valid arg isn't defined */ 2851e7bab347Sdougm optopt = c; 2852e7bab347Sdougm /*FALLTHROUGH*/ 285325a68471Sdougm case '?': 2854e7bab347Sdougm default: 2855e7bab347Sdougm /* 2856e7bab347Sdougm * Since a bad option gets to here, sort it 2857e7bab347Sdougm * out and return a syntax error return value 2858e7bab347Sdougm * if necessary. 2859e7bab347Sdougm */ 2860e7bab347Sdougm switch (optopt) { 2861e7bab347Sdougm default: 2862e7bab347Sdougm ret = SA_SYNTAX_ERR; 2863e7bab347Sdougm break; 2864e7bab347Sdougm case 'h': 2865e7bab347Sdougm case '?': 2866e7bab347Sdougm break; 2867e7bab347Sdougm } 286825a68471Sdougm (void) printf(gettext("usage: %s\n"), 286925a68471Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 2870e7bab347Sdougm return (ret); 28716185db85Sdougm } 28726185db85Sdougm } 28736185db85Sdougm 28746185db85Sdougm if (optind >= argc || sharepath == NULL) { 2875da6c28aaSamw (void) printf(gettext("usage: %s\n"), 2876da6c28aaSamw sa_get_usage(USAGE_MOVE_SHARE)); 2877da6c28aaSamw if (dryrun || verbose || sharepath != NULL) { 2878da6c28aaSamw (void) printf(gettext("\tgroup must be specified\n")); 2879da6c28aaSamw ret = SA_NO_SUCH_GROUP; 2880da6c28aaSamw } else { 2881da6c28aaSamw if (sharepath == NULL) { 2882da6c28aaSamw ret = SA_SYNTAX_ERR; 288325a68471Sdougm (void) printf(gettext( 2884da6c28aaSamw "\tsharepath must be specified\n")); 288525a68471Sdougm } else { 2886da6c28aaSamw ret = SA_OK; 288725a68471Sdougm } 2888da6c28aaSamw } 28896185db85Sdougm } else { 289025a68471Sdougm sa_group_t parent; 289125a68471Sdougm char *zfsold; 289225a68471Sdougm char *zfsnew; 289325a68471Sdougm 289425a68471Sdougm if (sharepath == NULL) { 289525a68471Sdougm (void) printf(gettext( 289625a68471Sdougm "sharepath must be specified with the -s " 289725a68471Sdougm "option\n")); 289825a68471Sdougm return (SA_BAD_PATH); 289925a68471Sdougm } 2900549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 290125a68471Sdougm if (group == NULL) { 290225a68471Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 290325a68471Sdougm argv[optind]); 290425a68471Sdougm return (SA_NO_SUCH_GROUP); 290525a68471Sdougm } 290625a68471Sdougm share = sa_find_share(handle, sharepath); 2907573b0c00Sdougm /* 2908573b0c00Sdougm * If a share wasn't found, it may have been a symlink 2909573b0c00Sdougm * or has a trailing '/'. Try again after resolving 2910573b0c00Sdougm * with realpath(). 2911573b0c00Sdougm */ 2912573b0c00Sdougm if (share == NULL) { 2913573b0c00Sdougm if (realpath(sharepath, dir) == NULL) { 2914573b0c00Sdougm (void) printf(gettext("Path " 2915573b0c00Sdougm "is not valid: %s\n"), 2916573b0c00Sdougm sharepath); 2917573b0c00Sdougm return (SA_BAD_PATH); 2918573b0c00Sdougm } 2919573b0c00Sdougm sharepath = dir; 2920573b0c00Sdougm share = sa_find_share(handle, sharepath); 2921573b0c00Sdougm } 292225a68471Sdougm if (share == NULL) { 29236185db85Sdougm (void) printf(gettext("Share not found: %s\n"), 292425a68471Sdougm sharepath); 292525a68471Sdougm return (SA_NO_SUCH_PATH); 292625a68471Sdougm } 2927573b0c00Sdougm authdst = check_authorizations(argv[optind], flags); 292825a68471Sdougm 292925a68471Sdougm parent = sa_get_parent_group(share); 293025a68471Sdougm if (parent != NULL) { 293125a68471Sdougm char *pname; 293225a68471Sdougm pname = sa_get_group_attr(parent, "name"); 293325a68471Sdougm if (pname != NULL) { 29346185db85Sdougm authsrc = check_authorizations(pname, flags); 29356185db85Sdougm sa_free_attr_string(pname); 293625a68471Sdougm } 293725a68471Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 293825a68471Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 293925a68471Sdougm if ((zfsold != NULL && zfsnew == NULL) || 294025a68471Sdougm (zfsold == NULL && zfsnew != NULL)) { 29416185db85Sdougm ret = SA_NOT_ALLOWED; 294225a68471Sdougm } 294325a68471Sdougm if (zfsold != NULL) 29446185db85Sdougm sa_free_attr_string(zfsold); 294525a68471Sdougm if (zfsnew != NULL) 29466185db85Sdougm sa_free_attr_string(zfsnew); 294725a68471Sdougm } 294825a68471Sdougm 294925a68471Sdougm if (ret == SA_OK && parent != group && !dryrun) { 295025a68471Sdougm char *oldstate; 295125a68471Sdougm /* 295225a68471Sdougm * Note that the share may need to be 2953da6c28aaSamw * "unshared" if the new group is disabled and 2954da6c28aaSamw * the old was enabled or it may need to be 2955da6c28aaSamw * share to update if the new group is 2956da6c28aaSamw * enabled. We disable before the move and 2957da6c28aaSamw * will have to enable after the move in order 2958da6c28aaSamw * to cleanup entries for protocols that 2959da6c28aaSamw * aren't in the new group. 296025a68471Sdougm */ 296125a68471Sdougm oldstate = sa_get_group_attr(parent, "state"); 2962fe1c642dSBill Krier if (oldstate != NULL) { 2963fe1c642dSBill Krier /* enable_share determines what to do */ 2964fe1c642dSBill Krier if (strcmp(oldstate, "enabled") == 0) 2965fe1c642dSBill Krier (void) sa_disable_share(share, NULL); 296625a68471Sdougm sa_free_attr_string(oldstate); 2967fe1c642dSBill Krier } 296825a68471Sdougm } 296925a68471Sdougm 2970da6c28aaSamw if (!dryrun && ret == SA_OK) 2971da6c28aaSamw ret = sa_move_share(group, share); 2972da6c28aaSamw 2973da6c28aaSamw /* 2974da6c28aaSamw * Reenable and update any config information. 2975da6c28aaSamw */ 2976da6c28aaSamw if (ret == SA_OK && parent != group && !dryrun) { 2977da6c28aaSamw ret = sa_update_config(handle); 2978da6c28aaSamw 2979da6c28aaSamw (void) enable_share(handle, group, share, 1); 2980da6c28aaSamw } 2981da6c28aaSamw 298225a68471Sdougm if (ret != SA_OK) 298325a68471Sdougm (void) printf(gettext("Could not move share: %s\n"), 298425a68471Sdougm sa_errorstr(ret)); 298525a68471Sdougm 298625a68471Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 298725a68471Sdougm verbose) { 298825a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 298925a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 29906185db85Sdougm } 29916185db85Sdougm } 29926185db85Sdougm return (ret); 29936185db85Sdougm } 29946185db85Sdougm 29956185db85Sdougm /* 29966185db85Sdougm * sa_removeshare(flags, argc, argv) 29976185db85Sdougm * 29986185db85Sdougm * implements remove-share subcommand. 29996185db85Sdougm */ 30006185db85Sdougm 30016185db85Sdougm int 3002549ec3ffSdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 30036185db85Sdougm { 30046185db85Sdougm int verbose = 0; 30056185db85Sdougm int dryrun = 0; 30066185db85Sdougm int force = 0; 30076185db85Sdougm int c; 30086185db85Sdougm int ret = SA_OK; 30096185db85Sdougm sa_group_t group; 3010da6c28aaSamw sa_resource_t resource = NULL; 3011da6c28aaSamw sa_share_t share = NULL; 3012da6c28aaSamw char *rsrcname = NULL; 30136185db85Sdougm char *sharepath = NULL; 30146185db85Sdougm char dir[MAXPATHLEN]; 30156185db85Sdougm int auth; 30166185db85Sdougm 3017da6c28aaSamw while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) { 301825a68471Sdougm switch (c) { 301925a68471Sdougm case 'n': 302025a68471Sdougm dryrun++; 302125a68471Sdougm break; 302225a68471Sdougm case 'v': 302325a68471Sdougm verbose++; 302425a68471Sdougm break; 302525a68471Sdougm case 'f': 302625a68471Sdougm force++; 302725a68471Sdougm break; 302825a68471Sdougm case 's': 302925a68471Sdougm /* 303025a68471Sdougm * Remove share path from group. Currently limit 303125a68471Sdougm * to one share per command. 303225a68471Sdougm */ 303325a68471Sdougm if (sharepath != NULL) { 303425a68471Sdougm (void) printf(gettext( 303525a68471Sdougm "Removing multiple shares not " 30366185db85Sdougm "supported\n")); 303725a68471Sdougm return (SA_SYNTAX_ERR); 303825a68471Sdougm } 303925a68471Sdougm sharepath = optarg; 304025a68471Sdougm break; 3041da6c28aaSamw case 'r': 3042da6c28aaSamw /* 3043da6c28aaSamw * Remove share from group if last resource or remove 3044da6c28aaSamw * resource from share if multiple resources. 3045da6c28aaSamw */ 3046da6c28aaSamw if (rsrcname != NULL) { 3047da6c28aaSamw (void) printf(gettext( 3048da6c28aaSamw "Removing multiple resource names not " 3049da6c28aaSamw "supported\n")); 3050da6c28aaSamw return (SA_SYNTAX_ERR); 3051da6c28aaSamw } 3052da6c28aaSamw rsrcname = optarg; 3053da6c28aaSamw break; 305425a68471Sdougm case 'h': 3055e7bab347Sdougm /* optopt on valid arg isn't defined */ 3056e7bab347Sdougm optopt = c; 3057e7bab347Sdougm /*FALLTHROUGH*/ 305825a68471Sdougm case '?': 3059e7bab347Sdougm default: 3060e7bab347Sdougm /* 3061e7bab347Sdougm * Since a bad option gets to here, sort it 3062e7bab347Sdougm * out and return a syntax error return value 3063e7bab347Sdougm * if necessary. 3064e7bab347Sdougm */ 3065e7bab347Sdougm switch (optopt) { 3066e7bab347Sdougm default: 3067e7bab347Sdougm ret = SA_SYNTAX_ERR; 3068e7bab347Sdougm break; 3069e7bab347Sdougm case 'h': 3070e7bab347Sdougm case '?': 3071e7bab347Sdougm break; 3072e7bab347Sdougm } 307325a68471Sdougm (void) printf(gettext("usage: %s\n"), 307425a68471Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 3075e7bab347Sdougm return (ret); 30766185db85Sdougm } 30776185db85Sdougm } 30786185db85Sdougm 3079da6c28aaSamw if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) { 3080da6c28aaSamw if (sharepath == NULL && rsrcname == NULL) { 30816185db85Sdougm (void) printf(gettext("usage: %s\n"), 308225a68471Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 3083da6c28aaSamw (void) printf(gettext("\t-s sharepath or -r resource" 3084da6c28aaSamw " must be specified\n")); 308525a68471Sdougm ret = SA_BAD_PATH; 308625a68471Sdougm } else { 308725a68471Sdougm ret = SA_OK; 308825a68471Sdougm } 30896185db85Sdougm } 309025a68471Sdougm if (ret != SA_OK) { 309125a68471Sdougm return (ret); 309225a68471Sdougm } 309325a68471Sdougm 309425a68471Sdougm if (optind < argc) { 30956185db85Sdougm if ((optind + 1) < argc) { 309625a68471Sdougm (void) printf(gettext("Extraneous group(s) at end of " 309725a68471Sdougm "command\n")); 309825a68471Sdougm ret = SA_SYNTAX_ERR; 30996185db85Sdougm } else { 310025a68471Sdougm group = sa_get_group(handle, argv[optind]); 310125a68471Sdougm if (group == NULL) { 310225a68471Sdougm (void) printf(gettext( 310325a68471Sdougm "Group \"%s\" not found\n"), argv[optind]); 310425a68471Sdougm ret = SA_NO_SUCH_GROUP; 310525a68471Sdougm } 31066185db85Sdougm } 310725a68471Sdougm } else { 31086185db85Sdougm group = NULL; 310925a68471Sdougm } 3110a99982a7Sdougm 3111da6c28aaSamw if (rsrcname != NULL) { 3112da6c28aaSamw resource = sa_find_resource(handle, rsrcname); 3113da6c28aaSamw if (resource == NULL) { 3114da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3115da6c28aaSamw (void) printf(gettext( 3116da6c28aaSamw "Resource name not found for share: %s\n"), 3117da6c28aaSamw rsrcname); 3118da6c28aaSamw } 3119da6c28aaSamw } 3120da6c28aaSamw 312125a68471Sdougm /* 312225a68471Sdougm * Lookup the path in the internal configuration. Care 312325a68471Sdougm * must be taken to handle the case where the 312425a68471Sdougm * underlying path has been removed since we need to 312525a68471Sdougm * be able to deal with that as well. 312625a68471Sdougm */ 312725a68471Sdougm if (ret == SA_OK) { 3128da6c28aaSamw if (sharepath != NULL) { 3129da6c28aaSamw if (group != NULL) 3130da6c28aaSamw share = sa_get_share(group, sharepath); 3131da6c28aaSamw else 3132da6c28aaSamw share = sa_find_share(handle, sharepath); 3133da6c28aaSamw } 3134da6c28aaSamw 3135da6c28aaSamw if (resource != NULL) { 3136da6c28aaSamw sa_share_t rsrcshare; 3137da6c28aaSamw rsrcshare = sa_get_resource_parent(resource); 3138da6c28aaSamw if (share == NULL) 3139da6c28aaSamw share = rsrcshare; 3140da6c28aaSamw else if (share != rsrcshare) { 3141da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3142da6c28aaSamw (void) printf(gettext( 3143da6c28aaSamw "Bad resource name for share: %s\n"), 3144da6c28aaSamw rsrcname); 3145da6c28aaSamw share = NULL; 3146da6c28aaSamw } 3147da6c28aaSamw } 3148da6c28aaSamw 3149a99982a7Sdougm /* 3150a99982a7Sdougm * If we didn't find the share with the provided path, 3151a99982a7Sdougm * it may be a symlink so attempt to resolve it using 3152a99982a7Sdougm * realpath and try again. Realpath will resolve any 3153a99982a7Sdougm * symlinks and place them in "dir". Note that 3154a99982a7Sdougm * sharepath is only used for the lookup the first 3155a99982a7Sdougm * time and later for error messages. dir will be used 3156a99982a7Sdougm * on the second attempt. Once a share is found, all 3157a99982a7Sdougm * operations are based off of the share variable. 3158a99982a7Sdougm */ 3159a99982a7Sdougm if (share == NULL) { 316025a68471Sdougm if (realpath(sharepath, dir) == NULL) { 316125a68471Sdougm ret = SA_BAD_PATH; 316225a68471Sdougm (void) printf(gettext( 316325a68471Sdougm "Path is not valid: %s\n"), sharepath); 316425a68471Sdougm } else { 316525a68471Sdougm if (group != NULL) 316625a68471Sdougm share = sa_get_share(group, dir); 316725a68471Sdougm else 316825a68471Sdougm share = sa_find_share(handle, dir); 316925a68471Sdougm } 3170a99982a7Sdougm } 317125a68471Sdougm } 3172a99982a7Sdougm 317325a68471Sdougm /* 317425a68471Sdougm * If there hasn't been an error, there was likely a 317525a68471Sdougm * path found. If not, give the appropriate error 317625a68471Sdougm * message and set the return error. If it was found, 317725a68471Sdougm * then disable the share and then remove it from the 317825a68471Sdougm * configuration. 317925a68471Sdougm */ 318025a68471Sdougm if (ret != SA_OK) { 318125a68471Sdougm return (ret); 318225a68471Sdougm } 318325a68471Sdougm if (share == NULL) { 318425a68471Sdougm if (group != NULL) 31856185db85Sdougm (void) printf(gettext("Share not found in group %s:" 318625a68471Sdougm " %s\n"), argv[optind], sharepath); 318725a68471Sdougm else 31886185db85Sdougm (void) printf(gettext("Share not found: %s\n"), 318925a68471Sdougm sharepath); 3190da6c28aaSamw ret = SA_NO_SUCH_PATH; 319125a68471Sdougm } else { 319225a68471Sdougm if (group == NULL) 31936185db85Sdougm group = sa_get_parent_group(share); 319425a68471Sdougm if (!dryrun) { 31956185db85Sdougm if (ret == SA_OK) { 3196da6c28aaSamw if (resource != NULL) 3197da6c28aaSamw ret = sa_disable_resource(resource, 3198da6c28aaSamw NULL); 3199da6c28aaSamw else 3200da6c28aaSamw ret = sa_disable_share(share, NULL); 32016185db85Sdougm /* 320225a68471Sdougm * We don't care if it fails since it 3203a99982a7Sdougm * could be disabled already. Some 3204a99982a7Sdougm * unexpected errors could occur that 3205a99982a7Sdougm * prevent removal, so also check for 3206a99982a7Sdougm * force being set. 32076185db85Sdougm */ 3208da6c28aaSamw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 320925a68471Sdougm ret == SA_NOT_SUPPORTED || 3210da6c28aaSamw ret == SA_SYSTEM_ERR || force) && 3211da6c28aaSamw resource == NULL) 321225a68471Sdougm ret = sa_remove_share(share); 3213da6c28aaSamw 3214da6c28aaSamw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 3215da6c28aaSamw ret == SA_NOT_SUPPORTED || 3216da6c28aaSamw ret == SA_SYSTEM_ERR || force) && 3217da6c28aaSamw resource != NULL) { 3218da6c28aaSamw ret = sa_remove_resource(resource); 3219da6c28aaSamw if (ret == SA_OK) { 3220da6c28aaSamw /* 3221da6c28aaSamw * If this was the 3222da6c28aaSamw * last one, remove 3223da6c28aaSamw * the share as well. 3224da6c28aaSamw */ 3225da6c28aaSamw resource = 3226da6c28aaSamw sa_get_share_resource( 3227da6c28aaSamw share, NULL); 3228da6c28aaSamw if (resource == NULL) 3229da6c28aaSamw ret = sa_remove_share( 3230da6c28aaSamw share); 3231da6c28aaSamw } 323225a68471Sdougm } 323325a68471Sdougm if (ret == SA_OK) 323425a68471Sdougm ret = sa_update_config(handle); 32356185db85Sdougm } 323625a68471Sdougm if (ret != SA_OK) 3237da6c28aaSamw (void) printf(gettext("Could not remove share:" 3238da6c28aaSamw " %s\n"), sa_errorstr(ret)); 323925a68471Sdougm } else if (ret == SA_OK) { 32406185db85Sdougm char *pname; 32416185db85Sdougm pname = sa_get_group_attr(group, "name"); 32426185db85Sdougm if (pname != NULL) { 324325a68471Sdougm auth = check_authorizations(pname, flags); 324425a68471Sdougm sa_free_attr_string(pname); 32456185db85Sdougm } 32466185db85Sdougm if (!auth && verbose) { 324725a68471Sdougm (void) printf(gettext( 324825a68471Sdougm "Command would fail: %s\n"), 324925a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 32506185db85Sdougm } 32516185db85Sdougm } 32526185db85Sdougm } 32536185db85Sdougm return (ret); 32546185db85Sdougm } 32556185db85Sdougm 32566185db85Sdougm /* 32576185db85Sdougm * sa_set_share(flags, argc, argv) 32586185db85Sdougm * 32596185db85Sdougm * implements set-share subcommand. 32606185db85Sdougm */ 32616185db85Sdougm 32626185db85Sdougm int 3263549ec3ffSdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 32646185db85Sdougm { 32656185db85Sdougm int dryrun = 0; 32666185db85Sdougm int c; 32676185db85Sdougm int ret = SA_OK; 32686185db85Sdougm sa_group_t group, sharegroup; 3269dc20a302Sas sa_share_t share = NULL; 3270da6c28aaSamw sa_resource_t resource = NULL; 32716185db85Sdougm char *sharepath = NULL; 32726185db85Sdougm char *description = NULL; 3273da6c28aaSamw char *rsrcname = NULL; 3274da6c28aaSamw char *rsrc = NULL; 3275da6c28aaSamw char *newname = NULL; 3276da6c28aaSamw char *newrsrc; 3277da6c28aaSamw char *groupname = NULL; 32786185db85Sdougm int auth; 32796185db85Sdougm int verbose = 0; 32806185db85Sdougm 32816185db85Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 328225a68471Sdougm switch (c) { 328325a68471Sdougm case 'n': 328425a68471Sdougm dryrun++; 328525a68471Sdougm break; 328625a68471Sdougm case 'd': 328725a68471Sdougm description = optarg; 328825a68471Sdougm break; 328925a68471Sdougm case 'v': 329025a68471Sdougm verbose++; 329125a68471Sdougm break; 3292da6c28aaSamw case 'r': 3293da6c28aaSamw /* 3294da6c28aaSamw * Update share by resource name 3295da6c28aaSamw */ 3296da6c28aaSamw if (rsrcname != NULL) { 3297da6c28aaSamw (void) printf(gettext( 3298da6c28aaSamw "Updating multiple resource names not " 3299da6c28aaSamw "supported\n")); 3300da6c28aaSamw return (SA_SYNTAX_ERR); 3301da6c28aaSamw } 3302da6c28aaSamw rsrcname = optarg; 3303da6c28aaSamw break; 330425a68471Sdougm case 's': 330525a68471Sdougm /* 330625a68471Sdougm * Save share path into group. Currently limit 330725a68471Sdougm * to one share per command. 330825a68471Sdougm */ 330925a68471Sdougm if (sharepath != NULL) { 331025a68471Sdougm (void) printf(gettext( 331125a68471Sdougm "Updating multiple shares not " 33126185db85Sdougm "supported\n")); 3313da6c28aaSamw return (SA_SYNTAX_ERR); 331425a68471Sdougm } 331525a68471Sdougm sharepath = optarg; 331625a68471Sdougm break; 331725a68471Sdougm case 'h': 3318e7bab347Sdougm /* optopt on valid arg isn't defined */ 3319e7bab347Sdougm optopt = c; 3320e7bab347Sdougm /*FALLTHROUGH*/ 332125a68471Sdougm case '?': 3322e7bab347Sdougm default: 3323e7bab347Sdougm /* 3324e7bab347Sdougm * Since a bad option gets to here, sort it 3325e7bab347Sdougm * out and return a syntax error return value 3326e7bab347Sdougm * if necessary. 3327e7bab347Sdougm */ 3328e7bab347Sdougm switch (optopt) { 3329e7bab347Sdougm default: 3330e7bab347Sdougm ret = SA_SYNTAX_ERR; 3331e7bab347Sdougm break; 3332e7bab347Sdougm case 'h': 3333e7bab347Sdougm case '?': 3334e7bab347Sdougm break; 3335e7bab347Sdougm } 333625a68471Sdougm (void) printf(gettext("usage: %s\n"), 333725a68471Sdougm sa_get_usage(USAGE_SET_SHARE)); 3338e7bab347Sdougm return (ret); 33396185db85Sdougm } 33406185db85Sdougm } 334125a68471Sdougm 3342da6c28aaSamw if (optind >= argc && sharepath == NULL && rsrcname == NULL) { 334325a68471Sdougm if (sharepath == NULL) { 334425a68471Sdougm (void) printf(gettext("usage: %s\n"), 334525a68471Sdougm sa_get_usage(USAGE_SET_SHARE)); 334625a68471Sdougm (void) printf(gettext("\tgroup must be specified\n")); 334725a68471Sdougm ret = SA_BAD_PATH; 334825a68471Sdougm } else { 334925a68471Sdougm ret = SA_OK; 335025a68471Sdougm } 33516185db85Sdougm } 33526185db85Sdougm if ((optind + 1) < argc) { 335325a68471Sdougm (void) printf(gettext("usage: %s\n"), 335425a68471Sdougm sa_get_usage(USAGE_SET_SHARE)); 3355da6c28aaSamw (void) printf(gettext("\tExtraneous group(s) at end\n")); 3356da6c28aaSamw ret = SA_SYNTAX_ERR; 3357da6c28aaSamw } 3358da6c28aaSamw 3359da6c28aaSamw /* 3360da6c28aaSamw * Must have at least one of sharepath and rsrcrname. 3361da6c28aaSamw * It is a syntax error to be missing both. 3362da6c28aaSamw */ 3363da6c28aaSamw if (sharepath == NULL && rsrcname == NULL) { 3364da6c28aaSamw (void) printf(gettext("usage: %s\n"), 3365da6c28aaSamw sa_get_usage(USAGE_SET_SHARE)); 336625a68471Sdougm ret = SA_SYNTAX_ERR; 33676185db85Sdougm } 336825a68471Sdougm 336925a68471Sdougm if (ret != SA_OK) 337025a68471Sdougm return (ret); 337125a68471Sdougm 337225a68471Sdougm if (optind < argc) { 33736185db85Sdougm groupname = argv[optind]; 3374549ec3ffSdougm group = sa_get_group(handle, groupname); 337525a68471Sdougm } else { 33766185db85Sdougm group = NULL; 33776185db85Sdougm groupname = NULL; 337825a68471Sdougm } 3379da6c28aaSamw if (rsrcname != NULL) { 3380da6c28aaSamw /* 3381da6c28aaSamw * If rsrcname exists, split rename syntax and then 3382da6c28aaSamw * convert to utf 8 if no errors. 3383da6c28aaSamw */ 3384da6c28aaSamw newname = strchr(rsrcname, '='); 3385da6c28aaSamw if (newname != NULL) { 3386da6c28aaSamw *newname++ = '\0'; 3387da6c28aaSamw } 3388da6c28aaSamw if (!validresource(rsrcname)) { 3389da6c28aaSamw ret = SA_INVALID_NAME; 3390da6c28aaSamw (void) printf(gettext("Invalid resource name: " 3391da6c28aaSamw "\"%s\"\n"), rsrcname); 339225a68471Sdougm } else { 3393da6c28aaSamw rsrc = conv_to_utf8(rsrcname); 339425a68471Sdougm } 3395da6c28aaSamw if (newname != NULL) { 3396da6c28aaSamw if (!validresource(newname)) { 3397da6c28aaSamw ret = SA_INVALID_NAME; 3398da6c28aaSamw (void) printf(gettext("Invalid resource name: " 3399da6c28aaSamw "%s\n"), newname); 3400ef18c5ecSDoug McCallum newname = NULL; 34016185db85Sdougm } else { 3402da6c28aaSamw newrsrc = conv_to_utf8(newname); 34036185db85Sdougm } 34046185db85Sdougm } 340525a68471Sdougm } 340625a68471Sdougm 3407da6c28aaSamw if (ret != SA_OK) { 3408da6c28aaSamw if (rsrcname != NULL && rsrcname != rsrc) 3409da6c28aaSamw sa_free_attr_string(rsrc); 3410da6c28aaSamw if (newname != NULL && newname != newrsrc) 3411da6c28aaSamw sa_free_attr_string(newrsrc); 3412da6c28aaSamw return (ret); 3413da6c28aaSamw } 3414da6c28aaSamw 3415da6c28aaSamw if (sharepath != NULL) { 3416da6c28aaSamw share = sa_find_share(handle, sharepath); 3417da6c28aaSamw } else if (rsrcname != NULL) { 3418da6c28aaSamw resource = sa_find_resource(handle, rsrc); 3419dc20a302Sas if (resource != NULL) 3420da6c28aaSamw share = sa_get_resource_parent(resource); 3421dc20a302Sas else 3422dc20a302Sas ret = SA_NO_SUCH_RESOURCE; 3423da6c28aaSamw } 3424da6c28aaSamw if (share != NULL) { 3425da6c28aaSamw sharegroup = sa_get_parent_group(share); 3426da6c28aaSamw if (group != NULL && group != sharegroup) { 3427da6c28aaSamw (void) printf(gettext("Group \"%s\" does not contain " 3428da6c28aaSamw "share %s\n"), 3429da6c28aaSamw argv[optind], sharepath); 3430da6c28aaSamw ret = SA_BAD_PATH; 3431da6c28aaSamw } else { 3432da6c28aaSamw int delgroupname = 0; 3433da6c28aaSamw if (groupname == NULL) { 3434da6c28aaSamw groupname = sa_get_group_attr(sharegroup, 3435da6c28aaSamw "name"); 3436da6c28aaSamw delgroupname = 1; 3437da6c28aaSamw } 3438da6c28aaSamw if (groupname != NULL) { 3439da6c28aaSamw auth = check_authorizations(groupname, flags); 3440da6c28aaSamw if (delgroupname) { 3441da6c28aaSamw sa_free_attr_string(groupname); 3442da6c28aaSamw groupname = NULL; 3443da6c28aaSamw } 3444da6c28aaSamw } else { 3445da6c28aaSamw ret = SA_NO_MEMORY; 3446da6c28aaSamw } 3447da6c28aaSamw if (rsrcname != NULL) { 3448da6c28aaSamw resource = sa_find_resource(handle, rsrc); 3449da6c28aaSamw if (!dryrun) { 3450da6c28aaSamw if (newname != NULL && 3451da6c28aaSamw resource != NULL) 3452da6c28aaSamw ret = sa_rename_resource( 3453da6c28aaSamw resource, newrsrc); 3454da6c28aaSamw else if (newname != NULL) 3455da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3456da6c28aaSamw if (newname != NULL && 3457da6c28aaSamw newname != newrsrc) 3458da6c28aaSamw sa_free_attr_string(newrsrc); 3459da6c28aaSamw } 3460da6c28aaSamw if (rsrc != rsrcname) 3461da6c28aaSamw sa_free_attr_string(rsrc); 3462da6c28aaSamw } 3463da6c28aaSamw 3464da6c28aaSamw /* 3465da6c28aaSamw * If the user has set a description, it will be 3466da6c28aaSamw * on the resource if -r was used otherwise it 3467da6c28aaSamw * must be on the share. 3468da6c28aaSamw */ 3469cbfb650aScp if (!dryrun && ret == SA_OK && description != NULL) { 3470cbfb650aScp char *desc; 3471cbfb650aScp desc = conv_to_utf8(description); 3472da6c28aaSamw if (resource != NULL) 3473cbfb650aScp ret = sa_set_resource_description( 3474cbfb650aScp resource, desc); 3475da6c28aaSamw else 3476cbfb650aScp ret = sa_set_share_description(share, 3477cbfb650aScp desc); 3478cbfb650aScp if (desc != description) 3479cbfb650aScp sa_free_share_description(desc); 3480da6c28aaSamw } 3481da6c28aaSamw } 3482da6c28aaSamw if (!dryrun && ret == SA_OK) { 3483da6c28aaSamw if (resource != NULL) 3484da6c28aaSamw (void) sa_enable_resource(resource, NULL); 3485da6c28aaSamw ret = sa_update_config(handle); 3486da6c28aaSamw } 3487da6c28aaSamw switch (ret) { 3488da6c28aaSamw case SA_DUPLICATE_NAME: 3489da6c28aaSamw (void) printf(gettext("Resource name in use: %s\n"), 3490da6c28aaSamw rsrcname); 3491da6c28aaSamw break; 3492da6c28aaSamw default: 3493da6c28aaSamw (void) printf(gettext("Could not set: %s\n"), 3494da6c28aaSamw sa_errorstr(ret)); 3495da6c28aaSamw break; 3496da6c28aaSamw case SA_OK: 3497da6c28aaSamw if (dryrun && !auth && verbose) { 3498da6c28aaSamw (void) printf(gettext( 3499da6c28aaSamw "Command would fail: %s\n"), 3500da6c28aaSamw sa_errorstr(SA_NO_PERMISSION)); 3501da6c28aaSamw } 3502da6c28aaSamw break; 3503da6c28aaSamw } 3504da6c28aaSamw } else { 3505dc20a302Sas switch (ret) { 3506dc20a302Sas case SA_NO_SUCH_RESOURCE: 3507dc20a302Sas (void) printf(gettext("Resource \"%s\" not found\n"), 3508dc20a302Sas rsrcname); 3509dc20a302Sas break; 3510dc20a302Sas default: 3511dc20a302Sas if (sharepath != NULL) { 3512dc20a302Sas (void) printf( 3513dc20a302Sas gettext("Share path \"%s\" not found\n"), 3514dc20a302Sas sharepath); 3515dc20a302Sas ret = SA_NO_SUCH_PATH; 3516dc20a302Sas } else { 3517dc20a302Sas (void) printf(gettext("Set failed: %s\n"), 3518dc20a302Sas sa_errorstr(ret)); 3519dc20a302Sas } 3520dc20a302Sas } 35216185db85Sdougm } 352225a68471Sdougm 35236185db85Sdougm return (ret); 35246185db85Sdougm } 35256185db85Sdougm 35266185db85Sdougm /* 35276185db85Sdougm * add_security(group, sectype, optlist, proto, *err) 35286185db85Sdougm * 35296185db85Sdougm * Helper function to add a security option (named optionset) to the 35306185db85Sdougm * group. 35316185db85Sdougm */ 35326185db85Sdougm 35336185db85Sdougm static int 35346185db85Sdougm add_security(sa_group_t group, char *sectype, 3535da6c28aaSamw struct options *optlist, char *proto, int *err) 35366185db85Sdougm { 35376185db85Sdougm sa_security_t security; 35386185db85Sdougm int ret = SA_OK; 35396185db85Sdougm int result = 0; 3540687915e9Sdougm sa_handle_t handle; 35416185db85Sdougm 35426185db85Sdougm sectype = sa_proto_space_alias(proto, sectype); 35436185db85Sdougm security = sa_get_security(group, sectype, proto); 354425a68471Sdougm if (security == NULL) 354525a68471Sdougm security = sa_create_security(group, sectype, proto); 354625a68471Sdougm 35476185db85Sdougm if (sectype != NULL) 354825a68471Sdougm sa_free_attr_string(sectype); 354925a68471Sdougm 355025a68471Sdougm if (security == NULL) 3551687915e9Sdougm goto done; 355225a68471Sdougm 3553687915e9Sdougm handle = sa_find_group_handle(group); 3554687915e9Sdougm if (handle == NULL) { 3555687915e9Sdougm ret = SA_CONFIG_ERR; 3556687915e9Sdougm goto done; 3557687915e9Sdougm } 355825a68471Sdougm while (optlist != NULL) { 35596185db85Sdougm sa_property_t prop; 35606185db85Sdougm prop = sa_get_property(security, optlist->optname); 35616185db85Sdougm if (prop == NULL) { 35626185db85Sdougm /* 356325a68471Sdougm * Add the property, but only if it is 35646185db85Sdougm * a non-NULL or non-zero length value 35656185db85Sdougm */ 356625a68471Sdougm if (optlist->optvalue != NULL) { 356725a68471Sdougm prop = sa_create_property(optlist->optname, 356825a68471Sdougm optlist->optvalue); 356925a68471Sdougm if (prop != NULL) { 3570687915e9Sdougm ret = sa_valid_property(handle, 3571687915e9Sdougm security, proto, prop); 357225a68471Sdougm if (ret != SA_OK) { 357325a68471Sdougm (void) sa_remove_property(prop); 357425a68471Sdougm (void) printf(gettext( 357525a68471Sdougm "Could not add " 357625a68471Sdougm "property %s: %s\n"), 357725a68471Sdougm optlist->optname, 357825a68471Sdougm sa_errorstr(ret)); 357925a68471Sdougm } 358025a68471Sdougm if (ret == SA_OK) { 358125a68471Sdougm ret = sa_add_property(security, 358225a68471Sdougm prop); 358325a68471Sdougm if (ret != SA_OK) { 358425a68471Sdougm (void) printf(gettext( 358525a68471Sdougm "Could not add " 3586da6c28aaSamw "property (%s=%s):" 3587da6c28aaSamw " %s\n"), 358825a68471Sdougm optlist->optname, 358925a68471Sdougm optlist->optvalue, 359025a68471Sdougm sa_errorstr(ret)); 359125a68471Sdougm } else { 359225a68471Sdougm result = 1; 359325a68471Sdougm } 359425a68471Sdougm } 35956185db85Sdougm } 35966185db85Sdougm } 35976185db85Sdougm } else { 359825a68471Sdougm ret = sa_update_property(prop, optlist->optvalue); 359925a68471Sdougm result = 1; /* should check if really changed */ 36006185db85Sdougm } 36016185db85Sdougm optlist = optlist->next; 36026185db85Sdougm } 360325a68471Sdougm /* 360425a68471Sdougm * When done, properties may have all been removed but 360525a68471Sdougm * we need to keep the security type itself until 360625a68471Sdougm * explicitly removed. 360725a68471Sdougm */ 360825a68471Sdougm if (result) 360925a68471Sdougm ret = sa_commit_properties(security, 0); 3610687915e9Sdougm done: 36116185db85Sdougm *err = ret; 36126185db85Sdougm return (result); 36136185db85Sdougm } 36146185db85Sdougm 3615f8825440Sdougm /* 3616f8825440Sdougm * zfscheck(group, share) 3617f8825440Sdougm * 3618f8825440Sdougm * For the special case where a share was provided, make sure it is a 3619f8825440Sdougm * compatible path for a ZFS property change. The only path 3620f8825440Sdougm * acceptable is the path that defines the zfs sub-group (dataset with 3621f8825440Sdougm * the sharenfs property set) and not one of the paths that inherited 3622f8825440Sdougm * the NFS properties. Returns SA_OK if it is usable and 3623f8825440Sdougm * SA_NOT_ALLOWED if it isn't. 3624f8825440Sdougm * 3625f8825440Sdougm * If group is not a ZFS group/subgroup, we assume OK since the check 3626f8825440Sdougm * on return will catch errors for those cases. What we are looking 3627f8825440Sdougm * for here is that the group is ZFS and the share is not the defining 3628f8825440Sdougm * share. All else is SA_OK. 3629f8825440Sdougm */ 3630f8825440Sdougm 3631f8825440Sdougm static int 3632f8825440Sdougm zfscheck(sa_group_t group, sa_share_t share) 3633f8825440Sdougm { 3634f8825440Sdougm int ret = SA_OK; 3635f8825440Sdougm char *attr; 3636f8825440Sdougm 3637f8825440Sdougm if (sa_group_is_zfs(group)) { 3638f8825440Sdougm /* 3639f8825440Sdougm * The group is a ZFS group. Does the share represent 3640f8825440Sdougm * the dataset that defined the group? It is only OK 3641f8825440Sdougm * if the attribute "subgroup" exists on the share and 3642f8825440Sdougm * has a value of "true". 3643f8825440Sdougm */ 3644f8825440Sdougm 3645f8825440Sdougm ret = SA_NOT_ALLOWED; 3646f8825440Sdougm attr = sa_get_share_attr(share, "subgroup"); 3647f8825440Sdougm if (attr != NULL) { 3648f8825440Sdougm if (strcmp(attr, "true") == 0) 3649f8825440Sdougm ret = SA_OK; 3650f8825440Sdougm sa_free_attr_string(attr); 3651f8825440Sdougm } 3652f8825440Sdougm } 3653f8825440Sdougm return (ret); 3654f8825440Sdougm } 3655f8825440Sdougm 36566185db85Sdougm /* 3657da6c28aaSamw * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 36586185db85Sdougm * 36596185db85Sdougm * This function implements "set" when a name space (-S) is not 36606185db85Sdougm * specified. It is a basic set. Options and other CLI parsing has 36616185db85Sdougm * already been done. 3662da6c28aaSamw * 3663da6c28aaSamw * "rsrcname" is a "resource name". If it is non-NULL, it must match 3664da6c28aaSamw * the sharepath if present or group if present, otherwise it is used 3665da6c28aaSamw * to set options. 3666da6c28aaSamw * 3667da6c28aaSamw * Resource names may take options if the protocol supports it. If the 3668da6c28aaSamw * protocol doesn't support resource level options, rsrcname is just 3669da6c28aaSamw * an alias for the share. 36706185db85Sdougm */ 36716185db85Sdougm 36726185db85Sdougm static int 3673549ec3ffSdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 3674da6c28aaSamw char *protocol, char *sharepath, char *rsrcname, int dryrun) 36756185db85Sdougm { 36766185db85Sdougm sa_group_t group; 36776185db85Sdougm int ret = SA_OK; 36786185db85Sdougm int change = 0; 36796185db85Sdougm struct list *worklist = NULL; 36806185db85Sdougm 3681549ec3ffSdougm group = sa_get_group(handle, groupname); 36826185db85Sdougm if (group != NULL) { 368325a68471Sdougm sa_share_t share = NULL; 3684da6c28aaSamw sa_resource_t resource = NULL; 3685da6c28aaSamw 3686da6c28aaSamw /* 3687da6c28aaSamw * If there is a sharepath, make sure it belongs to 3688da6c28aaSamw * the group. 3689da6c28aaSamw */ 369025a68471Sdougm if (sharepath != NULL) { 369125a68471Sdougm share = sa_get_share(group, sharepath); 369225a68471Sdougm if (share == NULL) { 369325a68471Sdougm (void) printf(gettext( 369425a68471Sdougm "Share does not exist in group %s\n"), 369525a68471Sdougm groupname, sharepath); 369625a68471Sdougm ret = SA_NO_SUCH_PATH; 3697f8825440Sdougm } else { 3698f8825440Sdougm /* if ZFS and OK, then only group */ 3699f8825440Sdougm ret = zfscheck(group, share); 3700f8825440Sdougm if (ret == SA_OK && 3701f8825440Sdougm sa_group_is_zfs(group)) 3702f8825440Sdougm share = NULL; 3703f8825440Sdougm if (ret == SA_NOT_ALLOWED) 3704f8825440Sdougm (void) printf(gettext( 3705f8825440Sdougm "Properties on ZFS group shares " 3706f8825440Sdougm "not supported: %s\n"), sharepath); 370725a68471Sdougm } 37086185db85Sdougm } 3709da6c28aaSamw 3710da6c28aaSamw /* 3711da6c28aaSamw * If a resource name exists, make sure it belongs to 3712da6c28aaSamw * the share if present else it belongs to the 3713da6c28aaSamw * group. Also check the protocol to see if it 3714da6c28aaSamw * supports resource level properties or not. If not, 3715da6c28aaSamw * use share only. 3716da6c28aaSamw */ 3717da6c28aaSamw if (rsrcname != NULL) { 3718da6c28aaSamw if (share != NULL) { 3719da6c28aaSamw resource = sa_get_share_resource(share, 3720da6c28aaSamw rsrcname); 3721da6c28aaSamw if (resource == NULL) 3722da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3723da6c28aaSamw } else { 3724da6c28aaSamw resource = sa_get_resource(group, rsrcname); 3725da6c28aaSamw if (resource != NULL) 3726da6c28aaSamw share = sa_get_resource_parent( 3727da6c28aaSamw resource); 3728da6c28aaSamw else 3729da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3730da6c28aaSamw } 3731da6c28aaSamw if (ret == SA_OK && resource != NULL) { 3732da6c28aaSamw uint64_t features; 3733da6c28aaSamw /* 3734da6c28aaSamw * Check to see if the resource can take 3735da6c28aaSamw * properties. If so, stick the resource into 3736da6c28aaSamw * "share" so it will all just work. 3737da6c28aaSamw */ 3738da6c28aaSamw features = sa_proto_get_featureset(protocol); 3739da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 3740da6c28aaSamw share = (sa_share_t)resource; 3741da6c28aaSamw } 3742da6c28aaSamw } 3743da6c28aaSamw 374425a68471Sdougm if (ret == SA_OK) { 374525a68471Sdougm /* group must exist */ 3746687915e9Sdougm ret = valid_options(handle, optlist, protocol, 374725a68471Sdougm share == NULL ? group : share, NULL); 374825a68471Sdougm if (ret == SA_OK && !dryrun) { 374925a68471Sdougm if (share != NULL) 375025a68471Sdougm change |= add_optionset(share, optlist, 375125a68471Sdougm protocol, &ret); 375225a68471Sdougm else 375325a68471Sdougm change |= add_optionset(group, optlist, 375425a68471Sdougm protocol, &ret); 375525a68471Sdougm if (ret == SA_OK && change) 375625a68471Sdougm worklist = add_list(worklist, group, 3757da6c28aaSamw share, protocol); 375825a68471Sdougm } 375925a68471Sdougm } 376025a68471Sdougm free_opt(optlist); 37616185db85Sdougm } else { 37626185db85Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 37636185db85Sdougm ret = SA_NO_SUCH_GROUP; 37646185db85Sdougm } 37656185db85Sdougm /* 37666185db85Sdougm * we have a group and potentially legal additions 37676185db85Sdougm */ 37686185db85Sdougm 376925a68471Sdougm /* 377025a68471Sdougm * Commit to configuration if not a dryrunp and properties 377125a68471Sdougm * have changed. 377225a68471Sdougm */ 377325a68471Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 37746185db85Sdougm /* properties changed, so update all shares */ 3775da6c28aaSamw (void) enable_all_groups(handle, worklist, 0, 0, protocol, 3776da6c28aaSamw B_TRUE); 377725a68471Sdougm 37786185db85Sdougm if (worklist != NULL) 377925a68471Sdougm free_list(worklist); 37806185db85Sdougm return (ret); 37816185db85Sdougm } 37826185db85Sdougm 37836185db85Sdougm /* 37846185db85Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 37856185db85Sdougm * 37866185db85Sdougm * This function implements "set" when a name space (-S) is 37876185db85Sdougm * specified. It is a namespace set. Options and other CLI parsing has 37886185db85Sdougm * already been done. 37896185db85Sdougm */ 37906185db85Sdougm 37916185db85Sdougm static int 3792549ec3ffSdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 3793da6c28aaSamw char *protocol, char *sharepath, int dryrun, char *sectype) 37946185db85Sdougm { 37956185db85Sdougm sa_group_t group; 37966185db85Sdougm int ret = SA_OK; 37976185db85Sdougm int change = 0; 37986185db85Sdougm struct list *worklist = NULL; 37996185db85Sdougm 38006185db85Sdougm /* 38016185db85Sdougm * make sure protcol and sectype are valid 38026185db85Sdougm */ 38036185db85Sdougm 38046185db85Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 380525a68471Sdougm (void) printf(gettext("Option space \"%s\" not valid " 380625a68471Sdougm "for protocol.\n"), sectype); 380725a68471Sdougm return (SA_INVALID_SECURITY); 38086185db85Sdougm } 38096185db85Sdougm 3810549ec3ffSdougm group = sa_get_group(handle, groupname); 38116185db85Sdougm if (group != NULL) { 381225a68471Sdougm sa_share_t share = NULL; 381325a68471Sdougm if (sharepath != NULL) { 381425a68471Sdougm share = sa_get_share(group, sharepath); 381525a68471Sdougm if (share == NULL) { 381625a68471Sdougm (void) printf(gettext( 381725a68471Sdougm "Share does not exist in group %s\n"), 381825a68471Sdougm groupname, sharepath); 381925a68471Sdougm ret = SA_NO_SUCH_PATH; 3820f8825440Sdougm } else { 3821f8825440Sdougm /* if ZFS and OK, then only group */ 3822f8825440Sdougm ret = zfscheck(group, share); 3823f8825440Sdougm if (ret == SA_OK && 3824f8825440Sdougm sa_group_is_zfs(group)) 3825f8825440Sdougm share = NULL; 3826f8825440Sdougm if (ret == SA_NOT_ALLOWED) 3827f8825440Sdougm (void) printf(gettext( 3828f8825440Sdougm "Properties on ZFS group shares " 3829f8825440Sdougm "not supported: %s\n"), sharepath); 383025a68471Sdougm } 38316185db85Sdougm } 383225a68471Sdougm if (ret == SA_OK) { 383325a68471Sdougm /* group must exist */ 3834687915e9Sdougm ret = valid_options(handle, optlist, protocol, 383525a68471Sdougm share == NULL ? group : share, sectype); 383625a68471Sdougm if (ret == SA_OK && !dryrun) { 383725a68471Sdougm if (share != NULL) 383825a68471Sdougm change = add_security(share, sectype, 383925a68471Sdougm optlist, protocol, &ret); 384025a68471Sdougm else 384125a68471Sdougm change = add_security(group, sectype, 384225a68471Sdougm optlist, protocol, &ret); 384325a68471Sdougm if (ret != SA_OK) 384425a68471Sdougm (void) printf(gettext( 384525a68471Sdougm "Could not set property: %s\n"), 384625a68471Sdougm sa_errorstr(ret)); 384725a68471Sdougm } 384825a68471Sdougm if (ret == SA_OK && change) 3849da6c28aaSamw worklist = add_list(worklist, group, share, 3850da6c28aaSamw protocol); 38516185db85Sdougm } 385225a68471Sdougm free_opt(optlist); 38536185db85Sdougm } else { 38546185db85Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 38556185db85Sdougm ret = SA_NO_SUCH_GROUP; 38566185db85Sdougm } 3857da6c28aaSamw 38586185db85Sdougm /* 3859da6c28aaSamw * We have a group and potentially legal additions. 38606185db85Sdougm */ 38616185db85Sdougm 386225a68471Sdougm /* Commit to configuration if not a dryrun */ 38636185db85Sdougm if (!dryrun && ret == 0) { 386425a68471Sdougm if (change && worklist != NULL) { 386525a68471Sdougm /* properties changed, so update all shares */ 386625a68471Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 3867da6c28aaSamw protocol, B_TRUE); 386825a68471Sdougm } 386925a68471Sdougm ret = sa_update_config(handle); 38706185db85Sdougm } 38716185db85Sdougm if (worklist != NULL) 387225a68471Sdougm free_list(worklist); 38736185db85Sdougm return (ret); 38746185db85Sdougm } 38756185db85Sdougm 38766185db85Sdougm /* 38776185db85Sdougm * sa_set(flags, argc, argv) 38786185db85Sdougm * 38796185db85Sdougm * Implements the set subcommand. It keys off of -S to determine which 38806185db85Sdougm * set of operations to actually do. 38816185db85Sdougm */ 38826185db85Sdougm 38836185db85Sdougm int 3884549ec3ffSdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 38856185db85Sdougm { 38866185db85Sdougm char *groupname; 38876185db85Sdougm int verbose = 0; 38886185db85Sdougm int dryrun = 0; 38896185db85Sdougm int c; 38906185db85Sdougm char *protocol = NULL; 38916185db85Sdougm int ret = SA_OK; 38926185db85Sdougm struct options *optlist = NULL; 3893da6c28aaSamw char *rsrcname = NULL; 38946185db85Sdougm char *sharepath = NULL; 38956185db85Sdougm char *optset = NULL; 38966185db85Sdougm int auth; 38976185db85Sdougm 3898da6c28aaSamw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 389925a68471Sdougm switch (c) { 390025a68471Sdougm case 'v': 390125a68471Sdougm verbose++; 390225a68471Sdougm break; 390325a68471Sdougm case 'n': 390425a68471Sdougm dryrun++; 390525a68471Sdougm break; 390625a68471Sdougm case 'P': 3907da6c28aaSamw if (protocol != NULL) { 3908da6c28aaSamw (void) printf(gettext( 3909da6c28aaSamw "Specifying multiple protocols " 3910da6c28aaSamw "not supported: %s\n"), protocol); 3911da6c28aaSamw return (SA_SYNTAX_ERR); 3912da6c28aaSamw } 391325a68471Sdougm protocol = optarg; 391425a68471Sdougm if (!sa_valid_protocol(protocol)) { 391525a68471Sdougm (void) printf(gettext( 391625a68471Sdougm "Invalid protocol specified: %s\n"), 391725a68471Sdougm protocol); 391825a68471Sdougm return (SA_INVALID_PROTOCOL); 391925a68471Sdougm } 392025a68471Sdougm break; 392125a68471Sdougm case 'p': 392225a68471Sdougm ret = add_opt(&optlist, optarg, 0); 392325a68471Sdougm switch (ret) { 392425a68471Sdougm case OPT_ADD_SYNTAX: 392525a68471Sdougm (void) printf(gettext("Property syntax error:" 392625a68471Sdougm " %s\n"), optarg); 392725a68471Sdougm return (SA_SYNTAX_ERR); 392825a68471Sdougm case OPT_ADD_MEMORY: 392925a68471Sdougm (void) printf(gettext("No memory to set " 393025a68471Sdougm "property: %s\n"), optarg); 393125a68471Sdougm return (SA_NO_MEMORY); 393225a68471Sdougm default: 393325a68471Sdougm break; 393425a68471Sdougm } 393525a68471Sdougm break; 3936da6c28aaSamw case 'r': 3937da6c28aaSamw if (rsrcname != NULL) { 3938da6c28aaSamw (void) printf(gettext( 3939da6c28aaSamw "Setting multiple resource names not" 3940da6c28aaSamw " supported\n")); 3941da6c28aaSamw return (SA_SYNTAX_ERR); 3942da6c28aaSamw } 3943da6c28aaSamw rsrcname = optarg; 3944da6c28aaSamw break; 394525a68471Sdougm case 's': 3946da6c28aaSamw if (sharepath != NULL) { 3947da6c28aaSamw (void) printf(gettext( 3948da6c28aaSamw "Setting multiple shares not supported\n")); 3949da6c28aaSamw return (SA_SYNTAX_ERR); 3950da6c28aaSamw } 395125a68471Sdougm sharepath = optarg; 395225a68471Sdougm break; 395325a68471Sdougm case 'S': 3954da6c28aaSamw if (optset != NULL) { 3955da6c28aaSamw (void) printf(gettext( 3956da6c28aaSamw "Specifying multiple property " 3957da6c28aaSamw "spaces not supported: %s\n"), optset); 3958da6c28aaSamw return (SA_SYNTAX_ERR); 3959da6c28aaSamw } 396025a68471Sdougm optset = optarg; 396125a68471Sdougm break; 396225a68471Sdougm case 'h': 3963e7bab347Sdougm /* optopt on valid arg isn't defined */ 3964e7bab347Sdougm optopt = c; 3965e7bab347Sdougm /*FALLTHROUGH*/ 396625a68471Sdougm case '?': 3967e7bab347Sdougm default: 3968e7bab347Sdougm /* 3969e7bab347Sdougm * Since a bad option gets to here, sort it 3970e7bab347Sdougm * out and return a syntax error return value 3971e7bab347Sdougm * if necessary. 3972e7bab347Sdougm */ 3973e7bab347Sdougm switch (optopt) { 3974e7bab347Sdougm default: 3975e7bab347Sdougm ret = SA_SYNTAX_ERR; 3976e7bab347Sdougm break; 3977e7bab347Sdougm case 'h': 3978e7bab347Sdougm case '?': 3979e7bab347Sdougm break; 3980e7bab347Sdougm } 398125a68471Sdougm (void) printf(gettext("usage: %s\n"), 398225a68471Sdougm sa_get_usage(USAGE_SET)); 3983e7bab347Sdougm return (ret); 39846185db85Sdougm } 39856185db85Sdougm } 39866185db85Sdougm 39876185db85Sdougm if (optlist != NULL) 398825a68471Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 39896185db85Sdougm 39906185db85Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 399125a68471Sdougm protocol == NULL || ret != OPT_ADD_OK) { 399225a68471Sdougm char *sep = "\t"; 399325a68471Sdougm 399425a68471Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 399525a68471Sdougm if (optind >= argc) { 399625a68471Sdougm (void) printf(gettext("%sgroup must be specified"), 399725a68471Sdougm sep); 399825a68471Sdougm sep = ", "; 399925a68471Sdougm } 400025a68471Sdougm if (optlist == NULL) { 400125a68471Sdougm (void) printf(gettext("%sat least one property must be" 400225a68471Sdougm " specified"), sep); 400325a68471Sdougm sep = ", "; 400425a68471Sdougm } 400525a68471Sdougm if (protocol == NULL) { 400625a68471Sdougm (void) printf(gettext("%sprotocol must be specified"), 400725a68471Sdougm sep); 400825a68471Sdougm sep = ", "; 400925a68471Sdougm } 401025a68471Sdougm (void) printf("\n"); 401125a68471Sdougm ret = SA_SYNTAX_ERR; 40126185db85Sdougm } else { 40136185db85Sdougm /* 4014f8825440Sdougm * Group already exists so we can proceed after a few 4015f8825440Sdougm * additional checks related to ZFS handling. 40166185db85Sdougm */ 40176185db85Sdougm 401825a68471Sdougm groupname = argv[optind]; 4019f8825440Sdougm if (strcmp(groupname, "zfs") == 0) { 4020f8825440Sdougm (void) printf(gettext("Changing properties for group " 4021f8825440Sdougm "\"zfs\" not allowed\n")); 4022f8825440Sdougm return (SA_NOT_ALLOWED); 4023f8825440Sdougm } 4024f8825440Sdougm 402525a68471Sdougm auth = check_authorizations(groupname, flags); 402625a68471Sdougm if (optset == NULL) 402725a68471Sdougm ret = basic_set(handle, groupname, optlist, protocol, 4028da6c28aaSamw sharepath, rsrcname, dryrun); 402925a68471Sdougm else 403025a68471Sdougm ret = space_set(handle, groupname, optlist, protocol, 403125a68471Sdougm sharepath, dryrun, optset); 403225a68471Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 403325a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 403425a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 403525a68471Sdougm } 40366185db85Sdougm } 40376185db85Sdougm return (ret); 40386185db85Sdougm } 40396185db85Sdougm 40406185db85Sdougm /* 40416185db85Sdougm * remove_options(group, optlist, proto, *err) 40426185db85Sdougm * 404325a68471Sdougm * Helper function to actually remove options from a group after all 40446185db85Sdougm * preprocessing is done. 40456185db85Sdougm */ 40466185db85Sdougm 40476185db85Sdougm static int 40486185db85Sdougm remove_options(sa_group_t group, struct options *optlist, 4049da6c28aaSamw char *proto, int *err) 40506185db85Sdougm { 40516185db85Sdougm struct options *cur; 40526185db85Sdougm sa_optionset_t optionset; 40536185db85Sdougm sa_property_t prop; 40546185db85Sdougm int change = 0; 40556185db85Sdougm int ret = SA_OK; 40566185db85Sdougm 40576185db85Sdougm optionset = sa_get_optionset(group, proto); 40586185db85Sdougm if (optionset != NULL) { 405925a68471Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 406025a68471Sdougm prop = sa_get_property(optionset, cur->optname); 406125a68471Sdougm if (prop != NULL) { 406225a68471Sdougm ret = sa_remove_property(prop); 406325a68471Sdougm if (ret != SA_OK) 406425a68471Sdougm break; 406525a68471Sdougm change = 1; 406625a68471Sdougm } 40676185db85Sdougm } 40686185db85Sdougm } 40696185db85Sdougm if (ret == SA_OK && change) 407025a68471Sdougm ret = sa_commit_properties(optionset, 0); 40716185db85Sdougm 40726185db85Sdougm if (err != NULL) 407325a68471Sdougm *err = ret; 40746185db85Sdougm return (change); 40756185db85Sdougm } 40766185db85Sdougm 40776185db85Sdougm /* 40786185db85Sdougm * valid_unset(group, optlist, proto) 40796185db85Sdougm * 40806185db85Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 40816185db85Sdougm * error if a property doesn't exist. 40826185db85Sdougm */ 40836185db85Sdougm 40846185db85Sdougm static int 40856185db85Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 40866185db85Sdougm { 40876185db85Sdougm struct options *cur; 40886185db85Sdougm sa_optionset_t optionset; 40896185db85Sdougm sa_property_t prop; 40906185db85Sdougm int ret = SA_OK; 40916185db85Sdougm 40926185db85Sdougm optionset = sa_get_optionset(group, proto); 40936185db85Sdougm if (optionset != NULL) { 409425a68471Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 409525a68471Sdougm prop = sa_get_property(optionset, cur->optname); 409625a68471Sdougm if (prop == NULL) { 409725a68471Sdougm (void) printf(gettext( 409825a68471Sdougm "Could not unset property %s: not set\n"), 409925a68471Sdougm cur->optname); 410025a68471Sdougm ret = SA_NO_SUCH_PROP; 410125a68471Sdougm } 41026185db85Sdougm } 41036185db85Sdougm } 41046185db85Sdougm return (ret); 41056185db85Sdougm } 41066185db85Sdougm 41076185db85Sdougm /* 41086185db85Sdougm * valid_unset_security(group, optlist, proto) 41096185db85Sdougm * 41106185db85Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 41116185db85Sdougm * error if a property doesn't exist. 41126185db85Sdougm */ 41136185db85Sdougm 41146185db85Sdougm static int 41156185db85Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 4116da6c28aaSamw char *sectype) 41176185db85Sdougm { 41186185db85Sdougm struct options *cur; 41196185db85Sdougm sa_security_t security; 41206185db85Sdougm sa_property_t prop; 41216185db85Sdougm int ret = SA_OK; 41226185db85Sdougm char *sec; 41236185db85Sdougm 41246185db85Sdougm sec = sa_proto_space_alias(proto, sectype); 41256185db85Sdougm security = sa_get_security(group, sec, proto); 41266185db85Sdougm if (security != NULL) { 412725a68471Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 412825a68471Sdougm prop = sa_get_property(security, cur->optname); 412925a68471Sdougm if (prop == NULL) { 413025a68471Sdougm (void) printf(gettext( 413125a68471Sdougm "Could not unset property %s: not set\n"), 413225a68471Sdougm cur->optname); 413325a68471Sdougm ret = SA_NO_SUCH_PROP; 413425a68471Sdougm } 41356185db85Sdougm } 41366185db85Sdougm } else { 413725a68471Sdougm (void) printf(gettext( 413825a68471Sdougm "Could not unset %s: space not defined\n"), sectype); 413925a68471Sdougm ret = SA_NO_SUCH_SECURITY; 41406185db85Sdougm } 41416185db85Sdougm if (sec != NULL) 414225a68471Sdougm sa_free_attr_string(sec); 41436185db85Sdougm return (ret); 41446185db85Sdougm } 41456185db85Sdougm 41466185db85Sdougm /* 41476185db85Sdougm * remove_security(group, optlist, proto) 41486185db85Sdougm * 41496185db85Sdougm * Remove the properties since they were checked as valid. 41506185db85Sdougm */ 41516185db85Sdougm 41526185db85Sdougm static int 41536185db85Sdougm remove_security(sa_group_t group, char *sectype, 4154da6c28aaSamw struct options *optlist, char *proto, int *err) 41556185db85Sdougm { 41566185db85Sdougm sa_security_t security; 41576185db85Sdougm int ret = SA_OK; 41586185db85Sdougm int change = 0; 41596185db85Sdougm 41606185db85Sdougm sectype = sa_proto_space_alias(proto, sectype); 41616185db85Sdougm security = sa_get_security(group, sectype, proto); 41626185db85Sdougm if (sectype != NULL) 416325a68471Sdougm sa_free_attr_string(sectype); 41646185db85Sdougm 41656185db85Sdougm if (security != NULL) { 416625a68471Sdougm while (optlist != NULL) { 416725a68471Sdougm sa_property_t prop; 416825a68471Sdougm prop = sa_get_property(security, optlist->optname); 416925a68471Sdougm if (prop != NULL) { 417025a68471Sdougm ret = sa_remove_property(prop); 417125a68471Sdougm if (ret != SA_OK) 417225a68471Sdougm break; 417325a68471Sdougm change = 1; 417425a68471Sdougm } 417525a68471Sdougm optlist = optlist->next; 41766185db85Sdougm } 41776185db85Sdougm /* 41786185db85Sdougm * when done, properties may have all been removed but 41796185db85Sdougm * we need to keep the security type itself until 41806185db85Sdougm * explicitly removed. 41816185db85Sdougm */ 418225a68471Sdougm if (ret == SA_OK && change) 418325a68471Sdougm ret = sa_commit_properties(security, 0); 41846185db85Sdougm } else { 418525a68471Sdougm ret = SA_NO_SUCH_PROP; 41866185db85Sdougm } 41876185db85Sdougm if (err != NULL) 418825a68471Sdougm *err = ret; 41896185db85Sdougm return (change); 41906185db85Sdougm } 41916185db85Sdougm 41926185db85Sdougm /* 4193da6c28aaSamw * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 41946185db85Sdougm * 419525a68471Sdougm * Unset non-named optionset properties. 41966185db85Sdougm */ 41976185db85Sdougm 41986185db85Sdougm static int 4199549ec3ffSdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 4200da6c28aaSamw char *protocol, char *sharepath, char *rsrcname, int dryrun) 42016185db85Sdougm { 42026185db85Sdougm sa_group_t group; 42036185db85Sdougm int ret = SA_OK; 42046185db85Sdougm int change = 0; 42056185db85Sdougm struct list *worklist = NULL; 420625a68471Sdougm sa_share_t share = NULL; 4207da6c28aaSamw sa_resource_t resource = NULL; 42086185db85Sdougm 4209549ec3ffSdougm group = sa_get_group(handle, groupname); 421025a68471Sdougm if (group == NULL) 421125a68471Sdougm return (ret); 421225a68471Sdougm 4213da6c28aaSamw /* 4214da6c28aaSamw * If there is a sharepath, make sure it belongs to 4215da6c28aaSamw * the group. 4216da6c28aaSamw */ 421725a68471Sdougm if (sharepath != NULL) { 42186185db85Sdougm share = sa_get_share(group, sharepath); 42196185db85Sdougm if (share == NULL) { 422025a68471Sdougm (void) printf(gettext( 422125a68471Sdougm "Share does not exist in group %s\n"), 422225a68471Sdougm groupname, sharepath); 422325a68471Sdougm ret = SA_NO_SUCH_PATH; 42246185db85Sdougm } 422525a68471Sdougm } 4226da6c28aaSamw /* 4227da6c28aaSamw * If a resource name exists, make sure it belongs to 4228da6c28aaSamw * the share if present else it belongs to the 4229da6c28aaSamw * group. Also check the protocol to see if it 4230da6c28aaSamw * supports resource level properties or not. If not, 4231da6c28aaSamw * use share only. 4232da6c28aaSamw */ 4233da6c28aaSamw if (rsrcname != NULL) { 4234da6c28aaSamw if (share != NULL) { 4235da6c28aaSamw resource = sa_get_share_resource(share, rsrcname); 4236da6c28aaSamw if (resource == NULL) 4237da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 4238da6c28aaSamw } else { 4239da6c28aaSamw resource = sa_get_resource(group, rsrcname); 4240da6c28aaSamw if (resource != NULL) { 4241da6c28aaSamw share = sa_get_resource_parent(resource); 4242da6c28aaSamw } else { 4243da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 4244da6c28aaSamw } 4245da6c28aaSamw } 4246da6c28aaSamw if (ret == SA_OK && resource != NULL) { 4247da6c28aaSamw uint64_t features; 4248da6c28aaSamw /* 4249da6c28aaSamw * Check to see if the resource can take 4250da6c28aaSamw * properties. If so, stick the resource into 4251da6c28aaSamw * "share" so it will all just work. 4252da6c28aaSamw */ 4253da6c28aaSamw features = sa_proto_get_featureset(protocol); 4254da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 4255da6c28aaSamw share = (sa_share_t)resource; 4256da6c28aaSamw } 4257da6c28aaSamw } 4258da6c28aaSamw 425925a68471Sdougm if (ret == SA_OK) { 42606185db85Sdougm /* group must exist */ 42616185db85Sdougm ret = valid_unset(share != NULL ? share : group, 426225a68471Sdougm optlist, protocol); 42636185db85Sdougm if (ret == SA_OK && !dryrun) { 426425a68471Sdougm if (share != NULL) { 426525a68471Sdougm sa_optionset_t optionset; 426625a68471Sdougm sa_property_t prop; 426725a68471Sdougm change |= remove_options(share, optlist, 426825a68471Sdougm protocol, &ret); 426925a68471Sdougm /* 427025a68471Sdougm * If a share optionset is 427125a68471Sdougm * empty, remove it. 427225a68471Sdougm */ 427325a68471Sdougm optionset = sa_get_optionset((sa_share_t)share, 427425a68471Sdougm protocol); 427525a68471Sdougm if (optionset != NULL) { 427625a68471Sdougm prop = sa_get_property(optionset, NULL); 427725a68471Sdougm if (prop == NULL) 427825a68471Sdougm (void) sa_destroy_optionset( 427925a68471Sdougm optionset); 428025a68471Sdougm } 428125a68471Sdougm } else { 428225a68471Sdougm change |= remove_options(group, 428325a68471Sdougm optlist, protocol, &ret); 428425a68471Sdougm } 428525a68471Sdougm if (ret == SA_OK && change) 4286da6c28aaSamw worklist = add_list(worklist, group, share, 4287da6c28aaSamw protocol); 428825a68471Sdougm if (ret != SA_OK) 428925a68471Sdougm (void) printf(gettext( 429025a68471Sdougm "Could not remove properties: " 429125a68471Sdougm "%s\n"), sa_errorstr(ret)); 429225a68471Sdougm } 429325a68471Sdougm } else { 4294da6c28aaSamw (void) printf(gettext("Group \"%s\" not found\n"), groupname); 42956185db85Sdougm ret = SA_NO_SUCH_GROUP; 42966185db85Sdougm } 429725a68471Sdougm free_opt(optlist); 42986185db85Sdougm 42996185db85Sdougm /* 430025a68471Sdougm * We have a group and potentially legal additions 430125a68471Sdougm * 430225a68471Sdougm * Commit to configuration if not a dryrun 43036185db85Sdougm */ 43046185db85Sdougm if (!dryrun && ret == SA_OK) { 430525a68471Sdougm if (change && worklist != NULL) { 430625a68471Sdougm /* properties changed, so update all shares */ 430725a68471Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 4308da6c28aaSamw protocol, B_TRUE); 430925a68471Sdougm } 43106185db85Sdougm } 43116185db85Sdougm if (worklist != NULL) 431225a68471Sdougm free_list(worklist); 43136185db85Sdougm return (ret); 43146185db85Sdougm } 43156185db85Sdougm 43166185db85Sdougm /* 43176185db85Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 43186185db85Sdougm * 431925a68471Sdougm * Unset named optionset properties. 43206185db85Sdougm */ 43216185db85Sdougm static int 4322549ec3ffSdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 4323da6c28aaSamw char *protocol, char *sharepath, int dryrun, char *sectype) 43246185db85Sdougm { 43256185db85Sdougm sa_group_t group; 43266185db85Sdougm int ret = SA_OK; 43276185db85Sdougm int change = 0; 43286185db85Sdougm struct list *worklist = NULL; 432925a68471Sdougm sa_share_t share = NULL; 43306185db85Sdougm 4331549ec3ffSdougm group = sa_get_group(handle, groupname); 433225a68471Sdougm if (group == NULL) { 433325a68471Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 433425a68471Sdougm return (SA_NO_SUCH_GROUP); 433525a68471Sdougm } 433625a68471Sdougm if (sharepath != NULL) { 43376185db85Sdougm share = sa_get_share(group, sharepath); 43386185db85Sdougm if (share == NULL) { 433925a68471Sdougm (void) printf(gettext( 434025a68471Sdougm "Share does not exist in group %s\n"), 434125a68471Sdougm groupname, sharepath); 434225a68471Sdougm return (SA_NO_SUCH_PATH); 434325a68471Sdougm } 434425a68471Sdougm } 4345da6c28aaSamw ret = valid_unset_security(share != NULL ? share : group, 4346da6c28aaSamw optlist, protocol, sectype); 434725a68471Sdougm 434825a68471Sdougm if (ret == SA_OK && !dryrun) { 434925a68471Sdougm if (optlist != NULL) { 43506185db85Sdougm if (share != NULL) { 435125a68471Sdougm sa_security_t optionset; 435225a68471Sdougm sa_property_t prop; 435325a68471Sdougm change = remove_security(share, 435425a68471Sdougm sectype, optlist, protocol, &ret); 435525a68471Sdougm 435625a68471Sdougm /* If a share security is empty, remove it */ 435725a68471Sdougm optionset = sa_get_security((sa_group_t)share, 435825a68471Sdougm sectype, protocol); 435925a68471Sdougm if (optionset != NULL) { 436025a68471Sdougm prop = sa_get_property(optionset, 436125a68471Sdougm NULL); 436225a68471Sdougm if (prop == NULL) 436325a68471Sdougm ret = sa_destroy_security( 436425a68471Sdougm optionset); 436525a68471Sdougm } 43666185db85Sdougm } else { 436725a68471Sdougm change = remove_security(group, sectype, 436825a68471Sdougm optlist, protocol, &ret); 43696185db85Sdougm } 437025a68471Sdougm } else { 43716185db85Sdougm sa_security_t security; 43726185db85Sdougm char *sec; 43736185db85Sdougm sec = sa_proto_space_alias(protocol, sectype); 43746185db85Sdougm security = sa_get_security(group, sec, protocol); 43756185db85Sdougm if (sec != NULL) 437625a68471Sdougm sa_free_attr_string(sec); 43776185db85Sdougm if (security != NULL) { 437825a68471Sdougm ret = sa_destroy_security(security); 437925a68471Sdougm if (ret == SA_OK) 438025a68471Sdougm change = 1; 43816185db85Sdougm } else { 438225a68471Sdougm ret = SA_NO_SUCH_PROP; 43836185db85Sdougm } 43846185db85Sdougm } 438525a68471Sdougm if (ret != SA_OK) 438625a68471Sdougm (void) printf(gettext("Could not unset property: %s\n"), 438725a68471Sdougm sa_errorstr(ret)); 43886185db85Sdougm } 438925a68471Sdougm 439025a68471Sdougm if (ret == SA_OK && change) 4391da6c28aaSamw worklist = add_list(worklist, group, 0, protocol); 439225a68471Sdougm 43936185db85Sdougm free_opt(optlist); 43946185db85Sdougm /* 439525a68471Sdougm * We have a group and potentially legal additions 43966185db85Sdougm */ 43976185db85Sdougm 439825a68471Sdougm /* Commit to configuration if not a dryrun */ 43996185db85Sdougm if (!dryrun && ret == 0) { 44006185db85Sdougm /* properties changed, so update all shares */ 440125a68471Sdougm if (change && worklist != NULL) 440225a68471Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 4403da6c28aaSamw protocol, B_TRUE); 440425a68471Sdougm ret = sa_update_config(handle); 44056185db85Sdougm } 44066185db85Sdougm if (worklist != NULL) 440725a68471Sdougm free_list(worklist); 44086185db85Sdougm return (ret); 44096185db85Sdougm } 44106185db85Sdougm 44116185db85Sdougm /* 44126185db85Sdougm * sa_unset(flags, argc, argv) 44136185db85Sdougm * 441425a68471Sdougm * Implements the unset subcommand. Parsing done here and then basic 44156185db85Sdougm * or space versions of the real code are called. 44166185db85Sdougm */ 44176185db85Sdougm 44186185db85Sdougm int 4419549ec3ffSdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 44206185db85Sdougm { 44216185db85Sdougm char *groupname; 44226185db85Sdougm int verbose = 0; 44236185db85Sdougm int dryrun = 0; 44246185db85Sdougm int c; 44256185db85Sdougm char *protocol = NULL; 44266185db85Sdougm int ret = SA_OK; 44276185db85Sdougm struct options *optlist = NULL; 4428da6c28aaSamw char *rsrcname = NULL; 44296185db85Sdougm char *sharepath = NULL; 44306185db85Sdougm char *optset = NULL; 44316185db85Sdougm int auth; 44326185db85Sdougm 4433da6c28aaSamw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 443425a68471Sdougm switch (c) { 443525a68471Sdougm case 'v': 443625a68471Sdougm verbose++; 443725a68471Sdougm break; 443825a68471Sdougm case 'n': 443925a68471Sdougm dryrun++; 444025a68471Sdougm break; 444125a68471Sdougm case 'P': 4442da6c28aaSamw if (protocol != NULL) { 4443da6c28aaSamw (void) printf(gettext( 4444da6c28aaSamw "Specifying multiple protocols " 4445da6c28aaSamw "not supported: %s\n"), protocol); 4446da6c28aaSamw return (SA_SYNTAX_ERR); 4447da6c28aaSamw } 444825a68471Sdougm protocol = optarg; 444925a68471Sdougm if (!sa_valid_protocol(protocol)) { 445025a68471Sdougm (void) printf(gettext( 445125a68471Sdougm "Invalid protocol specified: %s\n"), 445225a68471Sdougm protocol); 445325a68471Sdougm return (SA_INVALID_PROTOCOL); 445425a68471Sdougm } 445525a68471Sdougm break; 445625a68471Sdougm case 'p': 445725a68471Sdougm ret = add_opt(&optlist, optarg, 1); 445825a68471Sdougm switch (ret) { 445925a68471Sdougm case OPT_ADD_SYNTAX: 446025a68471Sdougm (void) printf(gettext("Property syntax error " 446125a68471Sdougm "for property %s\n"), optarg); 446225a68471Sdougm return (SA_SYNTAX_ERR); 446325a68471Sdougm 446425a68471Sdougm case OPT_ADD_PROPERTY: 446525a68471Sdougm (void) printf(gettext("Properties need to be " 446625a68471Sdougm "set with set command: %s\n"), optarg); 446725a68471Sdougm return (SA_SYNTAX_ERR); 446825a68471Sdougm 446925a68471Sdougm default: 447025a68471Sdougm break; 447125a68471Sdougm } 447225a68471Sdougm break; 4473da6c28aaSamw case 'r': 4474da6c28aaSamw /* 4475da6c28aaSamw * Unset properties on resource if applicable or on 4476da6c28aaSamw * share if resource for this protocol doesn't use 4477da6c28aaSamw * resources. 4478da6c28aaSamw */ 4479da6c28aaSamw if (rsrcname != NULL) { 4480da6c28aaSamw (void) printf(gettext( 4481da6c28aaSamw "Unsetting multiple resource " 4482da6c28aaSamw "names not supported\n")); 4483da6c28aaSamw return (SA_SYNTAX_ERR); 4484da6c28aaSamw } 4485da6c28aaSamw rsrcname = optarg; 4486da6c28aaSamw break; 448725a68471Sdougm case 's': 4488da6c28aaSamw if (sharepath != NULL) { 4489da6c28aaSamw (void) printf(gettext( 4490da6c28aaSamw "Adding multiple shares not supported\n")); 4491da6c28aaSamw return (SA_SYNTAX_ERR); 4492da6c28aaSamw } 449325a68471Sdougm sharepath = optarg; 449425a68471Sdougm break; 449525a68471Sdougm case 'S': 4496da6c28aaSamw if (optset != NULL) { 4497da6c28aaSamw (void) printf(gettext( 4498da6c28aaSamw "Specifying multiple property " 4499da6c28aaSamw "spaces not supported: %s\n"), optset); 4500da6c28aaSamw return (SA_SYNTAX_ERR); 4501da6c28aaSamw } 450225a68471Sdougm optset = optarg; 450325a68471Sdougm break; 450425a68471Sdougm case 'h': 4505e7bab347Sdougm /* optopt on valid arg isn't defined */ 4506e7bab347Sdougm optopt = c; 4507e7bab347Sdougm /*FALLTHROUGH*/ 450825a68471Sdougm case '?': 4509e7bab347Sdougm default: 4510e7bab347Sdougm /* 4511e7bab347Sdougm * Since a bad option gets to here, sort it 4512e7bab347Sdougm * out and return a syntax error return value 4513e7bab347Sdougm * if necessary. 4514e7bab347Sdougm */ 4515e7bab347Sdougm switch (optopt) { 4516e7bab347Sdougm default: 4517e7bab347Sdougm ret = SA_SYNTAX_ERR; 4518e7bab347Sdougm break; 4519e7bab347Sdougm case 'h': 4520e7bab347Sdougm case '?': 4521e7bab347Sdougm break; 4522e7bab347Sdougm } 452325a68471Sdougm (void) printf(gettext("usage: %s\n"), 452425a68471Sdougm sa_get_usage(USAGE_UNSET)); 4525e7bab347Sdougm return (ret); 45266185db85Sdougm } 45276185db85Sdougm } 45286185db85Sdougm 45296185db85Sdougm if (optlist != NULL) 453025a68471Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 45316185db85Sdougm 45326185db85Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 45336185db85Sdougm protocol == NULL) { 453425a68471Sdougm char *sep = "\t"; 453525a68471Sdougm (void) printf(gettext("usage: %s\n"), 453625a68471Sdougm sa_get_usage(USAGE_UNSET)); 453725a68471Sdougm if (optind >= argc) { 453825a68471Sdougm (void) printf(gettext("%sgroup must be specified"), 453925a68471Sdougm sep); 454025a68471Sdougm sep = ", "; 454125a68471Sdougm } 454225a68471Sdougm if (optlist == NULL) { 454325a68471Sdougm (void) printf(gettext("%sat least one property must " 454425a68471Sdougm "be specified"), sep); 454525a68471Sdougm sep = ", "; 454625a68471Sdougm } 454725a68471Sdougm if (protocol == NULL) { 454825a68471Sdougm (void) printf(gettext("%sprotocol must be specified"), 454925a68471Sdougm sep); 455025a68471Sdougm sep = ", "; 455125a68471Sdougm } 455225a68471Sdougm (void) printf("\n"); 455325a68471Sdougm ret = SA_SYNTAX_ERR; 45546185db85Sdougm } else { 45556185db85Sdougm 45566185db85Sdougm /* 455725a68471Sdougm * If a group already exists, we can only add a new 45586185db85Sdougm * protocol to it and not create a new one or add the 45596185db85Sdougm * same protocol again. 45606185db85Sdougm */ 45616185db85Sdougm 456225a68471Sdougm groupname = argv[optind]; 456325a68471Sdougm auth = check_authorizations(groupname, flags); 456425a68471Sdougm if (optset == NULL) 456525a68471Sdougm ret = basic_unset(handle, groupname, optlist, protocol, 4566da6c28aaSamw sharepath, rsrcname, dryrun); 456725a68471Sdougm else 456825a68471Sdougm ret = space_unset(handle, groupname, optlist, protocol, 456925a68471Sdougm sharepath, dryrun, optset); 45706185db85Sdougm 457125a68471Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 457225a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 457325a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 45746185db85Sdougm } 45756185db85Sdougm return (ret); 45766185db85Sdougm } 45776185db85Sdougm 45786185db85Sdougm /* 45796185db85Sdougm * sa_enable_group(flags, argc, argv) 45806185db85Sdougm * 45816185db85Sdougm * Implements the enable subcommand 45826185db85Sdougm */ 45836185db85Sdougm 45846185db85Sdougm int 4585549ec3ffSdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 45866185db85Sdougm { 45876185db85Sdougm int verbose = 0; 45886185db85Sdougm int dryrun = 0; 45896185db85Sdougm int all = 0; 45906185db85Sdougm int c; 45916185db85Sdougm int ret = SA_OK; 45926185db85Sdougm char *protocol = NULL; 45936185db85Sdougm char *state; 45946185db85Sdougm struct list *worklist = NULL; 45956185db85Sdougm int auth = 1; 459625a68471Sdougm sa_group_t group; 45976185db85Sdougm 45986185db85Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 459925a68471Sdougm switch (c) { 460025a68471Sdougm case 'a': 460125a68471Sdougm all = 1; 460225a68471Sdougm break; 460325a68471Sdougm case 'n': 460425a68471Sdougm dryrun++; 460525a68471Sdougm break; 460625a68471Sdougm case 'P': 4607da6c28aaSamw if (protocol != NULL) { 4608da6c28aaSamw (void) printf(gettext( 4609da6c28aaSamw "Specifying multiple protocols " 4610da6c28aaSamw "not supported: %s\n"), protocol); 4611da6c28aaSamw return (SA_SYNTAX_ERR); 4612da6c28aaSamw } 461325a68471Sdougm protocol = optarg; 461425a68471Sdougm if (!sa_valid_protocol(protocol)) { 461525a68471Sdougm (void) printf(gettext( 461625a68471Sdougm "Invalid protocol specified: %s\n"), 46176185db85Sdougm protocol); 461825a68471Sdougm return (SA_INVALID_PROTOCOL); 461925a68471Sdougm } 462025a68471Sdougm break; 462125a68471Sdougm case 'v': 462225a68471Sdougm verbose++; 462325a68471Sdougm break; 462425a68471Sdougm case 'h': 4625e7bab347Sdougm /* optopt on valid arg isn't defined */ 4626e7bab347Sdougm optopt = c; 4627e7bab347Sdougm /*FALLTHROUGH*/ 462825a68471Sdougm case '?': 4629e7bab347Sdougm default: 4630e7bab347Sdougm /* 4631e7bab347Sdougm * Since a bad option gets to here, sort it 4632e7bab347Sdougm * out and return a syntax error return value 4633e7bab347Sdougm * if necessary. 4634e7bab347Sdougm */ 4635e7bab347Sdougm switch (optopt) { 4636e7bab347Sdougm default: 4637e7bab347Sdougm ret = SA_SYNTAX_ERR; 4638e7bab347Sdougm break; 4639e7bab347Sdougm case 'h': 4640e7bab347Sdougm case '?': 4641e7bab347Sdougm (void) printf(gettext("usage: %s\n"), 4642e7bab347Sdougm sa_get_usage(USAGE_ENABLE)); 4643e7bab347Sdougm return (ret); 4644e7bab347Sdougm } 46456185db85Sdougm } 46466185db85Sdougm } 46476185db85Sdougm 46486185db85Sdougm if (optind == argc && !all) { 464925a68471Sdougm (void) printf(gettext("usage: %s\n"), 465025a68471Sdougm sa_get_usage(USAGE_ENABLE)); 465125a68471Sdougm (void) printf(gettext("\tmust specify group\n")); 465225a68471Sdougm return (SA_NO_SUCH_PATH); 465325a68471Sdougm } 465425a68471Sdougm if (!all) { 46556185db85Sdougm while (optind < argc) { 465625a68471Sdougm group = sa_get_group(handle, argv[optind]); 465725a68471Sdougm if (group != NULL) { 465825a68471Sdougm auth &= check_authorizations(argv[optind], 465925a68471Sdougm flags); 466025a68471Sdougm state = sa_get_group_attr(group, "state"); 466125a68471Sdougm if (state != NULL && 466225a68471Sdougm strcmp(state, "enabled") == 0) { 466325a68471Sdougm /* already enabled */ 466425a68471Sdougm if (verbose) 466525a68471Sdougm (void) printf(gettext( 466625a68471Sdougm "Group \"%s\" is already " 466725a68471Sdougm "enabled\n"), 466825a68471Sdougm argv[optind]); 466925a68471Sdougm ret = SA_BUSY; /* already enabled */ 467025a68471Sdougm } else { 467125a68471Sdougm worklist = add_list(worklist, group, 4672da6c28aaSamw 0, protocol); 467325a68471Sdougm if (verbose) 467425a68471Sdougm (void) printf(gettext( 467525a68471Sdougm "Enabling group \"%s\"\n"), 467625a68471Sdougm argv[optind]); 467725a68471Sdougm } 467825a68471Sdougm if (state != NULL) 467925a68471Sdougm sa_free_attr_string(state); 46806185db85Sdougm } else { 468125a68471Sdougm ret = SA_NO_SUCH_GROUP; 46826185db85Sdougm } 468325a68471Sdougm optind++; 46846185db85Sdougm } 468525a68471Sdougm } else { 468625a68471Sdougm for (group = sa_get_group(handle, NULL); 468725a68471Sdougm group != NULL; 46886185db85Sdougm group = sa_get_next_group(group)) { 4689da6c28aaSamw worklist = add_list(worklist, group, 0, protocol); 46906185db85Sdougm } 469125a68471Sdougm } 469225a68471Sdougm if (!dryrun && ret == SA_OK) 4693da6c28aaSamw ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE); 469425a68471Sdougm 469525a68471Sdougm if (ret != SA_OK && ret != SA_BUSY) 46966185db85Sdougm (void) printf(gettext("Could not enable group: %s\n"), 469725a68471Sdougm sa_errorstr(ret)); 469825a68471Sdougm if (ret == SA_BUSY) 46996185db85Sdougm ret = SA_OK; 470025a68471Sdougm 47016185db85Sdougm if (worklist != NULL) 470225a68471Sdougm free_list(worklist); 47036185db85Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 470425a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 470525a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 47066185db85Sdougm } 47076185db85Sdougm return (ret); 47086185db85Sdougm } 47096185db85Sdougm 47106185db85Sdougm /* 4711da6c28aaSamw * disable_group(group, proto) 47126185db85Sdougm * 4713da6c28aaSamw * Disable all the shares in the specified group.. This is a helper 4714da6c28aaSamw * for disable_all_groups in order to simplify regular and subgroup 4715da6c28aaSamw * (zfs) disabling. Group has already been checked for non-NULL. 47166185db85Sdougm */ 47176185db85Sdougm 47186185db85Sdougm static int 4719da6c28aaSamw disable_group(sa_group_t group, char *proto) 47206185db85Sdougm { 47216185db85Sdougm sa_share_t share; 47226185db85Sdougm int ret = SA_OK; 47236185db85Sdougm 4724da6c28aaSamw /* 4725da6c28aaSamw * If the protocol isn't enabled, skip it and treat as 4726da6c28aaSamw * successful. 4727da6c28aaSamw */ 4728da6c28aaSamw if (!has_protocol(group, proto)) 4729da6c28aaSamw return (ret); 4730da6c28aaSamw 47316185db85Sdougm for (share = sa_get_share(group, NULL); 47326185db85Sdougm share != NULL && ret == SA_OK; 47336185db85Sdougm share = sa_get_next_share(share)) { 4734da6c28aaSamw ret = sa_disable_share(share, proto); 473525a68471Sdougm if (ret == SA_NO_SUCH_PATH) { 473625a68471Sdougm /* 473725a68471Sdougm * this is OK since the path is gone. we can't 473825a68471Sdougm * re-share it anyway so no error. 473925a68471Sdougm */ 474025a68471Sdougm ret = SA_OK; 474125a68471Sdougm } 47426185db85Sdougm } 47436185db85Sdougm return (ret); 47446185db85Sdougm } 47456185db85Sdougm 47466185db85Sdougm /* 47476185db85Sdougm * disable_all_groups(work, setstate) 47486185db85Sdougm * 47496185db85Sdougm * helper function that disables the shares in the list of groups 47506185db85Sdougm * provided. It optionally marks the group as disabled. Used by both 47516185db85Sdougm * enable and start subcommands. 47526185db85Sdougm */ 47536185db85Sdougm 47546185db85Sdougm static int 4755549ec3ffSdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 47566185db85Sdougm { 47576185db85Sdougm int ret = SA_OK; 47586185db85Sdougm sa_group_t subgroup, group; 47596185db85Sdougm 47606185db85Sdougm while (work != NULL && ret == SA_OK) { 476125a68471Sdougm group = (sa_group_t)work->item; 476225a68471Sdougm if (setstate) 476325a68471Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 476425a68471Sdougm if (ret == SA_OK) { 476525a68471Sdougm char *name; 476625a68471Sdougm name = sa_get_group_attr(group, "name"); 476725a68471Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 476825a68471Sdougm /* need to get the sub-groups for stopping */ 476925a68471Sdougm for (subgroup = sa_get_sub_group(group); 477025a68471Sdougm subgroup != NULL; 477125a68471Sdougm subgroup = sa_get_next_group(subgroup)) { 4772da6c28aaSamw ret = disable_group(subgroup, 4773da6c28aaSamw work->proto); 477425a68471Sdougm } 477525a68471Sdougm } else { 4776da6c28aaSamw ret = disable_group(group, work->proto); 477725a68471Sdougm } 4778fe1c642dSBill Krier if (name != NULL) 4779fe1c642dSBill Krier sa_free_attr_string(name); 478025a68471Sdougm /* 478125a68471Sdougm * We don't want to "disable" since it won't come 478225a68471Sdougm * up after a reboot. The SMF framework should do 478325a68471Sdougm * the right thing. On enable we do want to do 478425a68471Sdougm * something. 478525a68471Sdougm */ 47866185db85Sdougm } 478725a68471Sdougm work = work->next; 47886185db85Sdougm } 47896185db85Sdougm if (ret == SA_OK) 479025a68471Sdougm ret = sa_update_config(handle); 47916185db85Sdougm return (ret); 47926185db85Sdougm } 47936185db85Sdougm 47946185db85Sdougm /* 47956185db85Sdougm * sa_disable_group(flags, argc, argv) 47966185db85Sdougm * 47976185db85Sdougm * Implements the disable subcommand 47986185db85Sdougm */ 47996185db85Sdougm 48006185db85Sdougm int 4801549ec3ffSdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 48026185db85Sdougm { 48036185db85Sdougm int verbose = 0; 48046185db85Sdougm int dryrun = 0; 48056185db85Sdougm int all = 0; 48066185db85Sdougm int c; 48076185db85Sdougm int ret = SA_OK; 4808da6c28aaSamw char *protocol = NULL; 48096185db85Sdougm char *state; 48106185db85Sdougm struct list *worklist = NULL; 481125a68471Sdougm sa_group_t group; 48126185db85Sdougm int auth = 1; 48136185db85Sdougm 48146185db85Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 481525a68471Sdougm switch (c) { 481625a68471Sdougm case 'a': 481725a68471Sdougm all = 1; 481825a68471Sdougm break; 481925a68471Sdougm case 'n': 482025a68471Sdougm dryrun++; 482125a68471Sdougm break; 482225a68471Sdougm case 'P': 4823da6c28aaSamw if (protocol != NULL) { 4824da6c28aaSamw (void) printf(gettext( 4825da6c28aaSamw "Specifying multiple protocols " 4826da6c28aaSamw "not supported: %s\n"), protocol); 4827da6c28aaSamw return (SA_SYNTAX_ERR); 4828da6c28aaSamw } 482925a68471Sdougm protocol = optarg; 483025a68471Sdougm if (!sa_valid_protocol(protocol)) { 483125a68471Sdougm (void) printf(gettext( 483225a68471Sdougm "Invalid protocol specified: %s\n"), 483325a68471Sdougm protocol); 483425a68471Sdougm return (SA_INVALID_PROTOCOL); 483525a68471Sdougm } 483625a68471Sdougm break; 483725a68471Sdougm case 'v': 483825a68471Sdougm verbose++; 483925a68471Sdougm break; 484025a68471Sdougm case 'h': 4841e7bab347Sdougm /* optopt on valid arg isn't defined */ 4842e7bab347Sdougm optopt = c; 4843e7bab347Sdougm /*FALLTHROUGH*/ 484425a68471Sdougm case '?': 4845e7bab347Sdougm default: 4846e7bab347Sdougm /* 4847e7bab347Sdougm * Since a bad option gets to here, sort it 4848e7bab347Sdougm * out and return a syntax error return value 4849e7bab347Sdougm * if necessary. 4850e7bab347Sdougm */ 4851e7bab347Sdougm switch (optopt) { 4852e7bab347Sdougm default: 4853e7bab347Sdougm ret = SA_SYNTAX_ERR; 4854e7bab347Sdougm break; 4855e7bab347Sdougm case 'h': 4856e7bab347Sdougm case '?': 4857e7bab347Sdougm break; 4858e7bab347Sdougm } 485925a68471Sdougm (void) printf(gettext("usage: %s\n"), 486025a68471Sdougm sa_get_usage(USAGE_DISABLE)); 4861e7bab347Sdougm return (ret); 48626185db85Sdougm } 48636185db85Sdougm } 48646185db85Sdougm 48656185db85Sdougm if (optind == argc && !all) { 48666185db85Sdougm (void) printf(gettext("usage: %s\n"), 486725a68471Sdougm sa_get_usage(USAGE_DISABLE)); 48686185db85Sdougm (void) printf(gettext("\tmust specify group\n")); 486925a68471Sdougm return (SA_NO_SUCH_PATH); 487025a68471Sdougm } 487125a68471Sdougm if (!all) { 487225a68471Sdougm while (optind < argc) { 4873549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 48746185db85Sdougm if (group != NULL) { 487525a68471Sdougm auth &= check_authorizations(argv[optind], 487625a68471Sdougm flags); 487725a68471Sdougm state = sa_get_group_attr(group, "state"); 487825a68471Sdougm if (state == NULL || 487925a68471Sdougm strcmp(state, "disabled") == 0) { 488025a68471Sdougm /* already disabled */ 488125a68471Sdougm if (verbose) 488225a68471Sdougm (void) printf(gettext( 488325a68471Sdougm "Group \"%s\" is " 488425a68471Sdougm "already disabled\n"), 488525a68471Sdougm argv[optind]); 4886da6c28aaSamw ret = SA_BUSY; /* already disabled */ 488725a68471Sdougm } else { 4888da6c28aaSamw worklist = add_list(worklist, group, 0, 4889da6c28aaSamw protocol); 489025a68471Sdougm if (verbose) 489125a68471Sdougm (void) printf(gettext( 489225a68471Sdougm "Disabling group " 489325a68471Sdougm "\"%s\"\n"), argv[optind]); 489425a68471Sdougm } 489525a68471Sdougm if (state != NULL) 489625a68471Sdougm sa_free_attr_string(state); 48976185db85Sdougm } else { 489825a68471Sdougm ret = SA_NO_SUCH_GROUP; 48996185db85Sdougm } 49006185db85Sdougm optind++; 49016185db85Sdougm } 490225a68471Sdougm } else { 490325a68471Sdougm for (group = sa_get_group(handle, NULL); 490425a68471Sdougm group != NULL; 490525a68471Sdougm group = sa_get_next_group(group)) 4906da6c28aaSamw worklist = add_list(worklist, group, 0, protocol); 49076185db85Sdougm } 490825a68471Sdougm 490925a68471Sdougm if (ret == SA_OK && !dryrun) 491025a68471Sdougm ret = disable_all_groups(handle, worklist, 1); 491125a68471Sdougm if (ret != SA_OK && ret != SA_BUSY) 491225a68471Sdougm (void) printf(gettext("Could not disable group: %s\n"), 491325a68471Sdougm sa_errorstr(ret)); 491425a68471Sdougm if (ret == SA_BUSY) 491525a68471Sdougm ret = SA_OK; 49166185db85Sdougm if (worklist != NULL) 491725a68471Sdougm free_list(worklist); 491825a68471Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 491925a68471Sdougm (void) printf(gettext("Command would fail: %s\n"), 492025a68471Sdougm sa_errorstr(SA_NO_PERMISSION)); 49216185db85Sdougm return (ret); 49226185db85Sdougm } 49236185db85Sdougm 49246185db85Sdougm /* 49256185db85Sdougm * sa_start_group(flags, argc, argv) 49266185db85Sdougm * 49276185db85Sdougm * Implements the start command. 49286185db85Sdougm * This is similar to enable except it doesn't change the state 49296185db85Sdougm * of the group(s) and only enables shares if the group is already 49306185db85Sdougm * enabled. 49316185db85Sdougm */ 4932da6c28aaSamw 49336185db85Sdougm int 4934549ec3ffSdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 49356185db85Sdougm { 49366185db85Sdougm int verbose = 0; 49376185db85Sdougm int all = 0; 49386185db85Sdougm int c; 49396185db85Sdougm int ret = SMF_EXIT_OK; 49406185db85Sdougm char *protocol = NULL; 49416185db85Sdougm char *state; 49426185db85Sdougm struct list *worklist = NULL; 494325a68471Sdougm sa_group_t group; 4944da6c28aaSamw #ifdef lint 4945da6c28aaSamw flags = flags; 4946da6c28aaSamw #endif 49476185db85Sdougm 49486185db85Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 494925a68471Sdougm switch (c) { 495025a68471Sdougm case 'a': 495125a68471Sdougm all = 1; 495225a68471Sdougm break; 495325a68471Sdougm case 'P': 4954da6c28aaSamw if (protocol != NULL) { 4955da6c28aaSamw (void) printf(gettext( 4956da6c28aaSamw "Specifying multiple protocols " 4957da6c28aaSamw "not supported: %s\n"), protocol); 4958da6c28aaSamw return (SA_SYNTAX_ERR); 4959da6c28aaSamw } 496025a68471Sdougm protocol = optarg; 496125a68471Sdougm if (!sa_valid_protocol(protocol)) { 496225a68471Sdougm (void) printf(gettext( 496325a68471Sdougm "Invalid protocol specified: %s\n"), 49646185db85Sdougm protocol); 496525a68471Sdougm return (SA_INVALID_PROTOCOL); 496625a68471Sdougm } 496725a68471Sdougm break; 496825a68471Sdougm case 'v': 496925a68471Sdougm verbose++; 497025a68471Sdougm break; 497125a68471Sdougm case 'h': 4972e7bab347Sdougm /* optopt on valid arg isn't defined */ 4973e7bab347Sdougm optopt = c; 4974e7bab347Sdougm /*FALLTHROUGH*/ 497525a68471Sdougm case '?': 4976e7bab347Sdougm default: 4977e7bab347Sdougm /* 4978e7bab347Sdougm * Since a bad option gets to here, sort it 4979e7bab347Sdougm * out and return a syntax error return value 4980e7bab347Sdougm * if necessary. 4981e7bab347Sdougm */ 4982e7bab347Sdougm ret = SA_OK; 4983e7bab347Sdougm switch (optopt) { 4984e7bab347Sdougm default: 4985e7bab347Sdougm ret = SA_SYNTAX_ERR; 4986e7bab347Sdougm break; 4987e7bab347Sdougm case 'h': 4988e7bab347Sdougm case '?': 4989e7bab347Sdougm break; 4990e7bab347Sdougm } 499125a68471Sdougm (void) printf(gettext("usage: %s\n"), 499225a68471Sdougm sa_get_usage(USAGE_START)); 4993e7bab347Sdougm return (ret); 49946185db85Sdougm } 49956185db85Sdougm } 49966185db85Sdougm 49976185db85Sdougm if (optind == argc && !all) { 49986185db85Sdougm (void) printf(gettext("usage: %s\n"), 499925a68471Sdougm sa_get_usage(USAGE_START)); 500025a68471Sdougm return (SMF_EXIT_ERR_FATAL); 500125a68471Sdougm } 50026185db85Sdougm 500325a68471Sdougm if (!all) { 500425a68471Sdougm while (optind < argc) { 5005549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 50066185db85Sdougm if (group != NULL) { 500725a68471Sdougm state = sa_get_group_attr(group, "state"); 500825a68471Sdougm if (state == NULL || 500925a68471Sdougm strcmp(state, "enabled") == 0) { 5010da6c28aaSamw worklist = add_list(worklist, group, 0, 5011da6c28aaSamw protocol); 501225a68471Sdougm if (verbose) 501325a68471Sdougm (void) printf(gettext( 501425a68471Sdougm "Starting group \"%s\"\n"), 501525a68471Sdougm argv[optind]); 501625a68471Sdougm } else { 501725a68471Sdougm /* 501825a68471Sdougm * Determine if there are any 5019da6c28aaSamw * protocols. If there aren't any, 502025a68471Sdougm * then there isn't anything to do in 502125a68471Sdougm * any case so no error. 502225a68471Sdougm */ 502325a68471Sdougm if (sa_get_optionset(group, 502425a68471Sdougm protocol) != NULL) { 502525a68471Sdougm ret = SMF_EXIT_OK; 502625a68471Sdougm } 50276185db85Sdougm } 502825a68471Sdougm if (state != NULL) 502925a68471Sdougm sa_free_attr_string(state); 50306185db85Sdougm } 50316185db85Sdougm optind++; 503225a68471Sdougm } 503325a68471Sdougm } else { 5034da6c28aaSamw for (group = sa_get_group(handle, NULL); 5035da6c28aaSamw group != NULL; 503625a68471Sdougm group = sa_get_next_group(group)) { 50376185db85Sdougm state = sa_get_group_attr(group, "state"); 50386185db85Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 5039da6c28aaSamw worklist = add_list(worklist, group, 0, 5040da6c28aaSamw protocol); 50416185db85Sdougm if (state != NULL) 504225a68471Sdougm sa_free_attr_string(state); 50436185db85Sdougm } 50446185db85Sdougm } 504525a68471Sdougm 5046da6c28aaSamw (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE); 504725a68471Sdougm 50486185db85Sdougm if (worklist != NULL) 504925a68471Sdougm free_list(worklist); 50506185db85Sdougm return (ret); 50516185db85Sdougm } 50526185db85Sdougm 50536185db85Sdougm /* 50546185db85Sdougm * sa_stop_group(flags, argc, argv) 50556185db85Sdougm * 50566185db85Sdougm * Implements the stop command. 50576185db85Sdougm * This is similar to disable except it doesn't change the state 50586185db85Sdougm * of the group(s) and only disables shares if the group is already 50596185db85Sdougm * enabled. 50606185db85Sdougm */ 50616185db85Sdougm int 5062549ec3ffSdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 50636185db85Sdougm { 50646185db85Sdougm int verbose = 0; 50656185db85Sdougm int all = 0; 50666185db85Sdougm int c; 50676185db85Sdougm int ret = SMF_EXIT_OK; 50686185db85Sdougm char *protocol = NULL; 50696185db85Sdougm char *state; 50706185db85Sdougm struct list *worklist = NULL; 507125a68471Sdougm sa_group_t group; 5072da6c28aaSamw #ifdef lint 5073da6c28aaSamw flags = flags; 5074da6c28aaSamw #endif 50756185db85Sdougm 50766185db85Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 507725a68471Sdougm switch (c) { 507825a68471Sdougm case 'a': 507925a68471Sdougm all = 1; 508025a68471Sdougm break; 508125a68471Sdougm case 'P': 5082da6c28aaSamw if (protocol != NULL) { 5083da6c28aaSamw (void) printf(gettext( 5084da6c28aaSamw "Specifying multiple protocols " 5085da6c28aaSamw "not supported: %s\n"), protocol); 5086da6c28aaSamw return (SA_SYNTAX_ERR); 5087da6c28aaSamw } 508825a68471Sdougm protocol = optarg; 508925a68471Sdougm if (!sa_valid_protocol(protocol)) { 509025a68471Sdougm (void) printf(gettext( 509125a68471Sdougm "Invalid protocol specified: %s\n"), 509225a68471Sdougm protocol); 509325a68471Sdougm return (SA_INVALID_PROTOCOL); 509425a68471Sdougm } 509525a68471Sdougm break; 509625a68471Sdougm case 'v': 509725a68471Sdougm verbose++; 509825a68471Sdougm break; 509925a68471Sdougm case 'h': 5100e7bab347Sdougm /* optopt on valid arg isn't defined */ 5101e7bab347Sdougm optopt = c; 5102e7bab347Sdougm /*FALLTHROUGH*/ 510325a68471Sdougm case '?': 5104e7bab347Sdougm default: 5105e7bab347Sdougm /* 5106e7bab347Sdougm * Since a bad option gets to here, sort it 5107e7bab347Sdougm * out and return a syntax error return value 5108e7bab347Sdougm * if necessary. 5109e7bab347Sdougm */ 5110e7bab347Sdougm ret = SA_OK; 5111e7bab347Sdougm switch (optopt) { 5112e7bab347Sdougm default: 5113e7bab347Sdougm ret = SA_SYNTAX_ERR; 5114e7bab347Sdougm break; 5115e7bab347Sdougm case 'h': 5116e7bab347Sdougm case '?': 5117e7bab347Sdougm break; 5118e7bab347Sdougm } 511925a68471Sdougm (void) printf(gettext("usage: %s\n"), 512025a68471Sdougm sa_get_usage(USAGE_STOP)); 5121e7bab347Sdougm return (ret); 51226185db85Sdougm } 51236185db85Sdougm } 51246185db85Sdougm 51256185db85Sdougm if (optind == argc && !all) { 512625a68471Sdougm (void) printf(gettext("usage: %s\n"), 512725a68471Sdougm sa_get_usage(USAGE_STOP)); 512825a68471Sdougm return (SMF_EXIT_ERR_FATAL); 512925a68471Sdougm } else if (!all) { 513025a68471Sdougm while (optind < argc) { 5131549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 51326185db85Sdougm if (group != NULL) { 513325a68471Sdougm state = sa_get_group_attr(group, "state"); 513425a68471Sdougm if (state == NULL || 513525a68471Sdougm strcmp(state, "enabled") == 0) { 5136da6c28aaSamw worklist = add_list(worklist, group, 0, 5137da6c28aaSamw protocol); 513825a68471Sdougm if (verbose) 513925a68471Sdougm (void) printf(gettext( 514025a68471Sdougm "Stopping group \"%s\"\n"), 514125a68471Sdougm argv[optind]); 514225a68471Sdougm } else { 514325a68471Sdougm ret = SMF_EXIT_OK; 514425a68471Sdougm } 514525a68471Sdougm if (state != NULL) 514625a68471Sdougm sa_free_attr_string(state); 51476185db85Sdougm } 51486185db85Sdougm optind++; 514925a68471Sdougm } 515025a68471Sdougm } else { 5151da6c28aaSamw for (group = sa_get_group(handle, NULL); 5152da6c28aaSamw group != NULL; 515325a68471Sdougm group = sa_get_next_group(group)) { 51546185db85Sdougm state = sa_get_group_attr(group, "state"); 51556185db85Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 5156da6c28aaSamw worklist = add_list(worklist, group, 0, 5157da6c28aaSamw protocol); 51586185db85Sdougm if (state != NULL) 515925a68471Sdougm sa_free_attr_string(state); 51606185db85Sdougm } 51616185db85Sdougm } 516225a68471Sdougm (void) disable_all_groups(handle, worklist, 0); 516325a68471Sdougm ret = sa_update_config(handle); 516425a68471Sdougm 51656185db85Sdougm if (worklist != NULL) 516625a68471Sdougm free_list(worklist); 51676185db85Sdougm return (ret); 51686185db85Sdougm } 51696185db85Sdougm 51706185db85Sdougm /* 51716185db85Sdougm * remove_all_options(share, proto) 51726185db85Sdougm * 51736185db85Sdougm * Removes all options on a share. 51746185db85Sdougm */ 51756185db85Sdougm 51766185db85Sdougm static void 51776185db85Sdougm remove_all_options(sa_share_t share, char *proto) 51786185db85Sdougm { 51796185db85Sdougm sa_optionset_t optionset; 51806185db85Sdougm sa_security_t security; 51816185db85Sdougm sa_security_t prevsec = NULL; 51826185db85Sdougm 51836185db85Sdougm optionset = sa_get_optionset(share, proto); 51846185db85Sdougm if (optionset != NULL) 518525a68471Sdougm (void) sa_destroy_optionset(optionset); 51866185db85Sdougm for (security = sa_get_security(share, NULL, NULL); 51876185db85Sdougm security != NULL; 51886185db85Sdougm security = sa_get_next_security(security)) { 518925a68471Sdougm char *type; 51906185db85Sdougm /* 519125a68471Sdougm * We walk through the list. prevsec keeps the 51926185db85Sdougm * previous security so we can delete it without 51936185db85Sdougm * destroying the list. 51946185db85Sdougm */ 519525a68471Sdougm if (prevsec != NULL) { 519625a68471Sdougm /* remove the previously seen security */ 519725a68471Sdougm (void) sa_destroy_security(prevsec); 519825a68471Sdougm /* set to NULL so we don't try multiple times */ 519925a68471Sdougm prevsec = NULL; 520025a68471Sdougm } 520125a68471Sdougm type = sa_get_security_attr(security, "type"); 520225a68471Sdougm if (type != NULL) { 520325a68471Sdougm /* 520425a68471Sdougm * if the security matches the specified protocol, we 520525a68471Sdougm * want to remove it. prevsec holds it until either 520625a68471Sdougm * the next pass or we fall out of the loop. 520725a68471Sdougm */ 520825a68471Sdougm if (strcmp(type, proto) == 0) 520925a68471Sdougm prevsec = security; 521025a68471Sdougm sa_free_attr_string(type); 521125a68471Sdougm } 52126185db85Sdougm } 52136185db85Sdougm /* in case there is one left */ 52146185db85Sdougm if (prevsec != NULL) 521525a68471Sdougm (void) sa_destroy_security(prevsec); 52166185db85Sdougm } 52176185db85Sdougm 52186185db85Sdougm 52196185db85Sdougm /* 52206185db85Sdougm * for legacy support, we need to handle the old syntax. This is what 52216185db85Sdougm * we get if sharemgr is called with the name "share" rather than 52226185db85Sdougm * sharemgr. 52236185db85Sdougm */ 52246185db85Sdougm 52256185db85Sdougm static int 52266185db85Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 52276185db85Sdougm { 52286185db85Sdougm int err; 52296185db85Sdougm 52306185db85Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 52316185db85Sdougm if (err > buffsize) 523225a68471Sdougm return (-1); 52336185db85Sdougm return (0); 52346185db85Sdougm } 52356185db85Sdougm 52366185db85Sdougm 52376185db85Sdougm /* 52386185db85Sdougm * check_legacy_cmd(proto, cmd) 52396185db85Sdougm * 52406185db85Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 52416185db85Sdougm * executable. 52426185db85Sdougm */ 52436185db85Sdougm 52446185db85Sdougm static int 52456185db85Sdougm check_legacy_cmd(char *path) 52466185db85Sdougm { 52476185db85Sdougm struct stat st; 52486185db85Sdougm int ret = 0; 52496185db85Sdougm 52506185db85Sdougm if (stat(path, &st) == 0) { 525125a68471Sdougm if (S_ISREG(st.st_mode) && 525225a68471Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 525325a68471Sdougm ret = 1; 52546185db85Sdougm } 52556185db85Sdougm return (ret); 52566185db85Sdougm } 52576185db85Sdougm 52586185db85Sdougm /* 52596185db85Sdougm * run_legacy_command(proto, cmd, argv) 52606185db85Sdougm * 526125a68471Sdougm * We know the command exists, so attempt to execute it with all the 52626185db85Sdougm * arguments. This implements full legacy share support for those 52636185db85Sdougm * protocols that don't have plugin providers. 52646185db85Sdougm */ 52656185db85Sdougm 52666185db85Sdougm static int 52676185db85Sdougm run_legacy_command(char *path, char *argv[]) 52686185db85Sdougm { 52696185db85Sdougm int ret; 52706185db85Sdougm 52716185db85Sdougm ret = execv(path, argv); 52726185db85Sdougm if (ret < 0) { 527325a68471Sdougm switch (errno) { 527425a68471Sdougm case EACCES: 527525a68471Sdougm ret = SA_NO_PERMISSION; 527625a68471Sdougm break; 527725a68471Sdougm default: 527825a68471Sdougm ret = SA_SYSTEM_ERR; 527925a68471Sdougm break; 528025a68471Sdougm } 52816185db85Sdougm } 52826185db85Sdougm return (ret); 52836185db85Sdougm } 52846185db85Sdougm 52856185db85Sdougm /* 5286f345c0beSdougm * out_share(out, group, proto) 52876185db85Sdougm * 52886185db85Sdougm * Display the share information in the format that the "share" 52896185db85Sdougm * command has traditionally used. 52906185db85Sdougm */ 52916185db85Sdougm 52926185db85Sdougm static void 5293f345c0beSdougm out_share(FILE *out, sa_group_t group, char *proto) 52946185db85Sdougm { 52956185db85Sdougm sa_share_t share; 52966185db85Sdougm char resfmt[128]; 5297da6c28aaSamw char *defprop; 5298da6c28aaSamw 5299da6c28aaSamw /* 5300da6c28aaSamw * The original share command defaulted to displaying NFS 5301da6c28aaSamw * shares or allowed a protocol to be specified. We want to 5302da6c28aaSamw * skip those shares that are not the specified protocol. 5303da6c28aaSamw */ 5304da6c28aaSamw if (proto != NULL && sa_get_optionset(group, proto) == NULL) 5305da6c28aaSamw return; 5306da6c28aaSamw 5307da6c28aaSamw if (proto == NULL) 5308da6c28aaSamw proto = "nfs"; 5309da6c28aaSamw 5310da6c28aaSamw /* 5311da6c28aaSamw * get the default property string. NFS uses "rw" but 5312da6c28aaSamw * everything else will use "". 5313da6c28aaSamw */ 5314da6c28aaSamw if (proto != NULL && strcmp(proto, "nfs") != 0) 5315da6c28aaSamw defprop = "\"\""; 5316da6c28aaSamw else 5317da6c28aaSamw defprop = "rw"; 53186185db85Sdougm 531925a68471Sdougm for (share = sa_get_share(group, NULL); 532025a68471Sdougm share != NULL; 532125a68471Sdougm share = sa_get_next_share(share)) { 532225a68471Sdougm char *path; 532325a68471Sdougm char *type; 532425a68471Sdougm char *resource; 532525a68471Sdougm char *description; 532625a68471Sdougm char *groupname; 532725a68471Sdougm char *sharedstate; 532825a68471Sdougm int shared = 1; 532925a68471Sdougm char *soptions; 5330da6c28aaSamw char shareopts[MAXNAMLEN]; 533125a68471Sdougm 533225a68471Sdougm sharedstate = sa_get_share_attr(share, "shared"); 533325a68471Sdougm path = sa_get_share_attr(share, "path"); 533425a68471Sdougm type = sa_get_share_attr(share, "type"); 5335da6c28aaSamw resource = get_resource(share); 533625a68471Sdougm groupname = sa_get_group_attr(group, "name"); 533725a68471Sdougm 533825a68471Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 533925a68471Sdougm sa_free_attr_string(groupname); 534025a68471Sdougm groupname = NULL; 534125a68471Sdougm } 534225a68471Sdougm description = sa_get_share_description(share); 534325a68471Sdougm 5344da6c28aaSamw /* 5345da6c28aaSamw * Want the sharetab version if it exists, defaulting 5346da6c28aaSamw * to NFS if no protocol specified. 5347da6c28aaSamw */ 5348da6c28aaSamw (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto); 5349da6c28aaSamw soptions = sa_get_share_attr(share, shareopts); 535025a68471Sdougm 535125a68471Sdougm if (sharedstate == NULL) 535225a68471Sdougm shared = 0; 535325a68471Sdougm 535425a68471Sdougm if (soptions == NULL) 535525a68471Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 535625a68471Sdougm 535725a68471Sdougm if (shared) { 535825a68471Sdougm /* only active shares go here */ 535925a68471Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 536025a68471Sdougm resource != NULL ? resource : "-", 536125a68471Sdougm groupname != NULL ? "@" : "", 536225a68471Sdougm groupname != NULL ? groupname : ""); 536325a68471Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 5364fe1c642dSBill Krier resfmt, (path != NULL) ? path : "", 536525a68471Sdougm (soptions != NULL && strlen(soptions) > 0) ? 5366da6c28aaSamw soptions : defprop, 536725a68471Sdougm (description != NULL) ? description : ""); 536825a68471Sdougm } 536925a68471Sdougm 537025a68471Sdougm if (path != NULL) 537125a68471Sdougm sa_free_attr_string(path); 537225a68471Sdougm if (type != NULL) 537325a68471Sdougm sa_free_attr_string(type); 537425a68471Sdougm if (resource != NULL) 537525a68471Sdougm sa_free_attr_string(resource); 537625a68471Sdougm if (groupname != NULL) 537725a68471Sdougm sa_free_attr_string(groupname); 537825a68471Sdougm if (description != NULL) 537925a68471Sdougm sa_free_share_description(description); 538025a68471Sdougm if (sharedstate != NULL) 538125a68471Sdougm sa_free_attr_string(sharedstate); 538225a68471Sdougm if (soptions != NULL) 538325a68471Sdougm sa_format_free(soptions); 53846185db85Sdougm } 53856185db85Sdougm } 53866185db85Sdougm 53876185db85Sdougm /* 53886185db85Sdougm * output_legacy_file(out, proto) 53896185db85Sdougm * 53906185db85Sdougm * Walk all of the groups for the specified protocol and call 53916185db85Sdougm * out_share() to format and write in the format displayed by the 53926185db85Sdougm * "share" command with no arguments. 53936185db85Sdougm */ 53946185db85Sdougm 53956185db85Sdougm static void 5396549ec3ffSdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 53976185db85Sdougm { 53986185db85Sdougm sa_group_t group; 53996185db85Sdougm 5400da6c28aaSamw for (group = sa_get_group(handle, NULL); 5401da6c28aaSamw group != NULL; 540225a68471Sdougm group = sa_get_next_group(group)) { 540325a68471Sdougm char *zfs; 54046185db85Sdougm 54056185db85Sdougm /* 5406da6c28aaSamw * Go through all the groups and ZFS 5407da6c28aaSamw * sub-groups. out_share() will format the shares in 5408da6c28aaSamw * the group appropriately. 54096185db85Sdougm */ 54106185db85Sdougm 541125a68471Sdougm zfs = sa_get_group_attr(group, "zfs"); 541225a68471Sdougm if (zfs != NULL) { 541325a68471Sdougm sa_group_t zgroup; 541425a68471Sdougm sa_free_attr_string(zfs); 541525a68471Sdougm for (zgroup = sa_get_sub_group(group); 541625a68471Sdougm zgroup != NULL; 541725a68471Sdougm zgroup = sa_get_next_group(zgroup)) { 541825a68471Sdougm 541925a68471Sdougm /* got a group, so display it */ 542025a68471Sdougm out_share(out, zgroup, proto); 542125a68471Sdougm } 542225a68471Sdougm } else { 542325a68471Sdougm out_share(out, group, proto); 54246185db85Sdougm } 54256185db85Sdougm } 54266185db85Sdougm } 54276185db85Sdougm 54286185db85Sdougm int 5429549ec3ffSdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 54306185db85Sdougm { 54316185db85Sdougm char *protocol = "nfs"; 54326185db85Sdougm char *options = NULL; 54336185db85Sdougm char *description = NULL; 54346185db85Sdougm char *groupname = NULL; 54356185db85Sdougm char *sharepath = NULL; 54366185db85Sdougm char *resource = NULL; 54376185db85Sdougm char *groupstatus = NULL; 54386185db85Sdougm int persist = SA_SHARE_TRANSIENT; 54396185db85Sdougm int argsused = 0; 54406185db85Sdougm int c; 54416185db85Sdougm int ret = SA_OK; 54426185db85Sdougm int zfs = 0; 54436185db85Sdougm int true_legacy = 0; 54446185db85Sdougm int curtype = SA_SHARE_TRANSIENT; 54456185db85Sdougm char cmd[MAXPATHLEN]; 544625a68471Sdougm sa_group_t group = NULL; 5447da6c28aaSamw sa_resource_t rsrc = NULL; 544825a68471Sdougm sa_share_t share; 544925a68471Sdougm char dir[MAXPATHLEN]; 5450da6c28aaSamw uint64_t features; 5451da6c28aaSamw #ifdef lint 5452da6c28aaSamw flags = flags; 5453da6c28aaSamw #endif 54546185db85Sdougm 54556185db85Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 545625a68471Sdougm switch (c) { 545725a68471Sdougm case 'd': 545825a68471Sdougm description = optarg; 545925a68471Sdougm argsused++; 546025a68471Sdougm break; 546125a68471Sdougm case 'F': 546225a68471Sdougm protocol = optarg; 546325a68471Sdougm if (!sa_valid_protocol(protocol)) { 546425a68471Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 546525a68471Sdougm protocol, "share") == 0 && 546625a68471Sdougm check_legacy_cmd(cmd)) { 546725a68471Sdougm true_legacy++; 546825a68471Sdougm } else { 546925a68471Sdougm (void) fprintf(stderr, gettext( 547025a68471Sdougm "Invalid protocol specified: " 547125a68471Sdougm "%s\n"), protocol); 547225a68471Sdougm return (SA_INVALID_PROTOCOL); 547325a68471Sdougm } 547425a68471Sdougm } 547525a68471Sdougm break; 547625a68471Sdougm case 'o': 547725a68471Sdougm options = optarg; 547825a68471Sdougm argsused++; 547925a68471Sdougm break; 548025a68471Sdougm case 'p': 548125a68471Sdougm persist = SA_SHARE_PERMANENT; 548225a68471Sdougm argsused++; 548325a68471Sdougm break; 548425a68471Sdougm case 'h': 5485e7bab347Sdougm /* optopt on valid arg isn't defined */ 5486e7bab347Sdougm optopt = c; 5487e7bab347Sdougm /*FALLTHROUGH*/ 548825a68471Sdougm case '?': 548925a68471Sdougm default: 5490e7bab347Sdougm /* 5491e7bab347Sdougm * Since a bad option gets to here, sort it 5492e7bab347Sdougm * out and return a syntax error return value 5493e7bab347Sdougm * if necessary. 5494e7bab347Sdougm */ 5495e7bab347Sdougm switch (optopt) { 5496e7bab347Sdougm default: 5497e7bab347Sdougm ret = SA_LEGACY_ERR; 5498e7bab347Sdougm break; 5499e7bab347Sdougm case 'h': 5500e7bab347Sdougm case '?': 5501e7bab347Sdougm break; 5502e7bab347Sdougm } 550325a68471Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 550425a68471Sdougm sa_get_usage(USAGE_SHARE)); 5505e7bab347Sdougm return (ret); 55066185db85Sdougm } 55076185db85Sdougm } 55086185db85Sdougm 550925a68471Sdougm /* Have the info so construct what is needed */ 55106185db85Sdougm if (!argsused && optind == argc) { 551125a68471Sdougm /* display current info in share format */ 5512da6c28aaSamw (void) output_legacy_file(stdout, protocol, handle); 551325a68471Sdougm return (ret); 551425a68471Sdougm } 55156185db85Sdougm 551625a68471Sdougm /* We are modifying the configuration */ 551725a68471Sdougm if (optind == argc) { 55186185db85Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 551925a68471Sdougm sa_get_usage(USAGE_SHARE)); 55206185db85Sdougm return (SA_LEGACY_ERR); 552125a68471Sdougm } 552225a68471Sdougm if (true_legacy) { 552325a68471Sdougm /* If still using legacy share/unshare, exec it */ 55246185db85Sdougm ret = run_legacy_command(cmd, argv); 55256185db85Sdougm return (ret); 552625a68471Sdougm } 55276185db85Sdougm 552825a68471Sdougm sharepath = argv[optind++]; 552925a68471Sdougm if (optind < argc) { 55306185db85Sdougm resource = argv[optind]; 55316185db85Sdougm groupname = strchr(resource, '@'); 55326185db85Sdougm if (groupname != NULL) 553325a68471Sdougm *groupname++ = '\0'; 553425a68471Sdougm } 553525a68471Sdougm if (realpath(sharepath, dir) == NULL) 55366185db85Sdougm ret = SA_BAD_PATH; 553725a68471Sdougm else 55386185db85Sdougm sharepath = dir; 553925a68471Sdougm if (ret == SA_OK) 5540549ec3ffSdougm share = sa_find_share(handle, sharepath); 554125a68471Sdougm else 55426185db85Sdougm share = NULL; 554325a68471Sdougm 5544da6c28aaSamw features = sa_proto_get_featureset(protocol); 5545da6c28aaSamw 554625a68471Sdougm if (groupname != NULL) { 554725a68471Sdougm ret = SA_NOT_ALLOWED; 554825a68471Sdougm } else if (ret == SA_OK) { 5549da6c28aaSamw char *legacygroup; 55506185db85Sdougm /* 555125a68471Sdougm * The legacy group is always present and zfs groups 55526185db85Sdougm * come and go. zfs shares may be in sub-groups and 55536185db85Sdougm * the zfs share will already be in that group so it 5554da6c28aaSamw * isn't an error. If the protocol is "smb", the group 5555da6c28aaSamw * "smb" is used when "default" would otherwise be 5556da6c28aaSamw * used. "default" is NFS only and "smb" is SMB only. 55576185db85Sdougm */ 5558da6c28aaSamw if (strcmp(protocol, "smb") == 0) 5559da6c28aaSamw legacygroup = "smb"; 5560da6c28aaSamw else 5561da6c28aaSamw legacygroup = "default"; 5562da6c28aaSamw 55636185db85Sdougm /* 556425a68471Sdougm * If the share exists (not NULL), then make sure it 556525a68471Sdougm * is one we want to handle by getting the parent 556625a68471Sdougm * group. 55676185db85Sdougm */ 5568da6c28aaSamw if (share != NULL) { 556925a68471Sdougm group = sa_get_parent_group(share); 5570da6c28aaSamw } else { 557125a68471Sdougm group = sa_get_group(handle, legacygroup); 5572da6c28aaSamw if (group == NULL && strcmp(legacygroup, "smb") == 0) { 5573da6c28aaSamw /* 5574da6c28aaSamw * This group may not exist, so create 5575da6c28aaSamw * as necessary. It only contains the 5576da6c28aaSamw * "smb" protocol. 5577da6c28aaSamw */ 5578da6c28aaSamw group = sa_create_group(handle, legacygroup, 5579da6c28aaSamw &ret); 5580da6c28aaSamw if (group != NULL) 5581da6c28aaSamw (void) sa_create_optionset(group, 5582da6c28aaSamw protocol); 5583da6c28aaSamw } 5584da6c28aaSamw } 558525a68471Sdougm 5586da6c28aaSamw if (group == NULL) { 5587da6c28aaSamw ret = SA_SYSTEM_ERR; 5588da6c28aaSamw goto err; 5589da6c28aaSamw } 5590da6c28aaSamw 5591da6c28aaSamw groupstatus = group_status(group); 5592da6c28aaSamw if (share == NULL) { 5593da6c28aaSamw share = sa_add_share(group, sharepath, 5594da6c28aaSamw persist, &ret); 5595da6c28aaSamw if (share == NULL && 5596da6c28aaSamw ret == SA_DUPLICATE_NAME) { 559725a68471Sdougm /* 5598da6c28aaSamw * Could be a ZFS path being started 559925a68471Sdougm */ 5600da6c28aaSamw if (sa_zfs_is_shared(handle, 5601da6c28aaSamw sharepath)) { 5602da6c28aaSamw ret = SA_OK; 5603da6c28aaSamw group = sa_get_group(handle, 5604da6c28aaSamw "zfs"); 5605da6c28aaSamw if (group == NULL) { 5606da6c28aaSamw /* 5607da6c28aaSamw * This shouldn't 5608da6c28aaSamw * happen. 5609da6c28aaSamw */ 5610da6c28aaSamw ret = SA_CONFIG_ERR; 5611da6c28aaSamw } else { 5612da6c28aaSamw share = sa_add_share( 5613da6c28aaSamw group, sharepath, 5614da6c28aaSamw persist, &ret); 5615da6c28aaSamw } 561625a68471Sdougm } 5617da6c28aaSamw } 5618da6c28aaSamw } else { 5619da6c28aaSamw char *type; 5620da6c28aaSamw /* 5621da6c28aaSamw * May want to change persist state, but the 5622da6c28aaSamw * important thing is to change options. We 5623da6c28aaSamw * need to change them regardless of the 5624da6c28aaSamw * source. 5625da6c28aaSamw */ 5626da6c28aaSamw 5627da6c28aaSamw if (sa_zfs_is_shared(handle, sharepath)) { 5628da6c28aaSamw zfs = 1; 5629da6c28aaSamw } 5630da6c28aaSamw remove_all_options(share, protocol); 5631da6c28aaSamw type = sa_get_share_attr(share, "type"); 5632da6c28aaSamw if (type != NULL && 5633da6c28aaSamw strcmp(type, "transient") != 0) { 5634da6c28aaSamw curtype = SA_SHARE_PERMANENT; 5635da6c28aaSamw } 5636da6c28aaSamw if (type != NULL) 5637da6c28aaSamw sa_free_attr_string(type); 5638da6c28aaSamw if (curtype != persist) { 5639da6c28aaSamw (void) sa_set_share_attr(share, "type", 5640da6c28aaSamw persist == SA_SHARE_PERMANENT ? 5641da6c28aaSamw "persist" : "transient"); 5642da6c28aaSamw } 5643da6c28aaSamw } 5644da6c28aaSamw 5645da6c28aaSamw /* 5646da6c28aaSamw * If there is a resource name, we may 5647da6c28aaSamw * actually care about it if this is share for 5648da6c28aaSamw * a protocol that uses resource level sharing 5649da6c28aaSamw * (SMB). We need to find the resource and, if 5650da6c28aaSamw * it exists, make sure it belongs to the 5651da6c28aaSamw * current share. If it doesn't exist, attempt 5652da6c28aaSamw * to create it. 5653da6c28aaSamw */ 5654da6c28aaSamw 5655da6c28aaSamw if (ret == SA_OK && resource != NULL) { 5656da6c28aaSamw rsrc = sa_find_resource(handle, resource); 5657da6c28aaSamw if (rsrc != NULL) { 5658da6c28aaSamw if (share != sa_get_resource_parent(rsrc)) 5659da6c28aaSamw ret = SA_DUPLICATE_NAME; 5660bc54f855SJohn Levon } else { 5661bc54f855SJohn Levon rsrc = sa_add_resource(share, resource, 5662bc54f855SJohn Levon persist, &ret); 56636185db85Sdougm } 5664bc54f855SJohn Levon if (features & SA_FEATURE_RESOURCE) 5665bc54f855SJohn Levon share = rsrc; 5666bc54f855SJohn Levon } 5667da6c28aaSamw 5668bc54f855SJohn Levon /* Have a group to hold this share path */ 5669bc54f855SJohn Levon if (ret == SA_OK && options != NULL && 5670bc54f855SJohn Levon strlen(options) > 0) { 5671bc54f855SJohn Levon ret = sa_parse_legacy_options(share, 5672bc54f855SJohn Levon options, 5673bc54f855SJohn Levon protocol); 5674bc54f855SJohn Levon } 5675bc54f855SJohn Levon if (!zfs) { 5676bc54f855SJohn Levon /* 5677bc54f855SJohn Levon * ZFS shares never have a description 5678bc54f855SJohn Levon * and we can't store the values so 5679bc54f855SJohn Levon * don't try. 5680bc54f855SJohn Levon */ 5681bc54f855SJohn Levon if (ret == SA_OK && description != NULL) 5682bc54f855SJohn Levon ret = sa_set_share_description(share, 5683bc54f855SJohn Levon description); 5684bc54f855SJohn Levon } 5685bc54f855SJohn Levon if (ret == SA_OK && 5686bc54f855SJohn Levon strcmp(groupstatus, "enabled") == 0) { 5687bc54f855SJohn Levon if (rsrc != share) 5688bc54f855SJohn Levon ret = sa_enable_share(share, protocol); 5689bc54f855SJohn Levon else 5690bc54f855SJohn Levon ret = sa_enable_resource(rsrc, 569125a68471Sdougm protocol); 5692da6c28aaSamw if (ret == SA_OK && 5693bc54f855SJohn Levon persist == SA_SHARE_PERMANENT) { 5694bc54f855SJohn Levon (void) sa_update_legacy(share, 5695bc54f855SJohn Levon protocol); 569625a68471Sdougm } 5697bc54f855SJohn Levon if (ret == SA_OK) 5698bc54f855SJohn Levon ret = sa_update_config(handle); 5699bc54f855SJohn Levon } 57006185db85Sdougm } 5701da6c28aaSamw err: 57026185db85Sdougm if (ret != SA_OK) { 570325a68471Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 570425a68471Sdougm sharepath, sa_errorstr(ret)); 570525a68471Sdougm ret = SA_LEGACY_ERR; 57066185db85Sdougm } 57076185db85Sdougm return (ret); 57086185db85Sdougm } 57096185db85Sdougm 57106185db85Sdougm /* 57116185db85Sdougm * sa_legacy_unshare(flags, argc, argv) 57126185db85Sdougm * 57136185db85Sdougm * Implements the original unshare command. 57146185db85Sdougm */ 57156185db85Sdougm int 5716549ec3ffSdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 57176185db85Sdougm { 57186185db85Sdougm char *protocol = "nfs"; /* for now */ 57196185db85Sdougm char *options = NULL; 57206185db85Sdougm char *sharepath = NULL; 57216185db85Sdougm int persist = SA_SHARE_TRANSIENT; 57226185db85Sdougm int argsused = 0; 57236185db85Sdougm int c; 57246185db85Sdougm int ret = SA_OK; 57256185db85Sdougm int true_legacy = 0; 5726da6c28aaSamw uint64_t features = 0; 5727da6c28aaSamw sa_resource_t resource = NULL; 57286185db85Sdougm char cmd[MAXPATHLEN]; 5729da6c28aaSamw #ifdef lint 5730da6c28aaSamw flags = flags; 5731da6c28aaSamw options = options; 5732da6c28aaSamw #endif 57336185db85Sdougm 57346185db85Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 573525a68471Sdougm switch (c) { 573625a68471Sdougm case 'F': 573725a68471Sdougm protocol = optarg; 573825a68471Sdougm if (!sa_valid_protocol(protocol)) { 573925a68471Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 574025a68471Sdougm protocol, "unshare") == 0 && 574125a68471Sdougm check_legacy_cmd(cmd)) { 574225a68471Sdougm true_legacy++; 574325a68471Sdougm } else { 574425a68471Sdougm (void) printf(gettext( 574525a68471Sdougm "Invalid file system name\n")); 574625a68471Sdougm return (SA_INVALID_PROTOCOL); 574725a68471Sdougm } 574825a68471Sdougm } 574925a68471Sdougm break; 575025a68471Sdougm case 'o': 575125a68471Sdougm options = optarg; 575225a68471Sdougm argsused++; 575325a68471Sdougm break; 575425a68471Sdougm case 'p': 575525a68471Sdougm persist = SA_SHARE_PERMANENT; 575625a68471Sdougm argsused++; 575725a68471Sdougm break; 5758e7bab347Sdougm case 'h': 5759e7bab347Sdougm /* optopt on valid arg isn't defined */ 5760e7bab347Sdougm optopt = c; 5761e7bab347Sdougm /*FALLTHROUGH*/ 5762e7bab347Sdougm case '?': 576325a68471Sdougm default: 5764e7bab347Sdougm /* 5765e7bab347Sdougm * Since a bad option gets to here, sort it 5766e7bab347Sdougm * out and return a syntax error return value 5767e7bab347Sdougm * if necessary. 5768e7bab347Sdougm */ 5769e7bab347Sdougm switch (optopt) { 5770e7bab347Sdougm default: 5771e7bab347Sdougm ret = SA_LEGACY_ERR; 5772e7bab347Sdougm break; 5773e7bab347Sdougm case 'h': 5774e7bab347Sdougm case '?': 5775e7bab347Sdougm break; 5776e7bab347Sdougm } 577725a68471Sdougm (void) printf(gettext("usage: %s\n"), 577825a68471Sdougm sa_get_usage(USAGE_UNSHARE)); 5779e7bab347Sdougm return (ret); 57806185db85Sdougm } 57816185db85Sdougm } 57826185db85Sdougm 578325a68471Sdougm /* Have the info so construct what is needed */ 578425a68471Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 578525a68471Sdougm ret = SA_SYNTAX_ERR; 57866185db85Sdougm } else { 578725a68471Sdougm sa_share_t share; 578825a68471Sdougm char dir[MAXPATHLEN]; 578925a68471Sdougm if (true_legacy) { 579025a68471Sdougm /* if still using legacy share/unshare, exec it */ 579125a68471Sdougm ret = run_legacy_command(cmd, argv); 579225a68471Sdougm return (ret); 579325a68471Sdougm } 5794a99982a7Sdougm /* 5795a99982a7Sdougm * Find the path in the internal configuration. If it 5796a99982a7Sdougm * isn't found, attempt to resolve the path via 5797a99982a7Sdougm * realpath() and try again. 5798a99982a7Sdougm */ 579925a68471Sdougm sharepath = argv[optind++]; 580025a68471Sdougm share = sa_find_share(handle, sharepath); 580125a68471Sdougm if (share == NULL) { 580225a68471Sdougm if (realpath(sharepath, dir) == NULL) { 580325a68471Sdougm ret = SA_NO_SUCH_PATH; 580425a68471Sdougm } else { 580525a68471Sdougm share = sa_find_share(handle, dir); 580625a68471Sdougm } 58076185db85Sdougm } 5808da6c28aaSamw if (share == NULL) { 5809da6c28aaSamw /* Could be a resource name so check that next */ 5810da6c28aaSamw features = sa_proto_get_featureset(protocol); 5811da6c28aaSamw resource = sa_find_resource(handle, sharepath); 5812da6c28aaSamw if (resource != NULL) { 5813da6c28aaSamw share = sa_get_resource_parent(resource); 5814da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 5815da6c28aaSamw (void) sa_disable_resource(resource, 5816da6c28aaSamw protocol); 5817da6c28aaSamw if (persist == SA_SHARE_PERMANENT) { 5818da6c28aaSamw ret = sa_remove_resource(resource); 5819da6c28aaSamw if (ret == SA_OK) 5820da6c28aaSamw ret = sa_update_config(handle); 5821da6c28aaSamw } 5822da6c28aaSamw /* 5823da6c28aaSamw * If we still have a resource on the 5824da6c28aaSamw * share, we don't disable the share 5825da6c28aaSamw * itself. IF there aren't anymore, we 5826da6c28aaSamw * need to remove the share. The 5827da6c28aaSamw * removal will be done in the next 5828da6c28aaSamw * section if appropriate. 5829da6c28aaSamw */ 5830da6c28aaSamw resource = sa_get_share_resource(share, NULL); 5831da6c28aaSamw if (resource != NULL) 5832da6c28aaSamw share = NULL; 5833da6c28aaSamw } else if (ret == SA_OK) { 5834da6c28aaSamw /* Didn't find path and no resource */ 5835da6c28aaSamw ret = SA_BAD_PATH; 5836da6c28aaSamw } 5837da6c28aaSamw } 5838da6c28aaSamw if (share != NULL && resource == NULL) { 583925a68471Sdougm ret = sa_disable_share(share, protocol); 584025a68471Sdougm /* 584125a68471Sdougm * Errors are ok and removal should still occur. The 584225a68471Sdougm * legacy unshare is more forgiving of errors than the 584325a68471Sdougm * remove-share subcommand which may need the force 584425a68471Sdougm * flag set for some error conditions. That is, the 584525a68471Sdougm * "unshare" command will always unshare if it can 584625a68471Sdougm * while "remove-share" might require the force option. 584725a68471Sdougm */ 584825a68471Sdougm if (persist == SA_SHARE_PERMANENT) { 584925a68471Sdougm ret = sa_remove_share(share); 585025a68471Sdougm if (ret == SA_OK) 585125a68471Sdougm ret = sa_update_config(handle); 585225a68471Sdougm } 5853da6c28aaSamw } else if (ret == SA_OK && share == NULL && resource == NULL) { 5854da6c28aaSamw /* 5855da6c28aaSamw * If both share and resource are NULL, then 5856da6c28aaSamw * share not found. If one or the other was 5857da6c28aaSamw * found or there was an earlier error, we 5858da6c28aaSamw * assume it was handled earlier. 5859da6c28aaSamw */ 586025a68471Sdougm ret = SA_NOT_SHARED; 5861a99982a7Sdougm } 58626185db85Sdougm } 58636185db85Sdougm switch (ret) { 58646185db85Sdougm default: 586525a68471Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 586625a68471Sdougm ret = SA_LEGACY_ERR; 586725a68471Sdougm break; 58686185db85Sdougm case SA_SYNTAX_ERR: 586925a68471Sdougm (void) printf(gettext("usage: %s\n"), 587025a68471Sdougm sa_get_usage(USAGE_UNSHARE)); 587125a68471Sdougm break; 58726185db85Sdougm case SA_OK: 587325a68471Sdougm break; 58746185db85Sdougm } 58756185db85Sdougm return (ret); 58766185db85Sdougm } 58776185db85Sdougm 58786185db85Sdougm /* 587925a68471Sdougm * Common commands that implement the sub-commands used by all 5880da6c28aaSamw * protocols. The entries are found via the lookup command 58816185db85Sdougm */ 58826185db85Sdougm 58836185db85Sdougm static sa_command_t commands[] = { 58846185db85Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 58856185db85Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 58866185db85Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 58876185db85Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 58886185db85Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 58896185db85Sdougm {"list", 0, sa_list, USAGE_LIST}, 58906185db85Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 58916185db85Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 58926185db85Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 58936185db85Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 58946185db85Sdougm {"show", 0, sa_show, USAGE_SHOW}, 58956185db85Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 58966185db85Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 5897da6c28aaSamw SVC_SET|SVC_ACTION}, 58986185db85Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 58996185db85Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 59006185db85Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 59016185db85Sdougm {NULL, 0, NULL, NULL} 59026185db85Sdougm }; 59036185db85Sdougm 59046185db85Sdougm static char * 59056185db85Sdougm sa_get_usage(sa_usage_t index) 59066185db85Sdougm { 59076185db85Sdougm char *ret = NULL; 59086185db85Sdougm switch (index) { 59096185db85Sdougm case USAGE_ADD_SHARE: 591025a68471Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 591125a68471Sdougm "[-d \"description text\"] -s sharepath group"); 591225a68471Sdougm break; 59136185db85Sdougm case USAGE_CREATE: 591425a68471Sdougm ret = gettext( 591525a68471Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 591625a68471Sdougm break; 59176185db85Sdougm case USAGE_DELETE: 591825a68471Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 591925a68471Sdougm break; 59206185db85Sdougm case USAGE_DISABLE: 592125a68471Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 592225a68471Sdougm break; 59236185db85Sdougm case USAGE_ENABLE: 592425a68471Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 592525a68471Sdougm break; 59266185db85Sdougm case USAGE_LIST: 592725a68471Sdougm ret = gettext("list [-vh] [-P proto]"); 592825a68471Sdougm break; 59296185db85Sdougm case USAGE_MOVE_SHARE: 593025a68471Sdougm ret = gettext( 593125a68471Sdougm "move-share [-nvh] -s sharepath destination-group"); 593225a68471Sdougm break; 59336185db85Sdougm case USAGE_REMOVE_SHARE: 5934da6c28aaSamw ret = gettext( 5935da6c28aaSamw "remove-share [-fnvh] {-s sharepath | -r resource} " 5936da6c28aaSamw "group"); 593725a68471Sdougm break; 59386185db85Sdougm case USAGE_SET: 593925a68471Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 5940da6c28aaSamw "[-p property=value]* [-s sharepath] [-r resource]] " 5941da6c28aaSamw "group"); 594225a68471Sdougm break; 59436185db85Sdougm case USAGE_SET_SECURITY: 594425a68471Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 594525a68471Sdougm "[-p property=value]* group"); 594625a68471Sdougm break; 59476185db85Sdougm case USAGE_SET_SHARE: 594825a68471Sdougm ret = gettext("set-share [-nh] [-r resource] " 594925a68471Sdougm "[-d \"description text\"] -s sharepath group"); 595025a68471Sdougm break; 59516185db85Sdougm case USAGE_SHOW: 595225a68471Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 595325a68471Sdougm break; 59546185db85Sdougm case USAGE_SHARE: 595525a68471Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 595625a68471Sdougm "[-d description] [pathname [resourcename]]"); 595725a68471Sdougm break; 59586185db85Sdougm case USAGE_START: 595925a68471Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 596025a68471Sdougm break; 59616185db85Sdougm case USAGE_STOP: 596225a68471Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 596325a68471Sdougm break; 59646185db85Sdougm case USAGE_UNSET: 596525a68471Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 596625a68471Sdougm "[-p property]* group"); 596725a68471Sdougm break; 59686185db85Sdougm case USAGE_UNSET_SECURITY: 5969da6c28aaSamw ret = gettext("unset-security [-nvh] -P proto " 5970da6c28aaSamw "-S security-type [-p property]* group"); 597125a68471Sdougm break; 59726185db85Sdougm case USAGE_UNSHARE: 597325a68471Sdougm ret = gettext( 5974da6c28aaSamw "unshare [-F fstype] [-p] [-o optionlist] sharepath"); 597525a68471Sdougm break; 59766185db85Sdougm } 59776185db85Sdougm return (ret); 59786185db85Sdougm } 59796185db85Sdougm 59806185db85Sdougm /* 59816185db85Sdougm * sa_lookup(cmd, proto) 59826185db85Sdougm * 59836185db85Sdougm * Lookup the sub-command. proto isn't currently used, but it may 59846185db85Sdougm * eventually provide a way to provide protocol specific sub-commands. 59856185db85Sdougm */ 59866185db85Sdougm sa_command_t * 59876185db85Sdougm sa_lookup(char *cmd, char *proto) 59886185db85Sdougm { 59896185db85Sdougm int i; 59906185db85Sdougm size_t len; 5991da6c28aaSamw #ifdef lint 5992da6c28aaSamw proto = proto; 5993da6c28aaSamw #endif 59946185db85Sdougm 59956185db85Sdougm len = strlen(cmd); 59966185db85Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 599725a68471Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 599825a68471Sdougm return (&commands[i]); 59996185db85Sdougm } 60006185db85Sdougm return (NULL); 60016185db85Sdougm } 60026185db85Sdougm 60036185db85Sdougm void 60046185db85Sdougm sub_command_help(char *proto) 60056185db85Sdougm { 60066185db85Sdougm int i; 6007da6c28aaSamw #ifdef lint 6008da6c28aaSamw proto = proto; 6009da6c28aaSamw #endif 60106185db85Sdougm 60116185db85Sdougm (void) printf(gettext("\tsub-commands:\n")); 60126185db85Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 601325a68471Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 601425a68471Sdougm (void) printf("\t%s\n", 601525a68471Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 60166185db85Sdougm } 60176185db85Sdougm } 6018