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 /* 23*0b4fd3b1SSurya Prakki * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 256185db85Sdougm */ 266185db85Sdougm 276185db85Sdougm #include <sys/types.h> 286185db85Sdougm #include <sys/stat.h> 296185db85Sdougm #include <fcntl.h> 306185db85Sdougm #include <stdlib.h> 316185db85Sdougm #include <stdio.h> 326185db85Sdougm #include <string.h> 336185db85Sdougm #include <ctype.h> 346185db85Sdougm #include <unistd.h> 356185db85Sdougm #include <getopt.h> 366185db85Sdougm #include <utmpx.h> 376185db85Sdougm #include <pwd.h> 386185db85Sdougm #include <auth_attr.h> 396185db85Sdougm #include <secdb.h> 406185db85Sdougm #include <sys/param.h> 416185db85Sdougm #include <sys/stat.h> 426185db85Sdougm #include <errno.h> 436185db85Sdougm 446185db85Sdougm #include <libshare.h> 456185db85Sdougm #include "sharemgr.h" 466185db85Sdougm #include <libscf.h> 476185db85Sdougm #include <libxml/tree.h> 486185db85Sdougm #include <libintl.h> 49da6c28aaSamw #include <assert.h> 50da6c28aaSamw #include <iconv.h> 51da6c28aaSamw #include <langinfo.h> 52da6c28aaSamw #include <dirent.h> 536185db85Sdougm 546185db85Sdougm static char *sa_get_usage(sa_usage_t); 556185db85Sdougm 566185db85Sdougm /* 576185db85Sdougm * Implementation of the common sub-commands supported by sharemgr. 586185db85Sdougm * A number of helper functions are also included. 596185db85Sdougm */ 606185db85Sdougm 616185db85Sdougm /* 626185db85Sdougm * has_protocol(group, proto) 636185db85Sdougm * If the group has an optionset with the specified protocol, 646185db85Sdougm * return true (1) otherwise false (0). 656185db85Sdougm */ 666185db85Sdougm static int 676185db85Sdougm has_protocol(sa_group_t group, char *protocol) 686185db85Sdougm { 696185db85Sdougm sa_optionset_t optionset; 706185db85Sdougm int result = 0; 716185db85Sdougm 726185db85Sdougm optionset = sa_get_optionset(group, protocol); 736185db85Sdougm if (optionset != NULL) { 746185db85Sdougm result++; 756185db85Sdougm } 766185db85Sdougm return (result); 776185db85Sdougm } 786185db85Sdougm 796185db85Sdougm /* 80da6c28aaSamw * validresource(name) 81da6c28aaSamw * 82da6c28aaSamw * Check that name only has valid characters in it. The current valid 83da6c28aaSamw * set are the printable characters but not including: 84da6c28aaSamw * " / \ [ ] : | < > + ; , ? * = \t 85da6c28aaSamw * Note that space is included and there is a maximum length. 86da6c28aaSamw */ 87da6c28aaSamw static int 88da6c28aaSamw validresource(const char *name) 89da6c28aaSamw { 90da6c28aaSamw const char *cp; 91da6c28aaSamw size_t len; 92da6c28aaSamw 93da6c28aaSamw if (name == NULL) 94da6c28aaSamw return (B_FALSE); 95da6c28aaSamw 96da6c28aaSamw len = strlen(name); 97da6c28aaSamw if (len == 0 || len > SA_MAX_RESOURCE_NAME) 98da6c28aaSamw return (B_FALSE); 99da6c28aaSamw 100da6c28aaSamw if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) { 101da6c28aaSamw return (B_FALSE); 102da6c28aaSamw } 103da6c28aaSamw 104da6c28aaSamw for (cp = name; *cp != '\0'; cp++) 105da6c28aaSamw if (iscntrl(*cp)) 106da6c28aaSamw return (B_FALSE); 107da6c28aaSamw 108da6c28aaSamw return (B_TRUE); 109da6c28aaSamw } 110da6c28aaSamw 111da6c28aaSamw /* 112da6c28aaSamw * conv_to_utf8(input) 113da6c28aaSamw * 114da6c28aaSamw * Convert the input string to utf8 from the current locale. If the 115da6c28aaSamw * conversion fails, use the current locale, it is likely close 116da6c28aaSamw * enough. For example, the "C" locale is a subset of utf-8. The 117da6c28aaSamw * return value may be a new string or the original input string. 118da6c28aaSamw */ 119da6c28aaSamw 120da6c28aaSamw static char * 121da6c28aaSamw conv_to_utf8(char *input) 122da6c28aaSamw { 123da6c28aaSamw iconv_t cd; 12455bf511dSas200622 char *inval = input; 125da6c28aaSamw char *output = input; 126da6c28aaSamw char *outleft; 127da6c28aaSamw char *curlocale; 128da6c28aaSamw size_t bytesleft; 129da6c28aaSamw size_t size; 130da6c28aaSamw size_t osize; 131da6c28aaSamw static int warned = 0; 132da6c28aaSamw 133da6c28aaSamw curlocale = nl_langinfo(CODESET); 134da6c28aaSamw if (curlocale == NULL) 135da6c28aaSamw curlocale = "C"; 136da6c28aaSamw cd = iconv_open("UTF-8", curlocale); 137da6c28aaSamw if (cd != NULL && cd != (iconv_t)-1) { 138da6c28aaSamw size = strlen(input); 139da6c28aaSamw /* Assume worst case of characters expanding to 4 bytes. */ 140da6c28aaSamw bytesleft = size * 4; 141da6c28aaSamw output = calloc(bytesleft, 1); 142da6c28aaSamw if (output != NULL) { 143da6c28aaSamw outleft = output; 14455bf511dSas200622 /* inval can be modified on return */ 14555bf511dSas200622 osize = iconv(cd, (const char **)&inval, &size, 146da6c28aaSamw &outleft, &bytesleft); 147da6c28aaSamw if (osize == (size_t)-1 || size != 0) { 148da6c28aaSamw free(output); 149da6c28aaSamw output = input; 150da6c28aaSamw } 15155bf511dSas200622 } else { 15255bf511dSas200622 /* Need to return something. */ 15355bf511dSas200622 output = input; 154da6c28aaSamw } 155da6c28aaSamw (void) iconv_close(cd); 156da6c28aaSamw } else { 157da6c28aaSamw if (!warned) 158da6c28aaSamw (void) fprintf(stderr, 159da6c28aaSamw gettext("Cannot convert to UTF-8 from %s\n"), 160da6c28aaSamw curlocale ? curlocale : gettext("unknown")); 161da6c28aaSamw warned = 1; 162da6c28aaSamw } 163da6c28aaSamw return (output); 164da6c28aaSamw } 165da6c28aaSamw 166da6c28aaSamw /* 167da6c28aaSamw * conv_from(input) 168da6c28aaSamw * 169da6c28aaSamw * Convert the input string from utf8 to current locale. If the 170da6c28aaSamw * conversion isn't supported, just use as is. The return value may be 171da6c28aaSamw * a new string or the original input string. 172da6c28aaSamw */ 173da6c28aaSamw 174da6c28aaSamw static char * 175da6c28aaSamw conv_from_utf8(char *input) 176da6c28aaSamw { 177da6c28aaSamw iconv_t cd; 178da6c28aaSamw char *output = input; 17955bf511dSas200622 char *inval = input; 180da6c28aaSamw char *outleft; 181da6c28aaSamw char *curlocale; 182da6c28aaSamw size_t bytesleft; 183da6c28aaSamw size_t size; 184da6c28aaSamw size_t osize; 185da6c28aaSamw static int warned = 0; 186da6c28aaSamw 187da6c28aaSamw curlocale = nl_langinfo(CODESET); 188da6c28aaSamw if (curlocale == NULL) 189da6c28aaSamw curlocale = "C"; 190da6c28aaSamw cd = iconv_open(curlocale, "UTF-8"); 191da6c28aaSamw if (cd != NULL && cd != (iconv_t)-1) { 192da6c28aaSamw size = strlen(input); 193da6c28aaSamw /* Assume worst case of characters expanding to 4 bytes. */ 194da6c28aaSamw bytesleft = size * 4; 195da6c28aaSamw output = calloc(bytesleft, 1); 196da6c28aaSamw if (output != NULL) { 197da6c28aaSamw outleft = output; 19855bf511dSas200622 osize = iconv(cd, (const char **)&inval, &size, 199da6c28aaSamw &outleft, &bytesleft); 20055bf511dSas200622 if (osize == (size_t)-1 || size != 0) 201da6c28aaSamw output = input; 20255bf511dSas200622 } else { 20355bf511dSas200622 /* Need to return something. */ 20455bf511dSas200622 output = input; 205da6c28aaSamw } 206da6c28aaSamw (void) iconv_close(cd); 207da6c28aaSamw } else { 208da6c28aaSamw if (!warned) 209da6c28aaSamw (void) fprintf(stderr, 210da6c28aaSamw gettext("Cannot convert to %s from UTF-8\n"), 211da6c28aaSamw curlocale ? curlocale : gettext("unknown")); 212da6c28aaSamw warned = 1; 213da6c28aaSamw } 214da6c28aaSamw return (output); 215da6c28aaSamw } 216da6c28aaSamw 217573b0c00Sdougm /* 218573b0c00Sdougm * print_rsrc_desc(resource, sharedesc) 219573b0c00Sdougm * 220573b0c00Sdougm * Print the resource description string after converting from UTF8 to 221573b0c00Sdougm * the current locale. If sharedesc is not NULL and there is no 222573b0c00Sdougm * description on the resource, use sharedesc. sharedesc will already 223573b0c00Sdougm * be converted to UTF8. 224573b0c00Sdougm */ 225573b0c00Sdougm 226da6c28aaSamw static void 227573b0c00Sdougm print_rsrc_desc(sa_resource_t resource, char *sharedesc) 228da6c28aaSamw { 229da6c28aaSamw char *description; 230da6c28aaSamw char *desc; 231da6c28aaSamw 232573b0c00Sdougm if (resource == NULL) 233573b0c00Sdougm return; 234573b0c00Sdougm 235da6c28aaSamw description = sa_get_resource_description(resource); 236da6c28aaSamw if (description != NULL) { 237da6c28aaSamw desc = conv_from_utf8(description); 238da6c28aaSamw if (desc != description) { 239da6c28aaSamw sa_free_share_description(description); 240da6c28aaSamw description = desc; 241da6c28aaSamw } 242573b0c00Sdougm } else if (sharedesc != NULL) { 243573b0c00Sdougm description = strdup(sharedesc); 244573b0c00Sdougm } 245573b0c00Sdougm if (description != NULL) { 246da6c28aaSamw (void) printf("\t\"%s\"", description); 247da6c28aaSamw sa_free_share_description(description); 248da6c28aaSamw } 249da6c28aaSamw } 250da6c28aaSamw 251573b0c00Sdougm /* 252573b0c00Sdougm * set_resource_desc(share, description) 253573b0c00Sdougm * 254573b0c00Sdougm * Set the share description value after converting the description 255573b0c00Sdougm * string to UTF8 from the current locale. 256573b0c00Sdougm */ 257573b0c00Sdougm 258573b0c00Sdougm static int 259573b0c00Sdougm set_resource_desc(sa_share_t share, char *description) 260573b0c00Sdougm { 261573b0c00Sdougm char *desc; 262573b0c00Sdougm int ret; 263573b0c00Sdougm 264573b0c00Sdougm desc = conv_to_utf8(description); 265573b0c00Sdougm ret = sa_set_resource_description(share, desc); 266573b0c00Sdougm if (description != desc) 267573b0c00Sdougm sa_free_share_description(desc); 268573b0c00Sdougm return (ret); 269573b0c00Sdougm } 270573b0c00Sdougm 271573b0c00Sdougm /* 272573b0c00Sdougm * set_share_desc(share, description) 273573b0c00Sdougm * 274573b0c00Sdougm * Set the resource description value after converting the description 275573b0c00Sdougm * string to UTF8 from the current locale. 276573b0c00Sdougm */ 277573b0c00Sdougm 278da6c28aaSamw static int 279da6c28aaSamw set_share_desc(sa_share_t share, char *description) 280da6c28aaSamw { 281da6c28aaSamw char *desc; 282da6c28aaSamw int ret; 283da6c28aaSamw 284da6c28aaSamw desc = conv_to_utf8(description); 285da6c28aaSamw ret = sa_set_share_description(share, desc); 286da6c28aaSamw if (description != desc) 287da6c28aaSamw sa_free_share_description(desc); 288da6c28aaSamw return (ret); 289da6c28aaSamw } 290da6c28aaSamw 291da6c28aaSamw /* 292da6c28aaSamw * add_list(list, item, data, proto) 293da6c28aaSamw * Adds a new list member that points holds item in the list. 2946185db85Sdougm * If list is NULL, it starts a new list. The function returns 2956185db85Sdougm * the first member of the list. 2966185db85Sdougm */ 2976185db85Sdougm struct list * 298da6c28aaSamw add_list(struct list *listp, void *item, void *data, char *proto) 2996185db85Sdougm { 3006185db85Sdougm struct list *new, *tmp; 3016185db85Sdougm 3026185db85Sdougm new = malloc(sizeof (struct list)); 3036185db85Sdougm if (new != NULL) { 3046185db85Sdougm new->next = NULL; 3056185db85Sdougm new->item = item; 3066185db85Sdougm new->itemdata = data; 307da6c28aaSamw new->proto = proto; 3086185db85Sdougm } else { 3096185db85Sdougm return (listp); 3106185db85Sdougm } 3116185db85Sdougm 3126185db85Sdougm if (listp == NULL) 3136185db85Sdougm return (new); 3146185db85Sdougm 3156185db85Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 3166185db85Sdougm /* get to end of list */ 3176185db85Sdougm } 3186185db85Sdougm tmp->next = new; 3196185db85Sdougm return (listp); 3206185db85Sdougm } 3216185db85Sdougm 3226185db85Sdougm /* 3236185db85Sdougm * free_list(list) 3246185db85Sdougm * Given a list, free all the members of the list; 3256185db85Sdougm */ 3266185db85Sdougm static void 3276185db85Sdougm free_list(struct list *listp) 3286185db85Sdougm { 3296185db85Sdougm struct list *tmp; 3306185db85Sdougm while (listp != NULL) { 3316185db85Sdougm tmp = listp; 3326185db85Sdougm listp = listp->next; 3336185db85Sdougm free(tmp); 3346185db85Sdougm } 3356185db85Sdougm } 3366185db85Sdougm 3376185db85Sdougm /* 3386185db85Sdougm * check_authorization(instname, which) 3396185db85Sdougm * 3406185db85Sdougm * Checks to see if the specific type of authorization in which is 3416185db85Sdougm * enabled for the user in this SMF service instance. 3426185db85Sdougm */ 3436185db85Sdougm 3446185db85Sdougm static int 3456185db85Sdougm check_authorization(char *instname, int which) 3466185db85Sdougm { 3476185db85Sdougm scf_handle_t *handle = NULL; 3486185db85Sdougm scf_simple_prop_t *prop = NULL; 3496185db85Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 3506185db85Sdougm char *authstr = NULL; 3516185db85Sdougm ssize_t numauths; 35225a68471Sdougm int ret = B_TRUE; 3536185db85Sdougm uid_t uid; 3546185db85Sdougm struct passwd *pw = NULL; 3556185db85Sdougm 3566185db85Sdougm uid = getuid(); 3576185db85Sdougm pw = getpwuid(uid); 35825a68471Sdougm if (pw == NULL) { 35925a68471Sdougm ret = B_FALSE; 36025a68471Sdougm } else { 36125a68471Sdougm /* 36225a68471Sdougm * Since names are restricted to SA_MAX_NAME_LEN won't 36325a68471Sdougm * overflow. 36425a68471Sdougm */ 36525a68471Sdougm (void) snprintf(svcstring, sizeof (svcstring), "%s:%s", 36625a68471Sdougm SA_SVC_FMRI_BASE, instname); 3676185db85Sdougm handle = scf_handle_create(SCF_VERSION); 3686185db85Sdougm if (handle != NULL) { 3696185db85Sdougm if (scf_handle_bind(handle) == 0) { 3706185db85Sdougm switch (which) { 3716185db85Sdougm case SVC_SET: 37225a68471Sdougm prop = scf_simple_prop_get(handle, 37325a68471Sdougm svcstring, "general", 3746185db85Sdougm SVC_AUTH_VALUE); 3756185db85Sdougm break; 3766185db85Sdougm case SVC_ACTION: 37725a68471Sdougm prop = scf_simple_prop_get(handle, 37825a68471Sdougm svcstring, "general", 3796185db85Sdougm SVC_AUTH_ACTION); 3806185db85Sdougm break; 3816185db85Sdougm } 3826185db85Sdougm } 3836185db85Sdougm } 3846185db85Sdougm } 3856185db85Sdougm /* make sure we have an authorization string property */ 3866185db85Sdougm if (prop != NULL) { 3876185db85Sdougm int i; 3886185db85Sdougm numauths = scf_simple_prop_numvalues(prop); 3896185db85Sdougm for (ret = 0, i = 0; i < numauths; i++) { 3906185db85Sdougm authstr = scf_simple_prop_next_astring(prop); 3916185db85Sdougm if (authstr != NULL) { 3926185db85Sdougm /* check if this user has one of the strings */ 3936185db85Sdougm if (chkauthattr(authstr, pw->pw_name)) { 3946185db85Sdougm ret = 1; 3956185db85Sdougm break; 3966185db85Sdougm } 3976185db85Sdougm } 3986185db85Sdougm } 3996185db85Sdougm endauthattr(); 4006185db85Sdougm scf_simple_prop_free(prop); 4016185db85Sdougm } else { 4026185db85Sdougm /* no authorization string defined */ 4036185db85Sdougm ret = 0; 4046185db85Sdougm } 4056185db85Sdougm if (handle != NULL) 4066185db85Sdougm scf_handle_destroy(handle); 4076185db85Sdougm return (ret); 4086185db85Sdougm } 4096185db85Sdougm 4106185db85Sdougm /* 4116185db85Sdougm * check_authorizations(instname, flags) 4126185db85Sdougm * 4136185db85Sdougm * check all the needed authorizations for the user in this service 4146185db85Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 4156185db85Sdougm * there are authorizations for the user or not. 4166185db85Sdougm */ 4176185db85Sdougm 4186185db85Sdougm static int 4196185db85Sdougm check_authorizations(char *instname, int flags) 4206185db85Sdougm { 4216185db85Sdougm int ret1 = 0; 4226185db85Sdougm int ret2 = 0; 4236185db85Sdougm int ret; 4246185db85Sdougm 4256185db85Sdougm if (flags & SVC_SET) 4266185db85Sdougm ret1 = check_authorization(instname, SVC_SET); 4276185db85Sdougm if (flags & SVC_ACTION) 4286185db85Sdougm ret2 = check_authorization(instname, SVC_ACTION); 4296185db85Sdougm switch (flags) { 4306185db85Sdougm case SVC_ACTION: 4316185db85Sdougm ret = ret2; 4326185db85Sdougm break; 4336185db85Sdougm case SVC_SET: 4346185db85Sdougm ret = ret1; 4356185db85Sdougm break; 4366185db85Sdougm case SVC_ACTION|SVC_SET: 4376185db85Sdougm ret = ret1 & ret2; 4386185db85Sdougm break; 4396185db85Sdougm default: 4406185db85Sdougm /* if not flags set, we assume we don't need authorizations */ 4416185db85Sdougm ret = 1; 4426185db85Sdougm } 4436185db85Sdougm return (ret); 4446185db85Sdougm } 4456185db85Sdougm 4466185db85Sdougm /* 447da6c28aaSamw * notify_or_enable_share(share, protocol) 448da6c28aaSamw * 449da6c28aaSamw * Since some protocols don't want an "enable" when properties change, 450da6c28aaSamw * this function will use the protocol specific notify function 451da6c28aaSamw * first. If that fails, it will then attempt to use the 452da6c28aaSamw * sa_enable_share(). "protocol" is the protocol that was specified 453da6c28aaSamw * on the command line. 454da6c28aaSamw */ 455da6c28aaSamw static void 456da6c28aaSamw notify_or_enable_share(sa_share_t share, char *protocol) 457da6c28aaSamw { 458da6c28aaSamw sa_group_t group; 459da6c28aaSamw sa_optionset_t opt; 460da6c28aaSamw int ret = SA_OK; 461da6c28aaSamw char *path; 462da6c28aaSamw char *groupproto; 463da6c28aaSamw sa_share_t parent = share; 464da6c28aaSamw 465da6c28aaSamw /* If really a resource, get parent share */ 466da6c28aaSamw if (!sa_is_share(share)) { 467da6c28aaSamw parent = sa_get_resource_parent((sa_resource_t)share); 468da6c28aaSamw } 469da6c28aaSamw 470da6c28aaSamw /* 471da6c28aaSamw * Now that we've got a share in "parent", make sure it has a path. 472da6c28aaSamw */ 473da6c28aaSamw path = sa_get_share_attr(parent, "path"); 474da6c28aaSamw if (path == NULL) 475da6c28aaSamw return; 476da6c28aaSamw 477da6c28aaSamw group = sa_get_parent_group(parent); 478da6c28aaSamw 479da6c28aaSamw if (group == NULL) { 480da6c28aaSamw sa_free_attr_string(path); 481da6c28aaSamw return; 482da6c28aaSamw } 483da6c28aaSamw for (opt = sa_get_optionset(group, NULL); 484da6c28aaSamw opt != NULL; 485da6c28aaSamw opt = sa_get_next_optionset(opt)) { 486da6c28aaSamw groupproto = sa_get_optionset_attr(opt, "type"); 487da6c28aaSamw if (groupproto == NULL || 488da6c28aaSamw (protocol != NULL && strcmp(groupproto, protocol) != 0)) { 489fe1c642dSBill Krier if (groupproto != NULL) 490da6c28aaSamw sa_free_attr_string(groupproto); 491da6c28aaSamw continue; 492da6c28aaSamw } 493da6c28aaSamw if (sa_is_share(share)) { 494da6c28aaSamw if ((ret = sa_proto_change_notify(share, 495da6c28aaSamw groupproto)) != SA_OK) { 496da6c28aaSamw ret = sa_enable_share(share, groupproto); 497da6c28aaSamw if (ret != SA_OK) { 498da6c28aaSamw (void) printf( 499da6c28aaSamw gettext("Could not reenable" 500da6c28aaSamw " share %s: %s\n"), 501da6c28aaSamw path, sa_errorstr(ret)); 502da6c28aaSamw } 503da6c28aaSamw } 504da6c28aaSamw } else { 505da6c28aaSamw /* Must be a resource */ 506da6c28aaSamw if ((ret = sa_proto_notify_resource(share, 507da6c28aaSamw groupproto)) != SA_OK) { 508da6c28aaSamw ret = sa_enable_resource(share, groupproto); 509da6c28aaSamw if (ret != SA_OK) { 510da6c28aaSamw (void) printf( 511da6c28aaSamw gettext("Could not " 512da6c28aaSamw "reenable resource %s: " 513da6c28aaSamw "%s\n"), path, 514da6c28aaSamw sa_errorstr(ret)); 515da6c28aaSamw } 516da6c28aaSamw } 517da6c28aaSamw } 518da6c28aaSamw sa_free_attr_string(groupproto); 519da6c28aaSamw } 520da6c28aaSamw sa_free_attr_string(path); 521da6c28aaSamw } 522da6c28aaSamw 523da6c28aaSamw /* 524da6c28aaSamw * enable_group(group, updateproto, notify, proto) 5257d968cb8Sdougm * 5267d968cb8Sdougm * enable all the shares in the specified group. This is a helper for 5277d968cb8Sdougm * enable_all_groups in order to simplify regular and subgroup (zfs) 528da6c28aaSamw * enabling. Group has already been checked for non-NULL. If notify 529da6c28aaSamw * is non-zero, attempt to use the notify interface rather than 530da6c28aaSamw * enable. 5316185db85Sdougm */ 5327d968cb8Sdougm static void 533da6c28aaSamw enable_group(sa_group_t group, char *updateproto, int notify, char *proto) 5346185db85Sdougm { 5356185db85Sdougm sa_share_t share; 5367d968cb8Sdougm 5377d968cb8Sdougm for (share = sa_get_share(group, NULL); 5387d968cb8Sdougm share != NULL; 5397d968cb8Sdougm share = sa_get_next_share(share)) { 5407d968cb8Sdougm if (updateproto != NULL) 5417d968cb8Sdougm (void) sa_update_legacy(share, updateproto); 542da6c28aaSamw if (notify) 543da6c28aaSamw notify_or_enable_share(share, proto); 544da6c28aaSamw else 545da6c28aaSamw (void) sa_enable_share(share, proto); 5467d968cb8Sdougm } 5477d968cb8Sdougm } 5487d968cb8Sdougm 5497d968cb8Sdougm /* 550330ef417Sdougm * isenabled(group) 551330ef417Sdougm * 552330ef417Sdougm * Returns B_TRUE if the group is enabled or B_FALSE if it isn't. 553330ef417Sdougm * Moved to separate function to reduce clutter in the code. 554330ef417Sdougm */ 555330ef417Sdougm 556330ef417Sdougm static int 557330ef417Sdougm isenabled(sa_group_t group) 558330ef417Sdougm { 559330ef417Sdougm char *state; 560330ef417Sdougm int ret = B_FALSE; 561330ef417Sdougm 562330ef417Sdougm if (group != NULL) { 563330ef417Sdougm state = sa_get_group_attr(group, "state"); 564330ef417Sdougm if (state != NULL) { 565da6c28aaSamw 566330ef417Sdougm if (strcmp(state, "enabled") == 0) 567330ef417Sdougm ret = B_TRUE; 568330ef417Sdougm sa_free_attr_string(state); 569330ef417Sdougm } 570330ef417Sdougm } 571330ef417Sdougm return (ret); 572330ef417Sdougm } 573330ef417Sdougm 574330ef417Sdougm /* 5757d968cb8Sdougm * enable_all_groups(list, setstate, online, updateproto) 576da6c28aaSamw * 577da6c28aaSamw * Given a list of groups, enable each one found. If updateproto is 578da6c28aaSamw * not NULL, then update all the shares for the protocol that was 579da6c28aaSamw * passed in. If enable is non-zero, tell enable_group to try the 580da6c28aaSamw * notify interface since this is a property change. 5817d968cb8Sdougm */ 5827d968cb8Sdougm static int 583549ec3ffSdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate, 584da6c28aaSamw int online, char *updateproto, int enable) 5857d968cb8Sdougm { 586330ef417Sdougm int ret; 5876185db85Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 5886185db85Sdougm char *state; 5896185db85Sdougm char *name; 5906185db85Sdougm char *zfs = NULL; 5916185db85Sdougm sa_group_t group; 5927d968cb8Sdougm sa_group_t subgroup; 5936185db85Sdougm 594330ef417Sdougm for (ret = SA_OK; work != NULL; work = work->next) { 5956185db85Sdougm group = (sa_group_t)work->item; 596330ef417Sdougm 597330ef417Sdougm /* 598330ef417Sdougm * If setstate == TRUE, then make sure to set 599330ef417Sdougm * enabled. This needs to be done here in order for 600330ef417Sdougm * the isenabled check to succeed on a newly enabled 601330ef417Sdougm * group. 602330ef417Sdougm */ 603330ef417Sdougm if (setstate == B_TRUE) { 604330ef417Sdougm ret = sa_set_group_attr(group, "state", "enabled"); 605330ef417Sdougm if (ret != SA_OK) 606330ef417Sdougm break; 607330ef417Sdougm } 608330ef417Sdougm 609330ef417Sdougm /* 610330ef417Sdougm * Check to see if group is enabled. If it isn't, skip 611330ef417Sdougm * the rest. We don't want shares starting if the 612330ef417Sdougm * group is disabled. The properties may have been 613330ef417Sdougm * updated, but there won't be a change until the 614330ef417Sdougm * group is enabled. 615330ef417Sdougm */ 616330ef417Sdougm if (!isenabled(group)) 617330ef417Sdougm continue; 618330ef417Sdougm 6196185db85Sdougm /* if itemdata != NULL then a single share */ 6206185db85Sdougm if (work->itemdata != NULL) { 621da6c28aaSamw if (enable) { 622da6c28aaSamw if (work->itemdata != NULL) 623da6c28aaSamw notify_or_enable_share(work->itemdata, 624da6c28aaSamw updateproto); 625da6c28aaSamw else 626da6c28aaSamw ret = SA_CONFIG_ERR; 627da6c28aaSamw } else { 628da6c28aaSamw if (sa_is_share(work->itemdata)) { 629da6c28aaSamw ret = sa_enable_share( 630da6c28aaSamw (sa_share_t)work->itemdata, 631da6c28aaSamw updateproto); 632da6c28aaSamw } else { 633da6c28aaSamw ret = sa_enable_resource( 634da6c28aaSamw (sa_resource_t)work->itemdata, 635da6c28aaSamw updateproto); 636da6c28aaSamw } 637da6c28aaSamw } 6386185db85Sdougm } 639330ef417Sdougm if (ret != SA_OK) 640330ef417Sdougm break; 641330ef417Sdougm 6426185db85Sdougm /* if itemdata == NULL then the whole group */ 6436185db85Sdougm if (work->itemdata == NULL) { 6447d968cb8Sdougm zfs = sa_get_group_attr(group, "zfs"); 6457d968cb8Sdougm /* 646da6c28aaSamw * If the share is managed by ZFS, don't 6477d968cb8Sdougm * update any of the protocols since ZFS is 648da6c28aaSamw * handling this. Updateproto will contain 6497d968cb8Sdougm * the name of the protocol that we want to 6507d968cb8Sdougm * update legacy files for. 6517d968cb8Sdougm */ 652da6c28aaSamw enable_group(group, zfs == NULL ? updateproto : NULL, 653da6c28aaSamw enable, work->proto); 654fe1c642dSBill Krier if (zfs != NULL) 655fe1c642dSBill Krier sa_free_attr_string(zfs); 656fe1c642dSBill Krier 65725a68471Sdougm for (subgroup = sa_get_sub_group(group); 65825a68471Sdougm subgroup != NULL; 6597d968cb8Sdougm subgroup = sa_get_next_group(subgroup)) { 6607d968cb8Sdougm /* never update legacy for ZFS subgroups */ 661da6c28aaSamw enable_group(subgroup, NULL, enable, 662da6c28aaSamw work->proto); 6636185db85Sdougm } 6646185db85Sdougm } 6656185db85Sdougm if (online) { 6666185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 6677d968cb8Sdougm name = sa_get_group_attr(group, "name"); 6686185db85Sdougm if (name != NULL) { 6696185db85Sdougm if (zfs == NULL) { 67025a68471Sdougm (void) snprintf(instance, 67125a68471Sdougm sizeof (instance), "%s:%s", 6726185db85Sdougm SA_SVC_FMRI_BASE, name); 6736185db85Sdougm state = smf_get_state(instance); 6746185db85Sdougm if (state == NULL || 6756185db85Sdougm strcmp(state, "online") != 0) { 67625a68471Sdougm (void) smf_enable_instance( 67725a68471Sdougm instance, 0); 6786185db85Sdougm free(state); 6796185db85Sdougm } 6806185db85Sdougm } else { 6816185db85Sdougm sa_free_attr_string(zfs); 6826185db85Sdougm zfs = NULL; 6836185db85Sdougm } 6846185db85Sdougm if (name != NULL) 6856185db85Sdougm sa_free_attr_string(name); 6866185db85Sdougm } 6876185db85Sdougm } 6886185db85Sdougm } 6896185db85Sdougm if (ret == SA_OK) { 690549ec3ffSdougm ret = sa_update_config(handle); 6916185db85Sdougm } 6926185db85Sdougm return (ret); 6936185db85Sdougm } 6946185db85Sdougm 6956185db85Sdougm /* 6966185db85Sdougm * chk_opt(optlistp, security, proto) 6976185db85Sdougm * 6986185db85Sdougm * Do a sanity check on the optlist provided for the protocol. This 6996185db85Sdougm * is a syntax check and verification that the property is either a 7006185db85Sdougm * general or specific to a names optionset. 7016185db85Sdougm */ 7026185db85Sdougm 7036185db85Sdougm static int 7046185db85Sdougm chk_opt(struct options *optlistp, int security, char *proto) 7056185db85Sdougm { 7066185db85Sdougm struct options *optlist; 7076185db85Sdougm char *sep = ""; 7086185db85Sdougm int notfirst = 0; 7096185db85Sdougm int ret; 7106185db85Sdougm 7116185db85Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 7126185db85Sdougm char *optname; 7136185db85Sdougm 7146185db85Sdougm optname = optlist->optname; 7156185db85Sdougm ret = OPT_ADD_OK; 7166185db85Sdougm /* extract property/value pair */ 7176185db85Sdougm if (sa_is_security(optname, proto)) { 7186185db85Sdougm if (!security) 7196185db85Sdougm ret = OPT_ADD_SECURITY; 7206185db85Sdougm } else { 7216185db85Sdougm if (security) 7226185db85Sdougm ret = OPT_ADD_PROPERTY; 7236185db85Sdougm } 7246185db85Sdougm if (ret != OPT_ADD_OK) { 7256185db85Sdougm if (notfirst == 0) 72625a68471Sdougm (void) printf( 72725a68471Sdougm gettext("Property syntax error: ")); 7286185db85Sdougm switch (ret) { 7296185db85Sdougm case OPT_ADD_SYNTAX: 7306185db85Sdougm (void) printf(gettext("%ssyntax error: %s"), 7316185db85Sdougm sep, optname); 7326185db85Sdougm sep = ", "; 7336185db85Sdougm break; 7346185db85Sdougm case OPT_ADD_SECURITY: 7356185db85Sdougm (void) printf(gettext("%s%s requires -S"), 7366185db85Sdougm optname, sep); 7376185db85Sdougm sep = ", "; 7386185db85Sdougm break; 7396185db85Sdougm case OPT_ADD_PROPERTY: 74025a68471Sdougm (void) printf( 74125a68471Sdougm gettext("%s%s not supported with -S"), 7426185db85Sdougm optname, sep); 7436185db85Sdougm sep = ", "; 7446185db85Sdougm break; 7456185db85Sdougm } 7466185db85Sdougm notfirst++; 7476185db85Sdougm } 7486185db85Sdougm } 7496185db85Sdougm if (notfirst) { 7506185db85Sdougm (void) printf("\n"); 7516185db85Sdougm ret = SA_SYNTAX_ERR; 7526185db85Sdougm } 7536185db85Sdougm return (ret); 7546185db85Sdougm } 7556185db85Sdougm 7566185db85Sdougm /* 7576185db85Sdougm * free_opt(optlist) 7586185db85Sdougm * Free the specified option list. 7596185db85Sdougm */ 7606185db85Sdougm static void 7616185db85Sdougm free_opt(struct options *optlist) 7626185db85Sdougm { 7636185db85Sdougm struct options *nextopt; 7646185db85Sdougm while (optlist != NULL) { 7656185db85Sdougm nextopt = optlist->next; 7666185db85Sdougm free(optlist); 7676185db85Sdougm optlist = nextopt; 7686185db85Sdougm } 7696185db85Sdougm } 7706185db85Sdougm 7716185db85Sdougm /* 7726185db85Sdougm * check property list for valid properties 7736185db85Sdougm * A null value is a remove which is always valid. 7746185db85Sdougm */ 7756185db85Sdougm static int 776687915e9Sdougm valid_options(sa_handle_t handle, struct options *optlist, char *proto, 777687915e9Sdougm void *object, char *sec) 7786185db85Sdougm { 7796185db85Sdougm int ret = SA_OK; 7806185db85Sdougm struct options *cur; 7816185db85Sdougm sa_property_t prop; 7826185db85Sdougm sa_optionset_t parent = NULL; 7836185db85Sdougm 7846185db85Sdougm if (object != NULL) { 7856185db85Sdougm if (sec == NULL) 7866185db85Sdougm parent = sa_get_optionset(object, proto); 7876185db85Sdougm else 7886185db85Sdougm parent = sa_get_security(object, sec, proto); 7896185db85Sdougm } 7906185db85Sdougm 7916185db85Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 79225a68471Sdougm if (cur->optvalue == NULL) 79325a68471Sdougm continue; 7946185db85Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 7956185db85Sdougm if (prop == NULL) 7966185db85Sdougm ret = SA_NO_MEMORY; 7976185db85Sdougm if (ret != SA_OK || 798687915e9Sdougm (ret = sa_valid_property(handle, parent, proto, prop)) != 799687915e9Sdougm SA_OK) { 80025a68471Sdougm (void) printf( 80125a68471Sdougm gettext("Could not add property %s: %s\n"), 80225a68471Sdougm cur->optname, sa_errorstr(ret)); 8036185db85Sdougm } 8046185db85Sdougm (void) sa_remove_property(prop); 8056185db85Sdougm } 8066185db85Sdougm return (ret); 8076185db85Sdougm } 8086185db85Sdougm 8096185db85Sdougm /* 8106185db85Sdougm * add_optionset(group, optlist, protocol, *err) 8116185db85Sdougm * Add the options in optlist to an optionset and then add the optionset 8126185db85Sdougm * to the group. 8136185db85Sdougm * 8146185db85Sdougm * The return value indicates if there was a "change" while errors are 8156185db85Sdougm * returned via the *err parameters. 8166185db85Sdougm */ 8176185db85Sdougm static int 8186185db85Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 8196185db85Sdougm { 8206185db85Sdougm sa_optionset_t optionset; 8216185db85Sdougm int ret = SA_OK; 822da6c28aaSamw int result = B_FALSE; 823687915e9Sdougm sa_handle_t handle; 8246185db85Sdougm 8256185db85Sdougm optionset = sa_get_optionset(group, proto); 8266185db85Sdougm if (optionset == NULL) { 8276185db85Sdougm optionset = sa_create_optionset(group, proto); 828da6c28aaSamw if (optionset == NULL) 829da6c28aaSamw ret = SA_NO_MEMORY; 830da6c28aaSamw result = B_TRUE; /* adding a protocol is a change */ 8316185db85Sdougm } 83225a68471Sdougm if (optionset == NULL) { 83325a68471Sdougm ret = SA_NO_MEMORY; 83425a68471Sdougm goto out; 83525a68471Sdougm } 836687915e9Sdougm handle = sa_find_group_handle(group); 837687915e9Sdougm if (handle == NULL) { 838687915e9Sdougm ret = SA_CONFIG_ERR; 839687915e9Sdougm goto out; 840687915e9Sdougm } 8416185db85Sdougm while (optlist != NULL) { 8426185db85Sdougm sa_property_t prop; 8436185db85Sdougm prop = sa_get_property(optionset, optlist->optname); 8446185db85Sdougm if (prop == NULL) { 8456185db85Sdougm /* 8466185db85Sdougm * add the property, but only if it is 8476185db85Sdougm * a non-NULL or non-zero length value 8486185db85Sdougm */ 8496185db85Sdougm if (optlist->optvalue != NULL) { 8506185db85Sdougm prop = sa_create_property(optlist->optname, 8516185db85Sdougm optlist->optvalue); 8526185db85Sdougm if (prop != NULL) { 853687915e9Sdougm ret = sa_valid_property(handle, 854687915e9Sdougm optionset, proto, prop); 8556185db85Sdougm if (ret != SA_OK) { 8566185db85Sdougm (void) sa_remove_property(prop); 85725a68471Sdougm (void) printf(gettext("Could " 85825a68471Sdougm "not add property " 8596185db85Sdougm "%s: %s\n"), 8606185db85Sdougm optlist->optname, 8616185db85Sdougm sa_errorstr(ret)); 8626185db85Sdougm } 8636185db85Sdougm } 8646185db85Sdougm if (ret == SA_OK) { 8656185db85Sdougm ret = sa_add_property(optionset, prop); 8666185db85Sdougm if (ret != SA_OK) { 86725a68471Sdougm (void) printf(gettext( 86825a68471Sdougm "Could not add property " 8696185db85Sdougm "%s: %s\n"), 8706185db85Sdougm optlist->optname, 8716185db85Sdougm sa_errorstr(ret)); 8726185db85Sdougm } else { 8736185db85Sdougm /* there was a change */ 874da6c28aaSamw result = B_TRUE; 8756185db85Sdougm } 8766185db85Sdougm } 8776185db85Sdougm } 8786185db85Sdougm } else { 8796185db85Sdougm ret = sa_update_property(prop, optlist->optvalue); 8806185db85Sdougm /* should check to see if value changed */ 8816185db85Sdougm if (ret != SA_OK) { 8826185db85Sdougm (void) printf(gettext("Could not update " 88325a68471Sdougm "property %s: %s\n"), optlist->optname, 8846185db85Sdougm sa_errorstr(ret)); 8856185db85Sdougm } else { 886da6c28aaSamw result = B_TRUE; 8876185db85Sdougm } 8886185db85Sdougm } 8896185db85Sdougm optlist = optlist->next; 8906185db85Sdougm } 8916185db85Sdougm ret = sa_commit_properties(optionset, 0); 89225a68471Sdougm 89325a68471Sdougm out: 8946185db85Sdougm if (err != NULL) 8956185db85Sdougm *err = ret; 8966185db85Sdougm return (result); 8976185db85Sdougm } 8986185db85Sdougm 8996185db85Sdougm /* 900da6c28aaSamw * resource_compliant(group) 901da6c28aaSamw * 902da6c28aaSamw * Go through all the shares in the group. Assume compliant, but if 903da6c28aaSamw * any share doesn't have at least one resource name, it isn't 904da6c28aaSamw * compliant. 905da6c28aaSamw */ 906da6c28aaSamw static int 907da6c28aaSamw resource_compliant(sa_group_t group) 908da6c28aaSamw { 909da6c28aaSamw sa_share_t share; 910da6c28aaSamw 911da6c28aaSamw for (share = sa_get_share(group, NULL); share != NULL; 912da6c28aaSamw share = sa_get_next_share(share)) { 913da6c28aaSamw if (sa_get_share_resource(share, NULL) == NULL) { 914da6c28aaSamw return (B_FALSE); 915da6c28aaSamw } 916da6c28aaSamw } 917da6c28aaSamw return (B_TRUE); 918da6c28aaSamw } 919da6c28aaSamw 920da6c28aaSamw /* 921da6c28aaSamw * fix_path(path) 922da6c28aaSamw * 923da6c28aaSamw * change all illegal characters to something else. For now, all get 924da6c28aaSamw * converted to '_' and the leading '/' is stripped off. This is used 925da6c28aaSamw * to construct an resource name (SMB share name) that is valid. 926da6c28aaSamw * Caller must pass a valid path. 927da6c28aaSamw */ 928da6c28aaSamw static void 929da6c28aaSamw fix_path(char *path) 930da6c28aaSamw { 931da6c28aaSamw char *cp; 932da6c28aaSamw size_t len; 933da6c28aaSamw 934da6c28aaSamw assert(path != NULL); 935da6c28aaSamw 936da6c28aaSamw /* make sure we are appropriate length */ 937da6c28aaSamw cp = path + 1; /* skip leading slash */ 938da6c28aaSamw while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) { 939da6c28aaSamw cp = strchr(cp, '/'); 940da6c28aaSamw if (cp != NULL) 941da6c28aaSamw cp++; 942da6c28aaSamw } 943da6c28aaSamw /* two cases - cp == NULL and cp is substring of path */ 944da6c28aaSamw if (cp == NULL) { 945da6c28aaSamw /* just take last SA_MAX_RESOURCE_NAME chars */ 946da6c28aaSamw len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME; 947da6c28aaSamw (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME); 948da6c28aaSamw path[SA_MAX_RESOURCE_NAME] = '\0'; 949da6c28aaSamw } else { 950da6c28aaSamw len = strlen(cp) + 1; 951da6c28aaSamw (void) memmove(path, cp, len); 952da6c28aaSamw } 953da6c28aaSamw 954da6c28aaSamw /* 955da6c28aaSamw * Don't want any of the characters that are not allowed 956da6c28aaSamw * in and SMB share name. Replace them with '_'. 957da6c28aaSamw */ 958da6c28aaSamw while (*path) { 959da6c28aaSamw switch (*path) { 960da6c28aaSamw case '/': 961da6c28aaSamw case '"': 962da6c28aaSamw case '\\': 963da6c28aaSamw case '[': 964da6c28aaSamw case ']': 965da6c28aaSamw case ':': 966da6c28aaSamw case '|': 967da6c28aaSamw case '<': 968da6c28aaSamw case '>': 969da6c28aaSamw case '+': 970da6c28aaSamw case ';': 971da6c28aaSamw case ',': 972da6c28aaSamw case '?': 973da6c28aaSamw case '*': 974da6c28aaSamw case '=': 975da6c28aaSamw case '\t': 976da6c28aaSamw *path = '_'; 977da6c28aaSamw break; 978da6c28aaSamw } 979da6c28aaSamw path++; 980da6c28aaSamw } 981da6c28aaSamw } 982da6c28aaSamw 983da6c28aaSamw /* 984da6c28aaSamw * name_adjust(path, count) 985da6c28aaSamw * 986da6c28aaSamw * Add a ~<count> in place of last few characters. The total number of 987da6c28aaSamw * characters is dependent on count. 988da6c28aaSamw */ 989da6c28aaSamw #define MAX_MANGLE_NUMBER 10000 990da6c28aaSamw 991da6c28aaSamw static int 992da6c28aaSamw name_adjust(char *path, int count) 993da6c28aaSamw { 994da6c28aaSamw size_t len; 995da6c28aaSamw 996da6c28aaSamw len = strlen(path) - 2; 997da6c28aaSamw if (count > 10) 998da6c28aaSamw len--; 999da6c28aaSamw if (count > 100) 1000da6c28aaSamw len--; 1001da6c28aaSamw if (count > 1000) 1002da6c28aaSamw len--; 1003da6c28aaSamw if (len > 0) 1004da6c28aaSamw (void) sprintf(path + len, "~%d", count); 1005da6c28aaSamw else 1006da6c28aaSamw return (SA_BAD_VALUE); 1007da6c28aaSamw 1008da6c28aaSamw return (SA_OK); 1009da6c28aaSamw } 1010da6c28aaSamw 1011da6c28aaSamw /* 1012da6c28aaSamw * make_resources(group) 1013da6c28aaSamw * 1014da6c28aaSamw * Go through all the shares in the group and make them have resource 1015da6c28aaSamw * names. 1016da6c28aaSamw */ 1017da6c28aaSamw static void 1018da6c28aaSamw make_resources(sa_group_t group) 1019da6c28aaSamw { 1020da6c28aaSamw sa_share_t share; 1021da6c28aaSamw int count; 1022da6c28aaSamw int err = SA_OK; 1023da6c28aaSamw 1024da6c28aaSamw for (share = sa_get_share(group, NULL); share != NULL; 1025da6c28aaSamw share = sa_get_next_share(share)) { 1026da6c28aaSamw /* Skip those with resources */ 1027da6c28aaSamw if (sa_get_share_resource(share, NULL) == NULL) { 1028da6c28aaSamw char *path; 1029da6c28aaSamw path = sa_get_share_attr(share, "path"); 1030da6c28aaSamw if (path == NULL) 1031da6c28aaSamw continue; 1032da6c28aaSamw fix_path(path); 1033da6c28aaSamw count = 0; /* reset for next resource */ 1034da6c28aaSamw while (sa_add_resource(share, path, 1035da6c28aaSamw SA_SHARE_PERMANENT, &err) == NULL && 1036da6c28aaSamw err == SA_DUPLICATE_NAME) { 1037da6c28aaSamw int ret; 1038da6c28aaSamw ret = name_adjust(path, count); 1039da6c28aaSamw count++; 1040da6c28aaSamw if (ret != SA_OK || 1041da6c28aaSamw count >= MAX_MANGLE_NUMBER) { 1042da6c28aaSamw (void) printf(gettext( 1043da6c28aaSamw "Cannot create resource name for" 1044da6c28aaSamw " path: %s\n"), path); 1045da6c28aaSamw break; 1046da6c28aaSamw } 1047da6c28aaSamw } 1048da6c28aaSamw sa_free_attr_string(path); 1049da6c28aaSamw } 1050da6c28aaSamw } 1051da6c28aaSamw } 1052da6c28aaSamw 1053da6c28aaSamw /* 10549e5da854Sdougm * check_valid_group(group, protocol) 10559e5da854Sdougm * 10569e5da854Sdougm * Check to see that the group should have the protocol added (if 10579e5da854Sdougm * there is one specified). 10589e5da854Sdougm */ 10599e5da854Sdougm 10609e5da854Sdougm static int 10619e5da854Sdougm check_valid_group(sa_group_t group, char *groupname, char *protocol) 10629e5da854Sdougm { 10639e5da854Sdougm 10649e5da854Sdougm if (protocol != NULL) { 10659e5da854Sdougm if (has_protocol(group, protocol)) { 10669e5da854Sdougm (void) printf(gettext( 10679e5da854Sdougm "Group \"%s\" already exists" 10689e5da854Sdougm " with protocol %s\n"), groupname, 10699e5da854Sdougm protocol); 10709e5da854Sdougm return (SA_DUPLICATE_NAME); 10719e5da854Sdougm } else if (strcmp(groupname, "default") == 0 && 10729e5da854Sdougm strcmp(protocol, "nfs") != 0) { 10739e5da854Sdougm (void) printf(gettext( 10749e5da854Sdougm "Group \"%s\" only allows protocol " 10759e5da854Sdougm "\"%s\"\n"), groupname, "nfs"); 10769e5da854Sdougm return (SA_INVALID_PROTOCOL); 10779e5da854Sdougm } 10789e5da854Sdougm } else { 10799e5da854Sdougm /* must add new protocol */ 10809e5da854Sdougm (void) printf(gettext( 10819e5da854Sdougm "Group already exists and no protocol " 10829e5da854Sdougm "specified.\n")); 10839e5da854Sdougm return (SA_DUPLICATE_NAME); 10849e5da854Sdougm } 10859e5da854Sdougm return (SA_OK); 10869e5da854Sdougm } 10879e5da854Sdougm 10889e5da854Sdougm /* 10899e5da854Sdougm * enforce_featureset(group, protocol, dryrun, force) 10909e5da854Sdougm * 10919e5da854Sdougm * Check the protocol featureset against the group and enforce any 10929e5da854Sdougm * rules that might be imposed. 10939e5da854Sdougm */ 10949e5da854Sdougm 10959e5da854Sdougm static int 10969e5da854Sdougm enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun, 10979e5da854Sdougm boolean_t force) 10989e5da854Sdougm { 10999e5da854Sdougm uint64_t features; 11009e5da854Sdougm 11019e5da854Sdougm if (protocol == NULL) 11029e5da854Sdougm return (SA_OK); 11039e5da854Sdougm 11049e5da854Sdougm /* 11059e5da854Sdougm * First check to see if specified protocol is one we want to 11069e5da854Sdougm * allow on a group. Only server protocols are allowed here. 11079e5da854Sdougm */ 11089e5da854Sdougm features = sa_proto_get_featureset(protocol); 11099e5da854Sdougm if (!(features & SA_FEATURE_SERVER)) { 11109e5da854Sdougm (void) printf( 11119e5da854Sdougm gettext("Protocol \"%s\" not supported.\n"), protocol); 11129e5da854Sdougm return (SA_INVALID_PROTOCOL); 11139e5da854Sdougm } 11149e5da854Sdougm 11159e5da854Sdougm /* 11169e5da854Sdougm * Check to see if the new protocol is one that requires 11179e5da854Sdougm * resource names and make sure we are compliant before 11189e5da854Sdougm * proceeding. 11199e5da854Sdougm */ 11209e5da854Sdougm if ((features & SA_FEATURE_RESOURCE) && 11219e5da854Sdougm !resource_compliant(group)) { 11229e5da854Sdougm if (force && !dryrun) { 11239e5da854Sdougm make_resources(group); 11249e5da854Sdougm } else { 11259e5da854Sdougm (void) printf( 11269e5da854Sdougm gettext("Protocol requires resource names to be " 11279e5da854Sdougm "set: %s\n"), protocol); 11289e5da854Sdougm return (SA_RESOURCE_REQUIRED); 11299e5da854Sdougm } 11309e5da854Sdougm } 11319e5da854Sdougm return (SA_OK); 11329e5da854Sdougm } 11339e5da854Sdougm 11349e5da854Sdougm /* 11359e5da854Sdougm * set_all_protocols(group) 11369e5da854Sdougm * 11379e5da854Sdougm * Get the list of all protocols and add all server protocols to the 11389e5da854Sdougm * group. 11399e5da854Sdougm */ 11409e5da854Sdougm 11419e5da854Sdougm static int 11429e5da854Sdougm set_all_protocols(sa_group_t group) 11439e5da854Sdougm { 11449e5da854Sdougm char **protolist; 11459e5da854Sdougm int numprotos, i; 11469e5da854Sdougm uint64_t features; 11479e5da854Sdougm sa_optionset_t optionset; 11489e5da854Sdougm int ret = SA_OK; 11499e5da854Sdougm 11509e5da854Sdougm /* 11519e5da854Sdougm * Now make sure we really want to put this protocol on a 11529e5da854Sdougm * group. Only server protocols can go here. 11539e5da854Sdougm */ 11549e5da854Sdougm numprotos = sa_get_protocols(&protolist); 11559e5da854Sdougm for (i = 0; i < numprotos; i++) { 11569e5da854Sdougm features = sa_proto_get_featureset(protolist[i]); 11579e5da854Sdougm if (features & SA_FEATURE_SERVER) { 11589e5da854Sdougm optionset = sa_create_optionset(group, protolist[i]); 11599e5da854Sdougm if (optionset == NULL) { 11609e5da854Sdougm ret = SA_NO_MEMORY; 11619e5da854Sdougm break; 11629e5da854Sdougm } 11639e5da854Sdougm } 11649e5da854Sdougm } 11659e5da854Sdougm 11669e5da854Sdougm if (protolist != NULL) 11679e5da854Sdougm free(protolist); 11689e5da854Sdougm 11699e5da854Sdougm return (ret); 11709e5da854Sdougm } 11719e5da854Sdougm 11729e5da854Sdougm /* 11736185db85Sdougm * sa_create(flags, argc, argv) 11746185db85Sdougm * create a new group 11756185db85Sdougm * this may or may not have a protocol associated with it. 11766185db85Sdougm * No protocol means "all" protocols in this case. 11776185db85Sdougm */ 11786185db85Sdougm static int 1179549ec3ffSdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[]) 11806185db85Sdougm { 11816185db85Sdougm char *groupname; 11826185db85Sdougm 11836185db85Sdougm sa_group_t group; 11849e5da854Sdougm boolean_t force = B_FALSE; 11859e5da854Sdougm boolean_t verbose = B_FALSE; 11869e5da854Sdougm boolean_t dryrun = B_FALSE; 11876185db85Sdougm int c; 11886185db85Sdougm char *protocol = NULL; 11896185db85Sdougm int ret = SA_OK; 11906185db85Sdougm struct options *optlist = NULL; 1191e7bab347Sdougm int err = SA_OK; 11926185db85Sdougm int auth; 11939e5da854Sdougm boolean_t created = B_FALSE; 11946185db85Sdougm 1195da6c28aaSamw while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) { 11966185db85Sdougm switch (c) { 1197da6c28aaSamw case 'f': 11989e5da854Sdougm force = B_TRUE; 1199da6c28aaSamw break; 12006185db85Sdougm case 'v': 12019e5da854Sdougm verbose = B_TRUE; 12026185db85Sdougm break; 12036185db85Sdougm case 'n': 12049e5da854Sdougm dryrun = B_TRUE; 12056185db85Sdougm break; 12066185db85Sdougm case 'P': 1207da6c28aaSamw if (protocol != NULL) { 1208da6c28aaSamw (void) printf(gettext("Specifying " 1209da6c28aaSamw "multiple protocols " 1210da6c28aaSamw "not supported: %s\n"), protocol); 1211da6c28aaSamw return (SA_SYNTAX_ERR); 1212da6c28aaSamw } 12136185db85Sdougm protocol = optarg; 121425a68471Sdougm if (sa_valid_protocol(protocol)) 121525a68471Sdougm break; 121625a68471Sdougm (void) printf(gettext( 121725a68471Sdougm "Invalid protocol specified: %s\n"), protocol); 12186185db85Sdougm return (SA_INVALID_PROTOCOL); 12196185db85Sdougm break; 12206185db85Sdougm case 'p': 12216185db85Sdougm ret = add_opt(&optlist, optarg, 0); 12226185db85Sdougm switch (ret) { 12236185db85Sdougm case OPT_ADD_SYNTAX: 122425a68471Sdougm (void) printf(gettext( 122525a68471Sdougm "Property syntax error for property: %s\n"), 12266185db85Sdougm optarg); 12276185db85Sdougm return (SA_SYNTAX_ERR); 12286185db85Sdougm case OPT_ADD_SECURITY: 122925a68471Sdougm (void) printf(gettext( 123025a68471Sdougm "Security properties need " 12316185db85Sdougm "to be set with set-security: %s\n"), 12326185db85Sdougm optarg); 12336185db85Sdougm return (SA_SYNTAX_ERR); 12346185db85Sdougm default: 12356185db85Sdougm break; 12366185db85Sdougm } 12376185db85Sdougm break; 1238e7bab347Sdougm case 'h': 1239e7bab347Sdougm /* optopt on valid arg isn't defined */ 1240e7bab347Sdougm optopt = c; 1241e7bab347Sdougm /*FALLTHROUGH*/ 1242e7bab347Sdougm case '?': 12436185db85Sdougm default: 1244e7bab347Sdougm /* 1245e7bab347Sdougm * Since a bad option gets to here, sort it 1246e7bab347Sdougm * out and return a syntax error return value 1247e7bab347Sdougm * if necessary. 1248e7bab347Sdougm */ 1249e7bab347Sdougm switch (optopt) { 1250e7bab347Sdougm default: 1251e7bab347Sdougm err = SA_SYNTAX_ERR; 1252e7bab347Sdougm break; 12536185db85Sdougm case 'h': 12546185db85Sdougm case '?': 1255e7bab347Sdougm break; 1256e7bab347Sdougm } 12576185db85Sdougm (void) printf(gettext("usage: %s\n"), 12586185db85Sdougm sa_get_usage(USAGE_CREATE)); 1259e7bab347Sdougm return (err); 12606185db85Sdougm } 12616185db85Sdougm } 12626185db85Sdougm 12636185db85Sdougm if (optind >= argc) { 126425a68471Sdougm (void) printf(gettext("usage: %s\n"), 126525a68471Sdougm sa_get_usage(USAGE_CREATE)); 12666185db85Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 12676185db85Sdougm return (SA_BAD_PATH); 12686185db85Sdougm } 12696185db85Sdougm 12706185db85Sdougm if ((optind + 1) < argc) { 127125a68471Sdougm (void) printf(gettext("usage: %s\n"), 127225a68471Sdougm sa_get_usage(USAGE_CREATE)); 12736185db85Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 12746185db85Sdougm return (SA_SYNTAX_ERR); 12756185db85Sdougm } 12766185db85Sdougm 12776185db85Sdougm if (protocol == NULL && optlist != NULL) { 12786185db85Sdougm /* lookup default protocol */ 127925a68471Sdougm (void) printf(gettext("usage: %s\n"), 128025a68471Sdougm sa_get_usage(USAGE_CREATE)); 12816185db85Sdougm (void) printf(gettext("\tprotocol must be specified " 12826185db85Sdougm "with properties\n")); 12836185db85Sdougm return (SA_INVALID_PROTOCOL); 12846185db85Sdougm } 12856185db85Sdougm 12866185db85Sdougm if (optlist != NULL) 12876185db85Sdougm ret = chk_opt(optlist, 0, protocol); 12886185db85Sdougm if (ret == OPT_ADD_SECURITY) { 12896185db85Sdougm (void) printf(gettext("Security properties not " 12906185db85Sdougm "supported with create\n")); 12916185db85Sdougm return (SA_SYNTAX_ERR); 12926185db85Sdougm } 12936185db85Sdougm 12946185db85Sdougm /* 129525a68471Sdougm * If a group already exists, we can only add a new protocol 12966185db85Sdougm * to it and not create a new one or add the same protocol 12976185db85Sdougm * again. 12986185db85Sdougm */ 12996185db85Sdougm 13006185db85Sdougm groupname = argv[optind]; 13016185db85Sdougm 13026185db85Sdougm auth = check_authorizations(groupname, flags); 13036185db85Sdougm 1304549ec3ffSdougm group = sa_get_group(handle, groupname); 13056185db85Sdougm if (group != NULL) { 13066185db85Sdougm /* group exists so must be a protocol add */ 13079e5da854Sdougm ret = check_valid_group(group, groupname, protocol); 13086185db85Sdougm } else { 13096185db85Sdougm /* 13106185db85Sdougm * is it a valid name? Must comply with SMF instance 13116185db85Sdougm * name restrictions. 13126185db85Sdougm */ 13136185db85Sdougm if (!sa_valid_group_name(groupname)) { 13146185db85Sdougm ret = SA_INVALID_NAME; 131525a68471Sdougm (void) printf(gettext("Invalid group name: %s\n"), 131625a68471Sdougm groupname); 13176185db85Sdougm } 13186185db85Sdougm } 13196185db85Sdougm if (ret == SA_OK) { 13206185db85Sdougm /* check protocol vs optlist */ 13216185db85Sdougm if (optlist != NULL) { 13226185db85Sdougm /* check options, if any, for validity */ 1323687915e9Sdougm ret = valid_options(handle, optlist, protocol, 1324687915e9Sdougm group, NULL); 13256185db85Sdougm } 13266185db85Sdougm } 13276185db85Sdougm if (ret == SA_OK && !dryrun) { 13286185db85Sdougm if (group == NULL) { 132925a68471Sdougm group = sa_create_group(handle, (char *)groupname, 133025a68471Sdougm &err); 13319e5da854Sdougm created = B_TRUE; 13326185db85Sdougm } 13336185db85Sdougm if (group != NULL) { 13346185db85Sdougm sa_optionset_t optionset; 1335da6c28aaSamw 13369e5da854Sdougm /* 13379e5da854Sdougm * Check group and protocol against featureset 13389e5da854Sdougm * requirements. 13399e5da854Sdougm */ 13409e5da854Sdougm ret = enforce_featureset(group, protocol, 13419e5da854Sdougm dryrun, force); 13429e5da854Sdougm if (ret != SA_OK) 1343da6c28aaSamw goto err; 13449e5da854Sdougm 13459e5da854Sdougm /* 13469e5da854Sdougm * So far so good. Now add the required 13479e5da854Sdougm * optionset(s) to the group. 13489e5da854Sdougm */ 13496185db85Sdougm if (optlist != NULL) { 135025a68471Sdougm (void) add_optionset(group, optlist, protocol, 135125a68471Sdougm &ret); 13526185db85Sdougm } else if (protocol != NULL) { 135325a68471Sdougm optionset = sa_create_optionset(group, 135425a68471Sdougm protocol); 13556185db85Sdougm if (optionset == NULL) 13566185db85Sdougm ret = SA_NO_MEMORY; 13576185db85Sdougm } else if (protocol == NULL) { 13589e5da854Sdougm /* default group create so add all protocols */ 13599e5da854Sdougm ret = set_all_protocols(group); 13606185db85Sdougm } 13616185db85Sdougm /* 136225a68471Sdougm * We have a group and legal additions 13636185db85Sdougm */ 13646185db85Sdougm if (ret == SA_OK) { 13656185db85Sdougm /* 136625a68471Sdougm * Commit to configuration for protocols that 13676185db85Sdougm * need to do block updates. For NFS, this 13686185db85Sdougm * doesn't do anything but it will be run for 13696185db85Sdougm * all protocols that implement the 13706185db85Sdougm * appropriate plugin. 13716185db85Sdougm */ 1372549ec3ffSdougm ret = sa_update_config(handle); 13736185db85Sdougm } else { 13746185db85Sdougm if (group != NULL) 13756185db85Sdougm (void) sa_remove_group(group); 13766185db85Sdougm } 13776185db85Sdougm } else { 13786185db85Sdougm ret = err; 13796185db85Sdougm (void) printf(gettext("Could not create group: %s\n"), 13806185db85Sdougm sa_errorstr(ret)); 13816185db85Sdougm } 13826185db85Sdougm } 13836185db85Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 13846185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 13856185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 13866185db85Sdougm ret = SA_NO_PERMISSION; 13876185db85Sdougm } 1388da6c28aaSamw err: 13899e5da854Sdougm if (ret != SA_OK && created) 13909e5da854Sdougm ret = sa_remove_group(group); 13919e5da854Sdougm 13926185db85Sdougm free_opt(optlist); 13936185db85Sdougm return (ret); 13946185db85Sdougm } 13956185db85Sdougm 13966185db85Sdougm /* 13976185db85Sdougm * group_status(group) 13986185db85Sdougm * 13996185db85Sdougm * return the current status (enabled/disabled) of the group. 14006185db85Sdougm */ 14016185db85Sdougm 14026185db85Sdougm static char * 14036185db85Sdougm group_status(sa_group_t group) 14046185db85Sdougm { 14056185db85Sdougm char *state; 14066185db85Sdougm int enabled = 0; 14076185db85Sdougm 14086185db85Sdougm state = sa_get_group_attr(group, "state"); 14096185db85Sdougm if (state != NULL) { 14106185db85Sdougm if (strcmp(state, "enabled") == 0) { 14116185db85Sdougm enabled = 1; 14126185db85Sdougm } 14136185db85Sdougm sa_free_attr_string(state); 14146185db85Sdougm } 14154db300d5Sdougm return (enabled ? "enabled" : "disabled"); 14166185db85Sdougm } 14176185db85Sdougm 14186185db85Sdougm /* 14196185db85Sdougm * sa_delete(flags, argc, argv) 14206185db85Sdougm * 14216185db85Sdougm * Delete a group. 14226185db85Sdougm */ 14236185db85Sdougm 14246185db85Sdougm static int 1425549ec3ffSdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[]) 14266185db85Sdougm { 14276185db85Sdougm char *groupname; 14286185db85Sdougm sa_group_t group; 14296185db85Sdougm sa_share_t share; 14306185db85Sdougm int verbose = 0; 14316185db85Sdougm int dryrun = 0; 14326185db85Sdougm int force = 0; 14336185db85Sdougm int c; 14346185db85Sdougm char *protocol = NULL; 14356185db85Sdougm char *sectype = NULL; 14366185db85Sdougm int ret = SA_OK; 14376185db85Sdougm int auth; 14386185db85Sdougm 14396185db85Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 14406185db85Sdougm switch (c) { 14416185db85Sdougm case 'v': 14426185db85Sdougm verbose++; 14436185db85Sdougm break; 14446185db85Sdougm case 'n': 14456185db85Sdougm dryrun++; 14466185db85Sdougm break; 14476185db85Sdougm case 'P': 1448da6c28aaSamw if (protocol != NULL) { 1449da6c28aaSamw (void) printf(gettext("Specifying " 1450da6c28aaSamw "multiple protocols " 1451da6c28aaSamw "not supported: %s\n"), protocol); 1452da6c28aaSamw return (SA_SYNTAX_ERR); 1453da6c28aaSamw } 14546185db85Sdougm protocol = optarg; 14556185db85Sdougm if (!sa_valid_protocol(protocol)) { 145625a68471Sdougm (void) printf(gettext("Invalid protocol " 145725a68471Sdougm "specified: %s\n"), protocol); 14586185db85Sdougm return (SA_INVALID_PROTOCOL); 14596185db85Sdougm } 14606185db85Sdougm break; 14616185db85Sdougm case 'S': 1462da6c28aaSamw if (sectype != NULL) { 1463da6c28aaSamw (void) printf(gettext("Specifying " 1464da6c28aaSamw "multiple property " 1465da6c28aaSamw "spaces not supported: %s\n"), sectype); 1466da6c28aaSamw return (SA_SYNTAX_ERR); 1467da6c28aaSamw } 14686185db85Sdougm sectype = optarg; 14696185db85Sdougm break; 14706185db85Sdougm case 'f': 14716185db85Sdougm force++; 14726185db85Sdougm break; 1473e7bab347Sdougm case 'h': 1474e7bab347Sdougm /* optopt on valid arg isn't defined */ 1475e7bab347Sdougm optopt = c; 1476e7bab347Sdougm /*FALLTHROUGH*/ 1477e7bab347Sdougm case '?': 14786185db85Sdougm default: 1479e7bab347Sdougm /* 1480e7bab347Sdougm * Since a bad option gets to here, sort it 1481e7bab347Sdougm * out and return a syntax error return value 1482e7bab347Sdougm * if necessary. 1483e7bab347Sdougm */ 1484e7bab347Sdougm switch (optopt) { 1485e7bab347Sdougm default: 1486e7bab347Sdougm ret = SA_SYNTAX_ERR; 1487e7bab347Sdougm break; 14886185db85Sdougm case 'h': 14896185db85Sdougm case '?': 1490e7bab347Sdougm break; 1491e7bab347Sdougm } 14926185db85Sdougm (void) printf(gettext("usage: %s\n"), 14936185db85Sdougm sa_get_usage(USAGE_DELETE)); 1494e7bab347Sdougm return (ret); 14956185db85Sdougm } 14966185db85Sdougm } 14976185db85Sdougm 14986185db85Sdougm if (optind >= argc) { 149925a68471Sdougm (void) printf(gettext("usage: %s\n"), 150025a68471Sdougm sa_get_usage(USAGE_DELETE)); 15016185db85Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 15026185db85Sdougm return (SA_SYNTAX_ERR); 15036185db85Sdougm } 15046185db85Sdougm 15056185db85Sdougm if ((optind + 1) < argc) { 150625a68471Sdougm (void) printf(gettext("usage: %s\n"), 150725a68471Sdougm sa_get_usage(USAGE_DELETE)); 15086185db85Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 15096185db85Sdougm return (SA_SYNTAX_ERR); 15106185db85Sdougm } 15116185db85Sdougm 15126185db85Sdougm if (sectype != NULL && protocol == NULL) { 151325a68471Sdougm (void) printf(gettext("usage: %s\n"), 151425a68471Sdougm sa_get_usage(USAGE_DELETE)); 15156185db85Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 15166185db85Sdougm "specified.\n")); 15176185db85Sdougm return (SA_SYNTAX_ERR); 15186185db85Sdougm } 15196185db85Sdougm 15206185db85Sdougm /* 15216185db85Sdougm * Determine if the group already exists since it must in 15226185db85Sdougm * order to be removed. 15236185db85Sdougm * 15246185db85Sdougm * We can delete when: 15256185db85Sdougm * 15266185db85Sdougm * - group is empty 15276185db85Sdougm * - force flag is set 15286185db85Sdougm * - if protocol specified, only delete the protocol 15296185db85Sdougm */ 15306185db85Sdougm 15316185db85Sdougm groupname = argv[optind]; 1532549ec3ffSdougm group = sa_get_group(handle, groupname); 15336185db85Sdougm if (group == NULL) { 15346185db85Sdougm ret = SA_NO_SUCH_GROUP; 153525a68471Sdougm goto done; 153625a68471Sdougm } 15376185db85Sdougm auth = check_authorizations(groupname, flags); 15386185db85Sdougm if (protocol == NULL) { 15396185db85Sdougm share = sa_get_share(group, NULL); 15406185db85Sdougm if (share != NULL) 15416185db85Sdougm ret = SA_BUSY; 15426185db85Sdougm if (share == NULL || (share != NULL && force == 1)) { 15436185db85Sdougm ret = SA_OK; 15446185db85Sdougm if (!dryrun) { 15456185db85Sdougm while (share != NULL) { 15466185db85Sdougm sa_share_t next_share; 15476185db85Sdougm next_share = sa_get_next_share(share); 15486185db85Sdougm /* 154925a68471Sdougm * need to do the disable of 155025a68471Sdougm * each share, but don't 155125a68471Sdougm * actually do anything on a 155225a68471Sdougm * dryrun. 15536185db85Sdougm */ 15546185db85Sdougm ret = sa_disable_share(share, NULL); 15556185db85Sdougm ret = sa_remove_share(share); 15566185db85Sdougm share = next_share; 15576185db85Sdougm } 15586185db85Sdougm ret = sa_remove_group(group); 15596185db85Sdougm } 15606185db85Sdougm } 156125a68471Sdougm /* Commit to configuration if not a dryrun */ 15626185db85Sdougm if (!dryrun && ret == SA_OK) { 1563549ec3ffSdougm ret = sa_update_config(handle); 15646185db85Sdougm } 15656185db85Sdougm } else { 15666185db85Sdougm /* a protocol delete */ 15676185db85Sdougm sa_optionset_t optionset; 15686185db85Sdougm sa_security_t security; 15696185db85Sdougm if (sectype != NULL) { 15706185db85Sdougm /* only delete specified security */ 15716185db85Sdougm security = sa_get_security(group, sectype, protocol); 157225a68471Sdougm if (security != NULL && !dryrun) 15736185db85Sdougm ret = sa_destroy_security(security); 157425a68471Sdougm else 15756185db85Sdougm ret = SA_INVALID_PROTOCOL; 15766185db85Sdougm } else { 15776185db85Sdougm optionset = sa_get_optionset(group, protocol); 15786185db85Sdougm if (optionset != NULL && !dryrun) { 157925a68471Sdougm /* 158025a68471Sdougm * have an optionset with 158125a68471Sdougm * protocol to delete 158225a68471Sdougm */ 15836185db85Sdougm ret = sa_destroy_optionset(optionset); 15846185db85Sdougm /* 158525a68471Sdougm * Now find all security sets 158625a68471Sdougm * for the protocol and remove 158725a68471Sdougm * them. Don't remove other 15886185db85Sdougm * protocols. 15896185db85Sdougm */ 159025a68471Sdougm for (security = 159125a68471Sdougm sa_get_security(group, NULL, NULL); 15926185db85Sdougm ret == SA_OK && security != NULL; 15936185db85Sdougm security = sa_get_next_security(security)) { 15946185db85Sdougm char *secprot; 159525a68471Sdougm secprot = sa_get_security_attr(security, 159625a68471Sdougm "type"); 15976185db85Sdougm if (secprot != NULL && 15986185db85Sdougm strcmp(secprot, protocol) == 0) 159925a68471Sdougm ret = sa_destroy_security( 160025a68471Sdougm security); 16016185db85Sdougm if (secprot != NULL) 16026185db85Sdougm sa_free_attr_string(secprot); 16036185db85Sdougm } 16046185db85Sdougm } else { 16056185db85Sdougm if (!dryrun) 16066185db85Sdougm ret = SA_INVALID_PROTOCOL; 16076185db85Sdougm } 16086185db85Sdougm } 1609da6c28aaSamw /* 1610da6c28aaSamw * With the protocol items removed, make sure that all 1611da6c28aaSamw * the shares are updated in the legacy files, if 1612da6c28aaSamw * necessary. 1613da6c28aaSamw */ 1614da6c28aaSamw for (share = sa_get_share(group, NULL); 1615da6c28aaSamw share != NULL; 1616da6c28aaSamw share = sa_get_next_share(share)) { 1617da6c28aaSamw (void) sa_delete_legacy(share, protocol); 1618da6c28aaSamw } 16196185db85Sdougm } 162025a68471Sdougm 162125a68471Sdougm done: 16226185db85Sdougm if (ret != SA_OK) { 16236185db85Sdougm (void) printf(gettext("Could not delete group: %s\n"), 16246185db85Sdougm sa_errorstr(ret)); 16256185db85Sdougm } else if (dryrun && !auth && verbose) { 16266185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 16276185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 16286185db85Sdougm } 16296185db85Sdougm return (ret); 16306185db85Sdougm } 16316185db85Sdougm 16326185db85Sdougm /* 16336185db85Sdougm * strndupr(*buff, str, buffsize) 16346185db85Sdougm * 16356185db85Sdougm * used with small strings to duplicate and possibly increase the 16366185db85Sdougm * buffer size of a string. 16376185db85Sdougm */ 16386185db85Sdougm static char * 16396185db85Sdougm strndupr(char *buff, char *str, int *buffsize) 16406185db85Sdougm { 16416185db85Sdougm int limit; 16426185db85Sdougm char *orig_buff = buff; 16436185db85Sdougm 16446185db85Sdougm if (buff == NULL) { 16456185db85Sdougm buff = (char *)malloc(64); 16466185db85Sdougm if (buff == NULL) 16476185db85Sdougm return (NULL); 16486185db85Sdougm *buffsize = 64; 16496185db85Sdougm buff[0] = '\0'; 16506185db85Sdougm } 16516185db85Sdougm limit = strlen(buff) + strlen(str) + 1; 16526185db85Sdougm if (limit > *buffsize) { 16536185db85Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 16546185db85Sdougm buff = realloc(buff, limit); 16556185db85Sdougm } 16566185db85Sdougm if (buff != NULL) { 16576185db85Sdougm (void) strcat(buff, str); 16586185db85Sdougm } else { 16596185db85Sdougm /* if it fails, fail it hard */ 16606185db85Sdougm if (orig_buff != NULL) 16616185db85Sdougm free(orig_buff); 16626185db85Sdougm } 16636185db85Sdougm return (buff); 16646185db85Sdougm } 16656185db85Sdougm 16666185db85Sdougm /* 16676185db85Sdougm * group_proto(group) 16686185db85Sdougm * 16696185db85Sdougm * return a string of all the protocols (space separated) associated 16706185db85Sdougm * with this group. 16716185db85Sdougm */ 16726185db85Sdougm 16736185db85Sdougm static char * 16746185db85Sdougm group_proto(sa_group_t group) 16756185db85Sdougm { 16766185db85Sdougm sa_optionset_t optionset; 16776185db85Sdougm char *proto; 16786185db85Sdougm char *buff = NULL; 16796185db85Sdougm int buffsize = 0; 16806185db85Sdougm int addspace = 0; 16816185db85Sdougm /* 16826185db85Sdougm * get the protocol list by finding the optionsets on this 16836185db85Sdougm * group and extracting the type value. The initial call to 16846185db85Sdougm * strndupr() initailizes buff. 16856185db85Sdougm */ 16866185db85Sdougm buff = strndupr(buff, "", &buffsize); 16876185db85Sdougm if (buff != NULL) { 16886185db85Sdougm for (optionset = sa_get_optionset(group, NULL); 16896185db85Sdougm optionset != NULL && buff != NULL; 16906185db85Sdougm optionset = sa_get_next_optionset(optionset)) { 16916185db85Sdougm /* 16926185db85Sdougm * extract out the protocol type from this optionset 16936185db85Sdougm * and append it to the buffer "buff". strndupr() will 16946185db85Sdougm * reallocate space as necessay. 16956185db85Sdougm */ 16966185db85Sdougm proto = sa_get_optionset_attr(optionset, "type"); 16976185db85Sdougm if (proto != NULL) { 16986185db85Sdougm if (addspace++) 16996185db85Sdougm buff = strndupr(buff, " ", &buffsize); 17006185db85Sdougm buff = strndupr(buff, proto, &buffsize); 17016185db85Sdougm sa_free_attr_string(proto); 17026185db85Sdougm } 17036185db85Sdougm } 17046185db85Sdougm } 17056185db85Sdougm return (buff); 17066185db85Sdougm } 17076185db85Sdougm 17086185db85Sdougm /* 17096185db85Sdougm * sa_list(flags, argc, argv) 17106185db85Sdougm * 17116185db85Sdougm * implements the "list" subcommand to list groups and optionally 17126185db85Sdougm * their state and protocols. 17136185db85Sdougm */ 17146185db85Sdougm 17156185db85Sdougm static int 1716549ec3ffSdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[]) 17176185db85Sdougm { 17186185db85Sdougm sa_group_t group; 17196185db85Sdougm int verbose = 0; 17206185db85Sdougm int c; 17216185db85Sdougm char *protocol = NULL; 1722e7bab347Sdougm int ret = SA_OK; 1723da6c28aaSamw #ifdef lint 1724da6c28aaSamw flags = flags; 1725da6c28aaSamw #endif 17266185db85Sdougm 17276185db85Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 17286185db85Sdougm switch (c) { 17296185db85Sdougm case 'v': 17306185db85Sdougm verbose++; 17316185db85Sdougm break; 17326185db85Sdougm case 'P': 1733da6c28aaSamw if (protocol != NULL) { 1734da6c28aaSamw (void) printf(gettext( 1735da6c28aaSamw "Specifying multiple protocols " 1736da6c28aaSamw "not supported: %s\n"), 1737da6c28aaSamw protocol); 1738da6c28aaSamw return (SA_SYNTAX_ERR); 1739da6c28aaSamw } 17406185db85Sdougm protocol = optarg; 17416185db85Sdougm if (!sa_valid_protocol(protocol)) { 174225a68471Sdougm (void) printf(gettext( 174325a68471Sdougm "Invalid protocol specified: %s\n"), 17446185db85Sdougm protocol); 17456185db85Sdougm return (SA_INVALID_PROTOCOL); 17466185db85Sdougm } 17476185db85Sdougm break; 1748e7bab347Sdougm case 'h': 1749e7bab347Sdougm /* optopt on valid arg isn't defined */ 1750e7bab347Sdougm optopt = c; 1751e7bab347Sdougm /*FALLTHROUGH*/ 1752e7bab347Sdougm case '?': 17536185db85Sdougm default: 1754e7bab347Sdougm /* 1755e7bab347Sdougm * Since a bad option gets to here, sort it 1756e7bab347Sdougm * out and return a syntax error return value 1757e7bab347Sdougm * if necessary. 1758e7bab347Sdougm */ 1759e7bab347Sdougm switch (optopt) { 1760e7bab347Sdougm default: 1761e7bab347Sdougm ret = SA_SYNTAX_ERR; 1762e7bab347Sdougm break; 17636185db85Sdougm case 'h': 17646185db85Sdougm case '?': 1765e7bab347Sdougm break; 1766e7bab347Sdougm } 176725a68471Sdougm (void) printf(gettext("usage: %s\n"), 176825a68471Sdougm sa_get_usage(USAGE_LIST)); 1769e7bab347Sdougm return (ret); 17706185db85Sdougm } 17716185db85Sdougm } 17726185db85Sdougm 1773573b0c00Sdougm if (optind != argc) { 1774573b0c00Sdougm (void) printf(gettext("usage: %s\n"), 1775573b0c00Sdougm sa_get_usage(USAGE_LIST)); 1776573b0c00Sdougm return (SA_SYNTAX_ERR); 1777573b0c00Sdougm } 1778573b0c00Sdougm 177925a68471Sdougm for (group = sa_get_group(handle, NULL); 178025a68471Sdougm group != NULL; 17816185db85Sdougm group = sa_get_next_group(group)) { 17826185db85Sdougm char *name; 17836185db85Sdougm char *proto; 17846185db85Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 17856185db85Sdougm name = sa_get_group_attr(group, "name"); 17866185db85Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 17876185db85Sdougm (void) printf("%s", (char *)name); 17886185db85Sdougm if (verbose) { 17896185db85Sdougm /* 179025a68471Sdougm * Need the list of protocols 179125a68471Sdougm * and current status once 179225a68471Sdougm * available. We do want to 179325a68471Sdougm * translate the 179425a68471Sdougm * enabled/disabled text here. 17956185db85Sdougm */ 17964db300d5Sdougm (void) printf("\t%s", isenabled(group) ? 17974db300d5Sdougm gettext("enabled") : 17984db300d5Sdougm gettext("disabled")); 17996185db85Sdougm proto = group_proto(group); 18006185db85Sdougm if (proto != NULL) { 180125a68471Sdougm (void) printf("\t%s", 180225a68471Sdougm (char *)proto); 18036185db85Sdougm free(proto); 18046185db85Sdougm } 18056185db85Sdougm } 18066185db85Sdougm (void) printf("\n"); 18076185db85Sdougm } 18086185db85Sdougm if (name != NULL) 18096185db85Sdougm sa_free_attr_string(name); 18106185db85Sdougm } 18116185db85Sdougm } 18126185db85Sdougm return (0); 18136185db85Sdougm } 18146185db85Sdougm 18156185db85Sdougm /* 18166185db85Sdougm * out_properties(optionset, proto, sec) 18176185db85Sdougm * 18186185db85Sdougm * Format the properties and encode the protocol and optional named 18196185db85Sdougm * optionset into the string. 18206185db85Sdougm * 18216185db85Sdougm * format is protocol[:name]=(property-list) 18226185db85Sdougm */ 18236185db85Sdougm 18246185db85Sdougm static void 18256185db85Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 18266185db85Sdougm { 18276185db85Sdougm char *type; 18286185db85Sdougm char *value; 18296185db85Sdougm int spacer; 18306185db85Sdougm sa_property_t prop; 18316185db85Sdougm 183225a68471Sdougm if (sec == NULL) 18336185db85Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 183425a68471Sdougm else 18356185db85Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 18366185db85Sdougm 18376185db85Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 183825a68471Sdougm prop != NULL; 183925a68471Sdougm prop = sa_get_next_property(prop)) { 18406185db85Sdougm 18416185db85Sdougm /* 18426185db85Sdougm * extract the property name/value and output with 18436185db85Sdougm * appropriate spacing. I.e. no prefixed space the 18446185db85Sdougm * first time through but a space on subsequent 18456185db85Sdougm * properties. 18466185db85Sdougm */ 18476185db85Sdougm type = sa_get_property_attr(prop, "type"); 18486185db85Sdougm value = sa_get_property_attr(prop, "value"); 18496185db85Sdougm if (type != NULL) { 18506185db85Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 18516185db85Sdougm spacer = 1; 18526185db85Sdougm if (value != NULL) 18536185db85Sdougm (void) printf("\"%s\"", value); 18546185db85Sdougm else 18556185db85Sdougm (void) printf("\"\""); 18566185db85Sdougm } 18576185db85Sdougm if (type != NULL) 18586185db85Sdougm sa_free_attr_string(type); 18596185db85Sdougm if (value != NULL) 18606185db85Sdougm sa_free_attr_string(value); 18616185db85Sdougm } 18626185db85Sdougm (void) printf(")"); 18636185db85Sdougm } 18646185db85Sdougm 18656185db85Sdougm /* 18666185db85Sdougm * show_properties(group, protocol, prefix) 18676185db85Sdougm * 18686185db85Sdougm * print the properties for a group. If protocol is NULL, do all 18696185db85Sdougm * protocols otherwise only the specified protocol. All security 18706185db85Sdougm * (named groups specific to the protocol) are included. 18716185db85Sdougm * 18726185db85Sdougm * The "prefix" is always applied. The caller knows whether it wants 18736185db85Sdougm * some type of prefix string (white space) or not. Once the prefix 18746185db85Sdougm * has been output, it is reduced to the zero length string for the 18756185db85Sdougm * remainder of the property output. 18766185db85Sdougm */ 18776185db85Sdougm 18786185db85Sdougm static void 18796185db85Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 18806185db85Sdougm { 18816185db85Sdougm sa_optionset_t optionset; 18826185db85Sdougm sa_security_t security; 18836185db85Sdougm char *value; 18846185db85Sdougm char *secvalue; 18856185db85Sdougm 18866185db85Sdougm if (protocol != NULL) { 18876185db85Sdougm optionset = sa_get_optionset(group, protocol); 18886185db85Sdougm if (optionset != NULL) { 18896185db85Sdougm (void) printf("%s", prefix); 18906185db85Sdougm prefix = ""; 18916185db85Sdougm out_properties(optionset, protocol, NULL); 18926185db85Sdougm } 18936185db85Sdougm security = sa_get_security(group, protocol, NULL); 18946185db85Sdougm if (security != NULL) { 18956185db85Sdougm (void) printf("%s", prefix); 18966185db85Sdougm prefix = ""; 18976185db85Sdougm out_properties(security, protocol, NULL); 18986185db85Sdougm } 18996185db85Sdougm } else { 19006185db85Sdougm for (optionset = sa_get_optionset(group, protocol); 19016185db85Sdougm optionset != NULL; 19026185db85Sdougm optionset = sa_get_next_optionset(optionset)) { 19036185db85Sdougm 19046185db85Sdougm value = sa_get_optionset_attr(optionset, "type"); 19056185db85Sdougm (void) printf("%s", prefix); 19066185db85Sdougm prefix = ""; 19076185db85Sdougm out_properties(optionset, value, 0); 19086185db85Sdougm if (value != NULL) 19096185db85Sdougm sa_free_attr_string(value); 19106185db85Sdougm } 19116185db85Sdougm for (security = sa_get_security(group, NULL, protocol); 19126185db85Sdougm security != NULL; 19136185db85Sdougm security = sa_get_next_security(security)) { 19146185db85Sdougm 19156185db85Sdougm value = sa_get_security_attr(security, "type"); 19166185db85Sdougm secvalue = sa_get_security_attr(security, "sectype"); 19176185db85Sdougm (void) printf("%s", prefix); 19186185db85Sdougm prefix = ""; 19196185db85Sdougm out_properties(security, value, secvalue); 19206185db85Sdougm if (value != NULL) 19216185db85Sdougm sa_free_attr_string(value); 19226185db85Sdougm if (secvalue != NULL) 19236185db85Sdougm sa_free_attr_string(secvalue); 19246185db85Sdougm } 19256185db85Sdougm } 19266185db85Sdougm } 19276185db85Sdougm 19286185db85Sdougm /* 1929da6c28aaSamw * get_resource(share) 1930da6c28aaSamw * 1931da6c28aaSamw * Get the first resource name, if any, and fix string to be in 1932da6c28aaSamw * current locale and have quotes if it has embedded spaces. Return 1933da6c28aaSamw * an attr string that must be freed. 1934da6c28aaSamw */ 1935da6c28aaSamw 1936da6c28aaSamw static char * 1937da6c28aaSamw get_resource(sa_share_t share) 1938da6c28aaSamw { 1939da6c28aaSamw sa_resource_t resource; 1940da6c28aaSamw char *resstring = NULL; 1941da6c28aaSamw char *retstring; 1942da6c28aaSamw 1943da6c28aaSamw if ((resource = sa_get_share_resource(share, NULL)) != NULL) { 1944da6c28aaSamw resstring = sa_get_resource_attr(resource, "name"); 1945da6c28aaSamw if (resstring != NULL) { 1946da6c28aaSamw char *cp; 1947da6c28aaSamw int len; 1948da6c28aaSamw 1949da6c28aaSamw retstring = conv_from_utf8(resstring); 1950da6c28aaSamw if (retstring != resstring) { 1951da6c28aaSamw sa_free_attr_string(resstring); 1952da6c28aaSamw resstring = retstring; 1953da6c28aaSamw } 1954da6c28aaSamw if (strpbrk(resstring, " ") != NULL) { 1955da6c28aaSamw /* account for quotes */ 1956da6c28aaSamw len = strlen(resstring) + 3; 1957da6c28aaSamw cp = calloc(len, sizeof (char)); 1958da6c28aaSamw if (cp != NULL) { 1959da6c28aaSamw (void) snprintf(cp, len, 1960da6c28aaSamw "\"%s\"", resstring); 1961da6c28aaSamw sa_free_attr_string(resstring); 1962da6c28aaSamw resstring = cp; 1963da6c28aaSamw } else { 1964da6c28aaSamw sa_free_attr_string(resstring); 1965da6c28aaSamw resstring = NULL; 1966da6c28aaSamw } 1967da6c28aaSamw } 1968da6c28aaSamw } 1969da6c28aaSamw } 1970da6c28aaSamw return (resstring); 1971da6c28aaSamw } 1972da6c28aaSamw 1973da6c28aaSamw /* 1974da6c28aaSamw * has_resource_with_opt(share) 1975da6c28aaSamw * 1976da6c28aaSamw * Check to see if the share has any resource names with optionsets 1977da6c28aaSamw * set. Also indicate if multiple resource names since the syntax 1978da6c28aaSamw * would be about the same. 1979da6c28aaSamw */ 1980da6c28aaSamw static int 1981da6c28aaSamw has_resource_with_opt(sa_share_t share) 1982da6c28aaSamw { 1983da6c28aaSamw sa_resource_t resource; 1984da6c28aaSamw int ret = B_FALSE; 1985da6c28aaSamw 1986da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1987da6c28aaSamw resource != NULL; 1988da6c28aaSamw resource = sa_get_next_resource(resource)) { 1989da6c28aaSamw 1990da6c28aaSamw if (sa_get_optionset(resource, NULL) != NULL) { 1991da6c28aaSamw ret = B_TRUE; 1992da6c28aaSamw break; 1993da6c28aaSamw } 1994da6c28aaSamw } 1995da6c28aaSamw return (ret); 1996da6c28aaSamw } 1997da6c28aaSamw 1998da6c28aaSamw /* 1999da6c28aaSamw * has_multiple_resource(share) 2000da6c28aaSamw * 2001573b0c00Sdougm * Check to see if the share has multiple resource names since 2002573b0c00Sdougm * the syntax would be about the same. 2003da6c28aaSamw */ 2004573b0c00Sdougm static boolean_t 2005da6c28aaSamw has_multiple_resource(sa_share_t share) 2006da6c28aaSamw { 2007da6c28aaSamw sa_resource_t resource; 2008da6c28aaSamw int num; 2009da6c28aaSamw 2010da6c28aaSamw for (num = 0, resource = sa_get_share_resource(share, NULL); 2011da6c28aaSamw resource != NULL; 2012da6c28aaSamw resource = sa_get_next_resource(resource)) { 2013da6c28aaSamw num++; 2014da6c28aaSamw if (num > 1) 2015da6c28aaSamw return (B_TRUE); 2016da6c28aaSamw } 2017da6c28aaSamw return (B_FALSE); 2018da6c28aaSamw } 2019da6c28aaSamw 2020da6c28aaSamw /* 2021da6c28aaSamw * show_share(share, verbose, properties, proto, iszfs, sharepath) 2022da6c28aaSamw * 2023da6c28aaSamw * print out the share information. With the addition of resource as a 2024da6c28aaSamw * full object that can have multiple instances below the share, we 2025da6c28aaSamw * need to display that as well. 2026da6c28aaSamw */ 2027da6c28aaSamw 2028da6c28aaSamw static void 2029da6c28aaSamw show_share(sa_share_t share, int verbose, int properties, char *proto, 2030da6c28aaSamw int iszfs, char *sharepath) 2031da6c28aaSamw { 2032da6c28aaSamw char *drive; 2033da6c28aaSamw char *exclude; 2034da6c28aaSamw sa_resource_t resource = NULL; 2035da6c28aaSamw char *description; 2036da6c28aaSamw char *rsrcname; 2037da6c28aaSamw int rsrcwithopt; 2038573b0c00Sdougm boolean_t multiple; 2039da6c28aaSamw char *type; 2040da6c28aaSamw 2041da6c28aaSamw rsrcwithopt = has_resource_with_opt(share); 2042da6c28aaSamw 2043da6c28aaSamw if (verbose || (properties && rsrcwithopt)) { 2044da6c28aaSamw /* First, indicate if transient */ 2045da6c28aaSamw type = sa_get_share_attr(share, "type"); 2046da6c28aaSamw if (type != NULL && !iszfs && verbose && 2047da6c28aaSamw strcmp(type, "transient") == 0) 2048da6c28aaSamw (void) printf("\t* "); 2049da6c28aaSamw else 2050da6c28aaSamw (void) printf("\t "); 2051da6c28aaSamw 2052da6c28aaSamw if (type != NULL) 2053da6c28aaSamw sa_free_attr_string(type); 2054da6c28aaSamw 2055da6c28aaSamw /* 2056da6c28aaSamw * If we came in with verbose, we want to handle the case of 2057da6c28aaSamw * multiple resources as though they had properties set. 2058da6c28aaSamw */ 2059da6c28aaSamw multiple = has_multiple_resource(share); 2060da6c28aaSamw 2061573b0c00Sdougm /* 2062573b0c00Sdougm * if there is a description on the share and there 2063573b0c00Sdougm * are resources, treat as multiple resources in order 2064573b0c00Sdougm * to get all descriptions displayed. 2065573b0c00Sdougm */ 2066573b0c00Sdougm description = sa_get_share_description(share); 2067573b0c00Sdougm resource = sa_get_share_resource(share, NULL); 2068573b0c00Sdougm 2069573b0c00Sdougm if (description != NULL && resource != NULL) 2070573b0c00Sdougm multiple = B_TRUE; 2071573b0c00Sdougm 2072da6c28aaSamw /* Next, if not multiple follow old model */ 2073da6c28aaSamw if (!multiple && !rsrcwithopt) { 2074da6c28aaSamw rsrcname = get_resource(share); 2075da6c28aaSamw if (rsrcname != NULL && strlen(rsrcname) > 0) { 2076da6c28aaSamw (void) printf("%s=%s", rsrcname, sharepath); 2077da6c28aaSamw } else { 2078da6c28aaSamw (void) printf("%s", sharepath); 2079da6c28aaSamw } 2080da6c28aaSamw if (rsrcname != NULL) 2081da6c28aaSamw sa_free_attr_string(rsrcname); 2082573b0c00Sdougm /* Print the description string if there is one. */ 2083573b0c00Sdougm print_rsrc_desc(resource, description); 2084da6c28aaSamw } else { 2085da6c28aaSamw /* Treat as simple and then resources come later */ 2086da6c28aaSamw (void) printf("%s", sharepath); 2087da6c28aaSamw } 2088da6c28aaSamw drive = sa_get_share_attr(share, "drive-letter"); 2089da6c28aaSamw if (drive != NULL) { 2090da6c28aaSamw if (strlen(drive) > 0) 2091da6c28aaSamw (void) printf(gettext("\tdrive-letter=\"%s:\""), 2092da6c28aaSamw drive); 2093da6c28aaSamw sa_free_attr_string(drive); 2094da6c28aaSamw } 2095da6c28aaSamw if (properties) 2096da6c28aaSamw show_properties(share, proto, "\t"); 2097da6c28aaSamw exclude = sa_get_share_attr(share, "exclude"); 2098da6c28aaSamw if (exclude != NULL) { 2099da6c28aaSamw (void) printf(gettext("\tnot-shared-with=[%s]"), 2100da6c28aaSamw exclude); 2101da6c28aaSamw sa_free_attr_string(exclude); 2102da6c28aaSamw } 2103da6c28aaSamw 2104573b0c00Sdougm if (description != NULL) { 2105573b0c00Sdougm print_rsrc_desc((sa_resource_t)share, description); 2106573b0c00Sdougm } 2107da6c28aaSamw /* 2108da6c28aaSamw * If there are resource names with options, show them 2109da6c28aaSamw * here, with one line per resource. Resource specific 2110da6c28aaSamw * options are at the end of the line followed by 2111da6c28aaSamw * description, if any. 2112da6c28aaSamw */ 2113da6c28aaSamw if (rsrcwithopt || multiple) { 2114da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 2115da6c28aaSamw resource != NULL; 2116da6c28aaSamw resource = sa_get_next_resource(resource)) { 2117da6c28aaSamw int has_space; 2118da6c28aaSamw char *rsrc; 2119da6c28aaSamw 2120da6c28aaSamw (void) printf("\n\t\t "); 2121da6c28aaSamw rsrcname = sa_get_resource_attr(resource, 2122da6c28aaSamw "name"); 2123da6c28aaSamw if (rsrcname == NULL) 2124da6c28aaSamw continue; 2125da6c28aaSamw 2126da6c28aaSamw rsrc = conv_from_utf8(rsrcname); 2127da6c28aaSamw has_space = strpbrk(rsrc, " ") != NULL; 2128da6c28aaSamw 2129da6c28aaSamw if (has_space) 2130da6c28aaSamw (void) printf("\"%s\"=%s", rsrc, 2131da6c28aaSamw sharepath); 2132da6c28aaSamw else 2133da6c28aaSamw (void) printf("%s=%s", rsrc, 2134da6c28aaSamw sharepath); 2135da6c28aaSamw if (rsrc != rsrcname) 2136da6c28aaSamw sa_free_attr_string(rsrc); 2137da6c28aaSamw sa_free_attr_string(rsrcname); 2138da6c28aaSamw if (properties || rsrcwithopt) 2139da6c28aaSamw show_properties(resource, proto, "\t"); 2140da6c28aaSamw 2141da6c28aaSamw /* Get description string if any */ 2142573b0c00Sdougm print_rsrc_desc(resource, description); 2143da6c28aaSamw } 2144da6c28aaSamw } 2145573b0c00Sdougm if (description != NULL) 2146573b0c00Sdougm sa_free_share_description(description); 2147da6c28aaSamw } else { 2148da6c28aaSamw (void) printf("\t %s", sharepath); 2149da6c28aaSamw if (properties) 2150da6c28aaSamw show_properties(share, proto, "\t"); 2151da6c28aaSamw } 2152da6c28aaSamw (void) printf("\n"); 2153da6c28aaSamw } 2154da6c28aaSamw 2155da6c28aaSamw /* 21566185db85Sdougm * show_group(group, verbose, properties, proto, subgroup) 21576185db85Sdougm * 21586185db85Sdougm * helper function to show the contents of a group. 21596185db85Sdougm */ 21606185db85Sdougm 21616185db85Sdougm static void 21626185db85Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 21636185db85Sdougm char *subgroup) 21646185db85Sdougm { 21656185db85Sdougm sa_share_t share; 21666185db85Sdougm char *groupname; 21676185db85Sdougm char *zfs = NULL; 21686185db85Sdougm int iszfs = 0; 2169da6c28aaSamw char *sharepath; 21706185db85Sdougm 21716185db85Sdougm groupname = sa_get_group_attr(group, "name"); 21726185db85Sdougm if (groupname != NULL) { 21736185db85Sdougm if (proto != NULL && !has_protocol(group, proto)) { 21746185db85Sdougm sa_free_attr_string(groupname); 21756185db85Sdougm return; 21766185db85Sdougm } 21776185db85Sdougm /* 21786185db85Sdougm * check to see if the group is managed by ZFS. If 21796185db85Sdougm * there is an attribute, then it is. A non-NULL zfs 21806185db85Sdougm * variable will trigger the different way to display 21816185db85Sdougm * and will remove the transient property indicator 21826185db85Sdougm * from the output. 21836185db85Sdougm */ 21846185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 21856185db85Sdougm if (zfs != NULL) { 21866185db85Sdougm iszfs = 1; 21876185db85Sdougm sa_free_attr_string(zfs); 21886185db85Sdougm } 21896185db85Sdougm share = sa_get_share(group, NULL); 21906185db85Sdougm if (subgroup == NULL) 21916185db85Sdougm (void) printf("%s", groupname); 21926185db85Sdougm else 21936185db85Sdougm (void) printf(" %s/%s", subgroup, groupname); 219425a68471Sdougm if (properties) 21956185db85Sdougm show_properties(group, proto, ""); 21966185db85Sdougm (void) printf("\n"); 21976185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 21986185db85Sdougm sa_group_t zgroup; 21996185db85Sdougm 220025a68471Sdougm for (zgroup = sa_get_sub_group(group); 220125a68471Sdougm zgroup != NULL; 22026185db85Sdougm zgroup = sa_get_next_group(zgroup)) { 220325a68471Sdougm show_group(zgroup, verbose, properties, proto, 220425a68471Sdougm "zfs"); 22056185db85Sdougm } 22066185db85Sdougm sa_free_attr_string(groupname); 22076185db85Sdougm return; 22086185db85Sdougm } 22096185db85Sdougm /* 221025a68471Sdougm * Have a group, so list the contents. Resource and 22116185db85Sdougm * description are only listed if verbose is set. 22126185db85Sdougm */ 221325a68471Sdougm for (share = sa_get_share(group, NULL); 221425a68471Sdougm share != NULL; 22156185db85Sdougm share = sa_get_next_share(share)) { 22166185db85Sdougm sharepath = sa_get_share_attr(share, "path"); 22176185db85Sdougm if (sharepath != NULL) { 2218da6c28aaSamw show_share(share, verbose, properties, proto, 2219da6c28aaSamw iszfs, sharepath); 22206185db85Sdougm sa_free_attr_string(sharepath); 22216185db85Sdougm } 22226185db85Sdougm } 22236185db85Sdougm } 22246185db85Sdougm if (groupname != NULL) { 22256185db85Sdougm sa_free_attr_string(groupname); 22266185db85Sdougm } 22276185db85Sdougm } 22286185db85Sdougm 22296185db85Sdougm /* 22306185db85Sdougm * show_group_xml_init() 22316185db85Sdougm * 22326185db85Sdougm * Create an XML document that will be used to display config info via 22336185db85Sdougm * XML format. 22346185db85Sdougm */ 22356185db85Sdougm 22366185db85Sdougm xmlDocPtr 22376185db85Sdougm show_group_xml_init() 22386185db85Sdougm { 22396185db85Sdougm xmlDocPtr doc; 22406185db85Sdougm xmlNodePtr root; 22416185db85Sdougm 22426185db85Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 22436185db85Sdougm if (doc != NULL) { 22446185db85Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 22456185db85Sdougm if (root != NULL) 2246*0b4fd3b1SSurya Prakki (void) xmlDocSetRootElement(doc, root); 22476185db85Sdougm } 22486185db85Sdougm return (doc); 22496185db85Sdougm } 22506185db85Sdougm 22516185db85Sdougm /* 22526185db85Sdougm * show_group_xml(doc, group) 22536185db85Sdougm * 22546185db85Sdougm * Copy the group info into the XML doc. 22556185db85Sdougm */ 22566185db85Sdougm 22576185db85Sdougm static void 22586185db85Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 22596185db85Sdougm { 22606185db85Sdougm xmlNodePtr node; 22616185db85Sdougm xmlNodePtr root; 22626185db85Sdougm 22636185db85Sdougm root = xmlDocGetRootElement(doc); 22646185db85Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 22656185db85Sdougm if (node != NULL && root != NULL) { 2266*0b4fd3b1SSurya Prakki (void) xmlAddChild(root, node); 22676185db85Sdougm /* 22686185db85Sdougm * In the future, we may have interally used tags that 22696185db85Sdougm * should not appear in the XML output. Remove 22706185db85Sdougm * anything we don't want to show here. 22716185db85Sdougm */ 22726185db85Sdougm } 22736185db85Sdougm } 22746185db85Sdougm 22756185db85Sdougm /* 22766185db85Sdougm * sa_show(flags, argc, argv) 22776185db85Sdougm * 22786185db85Sdougm * Implements the show subcommand. 22796185db85Sdougm */ 22806185db85Sdougm 22816185db85Sdougm int 2282549ec3ffSdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[]) 22836185db85Sdougm { 22846185db85Sdougm sa_group_t group; 22856185db85Sdougm int verbose = 0; 22866185db85Sdougm int properties = 0; 22876185db85Sdougm int c; 22886185db85Sdougm int ret = SA_OK; 22896185db85Sdougm char *protocol = NULL; 22906185db85Sdougm int xml = 0; 22916185db85Sdougm xmlDocPtr doc; 2292da6c28aaSamw #ifdef lint 2293da6c28aaSamw flags = flags; 2294da6c28aaSamw #endif 22956185db85Sdougm 22966185db85Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 22976185db85Sdougm switch (c) { 22986185db85Sdougm case 'v': 22996185db85Sdougm verbose++; 23006185db85Sdougm break; 23016185db85Sdougm case 'p': 23026185db85Sdougm properties++; 23036185db85Sdougm break; 23046185db85Sdougm case 'P': 2305da6c28aaSamw if (protocol != NULL) { 2306da6c28aaSamw (void) printf(gettext( 2307da6c28aaSamw "Specifying multiple protocols " 2308da6c28aaSamw "not supported: %s\n"), 2309da6c28aaSamw protocol); 2310da6c28aaSamw return (SA_SYNTAX_ERR); 2311da6c28aaSamw } 23126185db85Sdougm protocol = optarg; 23136185db85Sdougm if (!sa_valid_protocol(protocol)) { 231425a68471Sdougm (void) printf(gettext( 231525a68471Sdougm "Invalid protocol specified: %s\n"), 23166185db85Sdougm protocol); 23176185db85Sdougm return (SA_INVALID_PROTOCOL); 23186185db85Sdougm } 23196185db85Sdougm break; 23206185db85Sdougm case 'x': 23216185db85Sdougm xml++; 23226185db85Sdougm break; 2323e7bab347Sdougm case 'h': 2324e7bab347Sdougm /* optopt on valid arg isn't defined */ 2325e7bab347Sdougm optopt = c; 2326e7bab347Sdougm /*FALLTHROUGH*/ 2327e7bab347Sdougm case '?': 23286185db85Sdougm default: 2329e7bab347Sdougm /* 2330e7bab347Sdougm * Since a bad option gets to here, sort it 2331e7bab347Sdougm * out and return a syntax error return value 2332e7bab347Sdougm * if necessary. 2333e7bab347Sdougm */ 2334e7bab347Sdougm switch (optopt) { 2335e7bab347Sdougm default: 2336e7bab347Sdougm ret = SA_SYNTAX_ERR; 2337e7bab347Sdougm break; 23386185db85Sdougm case 'h': 23396185db85Sdougm case '?': 2340e7bab347Sdougm break; 2341e7bab347Sdougm } 234225a68471Sdougm (void) printf(gettext("usage: %s\n"), 234325a68471Sdougm sa_get_usage(USAGE_SHOW)); 2344e7bab347Sdougm return (ret); 23456185db85Sdougm } 23466185db85Sdougm } 23476185db85Sdougm 23486185db85Sdougm if (xml) { 23496185db85Sdougm doc = show_group_xml_init(); 23506185db85Sdougm if (doc == NULL) 23516185db85Sdougm ret = SA_NO_MEMORY; 23526185db85Sdougm } 23536185db85Sdougm 23546185db85Sdougm if (optind == argc) { 235525a68471Sdougm /* No group specified so go through them all */ 235625a68471Sdougm for (group = sa_get_group(handle, NULL); 235725a68471Sdougm group != NULL; 23586185db85Sdougm group = sa_get_next_group(group)) { 23596185db85Sdougm /* 236025a68471Sdougm * Have a group so check if one we want and then list 23616185db85Sdougm * contents with appropriate options. 23626185db85Sdougm */ 23636185db85Sdougm if (xml) 23646185db85Sdougm show_group_xml(doc, group); 23656185db85Sdougm else 236625a68471Sdougm show_group(group, verbose, properties, protocol, 236725a68471Sdougm NULL); 23686185db85Sdougm } 23696185db85Sdougm } else { 237025a68471Sdougm /* Have a specified list of groups */ 23716185db85Sdougm for (; optind < argc; optind++) { 2372549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 23736185db85Sdougm if (group != NULL) { 23746185db85Sdougm if (xml) 23756185db85Sdougm show_group_xml(doc, group); 23766185db85Sdougm else 237725a68471Sdougm show_group(group, verbose, properties, 237825a68471Sdougm protocol, NULL); 23796185db85Sdougm } else { 238025a68471Sdougm (void) printf(gettext("%s: not found\n"), 238125a68471Sdougm argv[optind]); 23826185db85Sdougm ret = SA_NO_SUCH_GROUP; 23836185db85Sdougm } 23846185db85Sdougm } 23856185db85Sdougm } 23866185db85Sdougm if (xml && ret == SA_OK) { 2387*0b4fd3b1SSurya Prakki (void) xmlDocFormatDump(stdout, doc, 1); 23886185db85Sdougm xmlFreeDoc(doc); 23896185db85Sdougm } 23906185db85Sdougm return (ret); 23916185db85Sdougm 23926185db85Sdougm } 23936185db85Sdougm 23946185db85Sdougm /* 23956185db85Sdougm * enable_share(group, share, update_legacy) 23966185db85Sdougm * 23976185db85Sdougm * helper function to enable a share if the group is enabled. 23986185db85Sdougm */ 23996185db85Sdougm 24006185db85Sdougm static int 2401549ec3ffSdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 2402549ec3ffSdougm int update_legacy) 24036185db85Sdougm { 24046185db85Sdougm char *value; 24056185db85Sdougm int enabled; 24066185db85Sdougm sa_optionset_t optionset; 2407da6c28aaSamw int err; 24086185db85Sdougm int ret = SA_OK; 24096185db85Sdougm char *zfs = NULL; 24106185db85Sdougm int iszfs = 0; 2411da6c28aaSamw int isshare; 24126185db85Sdougm 24136185db85Sdougm /* 24146185db85Sdougm * need to enable this share if the group is enabled but not 24156185db85Sdougm * otherwise. The enable is also done on each protocol 24166185db85Sdougm * represented in the group. 24176185db85Sdougm */ 24186185db85Sdougm value = sa_get_group_attr(group, "state"); 24196185db85Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 24206185db85Sdougm if (value != NULL) 24216185db85Sdougm sa_free_attr_string(value); 24226185db85Sdougm /* remove legacy config if necessary */ 24236185db85Sdougm if (update_legacy) 2424da6c28aaSamw ret = sa_delete_legacy(share, NULL); 24256185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 24266185db85Sdougm if (zfs != NULL) { 24276185db85Sdougm iszfs++; 24286185db85Sdougm sa_free_attr_string(zfs); 24296185db85Sdougm } 24306185db85Sdougm 24316185db85Sdougm /* 24326185db85Sdougm * Step through each optionset at the group level and 24336185db85Sdougm * enable the share based on the protocol type. This 24346185db85Sdougm * works because protocols must be set on the group 24356185db85Sdougm * for the protocol to be enabled. 24366185db85Sdougm */ 2437da6c28aaSamw isshare = sa_is_share(share); 24386185db85Sdougm for (optionset = sa_get_optionset(group, NULL); 24396185db85Sdougm optionset != NULL && ret == SA_OK; 24406185db85Sdougm optionset = sa_get_next_optionset(optionset)) { 24416185db85Sdougm value = sa_get_optionset_attr(optionset, "type"); 24426185db85Sdougm if (value != NULL) { 2443da6c28aaSamw if (enabled) { 2444da6c28aaSamw if (isshare) { 2445da6c28aaSamw err = sa_enable_share(share, value); 2446da6c28aaSamw } else { 2447da6c28aaSamw err = sa_enable_resource(share, value); 2448da6c28aaSamw if (err == SA_NOT_SUPPORTED) { 2449da6c28aaSamw sa_share_t parent; 2450da6c28aaSamw parent = sa_get_resource_parent( 2451da6c28aaSamw share); 2452da6c28aaSamw if (parent != NULL) 2453da6c28aaSamw err = sa_enable_share( 2454da6c28aaSamw parent, value); 2455da6c28aaSamw } 2456da6c28aaSamw } 2457da6c28aaSamw if (err != SA_OK) { 2458da6c28aaSamw ret = err; 2459da6c28aaSamw (void) printf(gettext( 2460da6c28aaSamw "Failed to enable share for " 2461da6c28aaSamw "\"%s\": %s\n"), 2462da6c28aaSamw value, sa_errorstr(ret)); 2463da6c28aaSamw } 2464da6c28aaSamw } 2465da6c28aaSamw /* 2466da6c28aaSamw * If we want to update the legacy, use a copy of 2467da6c28aaSamw * share so we can avoid breaking the loop we are in 2468da6c28aaSamw * since we might also need to go up the tree to the 2469da6c28aaSamw * parent. 2470da6c28aaSamw */ 2471da6c28aaSamw if (update_legacy && !iszfs) { 2472da6c28aaSamw sa_share_t update = share; 2473da6c28aaSamw if (!sa_is_share(share)) { 2474da6c28aaSamw update = sa_get_resource_parent(share); 2475da6c28aaSamw } 2476da6c28aaSamw (void) sa_update_legacy(update, value); 2477da6c28aaSamw } 24786185db85Sdougm sa_free_attr_string(value); 24796185db85Sdougm } 24806185db85Sdougm } 24816185db85Sdougm if (ret == SA_OK) 2482549ec3ffSdougm (void) sa_update_config(handle); 24836185db85Sdougm return (ret); 24846185db85Sdougm } 24856185db85Sdougm 24866185db85Sdougm /* 2487da6c28aaSamw * sa_require_resource(group) 2488da6c28aaSamw * 2489da6c28aaSamw * if any of the defined protocols on the group require resource 2490da6c28aaSamw * names, then all shares must have them. 2491da6c28aaSamw */ 2492da6c28aaSamw 2493da6c28aaSamw static int 2494da6c28aaSamw sa_require_resource(sa_group_t group) 2495da6c28aaSamw { 2496da6c28aaSamw sa_optionset_t optionset; 2497da6c28aaSamw 2498da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 2499da6c28aaSamw optionset != NULL; 2500da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 2501da6c28aaSamw char *proto; 2502da6c28aaSamw 2503da6c28aaSamw proto = sa_get_optionset_attr(optionset, "type"); 2504da6c28aaSamw if (proto != NULL) { 2505da6c28aaSamw uint64_t features; 2506da6c28aaSamw 2507da6c28aaSamw features = sa_proto_get_featureset(proto); 2508da6c28aaSamw if (features & SA_FEATURE_RESOURCE) { 2509da6c28aaSamw sa_free_attr_string(proto); 2510da6c28aaSamw return (B_TRUE); 2511da6c28aaSamw } 2512da6c28aaSamw sa_free_attr_string(proto); 2513da6c28aaSamw } 2514da6c28aaSamw } 2515da6c28aaSamw return (B_FALSE); 2516da6c28aaSamw } 2517da6c28aaSamw 2518da6c28aaSamw /* 25196185db85Sdougm * sa_addshare(flags, argc, argv) 25206185db85Sdougm * 25216185db85Sdougm * implements add-share subcommand. 25226185db85Sdougm */ 25236185db85Sdougm 2524da6c28aaSamw static int 2525549ec3ffSdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 25266185db85Sdougm { 25276185db85Sdougm int verbose = 0; 25286185db85Sdougm int dryrun = 0; 25296185db85Sdougm int c; 25306185db85Sdougm int ret = SA_OK; 25316185db85Sdougm sa_group_t group; 25326185db85Sdougm sa_share_t share; 2533da6c28aaSamw sa_resource_t resource = NULL; 25346185db85Sdougm char *sharepath = NULL; 25356185db85Sdougm char *description = NULL; 2536da6c28aaSamw char *rsrcname = NULL; 2537da6c28aaSamw char *rsrc = NULL; 25386185db85Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 25396185db85Sdougm int auth; 25406185db85Sdougm char dir[MAXPATHLEN]; 25416185db85Sdougm 25426185db85Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 25436185db85Sdougm switch (c) { 25446185db85Sdougm case 'n': 25456185db85Sdougm dryrun++; 25466185db85Sdougm break; 25476185db85Sdougm case 'v': 25486185db85Sdougm verbose++; 25496185db85Sdougm break; 25506185db85Sdougm case 'd': 25516185db85Sdougm description = optarg; 25526185db85Sdougm break; 25536185db85Sdougm case 'r': 2554da6c28aaSamw if (rsrcname != NULL) { 2555da6c28aaSamw (void) printf(gettext("Adding multiple " 2556da6c28aaSamw "resource names not" 2557da6c28aaSamw " supported\n")); 2558da6c28aaSamw return (SA_SYNTAX_ERR); 2559da6c28aaSamw } 2560da6c28aaSamw rsrcname = optarg; 25616185db85Sdougm break; 25626185db85Sdougm case 's': 25636185db85Sdougm /* 256425a68471Sdougm * Save share path into group. Currently limit 25656185db85Sdougm * to one share per command. 25666185db85Sdougm */ 25676185db85Sdougm if (sharepath != NULL) { 256825a68471Sdougm (void) printf(gettext( 256925a68471Sdougm "Adding multiple shares not supported\n")); 2570da6c28aaSamw return (SA_SYNTAX_ERR); 25716185db85Sdougm } 25726185db85Sdougm sharepath = optarg; 25736185db85Sdougm break; 25746185db85Sdougm case 't': 25756185db85Sdougm persist = SA_SHARE_TRANSIENT; 25766185db85Sdougm break; 2577e7bab347Sdougm case 'h': 2578e7bab347Sdougm /* optopt on valid arg isn't defined */ 2579e7bab347Sdougm optopt = c; 2580e7bab347Sdougm /*FALLTHROUGH*/ 2581e7bab347Sdougm case '?': 25826185db85Sdougm default: 2583e7bab347Sdougm /* 2584e7bab347Sdougm * Since a bad option gets to here, sort it 2585e7bab347Sdougm * out and return a syntax error return value 2586e7bab347Sdougm * if necessary. 2587e7bab347Sdougm */ 2588e7bab347Sdougm switch (optopt) { 2589e7bab347Sdougm default: 2590e7bab347Sdougm ret = SA_SYNTAX_ERR; 2591e7bab347Sdougm break; 25926185db85Sdougm case 'h': 25936185db85Sdougm case '?': 2594e7bab347Sdougm break; 2595e7bab347Sdougm } 25966185db85Sdougm (void) printf(gettext("usage: %s\n"), 25976185db85Sdougm sa_get_usage(USAGE_ADD_SHARE)); 2598e7bab347Sdougm return (ret); 25996185db85Sdougm } 26006185db85Sdougm } 26016185db85Sdougm 26026185db85Sdougm if (optind >= argc) { 26036185db85Sdougm (void) printf(gettext("usage: %s\n"), 26046185db85Sdougm sa_get_usage(USAGE_ADD_SHARE)); 26056185db85Sdougm if (dryrun || sharepath != NULL || description != NULL || 2606da6c28aaSamw rsrcname != NULL || verbose || persist) { 26076185db85Sdougm (void) printf(gettext("\tgroup must be specified\n")); 26086185db85Sdougm ret = SA_NO_SUCH_GROUP; 26096185db85Sdougm } else { 26106185db85Sdougm ret = SA_OK; 26116185db85Sdougm } 26126185db85Sdougm } else { 26136185db85Sdougm if (sharepath == NULL) { 26146185db85Sdougm (void) printf(gettext("usage: %s\n"), 26156185db85Sdougm sa_get_usage(USAGE_ADD_SHARE)); 261625a68471Sdougm (void) printf(gettext( 261725a68471Sdougm "\t-s sharepath must be specified\n")); 2618da6c28aaSamw ret = SA_BAD_PATH; 26196185db85Sdougm } 2620da6c28aaSamw if (ret == SA_OK) { 26216185db85Sdougm if (realpath(sharepath, dir) == NULL) { 2622da6c28aaSamw ret = SA_BAD_PATH; 2623da6c28aaSamw (void) printf(gettext("Path " 2624da6c28aaSamw "is not valid: %s\n"), 2625da6c28aaSamw sharepath); 26266185db85Sdougm } else { 26276185db85Sdougm sharepath = dir; 26286185db85Sdougm } 2629da6c28aaSamw } 2630da6c28aaSamw if (ret == SA_OK && rsrcname != NULL) { 2631da6c28aaSamw /* check for valid syntax */ 2632da6c28aaSamw if (validresource(rsrcname)) { 2633da6c28aaSamw rsrc = conv_to_utf8(rsrcname); 2634da6c28aaSamw resource = sa_find_resource(handle, rsrc); 2635da6c28aaSamw if (resource != NULL) { 2636da6c28aaSamw /* 2637da6c28aaSamw * Resource names must be 2638da6c28aaSamw * unique in the system 2639da6c28aaSamw */ 2640da6c28aaSamw ret = SA_DUPLICATE_NAME; 26416185db85Sdougm (void) printf(gettext("usage: %s\n"), 26426185db85Sdougm sa_get_usage(USAGE_ADD_SHARE)); 264325a68471Sdougm (void) printf(gettext( 2644da6c28aaSamw "\tresource names must be unique " 2645da6c28aaSamw "in the system\n")); 26466185db85Sdougm } 2647da6c28aaSamw } else { 2648da6c28aaSamw (void) printf(gettext("usage: %s\n"), 2649da6c28aaSamw sa_get_usage(USAGE_ADD_SHARE)); 2650da6c28aaSamw (void) printf(gettext( 2651da6c28aaSamw "\tresource names use restricted " 2652da6c28aaSamw "character set\n")); 2653da6c28aaSamw ret = SA_INVALID_NAME; 265425a68471Sdougm } 2655da6c28aaSamw } 2656da6c28aaSamw 2657da6c28aaSamw if (ret != SA_OK) { 2658da6c28aaSamw if (rsrc != NULL && rsrcname != rsrc) 2659da6c28aaSamw sa_free_attr_string(rsrc); 2660da6c28aaSamw return (ret); 2661da6c28aaSamw } 2662da6c28aaSamw 2663549ec3ffSdougm share = sa_find_share(handle, sharepath); 26646185db85Sdougm if (share != NULL) { 2665da6c28aaSamw if (rsrcname == NULL) { 26666185db85Sdougm /* 2667da6c28aaSamw * Can only have a duplicate share if a new 2668da6c28aaSamw * resource name is being added. 26696185db85Sdougm */ 2670da6c28aaSamw ret = SA_DUPLICATE_NAME; 2671da6c28aaSamw (void) printf(gettext("Share path already " 2672da6c28aaSamw "shared: %s\n"), sharepath); 2673da6c28aaSamw } 2674da6c28aaSamw } 2675da6c28aaSamw if (ret != SA_OK) 2676da6c28aaSamw return (ret); 2677da6c28aaSamw 2678da6c28aaSamw group = sa_get_group(handle, argv[optind]); 2679da6c28aaSamw if (group != NULL) { 2680da6c28aaSamw if (sa_require_resource(group) == B_TRUE && 2681da6c28aaSamw rsrcname == NULL) { 2682da6c28aaSamw (void) printf(gettext( 2683da6c28aaSamw "Resource name is required " 2684da6c28aaSamw "by at least one enabled protocol " 2685da6c28aaSamw "in group\n")); 2686da6c28aaSamw return (SA_RESOURCE_REQUIRED); 2687da6c28aaSamw } 2688da6c28aaSamw if (share == NULL && ret == SA_OK) { 26896185db85Sdougm if (dryrun) 2690f345c0beSdougm ret = sa_check_path(group, sharepath, 2691f345c0beSdougm SA_CHECK_NORMAL); 26926185db85Sdougm else 26936185db85Sdougm share = sa_add_share(group, sharepath, 26946185db85Sdougm persist, &ret); 2695da6c28aaSamw } 2696da6c28aaSamw /* 2697da6c28aaSamw * Make sure this isn't an attempt to put a resourced 2698da6c28aaSamw * share into a different group than it already is in. 2699da6c28aaSamw */ 2700da6c28aaSamw if (share != NULL) { 2701da6c28aaSamw sa_group_t parent; 2702da6c28aaSamw parent = sa_get_parent_group(share); 2703da6c28aaSamw if (parent != group) { 2704da6c28aaSamw ret = SA_DUPLICATE_NAME; 2705da6c28aaSamw (void) printf(gettext( 2706da6c28aaSamw "Share path already " 2707da6c28aaSamw "shared: %s\n"), sharepath); 2708da6c28aaSamw } 2709da6c28aaSamw } 27106185db85Sdougm if (!dryrun && share == NULL) { 271125a68471Sdougm (void) printf(gettext( 271225a68471Sdougm "Could not add share: %s\n"), 27136185db85Sdougm sa_errorstr(ret)); 27146185db85Sdougm } else { 2715da6c28aaSamw auth = check_authorizations(argv[optind], 2716da6c28aaSamw flags); 27176185db85Sdougm if (!dryrun && ret == SA_OK) { 2718da6c28aaSamw if (rsrcname != NULL) { 2719da6c28aaSamw resource = sa_add_resource( 2720da6c28aaSamw share, 2721da6c28aaSamw rsrc, 2722da6c28aaSamw SA_SHARE_PERMANENT, 2723da6c28aaSamw &ret); 27246185db85Sdougm } 272525a68471Sdougm if (ret == SA_OK && 272625a68471Sdougm description != NULL) { 2727573b0c00Sdougm if (resource != NULL) 2728573b0c00Sdougm ret = 2729573b0c00Sdougm set_resource_desc( 2730573b0c00Sdougm resource, 2731573b0c00Sdougm description); 2732573b0c00Sdougm else 2733da6c28aaSamw ret = 2734da6c28aaSamw set_share_desc( 2735da6c28aaSamw share, 2736da6c28aaSamw description); 2737da6c28aaSamw } 27386185db85Sdougm if (ret == SA_OK) { 2739da6c28aaSamw /* now enable the share(s) */ 2740da6c28aaSamw if (resource != NULL) { 2741da6c28aaSamw ret = enable_share( 2742da6c28aaSamw handle, 2743da6c28aaSamw group, 2744da6c28aaSamw resource, 2745da6c28aaSamw 1); 2746da6c28aaSamw } else { 2747da6c28aaSamw ret = enable_share( 2748da6c28aaSamw handle, 2749da6c28aaSamw group, 2750da6c28aaSamw share, 2751da6c28aaSamw 1); 2752da6c28aaSamw } 2753549ec3ffSdougm ret = sa_update_config(handle); 27546185db85Sdougm } 27556185db85Sdougm switch (ret) { 27566185db85Sdougm case SA_DUPLICATE_NAME: 275725a68471Sdougm (void) printf(gettext( 275825a68471Sdougm "Resource name in" 2759da6c28aaSamw "use: %s\n"), 2760da6c28aaSamw rsrcname); 27616185db85Sdougm break; 27626185db85Sdougm default: 2763da6c28aaSamw (void) printf(gettext( 2764da6c28aaSamw "Could not set " 27656185db85Sdougm "attribute: %s\n"), 27666185db85Sdougm sa_errorstr(ret)); 27676185db85Sdougm break; 27686185db85Sdougm case SA_OK: 27696185db85Sdougm break; 27706185db85Sdougm } 2771da6c28aaSamw } else if (dryrun && ret == SA_OK && 2772da6c28aaSamw !auth && verbose) { 277325a68471Sdougm (void) printf(gettext( 277425a68471Sdougm "Command would fail: %s\n"), 27756185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 27766185db85Sdougm ret = SA_NO_PERMISSION; 27776185db85Sdougm } 27786185db85Sdougm } 2779da6c28aaSamw } else { 2780da6c28aaSamw switch (ret) { 2781da6c28aaSamw default: 2782da6c28aaSamw (void) printf(gettext( 2783da6c28aaSamw "Group \"%s\" not found\n"), argv[optind]); 2784da6c28aaSamw ret = SA_NO_SUCH_GROUP; 2785da6c28aaSamw break; 2786da6c28aaSamw case SA_BAD_PATH: 2787da6c28aaSamw case SA_DUPLICATE_NAME: 2788da6c28aaSamw break; 2789da6c28aaSamw } 27906185db85Sdougm } 27916185db85Sdougm } 27926185db85Sdougm return (ret); 27936185db85Sdougm } 27946185db85Sdougm 27956185db85Sdougm /* 27966185db85Sdougm * sa_moveshare(flags, argc, argv) 27976185db85Sdougm * 27986185db85Sdougm * implements move-share subcommand. 27996185db85Sdougm */ 28006185db85Sdougm 28016185db85Sdougm int 2802549ec3ffSdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 28036185db85Sdougm { 28046185db85Sdougm int verbose = 0; 28056185db85Sdougm int dryrun = 0; 28066185db85Sdougm int c; 28076185db85Sdougm int ret = SA_OK; 28086185db85Sdougm sa_group_t group; 28096185db85Sdougm sa_share_t share; 2810da6c28aaSamw char *rsrcname = NULL; 28116185db85Sdougm char *sharepath = NULL; 28126185db85Sdougm int authsrc = 0, authdst = 0; 2813573b0c00Sdougm char dir[MAXPATHLEN]; 28146185db85Sdougm 2815da6c28aaSamw while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) { 28166185db85Sdougm switch (c) { 28176185db85Sdougm case 'n': 28186185db85Sdougm dryrun++; 28196185db85Sdougm break; 28206185db85Sdougm case 'v': 28216185db85Sdougm verbose++; 28226185db85Sdougm break; 2823da6c28aaSamw case 'r': 2824da6c28aaSamw if (rsrcname != NULL) { 2825da6c28aaSamw (void) printf(gettext( 2826da6c28aaSamw "Moving multiple resource names not" 2827da6c28aaSamw " supported\n")); 2828da6c28aaSamw return (SA_SYNTAX_ERR); 2829da6c28aaSamw } 2830da6c28aaSamw rsrcname = optarg; 2831da6c28aaSamw break; 28326185db85Sdougm case 's': 28336185db85Sdougm /* 283425a68471Sdougm * Remove share path from group. Currently limit 28356185db85Sdougm * to one share per command. 28366185db85Sdougm */ 28376185db85Sdougm if (sharepath != NULL) { 283825a68471Sdougm (void) printf(gettext("Moving multiple shares" 283925a68471Sdougm " not supported\n")); 2840da6c28aaSamw return (SA_SYNTAX_ERR); 28416185db85Sdougm } 28426185db85Sdougm sharepath = optarg; 28436185db85Sdougm break; 2844e7bab347Sdougm case 'h': 2845e7bab347Sdougm /* optopt on valid arg isn't defined */ 2846e7bab347Sdougm optopt = c; 2847e7bab347Sdougm /*FALLTHROUGH*/ 2848e7bab347Sdougm case '?': 28496185db85Sdougm default: 2850e7bab347Sdougm /* 2851e7bab347Sdougm * Since a bad option gets to here, sort it 2852e7bab347Sdougm * out and return a syntax error return value 2853e7bab347Sdougm * if necessary. 2854e7bab347Sdougm */ 2855e7bab347Sdougm switch (optopt) { 2856e7bab347Sdougm default: 2857e7bab347Sdougm ret = SA_SYNTAX_ERR; 2858e7bab347Sdougm break; 28596185db85Sdougm case 'h': 28606185db85Sdougm case '?': 2861e7bab347Sdougm break; 2862e7bab347Sdougm } 28636185db85Sdougm (void) printf(gettext("usage: %s\n"), 28646185db85Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 2865e7bab347Sdougm return (ret); 28666185db85Sdougm } 28676185db85Sdougm } 28686185db85Sdougm 28696185db85Sdougm if (optind >= argc || sharepath == NULL) { 28706185db85Sdougm (void) printf(gettext("usage: %s\n"), 28716185db85Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 28726185db85Sdougm if (dryrun || verbose || sharepath != NULL) { 2873da6c28aaSamw (void) printf(gettext("\tgroup must be specified\n")); 28746185db85Sdougm ret = SA_NO_SUCH_GROUP; 28756185db85Sdougm } else { 28766185db85Sdougm if (sharepath == NULL) { 28776185db85Sdougm ret = SA_SYNTAX_ERR; 287825a68471Sdougm (void) printf(gettext( 287925a68471Sdougm "\tsharepath must be specified\n")); 288025a68471Sdougm } else { 28816185db85Sdougm ret = SA_OK; 28826185db85Sdougm } 288325a68471Sdougm } 28846185db85Sdougm } else { 288525a68471Sdougm sa_group_t parent; 288625a68471Sdougm char *zfsold; 288725a68471Sdougm char *zfsnew; 288825a68471Sdougm 28896185db85Sdougm if (sharepath == NULL) { 289025a68471Sdougm (void) printf(gettext( 289125a68471Sdougm "sharepath must be specified with the -s " 289225a68471Sdougm "option\n")); 289325a68471Sdougm return (SA_BAD_PATH); 289425a68471Sdougm } 2895549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 289625a68471Sdougm if (group == NULL) { 289725a68471Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 289825a68471Sdougm argv[optind]); 289925a68471Sdougm return (SA_NO_SUCH_GROUP); 290025a68471Sdougm } 2901549ec3ffSdougm share = sa_find_share(handle, sharepath); 2902573b0c00Sdougm /* 2903573b0c00Sdougm * If a share wasn't found, it may have been a symlink 2904573b0c00Sdougm * or has a trailing '/'. Try again after resolving 2905573b0c00Sdougm * with realpath(). 2906573b0c00Sdougm */ 2907573b0c00Sdougm if (share == NULL) { 2908573b0c00Sdougm if (realpath(sharepath, dir) == NULL) { 2909573b0c00Sdougm (void) printf(gettext("Path " 2910573b0c00Sdougm "is not valid: %s\n"), 2911573b0c00Sdougm sharepath); 2912573b0c00Sdougm return (SA_BAD_PATH); 2913573b0c00Sdougm } 2914573b0c00Sdougm sharepath = dir; 2915573b0c00Sdougm share = sa_find_share(handle, sharepath); 2916573b0c00Sdougm } 29176185db85Sdougm if (share == NULL) { 29186185db85Sdougm (void) printf(gettext("Share not found: %s\n"), 29196185db85Sdougm sharepath); 292025a68471Sdougm return (SA_NO_SUCH_PATH); 292125a68471Sdougm } 2922573b0c00Sdougm authdst = check_authorizations(argv[optind], flags); 29236185db85Sdougm 29246185db85Sdougm parent = sa_get_parent_group(share); 29256185db85Sdougm if (parent != NULL) { 29266185db85Sdougm char *pname; 29276185db85Sdougm pname = sa_get_group_attr(parent, "name"); 29286185db85Sdougm if (pname != NULL) { 29296185db85Sdougm authsrc = check_authorizations(pname, flags); 29306185db85Sdougm sa_free_attr_string(pname); 29316185db85Sdougm } 29326185db85Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 29336185db85Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 29346185db85Sdougm if ((zfsold != NULL && zfsnew == NULL) || 29356185db85Sdougm (zfsold == NULL && zfsnew != NULL)) { 29366185db85Sdougm ret = SA_NOT_ALLOWED; 29376185db85Sdougm } 29386185db85Sdougm if (zfsold != NULL) 29396185db85Sdougm sa_free_attr_string(zfsold); 29406185db85Sdougm if (zfsnew != NULL) 29416185db85Sdougm sa_free_attr_string(zfsnew); 29426185db85Sdougm } 294325a68471Sdougm 29446185db85Sdougm if (ret == SA_OK && parent != group && !dryrun) { 29456185db85Sdougm char *oldstate; 29466185db85Sdougm /* 294725a68471Sdougm * Note that the share may need to be 2948da6c28aaSamw * "unshared" if the new group is disabled and 2949da6c28aaSamw * the old was enabled or it may need to be 2950da6c28aaSamw * share to update if the new group is 2951da6c28aaSamw * enabled. We disable before the move and 2952da6c28aaSamw * will have to enable after the move in order 2953da6c28aaSamw * to cleanup entries for protocols that 2954da6c28aaSamw * aren't in the new group. 29556185db85Sdougm */ 29566185db85Sdougm oldstate = sa_get_group_attr(parent, "state"); 2957fe1c642dSBill Krier if (oldstate != NULL) { 29586185db85Sdougm /* enable_share determines what to do */ 2959da6c28aaSamw if (strcmp(oldstate, "enabled") == 0) 29606185db85Sdougm (void) sa_disable_share(share, NULL); 29616185db85Sdougm sa_free_attr_string(oldstate); 29626185db85Sdougm } 2963fe1c642dSBill Krier } 296425a68471Sdougm 2965da6c28aaSamw if (!dryrun && ret == SA_OK) 2966da6c28aaSamw ret = sa_move_share(group, share); 2967da6c28aaSamw 2968da6c28aaSamw /* 2969da6c28aaSamw * Reenable and update any config information. 2970da6c28aaSamw */ 2971da6c28aaSamw if (ret == SA_OK && parent != group && !dryrun) { 2972da6c28aaSamw ret = sa_update_config(handle); 2973da6c28aaSamw 2974da6c28aaSamw (void) enable_share(handle, group, share, 1); 2975da6c28aaSamw } 2976da6c28aaSamw 297725a68471Sdougm if (ret != SA_OK) 29786185db85Sdougm (void) printf(gettext("Could not move share: %s\n"), 29796185db85Sdougm sa_errorstr(ret)); 298025a68471Sdougm 29816185db85Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 29826185db85Sdougm verbose) { 29836185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 29846185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 29856185db85Sdougm } 29866185db85Sdougm } 29876185db85Sdougm return (ret); 29886185db85Sdougm } 29896185db85Sdougm 29906185db85Sdougm /* 29916185db85Sdougm * sa_removeshare(flags, argc, argv) 29926185db85Sdougm * 29936185db85Sdougm * implements remove-share subcommand. 29946185db85Sdougm */ 29956185db85Sdougm 29966185db85Sdougm int 2997549ec3ffSdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 29986185db85Sdougm { 29996185db85Sdougm int verbose = 0; 30006185db85Sdougm int dryrun = 0; 30016185db85Sdougm int force = 0; 30026185db85Sdougm int c; 30036185db85Sdougm int ret = SA_OK; 30046185db85Sdougm sa_group_t group; 3005da6c28aaSamw sa_resource_t resource = NULL; 3006da6c28aaSamw sa_share_t share = NULL; 3007da6c28aaSamw char *rsrcname = NULL; 30086185db85Sdougm char *sharepath = NULL; 30096185db85Sdougm char dir[MAXPATHLEN]; 30106185db85Sdougm int auth; 30116185db85Sdougm 3012da6c28aaSamw while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) { 30136185db85Sdougm switch (c) { 30146185db85Sdougm case 'n': 30156185db85Sdougm dryrun++; 30166185db85Sdougm break; 30176185db85Sdougm case 'v': 30186185db85Sdougm verbose++; 30196185db85Sdougm break; 30206185db85Sdougm case 'f': 30216185db85Sdougm force++; 30226185db85Sdougm break; 30236185db85Sdougm case 's': 30246185db85Sdougm /* 302525a68471Sdougm * Remove share path from group. Currently limit 30266185db85Sdougm * to one share per command. 30276185db85Sdougm */ 30286185db85Sdougm if (sharepath != NULL) { 302925a68471Sdougm (void) printf(gettext( 303025a68471Sdougm "Removing multiple shares not " 30316185db85Sdougm "supported\n")); 30326185db85Sdougm return (SA_SYNTAX_ERR); 30336185db85Sdougm } 30346185db85Sdougm sharepath = optarg; 30356185db85Sdougm break; 3036da6c28aaSamw case 'r': 3037da6c28aaSamw /* 3038da6c28aaSamw * Remove share from group if last resource or remove 3039da6c28aaSamw * resource from share if multiple resources. 3040da6c28aaSamw */ 3041da6c28aaSamw if (rsrcname != NULL) { 3042da6c28aaSamw (void) printf(gettext( 3043da6c28aaSamw "Removing multiple resource names not " 3044da6c28aaSamw "supported\n")); 3045da6c28aaSamw return (SA_SYNTAX_ERR); 3046da6c28aaSamw } 3047da6c28aaSamw rsrcname = optarg; 3048da6c28aaSamw break; 3049e7bab347Sdougm case 'h': 3050e7bab347Sdougm /* optopt on valid arg isn't defined */ 3051e7bab347Sdougm optopt = c; 3052e7bab347Sdougm /*FALLTHROUGH*/ 3053e7bab347Sdougm case '?': 30546185db85Sdougm default: 3055e7bab347Sdougm /* 3056e7bab347Sdougm * Since a bad option gets to here, sort it 3057e7bab347Sdougm * out and return a syntax error return value 3058e7bab347Sdougm * if necessary. 3059e7bab347Sdougm */ 3060e7bab347Sdougm switch (optopt) { 3061e7bab347Sdougm default: 3062e7bab347Sdougm ret = SA_SYNTAX_ERR; 3063e7bab347Sdougm break; 30646185db85Sdougm case 'h': 30656185db85Sdougm case '?': 3066e7bab347Sdougm break; 3067e7bab347Sdougm } 30686185db85Sdougm (void) printf(gettext("usage: %s\n"), 30696185db85Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 3070e7bab347Sdougm return (ret); 30716185db85Sdougm } 30726185db85Sdougm } 30736185db85Sdougm 3074da6c28aaSamw if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) { 3075da6c28aaSamw if (sharepath == NULL && rsrcname == NULL) { 30766185db85Sdougm (void) printf(gettext("usage: %s\n"), 30776185db85Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 3078da6c28aaSamw (void) printf(gettext("\t-s sharepath or -r resource" 3079da6c28aaSamw " must be specified\n")); 30806185db85Sdougm ret = SA_BAD_PATH; 30816185db85Sdougm } else { 30826185db85Sdougm ret = SA_OK; 30836185db85Sdougm } 30846185db85Sdougm } 308525a68471Sdougm if (ret != SA_OK) { 308625a68471Sdougm return (ret); 308725a68471Sdougm } 308825a68471Sdougm 30896185db85Sdougm if (optind < argc) { 30906185db85Sdougm if ((optind + 1) < argc) { 30916185db85Sdougm (void) printf(gettext("Extraneous group(s) at end of " 30926185db85Sdougm "command\n")); 30936185db85Sdougm ret = SA_SYNTAX_ERR; 30946185db85Sdougm } else { 3095549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 30966185db85Sdougm if (group == NULL) { 309725a68471Sdougm (void) printf(gettext( 309825a68471Sdougm "Group \"%s\" not found\n"), argv[optind]); 30996185db85Sdougm ret = SA_NO_SUCH_GROUP; 31006185db85Sdougm } 31016185db85Sdougm } 31026185db85Sdougm } else { 31036185db85Sdougm group = NULL; 31046185db85Sdougm } 3105a99982a7Sdougm 3106da6c28aaSamw if (rsrcname != NULL) { 3107da6c28aaSamw resource = sa_find_resource(handle, rsrcname); 3108da6c28aaSamw if (resource == NULL) { 3109da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3110da6c28aaSamw (void) printf(gettext( 3111da6c28aaSamw "Resource name not found for share: %s\n"), 3112da6c28aaSamw rsrcname); 3113da6c28aaSamw } 3114da6c28aaSamw } 3115da6c28aaSamw 3116a99982a7Sdougm /* 3117a99982a7Sdougm * Lookup the path in the internal configuration. Care 3118a99982a7Sdougm * must be taken to handle the case where the 3119a99982a7Sdougm * underlying path has been removed since we need to 3120a99982a7Sdougm * be able to deal with that as well. 3121a99982a7Sdougm */ 31226185db85Sdougm if (ret == SA_OK) { 3123da6c28aaSamw if (sharepath != NULL) { 31246185db85Sdougm if (group != NULL) 31256185db85Sdougm share = sa_get_share(group, sharepath); 31266185db85Sdougm else 3127549ec3ffSdougm share = sa_find_share(handle, sharepath); 3128da6c28aaSamw } 3129da6c28aaSamw 3130da6c28aaSamw if (resource != NULL) { 3131da6c28aaSamw sa_share_t rsrcshare; 3132da6c28aaSamw rsrcshare = sa_get_resource_parent(resource); 3133da6c28aaSamw if (share == NULL) 3134da6c28aaSamw share = rsrcshare; 3135da6c28aaSamw else if (share != rsrcshare) { 3136da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3137da6c28aaSamw (void) printf(gettext( 3138da6c28aaSamw "Bad resource name for share: %s\n"), 3139da6c28aaSamw rsrcname); 3140da6c28aaSamw share = NULL; 3141da6c28aaSamw } 3142da6c28aaSamw } 3143da6c28aaSamw 3144a99982a7Sdougm /* 3145a99982a7Sdougm * If we didn't find the share with the provided path, 3146a99982a7Sdougm * it may be a symlink so attempt to resolve it using 3147a99982a7Sdougm * realpath and try again. Realpath will resolve any 3148a99982a7Sdougm * symlinks and place them in "dir". Note that 3149a99982a7Sdougm * sharepath is only used for the lookup the first 3150a99982a7Sdougm * time and later for error messages. dir will be used 3151a99982a7Sdougm * on the second attempt. Once a share is found, all 3152a99982a7Sdougm * operations are based off of the share variable. 3153a99982a7Sdougm */ 3154a99982a7Sdougm if (share == NULL) { 3155a99982a7Sdougm if (realpath(sharepath, dir) == NULL) { 3156a99982a7Sdougm ret = SA_BAD_PATH; 315725a68471Sdougm (void) printf(gettext( 315825a68471Sdougm "Path is not valid: %s\n"), sharepath); 3159a99982a7Sdougm } else { 3160a99982a7Sdougm if (group != NULL) 3161a99982a7Sdougm share = sa_get_share(group, dir); 3162a99982a7Sdougm else 3163549ec3ffSdougm share = sa_find_share(handle, dir); 3164a99982a7Sdougm } 3165a99982a7Sdougm } 3166a99982a7Sdougm } 3167a99982a7Sdougm 3168a99982a7Sdougm /* 3169a99982a7Sdougm * If there hasn't been an error, there was likely a 3170a99982a7Sdougm * path found. If not, give the appropriate error 3171a99982a7Sdougm * message and set the return error. If it was found, 3172a99982a7Sdougm * then disable the share and then remove it from the 3173a99982a7Sdougm * configuration. 3174a99982a7Sdougm */ 317525a68471Sdougm if (ret != SA_OK) { 317625a68471Sdougm return (ret); 317725a68471Sdougm } 31786185db85Sdougm if (share == NULL) { 31796185db85Sdougm if (group != NULL) 31806185db85Sdougm (void) printf(gettext("Share not found in group %s:" 318125a68471Sdougm " %s\n"), argv[optind], sharepath); 31826185db85Sdougm else 31836185db85Sdougm (void) printf(gettext("Share not found: %s\n"), 31846185db85Sdougm sharepath); 31856185db85Sdougm ret = SA_NO_SUCH_PATH; 31866185db85Sdougm } else { 31876185db85Sdougm if (group == NULL) 31886185db85Sdougm group = sa_get_parent_group(share); 31896185db85Sdougm if (!dryrun) { 31906185db85Sdougm if (ret == SA_OK) { 3191da6c28aaSamw if (resource != NULL) 3192da6c28aaSamw ret = sa_disable_resource(resource, 3193da6c28aaSamw NULL); 3194da6c28aaSamw else 31956185db85Sdougm ret = sa_disable_share(share, NULL); 31966185db85Sdougm /* 319725a68471Sdougm * We don't care if it fails since it 3198a99982a7Sdougm * could be disabled already. Some 3199a99982a7Sdougm * unexpected errors could occur that 3200a99982a7Sdougm * prevent removal, so also check for 3201a99982a7Sdougm * force being set. 32026185db85Sdougm */ 3203da6c28aaSamw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 3204a99982a7Sdougm ret == SA_NOT_SUPPORTED || 3205da6c28aaSamw ret == SA_SYSTEM_ERR || force) && 3206da6c28aaSamw resource == NULL) 32076185db85Sdougm ret = sa_remove_share(share); 3208da6c28aaSamw 3209da6c28aaSamw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 3210da6c28aaSamw ret == SA_NOT_SUPPORTED || 3211da6c28aaSamw ret == SA_SYSTEM_ERR || force) && 3212da6c28aaSamw resource != NULL) { 3213da6c28aaSamw ret = sa_remove_resource(resource); 3214da6c28aaSamw if (ret == SA_OK) { 3215da6c28aaSamw /* 3216da6c28aaSamw * If this was the 3217da6c28aaSamw * last one, remove 3218da6c28aaSamw * the share as well. 3219da6c28aaSamw */ 3220da6c28aaSamw resource = 3221da6c28aaSamw sa_get_share_resource( 3222da6c28aaSamw share, NULL); 3223da6c28aaSamw if (resource == NULL) 3224da6c28aaSamw ret = sa_remove_share( 3225da6c28aaSamw share); 3226da6c28aaSamw } 32276185db85Sdougm } 32286185db85Sdougm if (ret == SA_OK) 3229549ec3ffSdougm ret = sa_update_config(handle); 32306185db85Sdougm } 323125a68471Sdougm if (ret != SA_OK) 3232da6c28aaSamw (void) printf(gettext("Could not remove share:" 3233da6c28aaSamw " %s\n"), sa_errorstr(ret)); 32346185db85Sdougm } else if (ret == SA_OK) { 32356185db85Sdougm char *pname; 32366185db85Sdougm pname = sa_get_group_attr(group, "name"); 32376185db85Sdougm if (pname != NULL) { 32386185db85Sdougm auth = check_authorizations(pname, flags); 32396185db85Sdougm sa_free_attr_string(pname); 32406185db85Sdougm } 32416185db85Sdougm if (!auth && verbose) { 324225a68471Sdougm (void) printf(gettext( 324325a68471Sdougm "Command would fail: %s\n"), 32446185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 32456185db85Sdougm } 32466185db85Sdougm } 32476185db85Sdougm } 32486185db85Sdougm return (ret); 32496185db85Sdougm } 32506185db85Sdougm 32516185db85Sdougm /* 32526185db85Sdougm * sa_set_share(flags, argc, argv) 32536185db85Sdougm * 32546185db85Sdougm * implements set-share subcommand. 32556185db85Sdougm */ 32566185db85Sdougm 32576185db85Sdougm int 3258549ec3ffSdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 32596185db85Sdougm { 32606185db85Sdougm int dryrun = 0; 32616185db85Sdougm int c; 32626185db85Sdougm int ret = SA_OK; 32636185db85Sdougm sa_group_t group, sharegroup; 3264dc20a302Sas200622 sa_share_t share = NULL; 3265da6c28aaSamw sa_resource_t resource = NULL; 32666185db85Sdougm char *sharepath = NULL; 32676185db85Sdougm char *description = NULL; 3268da6c28aaSamw char *rsrcname = NULL; 3269da6c28aaSamw char *rsrc = NULL; 3270da6c28aaSamw char *newname = NULL; 3271da6c28aaSamw char *newrsrc; 3272da6c28aaSamw char *groupname = NULL; 32736185db85Sdougm int auth; 32746185db85Sdougm int verbose = 0; 32756185db85Sdougm 32766185db85Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 32776185db85Sdougm switch (c) { 32786185db85Sdougm case 'n': 32796185db85Sdougm dryrun++; 32806185db85Sdougm break; 32816185db85Sdougm case 'd': 32826185db85Sdougm description = optarg; 32836185db85Sdougm break; 32846185db85Sdougm case 'v': 32856185db85Sdougm verbose++; 32866185db85Sdougm break; 3287da6c28aaSamw case 'r': 3288da6c28aaSamw /* 3289da6c28aaSamw * Update share by resource name 3290da6c28aaSamw */ 3291da6c28aaSamw if (rsrcname != NULL) { 3292da6c28aaSamw (void) printf(gettext( 3293da6c28aaSamw "Updating multiple resource names not " 3294da6c28aaSamw "supported\n")); 3295da6c28aaSamw return (SA_SYNTAX_ERR); 3296da6c28aaSamw } 3297da6c28aaSamw rsrcname = optarg; 3298da6c28aaSamw break; 32996185db85Sdougm case 's': 33006185db85Sdougm /* 330125a68471Sdougm * Save share path into group. Currently limit 33026185db85Sdougm * to one share per command. 33036185db85Sdougm */ 33046185db85Sdougm if (sharepath != NULL) { 330525a68471Sdougm (void) printf(gettext( 330625a68471Sdougm "Updating multiple shares not " 33076185db85Sdougm "supported\n")); 3308da6c28aaSamw return (SA_SYNTAX_ERR); 33096185db85Sdougm } 33106185db85Sdougm sharepath = optarg; 33116185db85Sdougm break; 3312e7bab347Sdougm case 'h': 3313e7bab347Sdougm /* optopt on valid arg isn't defined */ 3314e7bab347Sdougm optopt = c; 3315e7bab347Sdougm /*FALLTHROUGH*/ 3316e7bab347Sdougm case '?': 33176185db85Sdougm default: 3318e7bab347Sdougm /* 3319e7bab347Sdougm * Since a bad option gets to here, sort it 3320e7bab347Sdougm * out and return a syntax error return value 3321e7bab347Sdougm * if necessary. 3322e7bab347Sdougm */ 3323e7bab347Sdougm switch (optopt) { 3324e7bab347Sdougm default: 3325e7bab347Sdougm ret = SA_SYNTAX_ERR; 3326e7bab347Sdougm break; 33276185db85Sdougm case 'h': 33286185db85Sdougm case '?': 3329e7bab347Sdougm break; 3330e7bab347Sdougm } 33316185db85Sdougm (void) printf(gettext("usage: %s\n"), 33326185db85Sdougm sa_get_usage(USAGE_SET_SHARE)); 3333e7bab347Sdougm return (ret); 33346185db85Sdougm } 33356185db85Sdougm } 333625a68471Sdougm 3337da6c28aaSamw if (optind >= argc && sharepath == NULL && rsrcname == NULL) { 33386185db85Sdougm if (sharepath == NULL) { 33396185db85Sdougm (void) printf(gettext("usage: %s\n"), 33406185db85Sdougm sa_get_usage(USAGE_SET_SHARE)); 33416185db85Sdougm (void) printf(gettext("\tgroup must be specified\n")); 33426185db85Sdougm ret = SA_BAD_PATH; 33436185db85Sdougm } else { 33446185db85Sdougm ret = SA_OK; 33456185db85Sdougm } 33466185db85Sdougm } 33476185db85Sdougm if ((optind + 1) < argc) { 33486185db85Sdougm (void) printf(gettext("usage: %s\n"), 33496185db85Sdougm sa_get_usage(USAGE_SET_SHARE)); 33506185db85Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 33516185db85Sdougm ret = SA_SYNTAX_ERR; 33526185db85Sdougm } 335325a68471Sdougm 3354da6c28aaSamw /* 3355da6c28aaSamw * Must have at least one of sharepath and rsrcrname. 3356da6c28aaSamw * It is a syntax error to be missing both. 3357da6c28aaSamw */ 3358da6c28aaSamw if (sharepath == NULL && rsrcname == NULL) { 3359da6c28aaSamw (void) printf(gettext("usage: %s\n"), 3360da6c28aaSamw sa_get_usage(USAGE_SET_SHARE)); 3361da6c28aaSamw ret = SA_SYNTAX_ERR; 3362da6c28aaSamw } 3363da6c28aaSamw 336425a68471Sdougm if (ret != SA_OK) 336525a68471Sdougm return (ret); 336625a68471Sdougm 33676185db85Sdougm if (optind < argc) { 33686185db85Sdougm groupname = argv[optind]; 3369549ec3ffSdougm group = sa_get_group(handle, groupname); 33706185db85Sdougm } else { 33716185db85Sdougm group = NULL; 33726185db85Sdougm groupname = NULL; 33736185db85Sdougm } 3374da6c28aaSamw if (rsrcname != NULL) { 3375da6c28aaSamw /* 3376da6c28aaSamw * If rsrcname exists, split rename syntax and then 3377da6c28aaSamw * convert to utf 8 if no errors. 3378da6c28aaSamw */ 3379da6c28aaSamw newname = strchr(rsrcname, '='); 3380da6c28aaSamw if (newname != NULL) { 3381da6c28aaSamw *newname++ = '\0'; 338225a68471Sdougm } 3383da6c28aaSamw if (!validresource(rsrcname)) { 3384da6c28aaSamw ret = SA_INVALID_NAME; 3385da6c28aaSamw (void) printf(gettext("Invalid resource name: " 3386da6c28aaSamw "\"%s\"\n"), rsrcname); 3387da6c28aaSamw } else { 3388da6c28aaSamw rsrc = conv_to_utf8(rsrcname); 3389da6c28aaSamw } 3390da6c28aaSamw if (newname != NULL) { 3391da6c28aaSamw if (!validresource(newname)) { 3392da6c28aaSamw ret = SA_INVALID_NAME; 3393da6c28aaSamw (void) printf(gettext("Invalid resource name: " 3394da6c28aaSamw "%s\n"), newname); 3395ef18c5ecSDoug McCallum newname = NULL; 3396da6c28aaSamw } else { 3397da6c28aaSamw newrsrc = conv_to_utf8(newname); 3398da6c28aaSamw } 3399da6c28aaSamw } 3400da6c28aaSamw } 3401da6c28aaSamw 3402da6c28aaSamw if (ret != SA_OK) { 3403da6c28aaSamw if (rsrcname != NULL && rsrcname != rsrc) 3404da6c28aaSamw sa_free_attr_string(rsrc); 3405da6c28aaSamw if (newname != NULL && newname != newrsrc) 3406da6c28aaSamw sa_free_attr_string(newrsrc); 3407da6c28aaSamw return (ret); 3408da6c28aaSamw } 3409da6c28aaSamw 3410da6c28aaSamw if (sharepath != NULL) { 3411da6c28aaSamw share = sa_find_share(handle, sharepath); 3412da6c28aaSamw } else if (rsrcname != NULL) { 3413da6c28aaSamw resource = sa_find_resource(handle, rsrc); 3414dc20a302Sas200622 if (resource != NULL) 3415da6c28aaSamw share = sa_get_resource_parent(resource); 3416dc20a302Sas200622 else 3417dc20a302Sas200622 ret = SA_NO_SUCH_RESOURCE; 3418da6c28aaSamw } 3419da6c28aaSamw if (share != NULL) { 34206185db85Sdougm sharegroup = sa_get_parent_group(share); 34216185db85Sdougm if (group != NULL && group != sharegroup) { 34226185db85Sdougm (void) printf(gettext("Group \"%s\" does not contain " 3423da6c28aaSamw "share %s\n"), 3424da6c28aaSamw argv[optind], sharepath); 34256185db85Sdougm ret = SA_BAD_PATH; 34266185db85Sdougm } else { 34276185db85Sdougm int delgroupname = 0; 34286185db85Sdougm if (groupname == NULL) { 3429da6c28aaSamw groupname = sa_get_group_attr(sharegroup, 3430da6c28aaSamw "name"); 34316185db85Sdougm delgroupname = 1; 34326185db85Sdougm } 34336185db85Sdougm if (groupname != NULL) { 34346185db85Sdougm auth = check_authorizations(groupname, flags); 34356185db85Sdougm if (delgroupname) { 34366185db85Sdougm sa_free_attr_string(groupname); 34376185db85Sdougm groupname = NULL; 34386185db85Sdougm } 34396185db85Sdougm } else { 34406185db85Sdougm ret = SA_NO_MEMORY; 34416185db85Sdougm } 3442da6c28aaSamw if (rsrcname != NULL) { 3443da6c28aaSamw resource = sa_find_resource(handle, rsrc); 34446185db85Sdougm if (!dryrun) { 3445da6c28aaSamw if (newname != NULL && 3446da6c28aaSamw resource != NULL) 3447da6c28aaSamw ret = sa_rename_resource( 3448da6c28aaSamw resource, newrsrc); 3449da6c28aaSamw else if (newname != NULL) 3450da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3451da6c28aaSamw if (newname != NULL && 3452da6c28aaSamw newname != newrsrc) 3453da6c28aaSamw sa_free_attr_string(newrsrc); 34546185db85Sdougm } 3455da6c28aaSamw if (rsrc != rsrcname) 3456da6c28aaSamw sa_free_attr_string(rsrc); 34576185db85Sdougm } 345825a68471Sdougm 3459da6c28aaSamw /* 3460da6c28aaSamw * If the user has set a description, it will be 3461da6c28aaSamw * on the resource if -r was used otherwise it 3462da6c28aaSamw * must be on the share. 3463da6c28aaSamw */ 3464cbfb650aScp160787 if (!dryrun && ret == SA_OK && description != NULL) { 3465cbfb650aScp160787 char *desc; 3466cbfb650aScp160787 desc = conv_to_utf8(description); 3467da6c28aaSamw if (resource != NULL) 3468cbfb650aScp160787 ret = sa_set_resource_description( 3469cbfb650aScp160787 resource, desc); 3470da6c28aaSamw else 3471cbfb650aScp160787 ret = sa_set_share_description(share, 3472cbfb650aScp160787 desc); 3473cbfb650aScp160787 if (desc != description) 3474cbfb650aScp160787 sa_free_share_description(desc); 3475da6c28aaSamw } 3476da6c28aaSamw } 3477da6c28aaSamw if (!dryrun && ret == SA_OK) { 3478da6c28aaSamw if (resource != NULL) 3479da6c28aaSamw (void) sa_enable_resource(resource, NULL); 3480da6c28aaSamw ret = sa_update_config(handle); 3481da6c28aaSamw } 34826185db85Sdougm switch (ret) { 34836185db85Sdougm case SA_DUPLICATE_NAME: 3484da6c28aaSamw (void) printf(gettext("Resource name in use: %s\n"), 3485da6c28aaSamw rsrcname); 34866185db85Sdougm break; 34876185db85Sdougm default: 3488da6c28aaSamw (void) printf(gettext("Could not set: %s\n"), 34896185db85Sdougm sa_errorstr(ret)); 34906185db85Sdougm break; 34916185db85Sdougm case SA_OK: 3492da6c28aaSamw if (dryrun && !auth && verbose) { 3493da6c28aaSamw (void) printf(gettext( 3494da6c28aaSamw "Command would fail: %s\n"), 34956185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 3496da6c28aaSamw } 34976185db85Sdougm break; 34986185db85Sdougm } 3499da6c28aaSamw } else { 3500dc20a302Sas200622 switch (ret) { 3501dc20a302Sas200622 case SA_NO_SUCH_RESOURCE: 3502dc20a302Sas200622 (void) printf(gettext("Resource \"%s\" not found\n"), 3503dc20a302Sas200622 rsrcname); 3504dc20a302Sas200622 break; 3505dc20a302Sas200622 default: 3506dc20a302Sas200622 if (sharepath != NULL) { 3507dc20a302Sas200622 (void) printf( 3508dc20a302Sas200622 gettext("Share path \"%s\" not found\n"), 3509da6c28aaSamw sharepath); 3510da6c28aaSamw ret = SA_NO_SUCH_PATH; 3511dc20a302Sas200622 } else { 3512dc20a302Sas200622 (void) printf(gettext("Set failed: %s\n"), 3513dc20a302Sas200622 sa_errorstr(ret)); 3514dc20a302Sas200622 } 3515dc20a302Sas200622 } 3516da6c28aaSamw } 351725a68471Sdougm 35186185db85Sdougm return (ret); 35196185db85Sdougm } 35206185db85Sdougm 35216185db85Sdougm /* 35226185db85Sdougm * add_security(group, sectype, optlist, proto, *err) 35236185db85Sdougm * 35246185db85Sdougm * Helper function to add a security option (named optionset) to the 35256185db85Sdougm * group. 35266185db85Sdougm */ 35276185db85Sdougm 35286185db85Sdougm static int 35296185db85Sdougm add_security(sa_group_t group, char *sectype, 35306185db85Sdougm struct options *optlist, char *proto, int *err) 35316185db85Sdougm { 35326185db85Sdougm sa_security_t security; 35336185db85Sdougm int ret = SA_OK; 35346185db85Sdougm int result = 0; 3535687915e9Sdougm sa_handle_t handle; 35366185db85Sdougm 35376185db85Sdougm sectype = sa_proto_space_alias(proto, sectype); 35386185db85Sdougm security = sa_get_security(group, sectype, proto); 353925a68471Sdougm if (security == NULL) 35406185db85Sdougm security = sa_create_security(group, sectype, proto); 354125a68471Sdougm 35426185db85Sdougm if (sectype != NULL) 35436185db85Sdougm sa_free_attr_string(sectype); 354425a68471Sdougm 354525a68471Sdougm if (security == NULL) 3546687915e9Sdougm goto done; 354725a68471Sdougm 3548687915e9Sdougm handle = sa_find_group_handle(group); 3549687915e9Sdougm if (handle == NULL) { 3550687915e9Sdougm ret = SA_CONFIG_ERR; 3551687915e9Sdougm goto done; 3552687915e9Sdougm } 35536185db85Sdougm while (optlist != NULL) { 35546185db85Sdougm sa_property_t prop; 35556185db85Sdougm prop = sa_get_property(security, optlist->optname); 35566185db85Sdougm if (prop == NULL) { 35576185db85Sdougm /* 355825a68471Sdougm * Add the property, but only if it is 35596185db85Sdougm * a non-NULL or non-zero length value 35606185db85Sdougm */ 35616185db85Sdougm if (optlist->optvalue != NULL) { 35626185db85Sdougm prop = sa_create_property(optlist->optname, 35636185db85Sdougm optlist->optvalue); 35646185db85Sdougm if (prop != NULL) { 3565687915e9Sdougm ret = sa_valid_property(handle, 3566687915e9Sdougm security, proto, prop); 35676185db85Sdougm if (ret != SA_OK) { 35686185db85Sdougm (void) sa_remove_property(prop); 356925a68471Sdougm (void) printf(gettext( 357025a68471Sdougm "Could not add " 35716185db85Sdougm "property %s: %s\n"), 35726185db85Sdougm optlist->optname, 35736185db85Sdougm sa_errorstr(ret)); 35746185db85Sdougm } 35756185db85Sdougm if (ret == SA_OK) { 357625a68471Sdougm ret = sa_add_property(security, 357725a68471Sdougm prop); 35786185db85Sdougm if (ret != SA_OK) { 357925a68471Sdougm (void) printf(gettext( 358025a68471Sdougm "Could not add " 358125a68471Sdougm "property (%s=%s):" 358225a68471Sdougm " %s\n"), 35836185db85Sdougm optlist->optname, 35846185db85Sdougm optlist->optvalue, 35856185db85Sdougm sa_errorstr(ret)); 35866185db85Sdougm } else { 35876185db85Sdougm result = 1; 35886185db85Sdougm } 35896185db85Sdougm } 35906185db85Sdougm } 35916185db85Sdougm } 35926185db85Sdougm } else { 35936185db85Sdougm ret = sa_update_property(prop, optlist->optvalue); 35946185db85Sdougm result = 1; /* should check if really changed */ 35956185db85Sdougm } 35966185db85Sdougm optlist = optlist->next; 35976185db85Sdougm } 35986185db85Sdougm /* 359925a68471Sdougm * When done, properties may have all been removed but 36006185db85Sdougm * we need to keep the security type itself until 36016185db85Sdougm * explicitly removed. 36026185db85Sdougm */ 36036185db85Sdougm if (result) 36046185db85Sdougm ret = sa_commit_properties(security, 0); 3605687915e9Sdougm done: 36066185db85Sdougm *err = ret; 36076185db85Sdougm return (result); 36086185db85Sdougm } 36096185db85Sdougm 36106185db85Sdougm /* 3611f8825440Sdougm * zfscheck(group, share) 3612f8825440Sdougm * 3613f8825440Sdougm * For the special case where a share was provided, make sure it is a 3614f8825440Sdougm * compatible path for a ZFS property change. The only path 3615f8825440Sdougm * acceptable is the path that defines the zfs sub-group (dataset with 3616f8825440Sdougm * the sharenfs property set) and not one of the paths that inherited 3617f8825440Sdougm * the NFS properties. Returns SA_OK if it is usable and 3618f8825440Sdougm * SA_NOT_ALLOWED if it isn't. 3619f8825440Sdougm * 3620f8825440Sdougm * If group is not a ZFS group/subgroup, we assume OK since the check 3621f8825440Sdougm * on return will catch errors for those cases. What we are looking 3622f8825440Sdougm * for here is that the group is ZFS and the share is not the defining 3623f8825440Sdougm * share. All else is SA_OK. 3624f8825440Sdougm */ 3625f8825440Sdougm 3626f8825440Sdougm static int 3627f8825440Sdougm zfscheck(sa_group_t group, sa_share_t share) 3628f8825440Sdougm { 3629f8825440Sdougm int ret = SA_OK; 3630f8825440Sdougm char *attr; 3631f8825440Sdougm 3632f8825440Sdougm if (sa_group_is_zfs(group)) { 3633f8825440Sdougm /* 3634f8825440Sdougm * The group is a ZFS group. Does the share represent 3635f8825440Sdougm * the dataset that defined the group? It is only OK 3636f8825440Sdougm * if the attribute "subgroup" exists on the share and 3637f8825440Sdougm * has a value of "true". 3638f8825440Sdougm */ 3639f8825440Sdougm 3640f8825440Sdougm ret = SA_NOT_ALLOWED; 3641f8825440Sdougm attr = sa_get_share_attr(share, "subgroup"); 3642f8825440Sdougm if (attr != NULL) { 3643f8825440Sdougm if (strcmp(attr, "true") == 0) 3644f8825440Sdougm ret = SA_OK; 3645f8825440Sdougm sa_free_attr_string(attr); 3646f8825440Sdougm } 3647f8825440Sdougm } 3648f8825440Sdougm return (ret); 3649f8825440Sdougm } 3650f8825440Sdougm 3651f8825440Sdougm /* 3652da6c28aaSamw * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 36536185db85Sdougm * 36546185db85Sdougm * This function implements "set" when a name space (-S) is not 36556185db85Sdougm * specified. It is a basic set. Options and other CLI parsing has 36566185db85Sdougm * already been done. 3657da6c28aaSamw * 3658da6c28aaSamw * "rsrcname" is a "resource name". If it is non-NULL, it must match 3659da6c28aaSamw * the sharepath if present or group if present, otherwise it is used 3660da6c28aaSamw * to set options. 3661da6c28aaSamw * 3662da6c28aaSamw * Resource names may take options if the protocol supports it. If the 3663da6c28aaSamw * protocol doesn't support resource level options, rsrcname is just 3664da6c28aaSamw * an alias for the share. 36656185db85Sdougm */ 36666185db85Sdougm 36676185db85Sdougm static int 3668549ec3ffSdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 3669da6c28aaSamw char *protocol, char *sharepath, char *rsrcname, int dryrun) 36706185db85Sdougm { 36716185db85Sdougm sa_group_t group; 36726185db85Sdougm int ret = SA_OK; 36736185db85Sdougm int change = 0; 36746185db85Sdougm struct list *worklist = NULL; 36756185db85Sdougm 3676549ec3ffSdougm group = sa_get_group(handle, groupname); 36776185db85Sdougm if (group != NULL) { 36786185db85Sdougm sa_share_t share = NULL; 3679da6c28aaSamw sa_resource_t resource = NULL; 3680da6c28aaSamw 3681da6c28aaSamw /* 3682da6c28aaSamw * If there is a sharepath, make sure it belongs to 3683da6c28aaSamw * the group. 3684da6c28aaSamw */ 36856185db85Sdougm if (sharepath != NULL) { 36866185db85Sdougm share = sa_get_share(group, sharepath); 36876185db85Sdougm if (share == NULL) { 368825a68471Sdougm (void) printf(gettext( 368925a68471Sdougm "Share does not exist in group %s\n"), 36906185db85Sdougm groupname, sharepath); 36916185db85Sdougm ret = SA_NO_SUCH_PATH; 3692f8825440Sdougm } else { 3693f8825440Sdougm /* if ZFS and OK, then only group */ 3694f8825440Sdougm ret = zfscheck(group, share); 3695f8825440Sdougm if (ret == SA_OK && 3696f8825440Sdougm sa_group_is_zfs(group)) 3697f8825440Sdougm share = NULL; 3698f8825440Sdougm if (ret == SA_NOT_ALLOWED) 3699f8825440Sdougm (void) printf(gettext( 3700f8825440Sdougm "Properties on ZFS group shares " 3701f8825440Sdougm "not supported: %s\n"), sharepath); 37026185db85Sdougm } 37036185db85Sdougm } 3704da6c28aaSamw 3705da6c28aaSamw /* 3706da6c28aaSamw * If a resource name exists, make sure it belongs to 3707da6c28aaSamw * the share if present else it belongs to the 3708da6c28aaSamw * group. Also check the protocol to see if it 3709da6c28aaSamw * supports resource level properties or not. If not, 3710da6c28aaSamw * use share only. 3711da6c28aaSamw */ 3712da6c28aaSamw if (rsrcname != NULL) { 3713da6c28aaSamw if (share != NULL) { 3714da6c28aaSamw resource = sa_get_share_resource(share, 3715da6c28aaSamw rsrcname); 3716da6c28aaSamw if (resource == NULL) 3717da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3718da6c28aaSamw } else { 3719da6c28aaSamw resource = sa_get_resource(group, rsrcname); 3720da6c28aaSamw if (resource != NULL) 3721da6c28aaSamw share = sa_get_resource_parent( 3722da6c28aaSamw resource); 3723da6c28aaSamw else 3724da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 3725da6c28aaSamw } 3726da6c28aaSamw if (ret == SA_OK && resource != NULL) { 3727da6c28aaSamw uint64_t features; 3728da6c28aaSamw /* 3729da6c28aaSamw * Check to see if the resource can take 3730da6c28aaSamw * properties. If so, stick the resource into 3731da6c28aaSamw * "share" so it will all just work. 3732da6c28aaSamw */ 3733da6c28aaSamw features = sa_proto_get_featureset(protocol); 3734da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 3735da6c28aaSamw share = (sa_share_t)resource; 3736da6c28aaSamw } 3737da6c28aaSamw } 3738da6c28aaSamw 37396185db85Sdougm if (ret == SA_OK) { 37406185db85Sdougm /* group must exist */ 3741687915e9Sdougm ret = valid_options(handle, optlist, protocol, 37426185db85Sdougm share == NULL ? group : share, NULL); 37436185db85Sdougm if (ret == SA_OK && !dryrun) { 37446185db85Sdougm if (share != NULL) 374525a68471Sdougm change |= add_optionset(share, optlist, 374625a68471Sdougm protocol, &ret); 37476185db85Sdougm else 374825a68471Sdougm change |= add_optionset(group, optlist, 374925a68471Sdougm protocol, &ret); 375025a68471Sdougm if (ret == SA_OK && change) 375125a68471Sdougm worklist = add_list(worklist, group, 3752da6c28aaSamw share, protocol); 37536185db85Sdougm } 37546185db85Sdougm } 37556185db85Sdougm free_opt(optlist); 37566185db85Sdougm } else { 37576185db85Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 37586185db85Sdougm ret = SA_NO_SUCH_GROUP; 37596185db85Sdougm } 37606185db85Sdougm /* 37616185db85Sdougm * we have a group and potentially legal additions 37626185db85Sdougm */ 37636185db85Sdougm 376425a68471Sdougm /* 376525a68471Sdougm * Commit to configuration if not a dryrunp and properties 376625a68471Sdougm * have changed. 376725a68471Sdougm */ 376825a68471Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 37696185db85Sdougm /* properties changed, so update all shares */ 3770da6c28aaSamw (void) enable_all_groups(handle, worklist, 0, 0, protocol, 3771da6c28aaSamw B_TRUE); 377225a68471Sdougm 37736185db85Sdougm if (worklist != NULL) 37746185db85Sdougm free_list(worklist); 37756185db85Sdougm return (ret); 37766185db85Sdougm } 37776185db85Sdougm 37786185db85Sdougm /* 37796185db85Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 37806185db85Sdougm * 37816185db85Sdougm * This function implements "set" when a name space (-S) is 37826185db85Sdougm * specified. It is a namespace set. Options and other CLI parsing has 37836185db85Sdougm * already been done. 37846185db85Sdougm */ 37856185db85Sdougm 37866185db85Sdougm static int 3787549ec3ffSdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 3788549ec3ffSdougm char *protocol, char *sharepath, int dryrun, char *sectype) 37896185db85Sdougm { 37906185db85Sdougm sa_group_t group; 37916185db85Sdougm int ret = SA_OK; 37926185db85Sdougm int change = 0; 37936185db85Sdougm struct list *worklist = NULL; 37946185db85Sdougm 37956185db85Sdougm /* 37966185db85Sdougm * make sure protcol and sectype are valid 37976185db85Sdougm */ 37986185db85Sdougm 37996185db85Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 38006185db85Sdougm (void) printf(gettext("Option space \"%s\" not valid " 380125a68471Sdougm "for protocol.\n"), sectype); 38026185db85Sdougm return (SA_INVALID_SECURITY); 38036185db85Sdougm } 38046185db85Sdougm 3805549ec3ffSdougm group = sa_get_group(handle, groupname); 38066185db85Sdougm if (group != NULL) { 38076185db85Sdougm sa_share_t share = NULL; 38086185db85Sdougm if (sharepath != NULL) { 38096185db85Sdougm share = sa_get_share(group, sharepath); 38106185db85Sdougm if (share == NULL) { 381125a68471Sdougm (void) printf(gettext( 381225a68471Sdougm "Share does not exist in group %s\n"), 38136185db85Sdougm groupname, sharepath); 38146185db85Sdougm ret = SA_NO_SUCH_PATH; 3815f8825440Sdougm } else { 3816f8825440Sdougm /* if ZFS and OK, then only group */ 3817f8825440Sdougm ret = zfscheck(group, share); 3818f8825440Sdougm if (ret == SA_OK && 3819f8825440Sdougm sa_group_is_zfs(group)) 3820f8825440Sdougm share = NULL; 3821f8825440Sdougm if (ret == SA_NOT_ALLOWED) 3822f8825440Sdougm (void) printf(gettext( 3823f8825440Sdougm "Properties on ZFS group shares " 3824f8825440Sdougm "not supported: %s\n"), sharepath); 38256185db85Sdougm } 38266185db85Sdougm } 38276185db85Sdougm if (ret == SA_OK) { 38286185db85Sdougm /* group must exist */ 3829687915e9Sdougm ret = valid_options(handle, optlist, protocol, 38306185db85Sdougm share == NULL ? group : share, sectype); 38316185db85Sdougm if (ret == SA_OK && !dryrun) { 38326185db85Sdougm if (share != NULL) 383325a68471Sdougm change = add_security(share, sectype, 383425a68471Sdougm optlist, protocol, &ret); 38356185db85Sdougm else 383625a68471Sdougm change = add_security(group, sectype, 383725a68471Sdougm optlist, protocol, &ret); 38386185db85Sdougm if (ret != SA_OK) 383925a68471Sdougm (void) printf(gettext( 384025a68471Sdougm "Could not set property: %s\n"), 38416185db85Sdougm sa_errorstr(ret)); 38426185db85Sdougm } 38436185db85Sdougm if (ret == SA_OK && change) 3844da6c28aaSamw worklist = add_list(worklist, group, share, 3845da6c28aaSamw protocol); 38466185db85Sdougm } 38476185db85Sdougm free_opt(optlist); 38486185db85Sdougm } else { 38496185db85Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 38506185db85Sdougm ret = SA_NO_SUCH_GROUP; 38516185db85Sdougm } 3852da6c28aaSamw 38536185db85Sdougm /* 3854da6c28aaSamw * We have a group and potentially legal additions. 38556185db85Sdougm */ 38566185db85Sdougm 385725a68471Sdougm /* Commit to configuration if not a dryrun */ 38586185db85Sdougm if (!dryrun && ret == 0) { 38596185db85Sdougm if (change && worklist != NULL) { 38606185db85Sdougm /* properties changed, so update all shares */ 386125a68471Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 3862da6c28aaSamw protocol, B_TRUE); 38636185db85Sdougm } 3864549ec3ffSdougm ret = sa_update_config(handle); 38656185db85Sdougm } 38666185db85Sdougm if (worklist != NULL) 38676185db85Sdougm free_list(worklist); 38686185db85Sdougm return (ret); 38696185db85Sdougm } 38706185db85Sdougm 38716185db85Sdougm /* 38726185db85Sdougm * sa_set(flags, argc, argv) 38736185db85Sdougm * 38746185db85Sdougm * Implements the set subcommand. It keys off of -S to determine which 38756185db85Sdougm * set of operations to actually do. 38766185db85Sdougm */ 38776185db85Sdougm 38786185db85Sdougm int 3879549ec3ffSdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 38806185db85Sdougm { 38816185db85Sdougm char *groupname; 38826185db85Sdougm int verbose = 0; 38836185db85Sdougm int dryrun = 0; 38846185db85Sdougm int c; 38856185db85Sdougm char *protocol = NULL; 38866185db85Sdougm int ret = SA_OK; 38876185db85Sdougm struct options *optlist = NULL; 3888da6c28aaSamw char *rsrcname = NULL; 38896185db85Sdougm char *sharepath = NULL; 38906185db85Sdougm char *optset = NULL; 38916185db85Sdougm int auth; 38926185db85Sdougm 3893da6c28aaSamw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 38946185db85Sdougm switch (c) { 38956185db85Sdougm case 'v': 38966185db85Sdougm verbose++; 38976185db85Sdougm break; 38986185db85Sdougm case 'n': 38996185db85Sdougm dryrun++; 39006185db85Sdougm break; 39016185db85Sdougm case 'P': 3902da6c28aaSamw if (protocol != NULL) { 3903da6c28aaSamw (void) printf(gettext( 3904da6c28aaSamw "Specifying multiple protocols " 3905da6c28aaSamw "not supported: %s\n"), protocol); 3906da6c28aaSamw return (SA_SYNTAX_ERR); 3907da6c28aaSamw } 39086185db85Sdougm protocol = optarg; 39096185db85Sdougm if (!sa_valid_protocol(protocol)) { 391025a68471Sdougm (void) printf(gettext( 391125a68471Sdougm "Invalid protocol specified: %s\n"), 39126185db85Sdougm protocol); 39136185db85Sdougm return (SA_INVALID_PROTOCOL); 39146185db85Sdougm } 39156185db85Sdougm break; 39166185db85Sdougm case 'p': 39176185db85Sdougm ret = add_opt(&optlist, optarg, 0); 39186185db85Sdougm switch (ret) { 39196185db85Sdougm case OPT_ADD_SYNTAX: 392025a68471Sdougm (void) printf(gettext("Property syntax error:" 392125a68471Sdougm " %s\n"), optarg); 39226185db85Sdougm return (SA_SYNTAX_ERR); 39236185db85Sdougm case OPT_ADD_MEMORY: 392425a68471Sdougm (void) printf(gettext("No memory to set " 392525a68471Sdougm "property: %s\n"), optarg); 39266185db85Sdougm return (SA_NO_MEMORY); 39276185db85Sdougm default: 39286185db85Sdougm break; 39296185db85Sdougm } 39306185db85Sdougm break; 3931da6c28aaSamw case 'r': 3932da6c28aaSamw if (rsrcname != NULL) { 3933da6c28aaSamw (void) printf(gettext( 3934da6c28aaSamw "Setting multiple resource names not" 3935da6c28aaSamw " supported\n")); 3936da6c28aaSamw return (SA_SYNTAX_ERR); 3937da6c28aaSamw } 3938da6c28aaSamw rsrcname = optarg; 3939da6c28aaSamw break; 39406185db85Sdougm case 's': 3941da6c28aaSamw if (sharepath != NULL) { 3942da6c28aaSamw (void) printf(gettext( 3943da6c28aaSamw "Setting multiple shares not supported\n")); 3944da6c28aaSamw return (SA_SYNTAX_ERR); 3945da6c28aaSamw } 39466185db85Sdougm sharepath = optarg; 39476185db85Sdougm break; 39486185db85Sdougm case 'S': 3949da6c28aaSamw if (optset != NULL) { 3950da6c28aaSamw (void) printf(gettext( 3951da6c28aaSamw "Specifying multiple property " 3952da6c28aaSamw "spaces not supported: %s\n"), optset); 3953da6c28aaSamw return (SA_SYNTAX_ERR); 3954da6c28aaSamw } 39556185db85Sdougm optset = optarg; 39566185db85Sdougm break; 3957e7bab347Sdougm case 'h': 3958e7bab347Sdougm /* optopt on valid arg isn't defined */ 3959e7bab347Sdougm optopt = c; 3960e7bab347Sdougm /*FALLTHROUGH*/ 3961e7bab347Sdougm case '?': 39626185db85Sdougm default: 3963e7bab347Sdougm /* 3964e7bab347Sdougm * Since a bad option gets to here, sort it 3965e7bab347Sdougm * out and return a syntax error return value 3966e7bab347Sdougm * if necessary. 3967e7bab347Sdougm */ 3968e7bab347Sdougm switch (optopt) { 3969e7bab347Sdougm default: 3970e7bab347Sdougm ret = SA_SYNTAX_ERR; 3971e7bab347Sdougm break; 39726185db85Sdougm case 'h': 39736185db85Sdougm case '?': 3974e7bab347Sdougm break; 3975e7bab347Sdougm } 39766185db85Sdougm (void) printf(gettext("usage: %s\n"), 39776185db85Sdougm sa_get_usage(USAGE_SET)); 3978e7bab347Sdougm return (ret); 39796185db85Sdougm } 39806185db85Sdougm } 39816185db85Sdougm 39826185db85Sdougm if (optlist != NULL) 39836185db85Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 39846185db85Sdougm 39856185db85Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 398625a68471Sdougm protocol == NULL || ret != OPT_ADD_OK) { 39876185db85Sdougm char *sep = "\t"; 398825a68471Sdougm 39896185db85Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 39906185db85Sdougm if (optind >= argc) { 399125a68471Sdougm (void) printf(gettext("%sgroup must be specified"), 399225a68471Sdougm sep); 39936185db85Sdougm sep = ", "; 39946185db85Sdougm } 39956185db85Sdougm if (optlist == NULL) { 39966185db85Sdougm (void) printf(gettext("%sat least one property must be" 39976185db85Sdougm " specified"), sep); 39986185db85Sdougm sep = ", "; 39996185db85Sdougm } 40006185db85Sdougm if (protocol == NULL) { 400125a68471Sdougm (void) printf(gettext("%sprotocol must be specified"), 400225a68471Sdougm sep); 40036185db85Sdougm sep = ", "; 40046185db85Sdougm } 40056185db85Sdougm (void) printf("\n"); 40066185db85Sdougm ret = SA_SYNTAX_ERR; 40076185db85Sdougm } else { 40086185db85Sdougm /* 4009f8825440Sdougm * Group already exists so we can proceed after a few 4010f8825440Sdougm * additional checks related to ZFS handling. 40116185db85Sdougm */ 40126185db85Sdougm 40136185db85Sdougm groupname = argv[optind]; 4014f8825440Sdougm if (strcmp(groupname, "zfs") == 0) { 4015f8825440Sdougm (void) printf(gettext("Changing properties for group " 4016f8825440Sdougm "\"zfs\" not allowed\n")); 4017f8825440Sdougm return (SA_NOT_ALLOWED); 4018f8825440Sdougm } 4019f8825440Sdougm 40206185db85Sdougm auth = check_authorizations(groupname, flags); 40216185db85Sdougm if (optset == NULL) 4022549ec3ffSdougm ret = basic_set(handle, groupname, optlist, protocol, 4023da6c28aaSamw sharepath, rsrcname, dryrun); 40246185db85Sdougm else 4025549ec3ffSdougm ret = space_set(handle, groupname, optlist, protocol, 40266185db85Sdougm sharepath, dryrun, optset); 40276185db85Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 40286185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 40296185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 40306185db85Sdougm } 40316185db85Sdougm } 40326185db85Sdougm return (ret); 40336185db85Sdougm } 40346185db85Sdougm 40356185db85Sdougm /* 40366185db85Sdougm * remove_options(group, optlist, proto, *err) 40376185db85Sdougm * 403825a68471Sdougm * Helper function to actually remove options from a group after all 40396185db85Sdougm * preprocessing is done. 40406185db85Sdougm */ 40416185db85Sdougm 40426185db85Sdougm static int 40436185db85Sdougm remove_options(sa_group_t group, struct options *optlist, 40446185db85Sdougm char *proto, int *err) 40456185db85Sdougm { 40466185db85Sdougm struct options *cur; 40476185db85Sdougm sa_optionset_t optionset; 40486185db85Sdougm sa_property_t prop; 40496185db85Sdougm int change = 0; 40506185db85Sdougm int ret = SA_OK; 40516185db85Sdougm 40526185db85Sdougm optionset = sa_get_optionset(group, proto); 40536185db85Sdougm if (optionset != NULL) { 40546185db85Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 40556185db85Sdougm prop = sa_get_property(optionset, cur->optname); 40566185db85Sdougm if (prop != NULL) { 40576185db85Sdougm ret = sa_remove_property(prop); 40586185db85Sdougm if (ret != SA_OK) 40596185db85Sdougm break; 40606185db85Sdougm change = 1; 40616185db85Sdougm } 40626185db85Sdougm } 40636185db85Sdougm } 40646185db85Sdougm if (ret == SA_OK && change) 40656185db85Sdougm ret = sa_commit_properties(optionset, 0); 40666185db85Sdougm 40676185db85Sdougm if (err != NULL) 40686185db85Sdougm *err = ret; 40696185db85Sdougm return (change); 40706185db85Sdougm } 40716185db85Sdougm 40726185db85Sdougm /* 40736185db85Sdougm * valid_unset(group, optlist, proto) 40746185db85Sdougm * 40756185db85Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 40766185db85Sdougm * error if a property doesn't exist. 40776185db85Sdougm */ 40786185db85Sdougm 40796185db85Sdougm static int 40806185db85Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 40816185db85Sdougm { 40826185db85Sdougm struct options *cur; 40836185db85Sdougm sa_optionset_t optionset; 40846185db85Sdougm sa_property_t prop; 40856185db85Sdougm int ret = SA_OK; 40866185db85Sdougm 40876185db85Sdougm optionset = sa_get_optionset(group, proto); 40886185db85Sdougm if (optionset != NULL) { 40896185db85Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 40906185db85Sdougm prop = sa_get_property(optionset, cur->optname); 40916185db85Sdougm if (prop == NULL) { 409225a68471Sdougm (void) printf(gettext( 409325a68471Sdougm "Could not unset property %s: not set\n"), 40946185db85Sdougm cur->optname); 40956185db85Sdougm ret = SA_NO_SUCH_PROP; 40966185db85Sdougm } 40976185db85Sdougm } 40986185db85Sdougm } 40996185db85Sdougm return (ret); 41006185db85Sdougm } 41016185db85Sdougm 41026185db85Sdougm /* 41036185db85Sdougm * valid_unset_security(group, optlist, proto) 41046185db85Sdougm * 41056185db85Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 41066185db85Sdougm * error if a property doesn't exist. 41076185db85Sdougm */ 41086185db85Sdougm 41096185db85Sdougm static int 41106185db85Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 41116185db85Sdougm char *sectype) 41126185db85Sdougm { 41136185db85Sdougm struct options *cur; 41146185db85Sdougm sa_security_t security; 41156185db85Sdougm sa_property_t prop; 41166185db85Sdougm int ret = SA_OK; 41176185db85Sdougm char *sec; 41186185db85Sdougm 41196185db85Sdougm sec = sa_proto_space_alias(proto, sectype); 41206185db85Sdougm security = sa_get_security(group, sec, proto); 41216185db85Sdougm if (security != NULL) { 41226185db85Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 41236185db85Sdougm prop = sa_get_property(security, cur->optname); 41246185db85Sdougm if (prop == NULL) { 412525a68471Sdougm (void) printf(gettext( 412625a68471Sdougm "Could not unset property %s: not set\n"), 41276185db85Sdougm cur->optname); 41286185db85Sdougm ret = SA_NO_SUCH_PROP; 41296185db85Sdougm } 41306185db85Sdougm } 41316185db85Sdougm } else { 413225a68471Sdougm (void) printf(gettext( 413325a68471Sdougm "Could not unset %s: space not defined\n"), sectype); 41346185db85Sdougm ret = SA_NO_SUCH_SECURITY; 41356185db85Sdougm } 41366185db85Sdougm if (sec != NULL) 41376185db85Sdougm sa_free_attr_string(sec); 41386185db85Sdougm return (ret); 41396185db85Sdougm } 41406185db85Sdougm 41416185db85Sdougm /* 41426185db85Sdougm * remove_security(group, optlist, proto) 41436185db85Sdougm * 41446185db85Sdougm * Remove the properties since they were checked as valid. 41456185db85Sdougm */ 41466185db85Sdougm 41476185db85Sdougm static int 41486185db85Sdougm remove_security(sa_group_t group, char *sectype, 41496185db85Sdougm struct options *optlist, char *proto, int *err) 41506185db85Sdougm { 41516185db85Sdougm sa_security_t security; 41526185db85Sdougm int ret = SA_OK; 41536185db85Sdougm int change = 0; 41546185db85Sdougm 41556185db85Sdougm sectype = sa_proto_space_alias(proto, sectype); 41566185db85Sdougm security = sa_get_security(group, sectype, proto); 41576185db85Sdougm if (sectype != NULL) 41586185db85Sdougm sa_free_attr_string(sectype); 41596185db85Sdougm 41606185db85Sdougm if (security != NULL) { 41616185db85Sdougm while (optlist != NULL) { 41626185db85Sdougm sa_property_t prop; 41636185db85Sdougm prop = sa_get_property(security, optlist->optname); 41646185db85Sdougm if (prop != NULL) { 41656185db85Sdougm ret = sa_remove_property(prop); 41666185db85Sdougm if (ret != SA_OK) 41676185db85Sdougm break; 41686185db85Sdougm change = 1; 41696185db85Sdougm } 41706185db85Sdougm optlist = optlist->next; 41716185db85Sdougm } 41726185db85Sdougm /* 41736185db85Sdougm * when done, properties may have all been removed but 41746185db85Sdougm * we need to keep the security type itself until 41756185db85Sdougm * explicitly removed. 41766185db85Sdougm */ 41776185db85Sdougm if (ret == SA_OK && change) 41786185db85Sdougm ret = sa_commit_properties(security, 0); 41796185db85Sdougm } else { 41806185db85Sdougm ret = SA_NO_SUCH_PROP; 41816185db85Sdougm } 41826185db85Sdougm if (err != NULL) 41836185db85Sdougm *err = ret; 41846185db85Sdougm return (change); 41856185db85Sdougm } 41866185db85Sdougm 41876185db85Sdougm /* 4188da6c28aaSamw * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 41896185db85Sdougm * 419025a68471Sdougm * Unset non-named optionset properties. 41916185db85Sdougm */ 41926185db85Sdougm 41936185db85Sdougm static int 4194549ec3ffSdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 4195da6c28aaSamw char *protocol, char *sharepath, char *rsrcname, int dryrun) 41966185db85Sdougm { 41976185db85Sdougm sa_group_t group; 41986185db85Sdougm int ret = SA_OK; 41996185db85Sdougm int change = 0; 42006185db85Sdougm struct list *worklist = NULL; 420125a68471Sdougm sa_share_t share = NULL; 4202da6c28aaSamw sa_resource_t resource = NULL; 42036185db85Sdougm 4204549ec3ffSdougm group = sa_get_group(handle, groupname); 420525a68471Sdougm if (group == NULL) 420625a68471Sdougm return (ret); 420725a68471Sdougm 4208da6c28aaSamw /* 4209da6c28aaSamw * If there is a sharepath, make sure it belongs to 4210da6c28aaSamw * the group. 4211da6c28aaSamw */ 42126185db85Sdougm if (sharepath != NULL) { 42136185db85Sdougm share = sa_get_share(group, sharepath); 42146185db85Sdougm if (share == NULL) { 421525a68471Sdougm (void) printf(gettext( 421625a68471Sdougm "Share does not exist in group %s\n"), 42176185db85Sdougm groupname, sharepath); 42186185db85Sdougm ret = SA_NO_SUCH_PATH; 42196185db85Sdougm } 42206185db85Sdougm } 4221da6c28aaSamw /* 4222da6c28aaSamw * If a resource name exists, make sure it belongs to 4223da6c28aaSamw * the share if present else it belongs to the 4224da6c28aaSamw * group. Also check the protocol to see if it 4225da6c28aaSamw * supports resource level properties or not. If not, 4226da6c28aaSamw * use share only. 4227da6c28aaSamw */ 4228da6c28aaSamw if (rsrcname != NULL) { 4229da6c28aaSamw if (share != NULL) { 4230da6c28aaSamw resource = sa_get_share_resource(share, rsrcname); 4231da6c28aaSamw if (resource == NULL) 4232da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 4233da6c28aaSamw } else { 4234da6c28aaSamw resource = sa_get_resource(group, rsrcname); 4235da6c28aaSamw if (resource != NULL) { 4236da6c28aaSamw share = sa_get_resource_parent(resource); 4237da6c28aaSamw } else { 4238da6c28aaSamw ret = SA_NO_SUCH_RESOURCE; 4239da6c28aaSamw } 4240da6c28aaSamw } 4241da6c28aaSamw if (ret == SA_OK && resource != NULL) { 4242da6c28aaSamw uint64_t features; 4243da6c28aaSamw /* 4244da6c28aaSamw * Check to see if the resource can take 4245da6c28aaSamw * properties. If so, stick the resource into 4246da6c28aaSamw * "share" so it will all just work. 4247da6c28aaSamw */ 4248da6c28aaSamw features = sa_proto_get_featureset(protocol); 4249da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 4250da6c28aaSamw share = (sa_share_t)resource; 4251da6c28aaSamw } 4252da6c28aaSamw } 4253da6c28aaSamw 42546185db85Sdougm if (ret == SA_OK) { 42556185db85Sdougm /* group must exist */ 42566185db85Sdougm ret = valid_unset(share != NULL ? share : group, 42576185db85Sdougm optlist, protocol); 42586185db85Sdougm if (ret == SA_OK && !dryrun) { 42596185db85Sdougm if (share != NULL) { 42606185db85Sdougm sa_optionset_t optionset; 42616185db85Sdougm sa_property_t prop; 426225a68471Sdougm change |= remove_options(share, optlist, 426325a68471Sdougm protocol, &ret); 426425a68471Sdougm /* 426525a68471Sdougm * If a share optionset is 426625a68471Sdougm * empty, remove it. 426725a68471Sdougm */ 42686185db85Sdougm optionset = sa_get_optionset((sa_share_t)share, 42696185db85Sdougm protocol); 42706185db85Sdougm if (optionset != NULL) { 42716185db85Sdougm prop = sa_get_property(optionset, NULL); 42726185db85Sdougm if (prop == NULL) 427325a68471Sdougm (void) sa_destroy_optionset( 427425a68471Sdougm optionset); 42756185db85Sdougm } 42766185db85Sdougm } else { 427725a68471Sdougm change |= remove_options(group, 427825a68471Sdougm optlist, protocol, &ret); 42796185db85Sdougm } 42806185db85Sdougm if (ret == SA_OK && change) 4281da6c28aaSamw worklist = add_list(worklist, group, share, 4282da6c28aaSamw protocol); 42836185db85Sdougm if (ret != SA_OK) 428425a68471Sdougm (void) printf(gettext( 428525a68471Sdougm "Could not remove properties: " 428625a68471Sdougm "%s\n"), sa_errorstr(ret)); 42876185db85Sdougm } 42886185db85Sdougm } else { 4289da6c28aaSamw (void) printf(gettext("Group \"%s\" not found\n"), groupname); 42906185db85Sdougm ret = SA_NO_SUCH_GROUP; 42916185db85Sdougm } 42926185db85Sdougm free_opt(optlist); 42936185db85Sdougm 42946185db85Sdougm /* 429525a68471Sdougm * We have a group and potentially legal additions 429625a68471Sdougm * 429725a68471Sdougm * Commit to configuration if not a dryrun 42986185db85Sdougm */ 42996185db85Sdougm if (!dryrun && ret == SA_OK) { 43006185db85Sdougm if (change && worklist != NULL) { 43016185db85Sdougm /* properties changed, so update all shares */ 430225a68471Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 4303da6c28aaSamw protocol, B_TRUE); 43046185db85Sdougm } 43056185db85Sdougm } 43066185db85Sdougm if (worklist != NULL) 43076185db85Sdougm free_list(worklist); 43086185db85Sdougm return (ret); 43096185db85Sdougm } 43106185db85Sdougm 43116185db85Sdougm /* 43126185db85Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 43136185db85Sdougm * 431425a68471Sdougm * Unset named optionset properties. 43156185db85Sdougm */ 43166185db85Sdougm static int 4317549ec3ffSdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 4318549ec3ffSdougm char *protocol, char *sharepath, int dryrun, char *sectype) 43196185db85Sdougm { 43206185db85Sdougm sa_group_t group; 43216185db85Sdougm int ret = SA_OK; 43226185db85Sdougm int change = 0; 43236185db85Sdougm struct list *worklist = NULL; 432425a68471Sdougm sa_share_t share = NULL; 43256185db85Sdougm 4326549ec3ffSdougm group = sa_get_group(handle, groupname); 432725a68471Sdougm if (group == NULL) { 432825a68471Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 432925a68471Sdougm return (SA_NO_SUCH_GROUP); 433025a68471Sdougm } 43316185db85Sdougm if (sharepath != NULL) { 43326185db85Sdougm share = sa_get_share(group, sharepath); 43336185db85Sdougm if (share == NULL) { 433425a68471Sdougm (void) printf(gettext( 433525a68471Sdougm "Share does not exist in group %s\n"), 43366185db85Sdougm groupname, sharepath); 433725a68471Sdougm return (SA_NO_SUCH_PATH); 43386185db85Sdougm } 43396185db85Sdougm } 4340da6c28aaSamw ret = valid_unset_security(share != NULL ? share : group, 4341da6c28aaSamw optlist, protocol, sectype); 434225a68471Sdougm 43436185db85Sdougm if (ret == SA_OK && !dryrun) { 43446185db85Sdougm if (optlist != NULL) { 43456185db85Sdougm if (share != NULL) { 43466185db85Sdougm sa_security_t optionset; 43476185db85Sdougm sa_property_t prop; 434825a68471Sdougm change = remove_security(share, 434925a68471Sdougm sectype, optlist, protocol, &ret); 435025a68471Sdougm 435125a68471Sdougm /* If a share security is empty, remove it */ 43526185db85Sdougm optionset = sa_get_security((sa_group_t)share, 435325a68471Sdougm sectype, protocol); 43546185db85Sdougm if (optionset != NULL) { 435525a68471Sdougm prop = sa_get_property(optionset, 435625a68471Sdougm NULL); 43576185db85Sdougm if (prop == NULL) 435825a68471Sdougm ret = sa_destroy_security( 435925a68471Sdougm optionset); 43606185db85Sdougm } 43616185db85Sdougm } else { 43626185db85Sdougm change = remove_security(group, sectype, 436325a68471Sdougm optlist, protocol, &ret); 43646185db85Sdougm } 43656185db85Sdougm } else { 43666185db85Sdougm sa_security_t security; 43676185db85Sdougm char *sec; 43686185db85Sdougm sec = sa_proto_space_alias(protocol, sectype); 43696185db85Sdougm security = sa_get_security(group, sec, protocol); 43706185db85Sdougm if (sec != NULL) 43716185db85Sdougm sa_free_attr_string(sec); 43726185db85Sdougm if (security != NULL) { 43736185db85Sdougm ret = sa_destroy_security(security); 43746185db85Sdougm if (ret == SA_OK) 43756185db85Sdougm change = 1; 43766185db85Sdougm } else { 43776185db85Sdougm ret = SA_NO_SUCH_PROP; 43786185db85Sdougm } 43796185db85Sdougm } 43806185db85Sdougm if (ret != SA_OK) 43816185db85Sdougm (void) printf(gettext("Could not unset property: %s\n"), 43826185db85Sdougm sa_errorstr(ret)); 43836185db85Sdougm } 43846185db85Sdougm 43856185db85Sdougm if (ret == SA_OK && change) 4386da6c28aaSamw worklist = add_list(worklist, group, 0, protocol); 438725a68471Sdougm 43886185db85Sdougm free_opt(optlist); 43896185db85Sdougm /* 439025a68471Sdougm * We have a group and potentially legal additions 43916185db85Sdougm */ 43926185db85Sdougm 439325a68471Sdougm /* Commit to configuration if not a dryrun */ 43946185db85Sdougm if (!dryrun && ret == 0) { 43956185db85Sdougm /* properties changed, so update all shares */ 439625a68471Sdougm if (change && worklist != NULL) 439725a68471Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 4398da6c28aaSamw protocol, B_TRUE); 4399549ec3ffSdougm ret = sa_update_config(handle); 44006185db85Sdougm } 44016185db85Sdougm if (worklist != NULL) 44026185db85Sdougm free_list(worklist); 44036185db85Sdougm return (ret); 44046185db85Sdougm } 44056185db85Sdougm 44066185db85Sdougm /* 44076185db85Sdougm * sa_unset(flags, argc, argv) 44086185db85Sdougm * 440925a68471Sdougm * Implements the unset subcommand. Parsing done here and then basic 44106185db85Sdougm * or space versions of the real code are called. 44116185db85Sdougm */ 44126185db85Sdougm 44136185db85Sdougm int 4414549ec3ffSdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 44156185db85Sdougm { 44166185db85Sdougm char *groupname; 44176185db85Sdougm int verbose = 0; 44186185db85Sdougm int dryrun = 0; 44196185db85Sdougm int c; 44206185db85Sdougm char *protocol = NULL; 44216185db85Sdougm int ret = SA_OK; 44226185db85Sdougm struct options *optlist = NULL; 4423da6c28aaSamw char *rsrcname = NULL; 44246185db85Sdougm char *sharepath = NULL; 44256185db85Sdougm char *optset = NULL; 44266185db85Sdougm int auth; 44276185db85Sdougm 4428da6c28aaSamw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 44296185db85Sdougm switch (c) { 44306185db85Sdougm case 'v': 44316185db85Sdougm verbose++; 44326185db85Sdougm break; 44336185db85Sdougm case 'n': 44346185db85Sdougm dryrun++; 44356185db85Sdougm break; 44366185db85Sdougm case 'P': 4437da6c28aaSamw if (protocol != NULL) { 4438da6c28aaSamw (void) printf(gettext( 4439da6c28aaSamw "Specifying multiple protocols " 4440da6c28aaSamw "not supported: %s\n"), protocol); 4441da6c28aaSamw return (SA_SYNTAX_ERR); 4442da6c28aaSamw } 44436185db85Sdougm protocol = optarg; 44446185db85Sdougm if (!sa_valid_protocol(protocol)) { 444525a68471Sdougm (void) printf(gettext( 444625a68471Sdougm "Invalid protocol specified: %s\n"), 44476185db85Sdougm protocol); 44486185db85Sdougm return (SA_INVALID_PROTOCOL); 44496185db85Sdougm } 44506185db85Sdougm break; 44516185db85Sdougm case 'p': 44526185db85Sdougm ret = add_opt(&optlist, optarg, 1); 44536185db85Sdougm switch (ret) { 44546185db85Sdougm case OPT_ADD_SYNTAX: 445525a68471Sdougm (void) printf(gettext("Property syntax error " 445625a68471Sdougm "for property %s\n"), optarg); 44576185db85Sdougm return (SA_SYNTAX_ERR); 445825a68471Sdougm 44596185db85Sdougm case OPT_ADD_PROPERTY: 446025a68471Sdougm (void) printf(gettext("Properties need to be " 446125a68471Sdougm "set with set command: %s\n"), optarg); 44626185db85Sdougm return (SA_SYNTAX_ERR); 446325a68471Sdougm 44646185db85Sdougm default: 44656185db85Sdougm break; 44666185db85Sdougm } 44676185db85Sdougm break; 4468da6c28aaSamw case 'r': 4469da6c28aaSamw /* 4470da6c28aaSamw * Unset properties on resource if applicable or on 4471da6c28aaSamw * share if resource for this protocol doesn't use 4472da6c28aaSamw * resources. 4473da6c28aaSamw */ 4474da6c28aaSamw if (rsrcname != NULL) { 4475da6c28aaSamw (void) printf(gettext( 4476da6c28aaSamw "Unsetting multiple resource " 4477da6c28aaSamw "names not supported\n")); 4478da6c28aaSamw return (SA_SYNTAX_ERR); 4479da6c28aaSamw } 4480da6c28aaSamw rsrcname = optarg; 4481da6c28aaSamw break; 44826185db85Sdougm case 's': 4483da6c28aaSamw if (sharepath != NULL) { 4484da6c28aaSamw (void) printf(gettext( 4485da6c28aaSamw "Adding multiple shares not supported\n")); 4486da6c28aaSamw return (SA_SYNTAX_ERR); 4487da6c28aaSamw } 44886185db85Sdougm sharepath = optarg; 44896185db85Sdougm break; 44906185db85Sdougm case 'S': 4491da6c28aaSamw if (optset != NULL) { 4492da6c28aaSamw (void) printf(gettext( 4493da6c28aaSamw "Specifying multiple property " 4494da6c28aaSamw "spaces not supported: %s\n"), optset); 4495da6c28aaSamw return (SA_SYNTAX_ERR); 4496da6c28aaSamw } 44976185db85Sdougm optset = optarg; 44986185db85Sdougm break; 4499e7bab347Sdougm case 'h': 4500e7bab347Sdougm /* optopt on valid arg isn't defined */ 4501e7bab347Sdougm optopt = c; 4502e7bab347Sdougm /*FALLTHROUGH*/ 4503e7bab347Sdougm case '?': 45046185db85Sdougm default: 4505e7bab347Sdougm /* 4506e7bab347Sdougm * Since a bad option gets to here, sort it 4507e7bab347Sdougm * out and return a syntax error return value 4508e7bab347Sdougm * if necessary. 4509e7bab347Sdougm */ 4510e7bab347Sdougm switch (optopt) { 4511e7bab347Sdougm default: 4512e7bab347Sdougm ret = SA_SYNTAX_ERR; 4513e7bab347Sdougm break; 45146185db85Sdougm case 'h': 45156185db85Sdougm case '?': 4516e7bab347Sdougm break; 4517e7bab347Sdougm } 45186185db85Sdougm (void) printf(gettext("usage: %s\n"), 45196185db85Sdougm sa_get_usage(USAGE_UNSET)); 4520e7bab347Sdougm return (ret); 45216185db85Sdougm } 45226185db85Sdougm } 45236185db85Sdougm 45246185db85Sdougm if (optlist != NULL) 45256185db85Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 45266185db85Sdougm 45276185db85Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 45286185db85Sdougm protocol == NULL) { 45296185db85Sdougm char *sep = "\t"; 453025a68471Sdougm (void) printf(gettext("usage: %s\n"), 453125a68471Sdougm sa_get_usage(USAGE_UNSET)); 45326185db85Sdougm if (optind >= argc) { 453325a68471Sdougm (void) printf(gettext("%sgroup must be specified"), 45346185db85Sdougm sep); 45356185db85Sdougm sep = ", "; 45366185db85Sdougm } 453725a68471Sdougm if (optlist == NULL) { 453825a68471Sdougm (void) printf(gettext("%sat least one property must " 453925a68471Sdougm "be specified"), sep); 454025a68471Sdougm sep = ", "; 454125a68471Sdougm } 45426185db85Sdougm if (protocol == NULL) { 454325a68471Sdougm (void) printf(gettext("%sprotocol must be specified"), 454425a68471Sdougm sep); 45456185db85Sdougm sep = ", "; 45466185db85Sdougm } 45476185db85Sdougm (void) printf("\n"); 45486185db85Sdougm ret = SA_SYNTAX_ERR; 45496185db85Sdougm } else { 45506185db85Sdougm 45516185db85Sdougm /* 455225a68471Sdougm * If a group already exists, we can only add a new 45536185db85Sdougm * protocol to it and not create a new one or add the 45546185db85Sdougm * same protocol again. 45556185db85Sdougm */ 45566185db85Sdougm 45576185db85Sdougm groupname = argv[optind]; 45586185db85Sdougm auth = check_authorizations(groupname, flags); 45596185db85Sdougm if (optset == NULL) 4560549ec3ffSdougm ret = basic_unset(handle, groupname, optlist, protocol, 4561da6c28aaSamw sharepath, rsrcname, dryrun); 45626185db85Sdougm else 4563549ec3ffSdougm ret = space_unset(handle, groupname, optlist, protocol, 45646185db85Sdougm sharepath, dryrun, optset); 45656185db85Sdougm 456625a68471Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 45676185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 45686185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 45696185db85Sdougm } 45706185db85Sdougm return (ret); 45716185db85Sdougm } 45726185db85Sdougm 45736185db85Sdougm /* 45746185db85Sdougm * sa_enable_group(flags, argc, argv) 45756185db85Sdougm * 45766185db85Sdougm * Implements the enable subcommand 45776185db85Sdougm */ 45786185db85Sdougm 45796185db85Sdougm int 4580549ec3ffSdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 45816185db85Sdougm { 45826185db85Sdougm int verbose = 0; 45836185db85Sdougm int dryrun = 0; 45846185db85Sdougm int all = 0; 45856185db85Sdougm int c; 45866185db85Sdougm int ret = SA_OK; 45876185db85Sdougm char *protocol = NULL; 45886185db85Sdougm char *state; 45896185db85Sdougm struct list *worklist = NULL; 45906185db85Sdougm int auth = 1; 459125a68471Sdougm sa_group_t group; 45926185db85Sdougm 45936185db85Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 45946185db85Sdougm switch (c) { 45956185db85Sdougm case 'a': 45966185db85Sdougm all = 1; 45976185db85Sdougm break; 45986185db85Sdougm case 'n': 45996185db85Sdougm dryrun++; 46006185db85Sdougm break; 46016185db85Sdougm case 'P': 4602da6c28aaSamw if (protocol != NULL) { 4603da6c28aaSamw (void) printf(gettext( 4604da6c28aaSamw "Specifying multiple protocols " 4605da6c28aaSamw "not supported: %s\n"), protocol); 4606da6c28aaSamw return (SA_SYNTAX_ERR); 4607da6c28aaSamw } 46086185db85Sdougm protocol = optarg; 46096185db85Sdougm if (!sa_valid_protocol(protocol)) { 461025a68471Sdougm (void) printf(gettext( 461125a68471Sdougm "Invalid protocol specified: %s\n"), 46126185db85Sdougm protocol); 46136185db85Sdougm return (SA_INVALID_PROTOCOL); 46146185db85Sdougm } 46156185db85Sdougm break; 46166185db85Sdougm case 'v': 46176185db85Sdougm verbose++; 46186185db85Sdougm break; 4619e7bab347Sdougm case 'h': 4620e7bab347Sdougm /* optopt on valid arg isn't defined */ 4621e7bab347Sdougm optopt = c; 4622e7bab347Sdougm /*FALLTHROUGH*/ 4623e7bab347Sdougm case '?': 46246185db85Sdougm default: 4625e7bab347Sdougm /* 4626e7bab347Sdougm * Since a bad option gets to here, sort it 4627e7bab347Sdougm * out and return a syntax error return value 4628e7bab347Sdougm * if necessary. 4629e7bab347Sdougm */ 4630e7bab347Sdougm switch (optopt) { 4631e7bab347Sdougm default: 4632e7bab347Sdougm ret = SA_SYNTAX_ERR; 4633e7bab347Sdougm break; 46346185db85Sdougm case 'h': 46356185db85Sdougm case '?': 46366185db85Sdougm (void) printf(gettext("usage: %s\n"), 46376185db85Sdougm sa_get_usage(USAGE_ENABLE)); 4638e7bab347Sdougm return (ret); 4639e7bab347Sdougm } 46406185db85Sdougm } 46416185db85Sdougm } 46426185db85Sdougm 46436185db85Sdougm if (optind == argc && !all) { 464425a68471Sdougm (void) printf(gettext("usage: %s\n"), 464525a68471Sdougm sa_get_usage(USAGE_ENABLE)); 46466185db85Sdougm (void) printf(gettext("\tmust specify group\n")); 464725a68471Sdougm return (SA_NO_SUCH_PATH); 464825a68471Sdougm } 46496185db85Sdougm if (!all) { 46506185db85Sdougm while (optind < argc) { 4651549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 46526185db85Sdougm if (group != NULL) { 465325a68471Sdougm auth &= check_authorizations(argv[optind], 465425a68471Sdougm flags); 46556185db85Sdougm state = sa_get_group_attr(group, "state"); 46566185db85Sdougm if (state != NULL && 46576185db85Sdougm strcmp(state, "enabled") == 0) { 46586185db85Sdougm /* already enabled */ 46596185db85Sdougm if (verbose) 466025a68471Sdougm (void) printf(gettext( 466125a68471Sdougm "Group \"%s\" is already " 46626185db85Sdougm "enabled\n"), 46636185db85Sdougm argv[optind]); 46646185db85Sdougm ret = SA_BUSY; /* already enabled */ 46656185db85Sdougm } else { 466625a68471Sdougm worklist = add_list(worklist, group, 4667da6c28aaSamw 0, protocol); 46686185db85Sdougm if (verbose) 466925a68471Sdougm (void) printf(gettext( 467025a68471Sdougm "Enabling group \"%s\"\n"), 46716185db85Sdougm argv[optind]); 46726185db85Sdougm } 46736185db85Sdougm if (state != NULL) 46746185db85Sdougm sa_free_attr_string(state); 46756185db85Sdougm } else { 46766185db85Sdougm ret = SA_NO_SUCH_GROUP; 46776185db85Sdougm } 46786185db85Sdougm optind++; 46796185db85Sdougm } 46806185db85Sdougm } else { 468125a68471Sdougm for (group = sa_get_group(handle, NULL); 468225a68471Sdougm group != NULL; 46836185db85Sdougm group = sa_get_next_group(group)) { 4684da6c28aaSamw worklist = add_list(worklist, group, 0, protocol); 46856185db85Sdougm } 46866185db85Sdougm } 468725a68471Sdougm if (!dryrun && ret == SA_OK) 4688da6c28aaSamw ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE); 468925a68471Sdougm 46906185db85Sdougm if (ret != SA_OK && ret != SA_BUSY) 46916185db85Sdougm (void) printf(gettext("Could not enable group: %s\n"), 46926185db85Sdougm sa_errorstr(ret)); 46936185db85Sdougm if (ret == SA_BUSY) 46946185db85Sdougm ret = SA_OK; 469525a68471Sdougm 46966185db85Sdougm if (worklist != NULL) 46976185db85Sdougm free_list(worklist); 46986185db85Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 46996185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 47006185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 47016185db85Sdougm } 47026185db85Sdougm return (ret); 47036185db85Sdougm } 47046185db85Sdougm 47056185db85Sdougm /* 4706da6c28aaSamw * disable_group(group, proto) 47076185db85Sdougm * 4708da6c28aaSamw * Disable all the shares in the specified group.. This is a helper 4709da6c28aaSamw * for disable_all_groups in order to simplify regular and subgroup 4710da6c28aaSamw * (zfs) disabling. Group has already been checked for non-NULL. 47116185db85Sdougm */ 47126185db85Sdougm 47136185db85Sdougm static int 4714da6c28aaSamw disable_group(sa_group_t group, char *proto) 47156185db85Sdougm { 47166185db85Sdougm sa_share_t share; 47176185db85Sdougm int ret = SA_OK; 47186185db85Sdougm 4719da6c28aaSamw /* 4720da6c28aaSamw * If the protocol isn't enabled, skip it and treat as 4721da6c28aaSamw * successful. 4722da6c28aaSamw */ 4723da6c28aaSamw if (!has_protocol(group, proto)) 4724da6c28aaSamw return (ret); 4725da6c28aaSamw 47266185db85Sdougm for (share = sa_get_share(group, NULL); 47276185db85Sdougm share != NULL && ret == SA_OK; 47286185db85Sdougm share = sa_get_next_share(share)) { 4729da6c28aaSamw ret = sa_disable_share(share, proto); 47306185db85Sdougm if (ret == SA_NO_SUCH_PATH) { 47316185db85Sdougm /* 47326185db85Sdougm * this is OK since the path is gone. we can't 47336185db85Sdougm * re-share it anyway so no error. 47346185db85Sdougm */ 47356185db85Sdougm ret = SA_OK; 47366185db85Sdougm } 47376185db85Sdougm } 47386185db85Sdougm return (ret); 47396185db85Sdougm } 47406185db85Sdougm 47416185db85Sdougm /* 47426185db85Sdougm * disable_all_groups(work, setstate) 47436185db85Sdougm * 47446185db85Sdougm * helper function that disables the shares in the list of groups 47456185db85Sdougm * provided. It optionally marks the group as disabled. Used by both 47466185db85Sdougm * enable and start subcommands. 47476185db85Sdougm */ 47486185db85Sdougm 47496185db85Sdougm static int 4750549ec3ffSdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 47516185db85Sdougm { 47526185db85Sdougm int ret = SA_OK; 47536185db85Sdougm sa_group_t subgroup, group; 47546185db85Sdougm 47556185db85Sdougm while (work != NULL && ret == SA_OK) { 47566185db85Sdougm group = (sa_group_t)work->item; 47576185db85Sdougm if (setstate) 47586185db85Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 47596185db85Sdougm if (ret == SA_OK) { 47606185db85Sdougm char *name; 47616185db85Sdougm name = sa_get_group_attr(group, "name"); 47626185db85Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 47636185db85Sdougm /* need to get the sub-groups for stopping */ 476425a68471Sdougm for (subgroup = sa_get_sub_group(group); 476525a68471Sdougm subgroup != NULL; 47666185db85Sdougm subgroup = sa_get_next_group(subgroup)) { 4767da6c28aaSamw ret = disable_group(subgroup, 4768da6c28aaSamw work->proto); 47696185db85Sdougm } 47706185db85Sdougm } else { 4771da6c28aaSamw ret = disable_group(group, work->proto); 47726185db85Sdougm } 4773fe1c642dSBill Krier if (name != NULL) 4774fe1c642dSBill Krier sa_free_attr_string(name); 47756185db85Sdougm /* 477625a68471Sdougm * We don't want to "disable" since it won't come 47776185db85Sdougm * up after a reboot. The SMF framework should do 47786185db85Sdougm * the right thing. On enable we do want to do 47796185db85Sdougm * something. 47806185db85Sdougm */ 47816185db85Sdougm } 47826185db85Sdougm work = work->next; 47836185db85Sdougm } 47846185db85Sdougm if (ret == SA_OK) 4785549ec3ffSdougm ret = sa_update_config(handle); 47866185db85Sdougm return (ret); 47876185db85Sdougm } 47886185db85Sdougm 47896185db85Sdougm /* 47906185db85Sdougm * sa_disable_group(flags, argc, argv) 47916185db85Sdougm * 47926185db85Sdougm * Implements the disable subcommand 47936185db85Sdougm */ 47946185db85Sdougm 47956185db85Sdougm int 4796549ec3ffSdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 47976185db85Sdougm { 47986185db85Sdougm int verbose = 0; 47996185db85Sdougm int dryrun = 0; 48006185db85Sdougm int all = 0; 48016185db85Sdougm int c; 48026185db85Sdougm int ret = SA_OK; 4803da6c28aaSamw char *protocol = NULL; 48046185db85Sdougm char *state; 48056185db85Sdougm struct list *worklist = NULL; 480625a68471Sdougm sa_group_t group; 48076185db85Sdougm int auth = 1; 48086185db85Sdougm 48096185db85Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 48106185db85Sdougm switch (c) { 48116185db85Sdougm case 'a': 48126185db85Sdougm all = 1; 48136185db85Sdougm break; 48146185db85Sdougm case 'n': 48156185db85Sdougm dryrun++; 48166185db85Sdougm break; 48176185db85Sdougm case 'P': 4818da6c28aaSamw if (protocol != NULL) { 4819da6c28aaSamw (void) printf(gettext( 4820da6c28aaSamw "Specifying multiple protocols " 4821da6c28aaSamw "not supported: %s\n"), protocol); 4822da6c28aaSamw return (SA_SYNTAX_ERR); 4823da6c28aaSamw } 48246185db85Sdougm protocol = optarg; 48256185db85Sdougm if (!sa_valid_protocol(protocol)) { 482625a68471Sdougm (void) printf(gettext( 482725a68471Sdougm "Invalid protocol specified: %s\n"), 48286185db85Sdougm protocol); 48296185db85Sdougm return (SA_INVALID_PROTOCOL); 48306185db85Sdougm } 48316185db85Sdougm break; 48326185db85Sdougm case 'v': 48336185db85Sdougm verbose++; 48346185db85Sdougm break; 4835e7bab347Sdougm case 'h': 4836e7bab347Sdougm /* optopt on valid arg isn't defined */ 4837e7bab347Sdougm optopt = c; 4838e7bab347Sdougm /*FALLTHROUGH*/ 4839e7bab347Sdougm case '?': 48406185db85Sdougm default: 4841e7bab347Sdougm /* 4842e7bab347Sdougm * Since a bad option gets to here, sort it 4843e7bab347Sdougm * out and return a syntax error return value 4844e7bab347Sdougm * if necessary. 4845e7bab347Sdougm */ 4846e7bab347Sdougm switch (optopt) { 4847e7bab347Sdougm default: 4848e7bab347Sdougm ret = SA_SYNTAX_ERR; 4849e7bab347Sdougm break; 48506185db85Sdougm case 'h': 48516185db85Sdougm case '?': 4852e7bab347Sdougm break; 4853e7bab347Sdougm } 48546185db85Sdougm (void) printf(gettext("usage: %s\n"), 48556185db85Sdougm sa_get_usage(USAGE_DISABLE)); 4856e7bab347Sdougm return (ret); 48576185db85Sdougm } 48586185db85Sdougm } 48596185db85Sdougm 48606185db85Sdougm if (optind == argc && !all) { 48616185db85Sdougm (void) printf(gettext("usage: %s\n"), 48626185db85Sdougm sa_get_usage(USAGE_DISABLE)); 48636185db85Sdougm (void) printf(gettext("\tmust specify group\n")); 486425a68471Sdougm return (SA_NO_SUCH_PATH); 486525a68471Sdougm } 48666185db85Sdougm if (!all) { 48676185db85Sdougm while (optind < argc) { 4868549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 48696185db85Sdougm if (group != NULL) { 487025a68471Sdougm auth &= check_authorizations(argv[optind], 487125a68471Sdougm flags); 48726185db85Sdougm state = sa_get_group_attr(group, "state"); 48736185db85Sdougm if (state == NULL || 48746185db85Sdougm strcmp(state, "disabled") == 0) { 48756185db85Sdougm /* already disabled */ 48766185db85Sdougm if (verbose) 487725a68471Sdougm (void) printf(gettext( 487825a68471Sdougm "Group \"%s\" is " 48796185db85Sdougm "already disabled\n"), 48806185db85Sdougm argv[optind]); 4881da6c28aaSamw ret = SA_BUSY; /* already disabled */ 48826185db85Sdougm } else { 4883da6c28aaSamw worklist = add_list(worklist, group, 0, 4884da6c28aaSamw protocol); 48856185db85Sdougm if (verbose) 488625a68471Sdougm (void) printf(gettext( 488725a68471Sdougm "Disabling group " 488825a68471Sdougm "\"%s\"\n"), argv[optind]); 48896185db85Sdougm } 48906185db85Sdougm if (state != NULL) 48916185db85Sdougm sa_free_attr_string(state); 48926185db85Sdougm } else { 48936185db85Sdougm ret = SA_NO_SUCH_GROUP; 48946185db85Sdougm } 48956185db85Sdougm optind++; 48966185db85Sdougm } 48976185db85Sdougm } else { 489825a68471Sdougm for (group = sa_get_group(handle, NULL); 489925a68471Sdougm group != NULL; 490025a68471Sdougm group = sa_get_next_group(group)) 4901da6c28aaSamw worklist = add_list(worklist, group, 0, protocol); 49026185db85Sdougm } 490325a68471Sdougm 490425a68471Sdougm if (ret == SA_OK && !dryrun) 4905549ec3ffSdougm ret = disable_all_groups(handle, worklist, 1); 49066185db85Sdougm if (ret != SA_OK && ret != SA_BUSY) 49076185db85Sdougm (void) printf(gettext("Could not disable group: %s\n"), 49086185db85Sdougm sa_errorstr(ret)); 49096185db85Sdougm if (ret == SA_BUSY) 49106185db85Sdougm ret = SA_OK; 49116185db85Sdougm if (worklist != NULL) 49126185db85Sdougm free_list(worklist); 491325a68471Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 49146185db85Sdougm (void) printf(gettext("Command would fail: %s\n"), 49156185db85Sdougm sa_errorstr(SA_NO_PERMISSION)); 49166185db85Sdougm return (ret); 49176185db85Sdougm } 49186185db85Sdougm 49196185db85Sdougm /* 49206185db85Sdougm * sa_start_group(flags, argc, argv) 49216185db85Sdougm * 49226185db85Sdougm * Implements the start command. 49236185db85Sdougm * This is similar to enable except it doesn't change the state 49246185db85Sdougm * of the group(s) and only enables shares if the group is already 49256185db85Sdougm * enabled. 49266185db85Sdougm */ 4927da6c28aaSamw 49286185db85Sdougm int 4929549ec3ffSdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 49306185db85Sdougm { 49316185db85Sdougm int verbose = 0; 49326185db85Sdougm int all = 0; 49336185db85Sdougm int c; 49346185db85Sdougm int ret = SMF_EXIT_OK; 49356185db85Sdougm char *protocol = NULL; 49366185db85Sdougm char *state; 49376185db85Sdougm struct list *worklist = NULL; 493825a68471Sdougm sa_group_t group; 4939da6c28aaSamw #ifdef lint 4940da6c28aaSamw flags = flags; 4941da6c28aaSamw #endif 49426185db85Sdougm 49436185db85Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 49446185db85Sdougm switch (c) { 49456185db85Sdougm case 'a': 49466185db85Sdougm all = 1; 49476185db85Sdougm break; 49486185db85Sdougm case 'P': 4949da6c28aaSamw if (protocol != NULL) { 4950da6c28aaSamw (void) printf(gettext( 4951da6c28aaSamw "Specifying multiple protocols " 4952da6c28aaSamw "not supported: %s\n"), protocol); 4953da6c28aaSamw return (SA_SYNTAX_ERR); 4954da6c28aaSamw } 49556185db85Sdougm protocol = optarg; 49566185db85Sdougm if (!sa_valid_protocol(protocol)) { 495725a68471Sdougm (void) printf(gettext( 495825a68471Sdougm "Invalid protocol specified: %s\n"), 49596185db85Sdougm protocol); 49606185db85Sdougm return (SA_INVALID_PROTOCOL); 49616185db85Sdougm } 49626185db85Sdougm break; 49636185db85Sdougm case 'v': 49646185db85Sdougm verbose++; 49656185db85Sdougm break; 4966e7bab347Sdougm case 'h': 4967e7bab347Sdougm /* optopt on valid arg isn't defined */ 4968e7bab347Sdougm optopt = c; 4969e7bab347Sdougm /*FALLTHROUGH*/ 4970e7bab347Sdougm case '?': 49716185db85Sdougm default: 4972e7bab347Sdougm /* 4973e7bab347Sdougm * Since a bad option gets to here, sort it 4974e7bab347Sdougm * out and return a syntax error return value 4975e7bab347Sdougm * if necessary. 4976e7bab347Sdougm */ 4977e7bab347Sdougm ret = SA_OK; 4978e7bab347Sdougm switch (optopt) { 4979e7bab347Sdougm default: 4980e7bab347Sdougm ret = SA_SYNTAX_ERR; 4981e7bab347Sdougm break; 49826185db85Sdougm case 'h': 49836185db85Sdougm case '?': 4984e7bab347Sdougm break; 4985e7bab347Sdougm } 49866185db85Sdougm (void) printf(gettext("usage: %s\n"), 49876185db85Sdougm sa_get_usage(USAGE_START)); 4988e7bab347Sdougm return (ret); 49896185db85Sdougm } 49906185db85Sdougm } 49916185db85Sdougm 49926185db85Sdougm if (optind == argc && !all) { 49936185db85Sdougm (void) printf(gettext("usage: %s\n"), 49946185db85Sdougm sa_get_usage(USAGE_START)); 499525a68471Sdougm return (SMF_EXIT_ERR_FATAL); 499625a68471Sdougm } 49976185db85Sdougm 49986185db85Sdougm if (!all) { 49996185db85Sdougm while (optind < argc) { 5000549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 50016185db85Sdougm if (group != NULL) { 50026185db85Sdougm state = sa_get_group_attr(group, "state"); 50036185db85Sdougm if (state == NULL || 50046185db85Sdougm strcmp(state, "enabled") == 0) { 5005da6c28aaSamw worklist = add_list(worklist, group, 0, 5006da6c28aaSamw protocol); 50076185db85Sdougm if (verbose) 500825a68471Sdougm (void) printf(gettext( 500925a68471Sdougm "Starting group \"%s\"\n"), 50106185db85Sdougm argv[optind]); 50116185db85Sdougm } else { 50126185db85Sdougm /* 501325a68471Sdougm * Determine if there are any 5014da6c28aaSamw * protocols. If there aren't any, 50156185db85Sdougm * then there isn't anything to do in 50166185db85Sdougm * any case so no error. 50176185db85Sdougm */ 501825a68471Sdougm if (sa_get_optionset(group, 501925a68471Sdougm protocol) != NULL) { 50206185db85Sdougm ret = SMF_EXIT_OK; 50216185db85Sdougm } 50226185db85Sdougm } 50236185db85Sdougm if (state != NULL) 50246185db85Sdougm sa_free_attr_string(state); 50256185db85Sdougm } 50266185db85Sdougm optind++; 50276185db85Sdougm } 50286185db85Sdougm } else { 5029da6c28aaSamw for (group = sa_get_group(handle, NULL); 5030da6c28aaSamw group != NULL; 50316185db85Sdougm group = sa_get_next_group(group)) { 50326185db85Sdougm state = sa_get_group_attr(group, "state"); 50336185db85Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 5034da6c28aaSamw worklist = add_list(worklist, group, 0, 5035da6c28aaSamw protocol); 50366185db85Sdougm if (state != NULL) 50376185db85Sdougm sa_free_attr_string(state); 50386185db85Sdougm } 50396185db85Sdougm } 504025a68471Sdougm 5041da6c28aaSamw (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE); 504225a68471Sdougm 50436185db85Sdougm if (worklist != NULL) 50446185db85Sdougm free_list(worklist); 50456185db85Sdougm return (ret); 50466185db85Sdougm } 50476185db85Sdougm 50486185db85Sdougm /* 50496185db85Sdougm * sa_stop_group(flags, argc, argv) 50506185db85Sdougm * 50516185db85Sdougm * Implements the stop command. 50526185db85Sdougm * This is similar to disable except it doesn't change the state 50536185db85Sdougm * of the group(s) and only disables shares if the group is already 50546185db85Sdougm * enabled. 50556185db85Sdougm */ 50566185db85Sdougm int 5057549ec3ffSdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 50586185db85Sdougm { 50596185db85Sdougm int verbose = 0; 50606185db85Sdougm int all = 0; 50616185db85Sdougm int c; 50626185db85Sdougm int ret = SMF_EXIT_OK; 50636185db85Sdougm char *protocol = NULL; 50646185db85Sdougm char *state; 50656185db85Sdougm struct list *worklist = NULL; 506625a68471Sdougm sa_group_t group; 5067da6c28aaSamw #ifdef lint 5068da6c28aaSamw flags = flags; 5069da6c28aaSamw #endif 50706185db85Sdougm 50716185db85Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 50726185db85Sdougm switch (c) { 50736185db85Sdougm case 'a': 50746185db85Sdougm all = 1; 50756185db85Sdougm break; 50766185db85Sdougm case 'P': 5077da6c28aaSamw if (protocol != NULL) { 5078da6c28aaSamw (void) printf(gettext( 5079da6c28aaSamw "Specifying multiple protocols " 5080da6c28aaSamw "not supported: %s\n"), protocol); 5081da6c28aaSamw return (SA_SYNTAX_ERR); 5082da6c28aaSamw } 50836185db85Sdougm protocol = optarg; 50846185db85Sdougm if (!sa_valid_protocol(protocol)) { 508525a68471Sdougm (void) printf(gettext( 508625a68471Sdougm "Invalid protocol specified: %s\n"), 50876185db85Sdougm protocol); 50886185db85Sdougm return (SA_INVALID_PROTOCOL); 50896185db85Sdougm } 50906185db85Sdougm break; 50916185db85Sdougm case 'v': 50926185db85Sdougm verbose++; 50936185db85Sdougm break; 5094e7bab347Sdougm case 'h': 5095e7bab347Sdougm /* optopt on valid arg isn't defined */ 5096e7bab347Sdougm optopt = c; 5097e7bab347Sdougm /*FALLTHROUGH*/ 5098e7bab347Sdougm case '?': 50996185db85Sdougm default: 5100e7bab347Sdougm /* 5101e7bab347Sdougm * Since a bad option gets to here, sort it 5102e7bab347Sdougm * out and return a syntax error return value 5103e7bab347Sdougm * if necessary. 5104e7bab347Sdougm */ 5105e7bab347Sdougm ret = SA_OK; 5106e7bab347Sdougm switch (optopt) { 5107e7bab347Sdougm default: 5108e7bab347Sdougm ret = SA_SYNTAX_ERR; 5109e7bab347Sdougm break; 51106185db85Sdougm case 'h': 51116185db85Sdougm case '?': 5112e7bab347Sdougm break; 5113e7bab347Sdougm } 51146185db85Sdougm (void) printf(gettext("usage: %s\n"), 51156185db85Sdougm sa_get_usage(USAGE_STOP)); 5116e7bab347Sdougm return (ret); 51176185db85Sdougm } 51186185db85Sdougm } 51196185db85Sdougm 51206185db85Sdougm if (optind == argc && !all) { 512125a68471Sdougm (void) printf(gettext("usage: %s\n"), 512225a68471Sdougm sa_get_usage(USAGE_STOP)); 512325a68471Sdougm return (SMF_EXIT_ERR_FATAL); 512425a68471Sdougm } else if (!all) { 51256185db85Sdougm while (optind < argc) { 5126549ec3ffSdougm group = sa_get_group(handle, argv[optind]); 51276185db85Sdougm if (group != NULL) { 51286185db85Sdougm state = sa_get_group_attr(group, "state"); 51296185db85Sdougm if (state == NULL || 51306185db85Sdougm strcmp(state, "enabled") == 0) { 5131da6c28aaSamw worklist = add_list(worklist, group, 0, 5132da6c28aaSamw protocol); 51336185db85Sdougm if (verbose) 513425a68471Sdougm (void) printf(gettext( 513525a68471Sdougm "Stopping group \"%s\"\n"), 51366185db85Sdougm argv[optind]); 51376185db85Sdougm } else { 51386185db85Sdougm ret = SMF_EXIT_OK; 51396185db85Sdougm } 51406185db85Sdougm if (state != NULL) 51416185db85Sdougm sa_free_attr_string(state); 51426185db85Sdougm } 51436185db85Sdougm optind++; 51446185db85Sdougm } 51456185db85Sdougm } else { 5146da6c28aaSamw for (group = sa_get_group(handle, NULL); 5147da6c28aaSamw group != NULL; 51486185db85Sdougm group = sa_get_next_group(group)) { 51496185db85Sdougm state = sa_get_group_attr(group, "state"); 51506185db85Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 5151da6c28aaSamw worklist = add_list(worklist, group, 0, 5152da6c28aaSamw protocol); 51536185db85Sdougm if (state != NULL) 51546185db85Sdougm sa_free_attr_string(state); 51556185db85Sdougm } 51566185db85Sdougm } 5157549ec3ffSdougm (void) disable_all_groups(handle, worklist, 0); 5158549ec3ffSdougm ret = sa_update_config(handle); 515925a68471Sdougm 51606185db85Sdougm if (worklist != NULL) 51616185db85Sdougm free_list(worklist); 51626185db85Sdougm return (ret); 51636185db85Sdougm } 51646185db85Sdougm 51656185db85Sdougm /* 51666185db85Sdougm * remove_all_options(share, proto) 51676185db85Sdougm * 51686185db85Sdougm * Removes all options on a share. 51696185db85Sdougm */ 51706185db85Sdougm 51716185db85Sdougm static void 51726185db85Sdougm remove_all_options(sa_share_t share, char *proto) 51736185db85Sdougm { 51746185db85Sdougm sa_optionset_t optionset; 51756185db85Sdougm sa_security_t security; 51766185db85Sdougm sa_security_t prevsec = NULL; 51776185db85Sdougm 51786185db85Sdougm optionset = sa_get_optionset(share, proto); 51796185db85Sdougm if (optionset != NULL) 51806185db85Sdougm (void) sa_destroy_optionset(optionset); 51816185db85Sdougm for (security = sa_get_security(share, NULL, NULL); 51826185db85Sdougm security != NULL; 51836185db85Sdougm security = sa_get_next_security(security)) { 51846185db85Sdougm char *type; 51856185db85Sdougm /* 518625a68471Sdougm * We walk through the list. prevsec keeps the 51876185db85Sdougm * previous security so we can delete it without 51886185db85Sdougm * destroying the list. 51896185db85Sdougm */ 51906185db85Sdougm if (prevsec != NULL) { 51916185db85Sdougm /* remove the previously seen security */ 51926185db85Sdougm (void) sa_destroy_security(prevsec); 51936185db85Sdougm /* set to NULL so we don't try multiple times */ 51946185db85Sdougm prevsec = NULL; 51956185db85Sdougm } 51966185db85Sdougm type = sa_get_security_attr(security, "type"); 51976185db85Sdougm if (type != NULL) { 51986185db85Sdougm /* 51996185db85Sdougm * if the security matches the specified protocol, we 52006185db85Sdougm * want to remove it. prevsec holds it until either 52016185db85Sdougm * the next pass or we fall out of the loop. 52026185db85Sdougm */ 52036185db85Sdougm if (strcmp(type, proto) == 0) 52046185db85Sdougm prevsec = security; 52056185db85Sdougm sa_free_attr_string(type); 52066185db85Sdougm } 52076185db85Sdougm } 52086185db85Sdougm /* in case there is one left */ 52096185db85Sdougm if (prevsec != NULL) 52106185db85Sdougm (void) sa_destroy_security(prevsec); 52116185db85Sdougm } 52126185db85Sdougm 52136185db85Sdougm 52146185db85Sdougm /* 52156185db85Sdougm * for legacy support, we need to handle the old syntax. This is what 52166185db85Sdougm * we get if sharemgr is called with the name "share" rather than 52176185db85Sdougm * sharemgr. 52186185db85Sdougm */ 52196185db85Sdougm 52206185db85Sdougm static int 52216185db85Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 52226185db85Sdougm { 52236185db85Sdougm int err; 52246185db85Sdougm 52256185db85Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 52266185db85Sdougm if (err > buffsize) 52276185db85Sdougm return (-1); 52286185db85Sdougm return (0); 52296185db85Sdougm } 52306185db85Sdougm 52316185db85Sdougm 52326185db85Sdougm /* 52336185db85Sdougm * check_legacy_cmd(proto, cmd) 52346185db85Sdougm * 52356185db85Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 52366185db85Sdougm * executable. 52376185db85Sdougm */ 52386185db85Sdougm 52396185db85Sdougm static int 52406185db85Sdougm check_legacy_cmd(char *path) 52416185db85Sdougm { 52426185db85Sdougm struct stat st; 52436185db85Sdougm int ret = 0; 52446185db85Sdougm 52456185db85Sdougm if (stat(path, &st) == 0) { 524625a68471Sdougm if (S_ISREG(st.st_mode) && 524725a68471Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 52486185db85Sdougm ret = 1; 52496185db85Sdougm } 52506185db85Sdougm return (ret); 52516185db85Sdougm } 52526185db85Sdougm 52536185db85Sdougm /* 52546185db85Sdougm * run_legacy_command(proto, cmd, argv) 52556185db85Sdougm * 525625a68471Sdougm * We know the command exists, so attempt to execute it with all the 52576185db85Sdougm * arguments. This implements full legacy share support for those 52586185db85Sdougm * protocols that don't have plugin providers. 52596185db85Sdougm */ 52606185db85Sdougm 52616185db85Sdougm static int 52626185db85Sdougm run_legacy_command(char *path, char *argv[]) 52636185db85Sdougm { 52646185db85Sdougm int ret; 52656185db85Sdougm 52666185db85Sdougm ret = execv(path, argv); 52676185db85Sdougm if (ret < 0) { 52686185db85Sdougm switch (errno) { 52696185db85Sdougm case EACCES: 52706185db85Sdougm ret = SA_NO_PERMISSION; 52716185db85Sdougm break; 52726185db85Sdougm default: 52736185db85Sdougm ret = SA_SYSTEM_ERR; 52746185db85Sdougm break; 52756185db85Sdougm } 52766185db85Sdougm } 52776185db85Sdougm return (ret); 52786185db85Sdougm } 52796185db85Sdougm 52806185db85Sdougm /* 5281f345c0beSdougm * out_share(out, group, proto) 52826185db85Sdougm * 52836185db85Sdougm * Display the share information in the format that the "share" 52846185db85Sdougm * command has traditionally used. 52856185db85Sdougm */ 52866185db85Sdougm 52876185db85Sdougm static void 5288f345c0beSdougm out_share(FILE *out, sa_group_t group, char *proto) 52896185db85Sdougm { 52906185db85Sdougm sa_share_t share; 52916185db85Sdougm char resfmt[128]; 5292da6c28aaSamw char *defprop; 5293da6c28aaSamw 5294da6c28aaSamw /* 5295da6c28aaSamw * The original share command defaulted to displaying NFS 5296da6c28aaSamw * shares or allowed a protocol to be specified. We want to 5297da6c28aaSamw * skip those shares that are not the specified protocol. 5298da6c28aaSamw */ 5299da6c28aaSamw if (proto != NULL && sa_get_optionset(group, proto) == NULL) 5300da6c28aaSamw return; 5301da6c28aaSamw 5302da6c28aaSamw if (proto == NULL) 5303da6c28aaSamw proto = "nfs"; 5304da6c28aaSamw 5305da6c28aaSamw /* 5306da6c28aaSamw * get the default property string. NFS uses "rw" but 5307da6c28aaSamw * everything else will use "". 5308da6c28aaSamw */ 5309da6c28aaSamw if (proto != NULL && strcmp(proto, "nfs") != 0) 5310da6c28aaSamw defprop = "\"\""; 5311da6c28aaSamw else 5312da6c28aaSamw defprop = "rw"; 53136185db85Sdougm 531425a68471Sdougm for (share = sa_get_share(group, NULL); 531525a68471Sdougm share != NULL; 53166185db85Sdougm share = sa_get_next_share(share)) { 53176185db85Sdougm char *path; 53186185db85Sdougm char *type; 53196185db85Sdougm char *resource; 53206185db85Sdougm char *description; 53216185db85Sdougm char *groupname; 53226185db85Sdougm char *sharedstate; 53236185db85Sdougm int shared = 1; 53246185db85Sdougm char *soptions; 5325da6c28aaSamw char shareopts[MAXNAMLEN]; 53266185db85Sdougm 53276185db85Sdougm sharedstate = sa_get_share_attr(share, "shared"); 53286185db85Sdougm path = sa_get_share_attr(share, "path"); 53296185db85Sdougm type = sa_get_share_attr(share, "type"); 5330da6c28aaSamw resource = get_resource(share); 53316185db85Sdougm groupname = sa_get_group_attr(group, "name"); 53326185db85Sdougm 53336185db85Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 53346185db85Sdougm sa_free_attr_string(groupname); 53356185db85Sdougm groupname = NULL; 53366185db85Sdougm } 53376185db85Sdougm description = sa_get_share_description(share); 5338f345c0beSdougm 5339da6c28aaSamw /* 5340da6c28aaSamw * Want the sharetab version if it exists, defaulting 5341da6c28aaSamw * to NFS if no protocol specified. 5342da6c28aaSamw */ 5343da6c28aaSamw (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto); 5344da6c28aaSamw soptions = sa_get_share_attr(share, shareopts); 53456185db85Sdougm 53466185db85Sdougm if (sharedstate == NULL) 53476185db85Sdougm shared = 0; 53486185db85Sdougm 5349f345c0beSdougm if (soptions == NULL) 53506185db85Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 53516185db85Sdougm 53526185db85Sdougm if (shared) { 5353f345c0beSdougm /* only active shares go here */ 53546185db85Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 53556185db85Sdougm resource != NULL ? resource : "-", 53566185db85Sdougm groupname != NULL ? "@" : "", 53576185db85Sdougm groupname != NULL ? groupname : ""); 53586185db85Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 5359fe1c642dSBill Krier resfmt, (path != NULL) ? path : "", 53606185db85Sdougm (soptions != NULL && strlen(soptions) > 0) ? 5361da6c28aaSamw soptions : defprop, 53626185db85Sdougm (description != NULL) ? description : ""); 53636185db85Sdougm } 53646185db85Sdougm 53656185db85Sdougm if (path != NULL) 53666185db85Sdougm sa_free_attr_string(path); 53676185db85Sdougm if (type != NULL) 53686185db85Sdougm sa_free_attr_string(type); 53696185db85Sdougm if (resource != NULL) 53706185db85Sdougm sa_free_attr_string(resource); 53716185db85Sdougm if (groupname != NULL) 53726185db85Sdougm sa_free_attr_string(groupname); 53736185db85Sdougm if (description != NULL) 53746185db85Sdougm sa_free_share_description(description); 53756185db85Sdougm if (sharedstate != NULL) 53766185db85Sdougm sa_free_attr_string(sharedstate); 5377f345c0beSdougm if (soptions != NULL) 53786185db85Sdougm sa_format_free(soptions); 53796185db85Sdougm } 53806185db85Sdougm } 53816185db85Sdougm 53826185db85Sdougm /* 53836185db85Sdougm * output_legacy_file(out, proto) 53846185db85Sdougm * 53856185db85Sdougm * Walk all of the groups for the specified protocol and call 53866185db85Sdougm * out_share() to format and write in the format displayed by the 53876185db85Sdougm * "share" command with no arguments. 53886185db85Sdougm */ 53896185db85Sdougm 53906185db85Sdougm static void 5391549ec3ffSdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 53926185db85Sdougm { 53936185db85Sdougm sa_group_t group; 53946185db85Sdougm 5395da6c28aaSamw for (group = sa_get_group(handle, NULL); 5396da6c28aaSamw group != NULL; 53976185db85Sdougm group = sa_get_next_group(group)) { 53986185db85Sdougm char *zfs; 53996185db85Sdougm 54006185db85Sdougm /* 5401da6c28aaSamw * Go through all the groups and ZFS 5402da6c28aaSamw * sub-groups. out_share() will format the shares in 5403da6c28aaSamw * the group appropriately. 54046185db85Sdougm */ 54056185db85Sdougm 54066185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 54076185db85Sdougm if (zfs != NULL) { 54086185db85Sdougm sa_group_t zgroup; 54096185db85Sdougm sa_free_attr_string(zfs); 541025a68471Sdougm for (zgroup = sa_get_sub_group(group); 541125a68471Sdougm zgroup != NULL; 54126185db85Sdougm zgroup = sa_get_next_group(zgroup)) { 54136185db85Sdougm 54146185db85Sdougm /* got a group, so display it */ 5415f345c0beSdougm out_share(out, zgroup, proto); 54166185db85Sdougm } 54176185db85Sdougm } else { 5418f345c0beSdougm out_share(out, group, proto); 54196185db85Sdougm } 54206185db85Sdougm } 54216185db85Sdougm } 54226185db85Sdougm 54236185db85Sdougm int 5424549ec3ffSdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 54256185db85Sdougm { 54266185db85Sdougm char *protocol = "nfs"; 54276185db85Sdougm char *options = NULL; 54286185db85Sdougm char *description = NULL; 54296185db85Sdougm char *groupname = NULL; 54306185db85Sdougm char *sharepath = NULL; 54316185db85Sdougm char *resource = NULL; 54326185db85Sdougm char *groupstatus = NULL; 54336185db85Sdougm int persist = SA_SHARE_TRANSIENT; 54346185db85Sdougm int argsused = 0; 54356185db85Sdougm int c; 54366185db85Sdougm int ret = SA_OK; 54376185db85Sdougm int zfs = 0; 54386185db85Sdougm int true_legacy = 0; 54396185db85Sdougm int curtype = SA_SHARE_TRANSIENT; 54406185db85Sdougm char cmd[MAXPATHLEN]; 544125a68471Sdougm sa_group_t group = NULL; 5442da6c28aaSamw sa_resource_t rsrc = NULL; 544325a68471Sdougm sa_share_t share; 544425a68471Sdougm char dir[MAXPATHLEN]; 5445da6c28aaSamw uint64_t features; 5446da6c28aaSamw #ifdef lint 5447da6c28aaSamw flags = flags; 5448da6c28aaSamw #endif 54496185db85Sdougm 54506185db85Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 54516185db85Sdougm switch (c) { 54526185db85Sdougm case 'd': 54536185db85Sdougm description = optarg; 54546185db85Sdougm argsused++; 54556185db85Sdougm break; 54566185db85Sdougm case 'F': 54576185db85Sdougm protocol = optarg; 54586185db85Sdougm if (!sa_valid_protocol(protocol)) { 54596185db85Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 546025a68471Sdougm protocol, "share") == 0 && 546125a68471Sdougm check_legacy_cmd(cmd)) { 54626185db85Sdougm true_legacy++; 54636185db85Sdougm } else { 546425a68471Sdougm (void) fprintf(stderr, gettext( 546525a68471Sdougm "Invalid protocol specified: " 546625a68471Sdougm "%s\n"), protocol); 54676185db85Sdougm return (SA_INVALID_PROTOCOL); 54686185db85Sdougm } 54696185db85Sdougm } 54706185db85Sdougm break; 54716185db85Sdougm case 'o': 54726185db85Sdougm options = optarg; 54736185db85Sdougm argsused++; 54746185db85Sdougm break; 54756185db85Sdougm case 'p': 54766185db85Sdougm persist = SA_SHARE_PERMANENT; 54776185db85Sdougm argsused++; 54786185db85Sdougm break; 54796185db85Sdougm case 'h': 5480e7bab347Sdougm /* optopt on valid arg isn't defined */ 5481e7bab347Sdougm optopt = c; 5482e7bab347Sdougm /*FALLTHROUGH*/ 54836185db85Sdougm case '?': 54846185db85Sdougm default: 5485e7bab347Sdougm /* 5486e7bab347Sdougm * Since a bad option gets to here, sort it 5487e7bab347Sdougm * out and return a syntax error return value 5488e7bab347Sdougm * if necessary. 5489e7bab347Sdougm */ 5490e7bab347Sdougm switch (optopt) { 5491e7bab347Sdougm default: 5492e7bab347Sdougm ret = SA_LEGACY_ERR; 5493e7bab347Sdougm break; 5494e7bab347Sdougm case 'h': 5495e7bab347Sdougm case '?': 5496e7bab347Sdougm break; 5497e7bab347Sdougm } 54986185db85Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 54996185db85Sdougm sa_get_usage(USAGE_SHARE)); 5500e7bab347Sdougm return (ret); 55016185db85Sdougm } 55026185db85Sdougm } 55036185db85Sdougm 550425a68471Sdougm /* Have the info so construct what is needed */ 55056185db85Sdougm if (!argsused && optind == argc) { 55066185db85Sdougm /* display current info in share format */ 5507da6c28aaSamw (void) output_legacy_file(stdout, protocol, handle); 550825a68471Sdougm return (ret); 550925a68471Sdougm } 55106185db85Sdougm 551125a68471Sdougm /* We are modifying the configuration */ 55126185db85Sdougm if (optind == argc) { 55136185db85Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 55146185db85Sdougm sa_get_usage(USAGE_SHARE)); 55156185db85Sdougm return (SA_LEGACY_ERR); 55166185db85Sdougm } 55176185db85Sdougm if (true_legacy) { 551825a68471Sdougm /* If still using legacy share/unshare, exec it */ 55196185db85Sdougm ret = run_legacy_command(cmd, argv); 55206185db85Sdougm return (ret); 55216185db85Sdougm } 55226185db85Sdougm 55236185db85Sdougm sharepath = argv[optind++]; 55246185db85Sdougm if (optind < argc) { 55256185db85Sdougm resource = argv[optind]; 55266185db85Sdougm groupname = strchr(resource, '@'); 55276185db85Sdougm if (groupname != NULL) 55286185db85Sdougm *groupname++ = '\0'; 55296185db85Sdougm } 55306185db85Sdougm if (realpath(sharepath, dir) == NULL) 55316185db85Sdougm ret = SA_BAD_PATH; 55326185db85Sdougm else 55336185db85Sdougm sharepath = dir; 553425a68471Sdougm if (ret == SA_OK) 5535549ec3ffSdougm share = sa_find_share(handle, sharepath); 553625a68471Sdougm else 55376185db85Sdougm share = NULL; 553825a68471Sdougm 5539da6c28aaSamw features = sa_proto_get_featureset(protocol); 5540da6c28aaSamw 55416185db85Sdougm if (groupname != NULL) { 55426185db85Sdougm ret = SA_NOT_ALLOWED; 55436185db85Sdougm } else if (ret == SA_OK) { 5544da6c28aaSamw char *legacygroup; 55456185db85Sdougm /* 554625a68471Sdougm * The legacy group is always present and zfs groups 55476185db85Sdougm * come and go. zfs shares may be in sub-groups and 55486185db85Sdougm * the zfs share will already be in that group so it 5549da6c28aaSamw * isn't an error. If the protocol is "smb", the group 5550da6c28aaSamw * "smb" is used when "default" would otherwise be 5551da6c28aaSamw * used. "default" is NFS only and "smb" is SMB only. 55526185db85Sdougm */ 5553da6c28aaSamw if (strcmp(protocol, "smb") == 0) 5554da6c28aaSamw legacygroup = "smb"; 5555da6c28aaSamw else 5556da6c28aaSamw legacygroup = "default"; 5557da6c28aaSamw 55586185db85Sdougm /* 555925a68471Sdougm * If the share exists (not NULL), then make sure it 556025a68471Sdougm * is one we want to handle by getting the parent 556125a68471Sdougm * group. 55626185db85Sdougm */ 5563da6c28aaSamw if (share != NULL) { 55646185db85Sdougm group = sa_get_parent_group(share); 5565da6c28aaSamw } else { 5566549ec3ffSdougm group = sa_get_group(handle, legacygroup); 5567da6c28aaSamw if (group == NULL && strcmp(legacygroup, "smb") == 0) { 5568da6c28aaSamw /* 5569da6c28aaSamw * This group may not exist, so create 5570da6c28aaSamw * as necessary. It only contains the 5571da6c28aaSamw * "smb" protocol. 5572da6c28aaSamw */ 5573da6c28aaSamw group = sa_create_group(handle, legacygroup, 5574da6c28aaSamw &ret); 5575da6c28aaSamw if (group != NULL) 5576da6c28aaSamw (void) sa_create_optionset(group, 5577da6c28aaSamw protocol); 5578da6c28aaSamw } 5579da6c28aaSamw } 558025a68471Sdougm 5581da6c28aaSamw if (group == NULL) { 5582da6c28aaSamw ret = SA_SYSTEM_ERR; 5583da6c28aaSamw goto err; 5584da6c28aaSamw } 5585da6c28aaSamw 55866185db85Sdougm groupstatus = group_status(group); 55876185db85Sdougm if (share == NULL) { 55886185db85Sdougm share = sa_add_share(group, sharepath, 55896185db85Sdougm persist, &ret); 559025a68471Sdougm if (share == NULL && 559125a68471Sdougm ret == SA_DUPLICATE_NAME) { 559225a68471Sdougm /* 559325a68471Sdougm * Could be a ZFS path being started 559425a68471Sdougm */ 559525a68471Sdougm if (sa_zfs_is_shared(handle, 559625a68471Sdougm sharepath)) { 559725a68471Sdougm ret = SA_OK; 559825a68471Sdougm group = sa_get_group(handle, 559925a68471Sdougm "zfs"); 560025a68471Sdougm if (group == NULL) { 560125a68471Sdougm /* 560225a68471Sdougm * This shouldn't 560325a68471Sdougm * happen. 560425a68471Sdougm */ 560525a68471Sdougm ret = SA_CONFIG_ERR; 560625a68471Sdougm } else { 560725a68471Sdougm share = sa_add_share( 560825a68471Sdougm group, sharepath, 560925a68471Sdougm persist, &ret); 56106185db85Sdougm } 56116185db85Sdougm } 56126185db85Sdougm } 56136185db85Sdougm } else { 561493a6f655Sdougm char *type; 56156185db85Sdougm /* 561625a68471Sdougm * May want to change persist state, but the 561793a6f655Sdougm * important thing is to change options. We 561893a6f655Sdougm * need to change them regardless of the 561993a6f655Sdougm * source. 56206185db85Sdougm */ 5621da6c28aaSamw 5622549ec3ffSdougm if (sa_zfs_is_shared(handle, sharepath)) { 562393a6f655Sdougm zfs = 1; 562493a6f655Sdougm } 56256185db85Sdougm remove_all_options(share, protocol); 56266185db85Sdougm type = sa_get_share_attr(share, "type"); 56276185db85Sdougm if (type != NULL && 56286185db85Sdougm strcmp(type, "transient") != 0) { 56296185db85Sdougm curtype = SA_SHARE_PERMANENT; 56306185db85Sdougm } 56316185db85Sdougm if (type != NULL) 56326185db85Sdougm sa_free_attr_string(type); 56336185db85Sdougm if (curtype != persist) { 56346185db85Sdougm (void) sa_set_share_attr(share, "type", 56356185db85Sdougm persist == SA_SHARE_PERMANENT ? 56366185db85Sdougm "persist" : "transient"); 56376185db85Sdougm } 56386185db85Sdougm } 5639da6c28aaSamw 5640da6c28aaSamw /* 5641da6c28aaSamw * If there is a resource name, we may 5642da6c28aaSamw * actually care about it if this is share for 5643da6c28aaSamw * a protocol that uses resource level sharing 5644da6c28aaSamw * (SMB). We need to find the resource and, if 5645da6c28aaSamw * it exists, make sure it belongs to the 5646da6c28aaSamw * current share. If it doesn't exist, attempt 5647da6c28aaSamw * to create it. 5648da6c28aaSamw */ 5649da6c28aaSamw 5650da6c28aaSamw if (ret == SA_OK && resource != NULL) { 5651da6c28aaSamw rsrc = sa_find_resource(handle, resource); 5652da6c28aaSamw if (rsrc != NULL) { 5653da6c28aaSamw if (share != sa_get_resource_parent(rsrc)) 5654da6c28aaSamw ret = SA_DUPLICATE_NAME; 5655da6c28aaSamw } else { 5656da6c28aaSamw rsrc = sa_add_resource(share, resource, 5657da6c28aaSamw persist, &ret); 5658da6c28aaSamw } 5659da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 5660da6c28aaSamw share = rsrc; 5661da6c28aaSamw } 5662da6c28aaSamw 566325a68471Sdougm /* Have a group to hold this share path */ 56646185db85Sdougm if (ret == SA_OK && options != NULL && 56656185db85Sdougm strlen(options) > 0) { 56666185db85Sdougm ret = sa_parse_legacy_options(share, 56676185db85Sdougm options, 56686185db85Sdougm protocol); 56696185db85Sdougm } 567093a6f655Sdougm if (!zfs) { 567193a6f655Sdougm /* 5672da6c28aaSamw * ZFS shares never have a description 5673da6c28aaSamw * and we can't store the values so 5674da6c28aaSamw * don't try. 567593a6f655Sdougm */ 56766185db85Sdougm if (ret == SA_OK && description != NULL) 567725a68471Sdougm ret = sa_set_share_description(share, 567825a68471Sdougm description); 56796185db85Sdougm } 5680da6c28aaSamw if (ret == SA_OK && 5681da6c28aaSamw strcmp(groupstatus, "enabled") == 0) { 5682da6c28aaSamw if (rsrc != share) 56836185db85Sdougm ret = sa_enable_share(share, protocol); 5684da6c28aaSamw else 5685da6c28aaSamw ret = sa_enable_resource(rsrc, 5686da6c28aaSamw protocol); 568725a68471Sdougm if (ret == SA_OK && 568825a68471Sdougm persist == SA_SHARE_PERMANENT) { 568925a68471Sdougm (void) sa_update_legacy(share, 569025a68471Sdougm protocol); 56916185db85Sdougm } 56926185db85Sdougm if (ret == SA_OK) 5693549ec3ffSdougm ret = sa_update_config(handle); 56946185db85Sdougm } 56956185db85Sdougm } 5696da6c28aaSamw err: 56976185db85Sdougm if (ret != SA_OK) { 56986185db85Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 56996185db85Sdougm sharepath, sa_errorstr(ret)); 57006185db85Sdougm ret = SA_LEGACY_ERR; 57016185db85Sdougm } 57026185db85Sdougm return (ret); 57036185db85Sdougm } 57046185db85Sdougm 57056185db85Sdougm /* 57066185db85Sdougm * sa_legacy_unshare(flags, argc, argv) 57076185db85Sdougm * 57086185db85Sdougm * Implements the original unshare command. 57096185db85Sdougm */ 57106185db85Sdougm int 5711549ec3ffSdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 57126185db85Sdougm { 57136185db85Sdougm char *protocol = "nfs"; /* for now */ 57146185db85Sdougm char *options = NULL; 57156185db85Sdougm char *sharepath = NULL; 57166185db85Sdougm int persist = SA_SHARE_TRANSIENT; 57176185db85Sdougm int argsused = 0; 57186185db85Sdougm int c; 57196185db85Sdougm int ret = SA_OK; 57206185db85Sdougm int true_legacy = 0; 5721da6c28aaSamw uint64_t features = 0; 5722da6c28aaSamw sa_resource_t resource = NULL; 57236185db85Sdougm char cmd[MAXPATHLEN]; 5724da6c28aaSamw #ifdef lint 5725da6c28aaSamw flags = flags; 5726da6c28aaSamw options = options; 5727da6c28aaSamw #endif 57286185db85Sdougm 57296185db85Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 57306185db85Sdougm switch (c) { 57316185db85Sdougm case 'F': 57326185db85Sdougm protocol = optarg; 57336185db85Sdougm if (!sa_valid_protocol(protocol)) { 57346185db85Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 57356185db85Sdougm protocol, "unshare") == 0 && 57366185db85Sdougm check_legacy_cmd(cmd)) { 57376185db85Sdougm true_legacy++; 57386185db85Sdougm } else { 573925a68471Sdougm (void) printf(gettext( 574025a68471Sdougm "Invalid file system name\n")); 57416185db85Sdougm return (SA_INVALID_PROTOCOL); 57426185db85Sdougm } 57436185db85Sdougm } 57446185db85Sdougm break; 57456185db85Sdougm case 'o': 57466185db85Sdougm options = optarg; 57476185db85Sdougm argsused++; 57486185db85Sdougm break; 57496185db85Sdougm case 'p': 57506185db85Sdougm persist = SA_SHARE_PERMANENT; 57516185db85Sdougm argsused++; 57526185db85Sdougm break; 5753e7bab347Sdougm case 'h': 5754e7bab347Sdougm /* optopt on valid arg isn't defined */ 5755e7bab347Sdougm optopt = c; 5756e7bab347Sdougm /*FALLTHROUGH*/ 5757e7bab347Sdougm case '?': 57586185db85Sdougm default: 5759e7bab347Sdougm /* 5760e7bab347Sdougm * Since a bad option gets to here, sort it 5761e7bab347Sdougm * out and return a syntax error return value 5762e7bab347Sdougm * if necessary. 5763e7bab347Sdougm */ 5764e7bab347Sdougm switch (optopt) { 5765e7bab347Sdougm default: 5766e7bab347Sdougm ret = SA_LEGACY_ERR; 5767e7bab347Sdougm break; 5768e7bab347Sdougm case 'h': 5769e7bab347Sdougm case '?': 5770e7bab347Sdougm break; 5771e7bab347Sdougm } 57726185db85Sdougm (void) printf(gettext("usage: %s\n"), 57736185db85Sdougm sa_get_usage(USAGE_UNSHARE)); 5774e7bab347Sdougm return (ret); 57756185db85Sdougm } 57766185db85Sdougm } 57776185db85Sdougm 577825a68471Sdougm /* Have the info so construct what is needed */ 577925a68471Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 57806185db85Sdougm ret = SA_SYNTAX_ERR; 57816185db85Sdougm } else { 57826185db85Sdougm sa_share_t share; 57836185db85Sdougm char dir[MAXPATHLEN]; 57846185db85Sdougm if (true_legacy) { 57856185db85Sdougm /* if still using legacy share/unshare, exec it */ 57866185db85Sdougm ret = run_legacy_command(cmd, argv); 57876185db85Sdougm return (ret); 57886185db85Sdougm } 5789a99982a7Sdougm /* 5790a99982a7Sdougm * Find the path in the internal configuration. If it 5791a99982a7Sdougm * isn't found, attempt to resolve the path via 5792a99982a7Sdougm * realpath() and try again. 5793a99982a7Sdougm */ 57946185db85Sdougm sharepath = argv[optind++]; 5795549ec3ffSdougm share = sa_find_share(handle, sharepath); 5796a99982a7Sdougm if (share == NULL) { 57976185db85Sdougm if (realpath(sharepath, dir) == NULL) { 57986185db85Sdougm ret = SA_NO_SUCH_PATH; 57996185db85Sdougm } else { 5800549ec3ffSdougm share = sa_find_share(handle, dir); 5801a99982a7Sdougm } 5802a99982a7Sdougm } 5803da6c28aaSamw if (share == NULL) { 5804da6c28aaSamw /* Could be a resource name so check that next */ 5805da6c28aaSamw features = sa_proto_get_featureset(protocol); 5806da6c28aaSamw resource = sa_find_resource(handle, sharepath); 5807da6c28aaSamw if (resource != NULL) { 5808da6c28aaSamw share = sa_get_resource_parent(resource); 5809da6c28aaSamw if (features & SA_FEATURE_RESOURCE) 5810da6c28aaSamw (void) sa_disable_resource(resource, 5811da6c28aaSamw protocol); 5812da6c28aaSamw if (persist == SA_SHARE_PERMANENT) { 5813da6c28aaSamw ret = sa_remove_resource(resource); 5814da6c28aaSamw if (ret == SA_OK) 5815da6c28aaSamw ret = sa_update_config(handle); 5816da6c28aaSamw } 5817da6c28aaSamw /* 5818da6c28aaSamw * If we still have a resource on the 5819da6c28aaSamw * share, we don't disable the share 5820da6c28aaSamw * itself. IF there aren't anymore, we 5821da6c28aaSamw * need to remove the share. The 5822da6c28aaSamw * removal will be done in the next 5823da6c28aaSamw * section if appropriate. 5824da6c28aaSamw */ 5825da6c28aaSamw resource = sa_get_share_resource(share, NULL); 5826da6c28aaSamw if (resource != NULL) 5827da6c28aaSamw share = NULL; 5828da6c28aaSamw } else if (ret == SA_OK) { 5829da6c28aaSamw /* Didn't find path and no resource */ 5830da6c28aaSamw ret = SA_BAD_PATH; 5831da6c28aaSamw } 5832da6c28aaSamw } 5833da6c28aaSamw if (share != NULL && resource == NULL) { 58346185db85Sdougm ret = sa_disable_share(share, protocol); 5835a99982a7Sdougm /* 5836a99982a7Sdougm * Errors are ok and removal should still occur. The 5837a99982a7Sdougm * legacy unshare is more forgiving of errors than the 5838a99982a7Sdougm * remove-share subcommand which may need the force 5839a99982a7Sdougm * flag set for some error conditions. That is, the 5840a99982a7Sdougm * "unshare" command will always unshare if it can 5841a99982a7Sdougm * while "remove-share" might require the force option. 5842a99982a7Sdougm */ 5843a99982a7Sdougm if (persist == SA_SHARE_PERMANENT) { 58446185db85Sdougm ret = sa_remove_share(share); 5845a99982a7Sdougm if (ret == SA_OK) 5846549ec3ffSdougm ret = sa_update_config(handle); 58476185db85Sdougm } 5848da6c28aaSamw } else if (ret == SA_OK && share == NULL && resource == NULL) { 5849da6c28aaSamw /* 5850da6c28aaSamw * If both share and resource are NULL, then 5851da6c28aaSamw * share not found. If one or the other was 5852da6c28aaSamw * found or there was an earlier error, we 5853da6c28aaSamw * assume it was handled earlier. 5854da6c28aaSamw */ 58556185db85Sdougm ret = SA_NOT_SHARED; 58566185db85Sdougm } 58576185db85Sdougm } 58586185db85Sdougm switch (ret) { 58596185db85Sdougm default: 58606185db85Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 58616185db85Sdougm ret = SA_LEGACY_ERR; 58626185db85Sdougm break; 58636185db85Sdougm case SA_SYNTAX_ERR: 58646185db85Sdougm (void) printf(gettext("usage: %s\n"), 58656185db85Sdougm sa_get_usage(USAGE_UNSHARE)); 58666185db85Sdougm break; 58676185db85Sdougm case SA_OK: 58686185db85Sdougm break; 58696185db85Sdougm } 58706185db85Sdougm return (ret); 58716185db85Sdougm } 58726185db85Sdougm 58736185db85Sdougm /* 587425a68471Sdougm * Common commands that implement the sub-commands used by all 5875da6c28aaSamw * protocols. The entries are found via the lookup command 58766185db85Sdougm */ 58776185db85Sdougm 58786185db85Sdougm static sa_command_t commands[] = { 58796185db85Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 58806185db85Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 58816185db85Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 58826185db85Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 58836185db85Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 58846185db85Sdougm {"list", 0, sa_list, USAGE_LIST}, 58856185db85Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 58866185db85Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 58876185db85Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 58886185db85Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 58896185db85Sdougm {"show", 0, sa_show, USAGE_SHOW}, 58906185db85Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 58916185db85Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 58926185db85Sdougm SVC_SET|SVC_ACTION}, 58936185db85Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 58946185db85Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 58956185db85Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 58966185db85Sdougm {NULL, 0, NULL, NULL} 58976185db85Sdougm }; 58986185db85Sdougm 58996185db85Sdougm static char * 59006185db85Sdougm sa_get_usage(sa_usage_t index) 59016185db85Sdougm { 59026185db85Sdougm char *ret = NULL; 59036185db85Sdougm switch (index) { 59046185db85Sdougm case USAGE_ADD_SHARE: 59056185db85Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 59066185db85Sdougm "[-d \"description text\"] -s sharepath group"); 59076185db85Sdougm break; 59086185db85Sdougm case USAGE_CREATE: 590925a68471Sdougm ret = gettext( 591025a68471Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 59116185db85Sdougm break; 59126185db85Sdougm case USAGE_DELETE: 59136185db85Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 59146185db85Sdougm break; 59156185db85Sdougm case USAGE_DISABLE: 59166185db85Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 59176185db85Sdougm break; 59186185db85Sdougm case USAGE_ENABLE: 59196185db85Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 59206185db85Sdougm break; 59216185db85Sdougm case USAGE_LIST: 59226185db85Sdougm ret = gettext("list [-vh] [-P proto]"); 59236185db85Sdougm break; 59246185db85Sdougm case USAGE_MOVE_SHARE: 592525a68471Sdougm ret = gettext( 592625a68471Sdougm "move-share [-nvh] -s sharepath destination-group"); 59276185db85Sdougm break; 59286185db85Sdougm case USAGE_REMOVE_SHARE: 5929da6c28aaSamw ret = gettext( 5930da6c28aaSamw "remove-share [-fnvh] {-s sharepath | -r resource} " 5931da6c28aaSamw "group"); 59326185db85Sdougm break; 59336185db85Sdougm case USAGE_SET: 59346185db85Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 5935da6c28aaSamw "[-p property=value]* [-s sharepath] [-r resource]] " 5936da6c28aaSamw "group"); 59376185db85Sdougm break; 59386185db85Sdougm case USAGE_SET_SECURITY: 59396185db85Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 59406185db85Sdougm "[-p property=value]* group"); 59416185db85Sdougm break; 59426185db85Sdougm case USAGE_SET_SHARE: 59436185db85Sdougm ret = gettext("set-share [-nh] [-r resource] " 59446185db85Sdougm "[-d \"description text\"] -s sharepath group"); 59456185db85Sdougm break; 59466185db85Sdougm case USAGE_SHOW: 59476185db85Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 59486185db85Sdougm break; 59496185db85Sdougm case USAGE_SHARE: 59506185db85Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 59516185db85Sdougm "[-d description] [pathname [resourcename]]"); 59526185db85Sdougm break; 59536185db85Sdougm case USAGE_START: 59546185db85Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 59556185db85Sdougm break; 59566185db85Sdougm case USAGE_STOP: 59576185db85Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 59586185db85Sdougm break; 59596185db85Sdougm case USAGE_UNSET: 59606185db85Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 59616185db85Sdougm "[-p property]* group"); 59626185db85Sdougm break; 59636185db85Sdougm case USAGE_UNSET_SECURITY: 5964da6c28aaSamw ret = gettext("unset-security [-nvh] -P proto " 5965da6c28aaSamw "-S security-type [-p property]* group"); 59666185db85Sdougm break; 59676185db85Sdougm case USAGE_UNSHARE: 596825a68471Sdougm ret = gettext( 5969da6c28aaSamw "unshare [-F fstype] [-p] [-o optionlist] sharepath"); 59706185db85Sdougm break; 59716185db85Sdougm } 59726185db85Sdougm return (ret); 59736185db85Sdougm } 59746185db85Sdougm 59756185db85Sdougm /* 59766185db85Sdougm * sa_lookup(cmd, proto) 59776185db85Sdougm * 59786185db85Sdougm * Lookup the sub-command. proto isn't currently used, but it may 59796185db85Sdougm * eventually provide a way to provide protocol specific sub-commands. 59806185db85Sdougm */ 59816185db85Sdougm sa_command_t * 59826185db85Sdougm sa_lookup(char *cmd, char *proto) 59836185db85Sdougm { 59846185db85Sdougm int i; 59856185db85Sdougm size_t len; 5986da6c28aaSamw #ifdef lint 5987da6c28aaSamw proto = proto; 5988da6c28aaSamw #endif 59896185db85Sdougm 59906185db85Sdougm len = strlen(cmd); 59916185db85Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 59926185db85Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 59936185db85Sdougm return (&commands[i]); 59946185db85Sdougm } 59956185db85Sdougm return (NULL); 59966185db85Sdougm } 59976185db85Sdougm 59986185db85Sdougm void 59996185db85Sdougm sub_command_help(char *proto) 60006185db85Sdougm { 60016185db85Sdougm int i; 6002da6c28aaSamw #ifdef lint 6003da6c28aaSamw proto = proto; 6004da6c28aaSamw #endif 60056185db85Sdougm 60066185db85Sdougm (void) printf(gettext("\tsub-commands:\n")); 60076185db85Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 60086185db85Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 60096185db85Sdougm (void) printf("\t%s\n", 60106185db85Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 60116185db85Sdougm } 60126185db85Sdougm } 6013