13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 233348Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm #include <sys/types.h> 303034Sdougm #include <sys/stat.h> 313034Sdougm #include <fcntl.h> 323034Sdougm #include <stdlib.h> 333034Sdougm #include <stdio.h> 343034Sdougm #include <string.h> 353034Sdougm #include <ctype.h> 363034Sdougm #include <unistd.h> 373034Sdougm #include <getopt.h> 383034Sdougm #include <utmpx.h> 393034Sdougm #include <pwd.h> 403034Sdougm #include <auth_attr.h> 413034Sdougm #include <secdb.h> 423034Sdougm #include <sys/param.h> 433034Sdougm #include <sys/stat.h> 443034Sdougm #include <errno.h> 453034Sdougm 463034Sdougm #include <libshare.h> 473034Sdougm #include "sharemgr.h" 483034Sdougm #include <libscf.h> 493034Sdougm #include <libxml/tree.h> 503034Sdougm #include <libintl.h> 51*5331Samw #include <assert.h> 52*5331Samw #include <iconv.h> 53*5331Samw #include <langinfo.h> 54*5331Samw #include <dirent.h> 553034Sdougm 563034Sdougm static char *sa_get_usage(sa_usage_t); 573034Sdougm 583034Sdougm /* 593034Sdougm * Implementation of the common sub-commands supported by sharemgr. 603034Sdougm * A number of helper functions are also included. 613034Sdougm */ 623034Sdougm 633034Sdougm /* 643034Sdougm * has_protocol(group, proto) 653034Sdougm * If the group has an optionset with the specified protocol, 663034Sdougm * return true (1) otherwise false (0). 673034Sdougm */ 683034Sdougm static int 693034Sdougm has_protocol(sa_group_t group, char *protocol) 703034Sdougm { 713034Sdougm sa_optionset_t optionset; 723034Sdougm int result = 0; 733034Sdougm 743034Sdougm optionset = sa_get_optionset(group, protocol); 753034Sdougm if (optionset != NULL) { 764653Sdougm result++; 773034Sdougm } 783034Sdougm return (result); 793034Sdougm } 803034Sdougm 813034Sdougm /* 82*5331Samw * validresource(name) 83*5331Samw * 84*5331Samw * Check that name only has valid characters in it. The current valid 85*5331Samw * set are the printable characters but not including: 86*5331Samw * " / \ [ ] : | < > + ; , ? * = \t 87*5331Samw * Note that space is included and there is a maximum length. 88*5331Samw */ 89*5331Samw static int 90*5331Samw validresource(const char *name) 91*5331Samw { 92*5331Samw const char *cp; 93*5331Samw size_t len; 94*5331Samw 95*5331Samw if (name == NULL) 96*5331Samw return (B_FALSE); 97*5331Samw 98*5331Samw len = strlen(name); 99*5331Samw if (len == 0 || len > SA_MAX_RESOURCE_NAME) 100*5331Samw return (B_FALSE); 101*5331Samw 102*5331Samw if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) { 103*5331Samw return (B_FALSE); 104*5331Samw } 105*5331Samw 106*5331Samw for (cp = name; *cp != '\0'; cp++) 107*5331Samw if (iscntrl(*cp)) 108*5331Samw return (B_FALSE); 109*5331Samw 110*5331Samw return (B_TRUE); 111*5331Samw } 112*5331Samw 113*5331Samw /* 114*5331Samw * conv_to_utf8(input) 115*5331Samw * 116*5331Samw * Convert the input string to utf8 from the current locale. If the 117*5331Samw * conversion fails, use the current locale, it is likely close 118*5331Samw * enough. For example, the "C" locale is a subset of utf-8. The 119*5331Samw * return value may be a new string or the original input string. 120*5331Samw */ 121*5331Samw 122*5331Samw static char * 123*5331Samw conv_to_utf8(char *input) 124*5331Samw { 125*5331Samw iconv_t cd; 126*5331Samw char *output = input; 127*5331Samw char *outleft; 128*5331Samw char *curlocale; 129*5331Samw size_t bytesleft; 130*5331Samw size_t size; 131*5331Samw size_t osize; 132*5331Samw static int warned = 0; 133*5331Samw 134*5331Samw curlocale = nl_langinfo(CODESET); 135*5331Samw if (curlocale == NULL) 136*5331Samw curlocale = "C"; 137*5331Samw cd = iconv_open("UTF-8", curlocale); 138*5331Samw if (cd != NULL && cd != (iconv_t)-1) { 139*5331Samw size = strlen(input); 140*5331Samw /* Assume worst case of characters expanding to 4 bytes. */ 141*5331Samw bytesleft = size * 4; 142*5331Samw output = calloc(bytesleft, 1); 143*5331Samw if (output != NULL) { 144*5331Samw outleft = output; 145*5331Samw osize = iconv(cd, (const char **)&input, &size, 146*5331Samw &outleft, &bytesleft); 147*5331Samw if (osize == (size_t)-1 || size != 0) { 148*5331Samw free(output); 149*5331Samw output = input; 150*5331Samw } 151*5331Samw } 152*5331Samw (void) iconv_close(cd); 153*5331Samw } else { 154*5331Samw if (!warned) 155*5331Samw (void) fprintf(stderr, 156*5331Samw gettext("Cannot convert to UTF-8 from %s\n"), 157*5331Samw curlocale ? curlocale : gettext("unknown")); 158*5331Samw warned = 1; 159*5331Samw } 160*5331Samw return (output); 161*5331Samw } 162*5331Samw 163*5331Samw /* 164*5331Samw * conv_from(input) 165*5331Samw * 166*5331Samw * Convert the input string from utf8 to current locale. If the 167*5331Samw * conversion isn't supported, just use as is. The return value may be 168*5331Samw * a new string or the original input string. 169*5331Samw */ 170*5331Samw 171*5331Samw static char * 172*5331Samw conv_from_utf8(char *input) 173*5331Samw { 174*5331Samw iconv_t cd; 175*5331Samw char *output = input; 176*5331Samw char *outleft; 177*5331Samw char *curlocale; 178*5331Samw size_t bytesleft; 179*5331Samw size_t size; 180*5331Samw size_t osize; 181*5331Samw static int warned = 0; 182*5331Samw 183*5331Samw curlocale = nl_langinfo(CODESET); 184*5331Samw if (curlocale == NULL) 185*5331Samw curlocale = "C"; 186*5331Samw cd = iconv_open(curlocale, "UTF-8"); 187*5331Samw if (cd != NULL && cd != (iconv_t)-1) { 188*5331Samw size = strlen(input); 189*5331Samw /* Assume worst case of characters expanding to 4 bytes. */ 190*5331Samw bytesleft = size * 4; 191*5331Samw output = calloc(bytesleft, 1); 192*5331Samw if (output != NULL) { 193*5331Samw outleft = output; 194*5331Samw osize = iconv(cd, (const char **)&input, &size, 195*5331Samw &outleft, &bytesleft); 196*5331Samw if (osize == (size_t)-1 || size != 0) { 197*5331Samw free(output); 198*5331Samw output = input; 199*5331Samw } 200*5331Samw } 201*5331Samw (void) iconv_close(cd); 202*5331Samw } else { 203*5331Samw if (!warned) 204*5331Samw (void) fprintf(stderr, 205*5331Samw gettext("Cannot convert to %s from UTF-8\n"), 206*5331Samw curlocale ? curlocale : gettext("unknown")); 207*5331Samw warned = 1; 208*5331Samw } 209*5331Samw return (output); 210*5331Samw } 211*5331Samw 212*5331Samw static void 213*5331Samw print_rsrc_desc(char *resource) 214*5331Samw { 215*5331Samw char *description; 216*5331Samw char *desc; 217*5331Samw 218*5331Samw description = sa_get_resource_description(resource); 219*5331Samw if (description != NULL) { 220*5331Samw desc = conv_from_utf8(description); 221*5331Samw if (desc != description) { 222*5331Samw sa_free_share_description(description); 223*5331Samw description = desc; 224*5331Samw } 225*5331Samw (void) printf("\t\"%s\"", description); 226*5331Samw sa_free_share_description(description); 227*5331Samw } 228*5331Samw } 229*5331Samw 230*5331Samw static int 231*5331Samw set_share_desc(sa_share_t share, char *description) 232*5331Samw { 233*5331Samw char *desc; 234*5331Samw int ret; 235*5331Samw 236*5331Samw desc = conv_to_utf8(description); 237*5331Samw ret = sa_set_share_description(share, desc); 238*5331Samw if (description != desc) 239*5331Samw sa_free_share_description(desc); 240*5331Samw return (ret); 241*5331Samw } 242*5331Samw 243*5331Samw /* 244*5331Samw * add_list(list, item, data, proto) 245*5331Samw * Adds a new list member that points holds item in the list. 2463034Sdougm * If list is NULL, it starts a new list. The function returns 2473034Sdougm * the first member of the list. 2483034Sdougm */ 2493034Sdougm struct list * 250*5331Samw add_list(struct list *listp, void *item, void *data, char *proto) 2513034Sdougm { 2523034Sdougm struct list *new, *tmp; 2533034Sdougm 2543034Sdougm new = malloc(sizeof (struct list)); 2553034Sdougm if (new != NULL) { 2564653Sdougm new->next = NULL; 2574653Sdougm new->item = item; 2584653Sdougm new->itemdata = data; 259*5331Samw new->proto = proto; 2603034Sdougm } else { 2614653Sdougm return (listp); 2623034Sdougm } 2633034Sdougm 2643034Sdougm if (listp == NULL) 2654653Sdougm return (new); 2663034Sdougm 2673034Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 2683034Sdougm /* get to end of list */ 2693034Sdougm } 2703034Sdougm tmp->next = new; 2713034Sdougm return (listp); 2723034Sdougm } 2733034Sdougm 2743034Sdougm /* 2753034Sdougm * free_list(list) 2763034Sdougm * Given a list, free all the members of the list; 2773034Sdougm */ 2783034Sdougm static void 2793034Sdougm free_list(struct list *listp) 2803034Sdougm { 2813034Sdougm struct list *tmp; 2823034Sdougm while (listp != NULL) { 2834653Sdougm tmp = listp; 2844653Sdougm listp = listp->next; 2854653Sdougm free(tmp); 2863034Sdougm } 2873034Sdougm } 2883034Sdougm 2893034Sdougm /* 2903034Sdougm * check_authorization(instname, which) 2913034Sdougm * 2923034Sdougm * Checks to see if the specific type of authorization in which is 2933034Sdougm * enabled for the user in this SMF service instance. 2943034Sdougm */ 2953034Sdougm 2963034Sdougm static int 2973034Sdougm check_authorization(char *instname, int which) 2983034Sdougm { 2993034Sdougm scf_handle_t *handle = NULL; 3003034Sdougm scf_simple_prop_t *prop = NULL; 3013034Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 3023034Sdougm char *authstr = NULL; 3033034Sdougm ssize_t numauths; 3044653Sdougm int ret = B_TRUE; 3053034Sdougm uid_t uid; 3063034Sdougm struct passwd *pw = NULL; 3073034Sdougm 3083034Sdougm uid = getuid(); 3093034Sdougm pw = getpwuid(uid); 3104653Sdougm if (pw == NULL) { 3114653Sdougm ret = B_FALSE; 3124653Sdougm } else { 3134653Sdougm /* 3144653Sdougm * Since names are restricted to SA_MAX_NAME_LEN won't 3154653Sdougm * overflow. 3164653Sdougm */ 3174653Sdougm (void) snprintf(svcstring, sizeof (svcstring), "%s:%s", 3184653Sdougm SA_SVC_FMRI_BASE, instname); 3194653Sdougm handle = scf_handle_create(SCF_VERSION); 3204653Sdougm if (handle != NULL) { 3214653Sdougm if (scf_handle_bind(handle) == 0) { 3224653Sdougm switch (which) { 3234653Sdougm case SVC_SET: 3244653Sdougm prop = scf_simple_prop_get(handle, 3254653Sdougm svcstring, "general", 3264653Sdougm SVC_AUTH_VALUE); 3274653Sdougm break; 3284653Sdougm case SVC_ACTION: 3294653Sdougm prop = scf_simple_prop_get(handle, 3304653Sdougm svcstring, "general", 3314653Sdougm SVC_AUTH_ACTION); 3324653Sdougm break; 3334653Sdougm } 3344653Sdougm } 3353034Sdougm } 3363034Sdougm } 3373034Sdougm /* make sure we have an authorization string property */ 3383034Sdougm if (prop != NULL) { 3394653Sdougm int i; 3404653Sdougm numauths = scf_simple_prop_numvalues(prop); 3414653Sdougm for (ret = 0, i = 0; i < numauths; i++) { 3424653Sdougm authstr = scf_simple_prop_next_astring(prop); 3434653Sdougm if (authstr != NULL) { 3444653Sdougm /* check if this user has one of the strings */ 3454653Sdougm if (chkauthattr(authstr, pw->pw_name)) { 3464653Sdougm ret = 1; 3474653Sdougm break; 3484653Sdougm } 3494653Sdougm } 3503034Sdougm } 3514653Sdougm endauthattr(); 3524653Sdougm scf_simple_prop_free(prop); 3533034Sdougm } else { 3544653Sdougm /* no authorization string defined */ 3554653Sdougm ret = 0; 3563034Sdougm } 3573034Sdougm if (handle != NULL) 3584653Sdougm scf_handle_destroy(handle); 3593034Sdougm return (ret); 3603034Sdougm } 3613034Sdougm 3623034Sdougm /* 3633034Sdougm * check_authorizations(instname, flags) 3643034Sdougm * 3653034Sdougm * check all the needed authorizations for the user in this service 3663034Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 3673034Sdougm * there are authorizations for the user or not. 3683034Sdougm */ 3693034Sdougm 3703034Sdougm static int 3713034Sdougm check_authorizations(char *instname, int flags) 3723034Sdougm { 3733034Sdougm int ret1 = 0; 3743034Sdougm int ret2 = 0; 3753034Sdougm int ret; 3763034Sdougm 3773034Sdougm if (flags & SVC_SET) 3784653Sdougm ret1 = check_authorization(instname, SVC_SET); 3793034Sdougm if (flags & SVC_ACTION) 3804653Sdougm ret2 = check_authorization(instname, SVC_ACTION); 3813034Sdougm switch (flags) { 3823034Sdougm case SVC_ACTION: 3834653Sdougm ret = ret2; 3844653Sdougm break; 3853034Sdougm case SVC_SET: 3864653Sdougm ret = ret1; 3874653Sdougm break; 3883034Sdougm case SVC_ACTION|SVC_SET: 3894653Sdougm ret = ret1 & ret2; 3904653Sdougm break; 3913034Sdougm default: 3924653Sdougm /* if not flags set, we assume we don't need authorizations */ 3934653Sdougm ret = 1; 3943034Sdougm } 3953034Sdougm return (ret); 3963034Sdougm } 3973034Sdougm 3983034Sdougm /* 399*5331Samw * notify_or_enable_share(share, protocol) 400*5331Samw * 401*5331Samw * Since some protocols don't want an "enable" when properties change, 402*5331Samw * this function will use the protocol specific notify function 403*5331Samw * first. If that fails, it will then attempt to use the 404*5331Samw * sa_enable_share(). "protocol" is the protocol that was specified 405*5331Samw * on the command line. 406*5331Samw */ 407*5331Samw static void 408*5331Samw notify_or_enable_share(sa_share_t share, char *protocol) 409*5331Samw { 410*5331Samw sa_group_t group; 411*5331Samw sa_optionset_t opt; 412*5331Samw int ret = SA_OK; 413*5331Samw char *path; 414*5331Samw char *groupproto; 415*5331Samw sa_share_t parent = share; 416*5331Samw 417*5331Samw /* If really a resource, get parent share */ 418*5331Samw if (!sa_is_share(share)) { 419*5331Samw parent = sa_get_resource_parent((sa_resource_t)share); 420*5331Samw } 421*5331Samw 422*5331Samw /* 423*5331Samw * Now that we've got a share in "parent", make sure it has a path. 424*5331Samw */ 425*5331Samw path = sa_get_share_attr(parent, "path"); 426*5331Samw if (path == NULL) 427*5331Samw return; 428*5331Samw 429*5331Samw group = sa_get_parent_group(parent); 430*5331Samw 431*5331Samw if (group == NULL) { 432*5331Samw sa_free_attr_string(path); 433*5331Samw return; 434*5331Samw } 435*5331Samw for (opt = sa_get_optionset(group, NULL); 436*5331Samw opt != NULL; 437*5331Samw opt = sa_get_next_optionset(opt)) { 438*5331Samw groupproto = sa_get_optionset_attr(opt, "type"); 439*5331Samw if (groupproto == NULL || 440*5331Samw (protocol != NULL && strcmp(groupproto, protocol) != 0)) { 441*5331Samw sa_free_attr_string(groupproto); 442*5331Samw continue; 443*5331Samw } 444*5331Samw if (sa_is_share(share)) { 445*5331Samw if ((ret = sa_proto_change_notify(share, 446*5331Samw groupproto)) != SA_OK) { 447*5331Samw ret = sa_enable_share(share, groupproto); 448*5331Samw if (ret != SA_OK) { 449*5331Samw (void) printf( 450*5331Samw gettext("Could not reenable" 451*5331Samw " share %s: %s\n"), 452*5331Samw path, sa_errorstr(ret)); 453*5331Samw } 454*5331Samw } 455*5331Samw } else { 456*5331Samw /* Must be a resource */ 457*5331Samw if ((ret = sa_proto_notify_resource(share, 458*5331Samw groupproto)) != SA_OK) { 459*5331Samw ret = sa_enable_resource(share, groupproto); 460*5331Samw if (ret != SA_OK) { 461*5331Samw (void) printf( 462*5331Samw gettext("Could not " 463*5331Samw "reenable resource %s: " 464*5331Samw "%s\n"), path, 465*5331Samw sa_errorstr(ret)); 466*5331Samw } 467*5331Samw } 468*5331Samw } 469*5331Samw sa_free_attr_string(groupproto); 470*5331Samw } 471*5331Samw sa_free_attr_string(path); 472*5331Samw } 473*5331Samw 474*5331Samw /* 475*5331Samw * enable_group(group, updateproto, notify, proto) 4763082Sdougm * 4773082Sdougm * enable all the shares in the specified group. This is a helper for 4783082Sdougm * enable_all_groups in order to simplify regular and subgroup (zfs) 479*5331Samw * enabling. Group has already been checked for non-NULL. If notify 480*5331Samw * is non-zero, attempt to use the notify interface rather than 481*5331Samw * enable. 4823082Sdougm */ 4833082Sdougm static void 484*5331Samw enable_group(sa_group_t group, char *updateproto, int notify, char *proto) 4853082Sdougm { 4863082Sdougm sa_share_t share; 4873082Sdougm 4883082Sdougm for (share = sa_get_share(group, NULL); 4893082Sdougm share != NULL; 4903082Sdougm share = sa_get_next_share(share)) { 4914653Sdougm if (updateproto != NULL) 4924653Sdougm (void) sa_update_legacy(share, updateproto); 493*5331Samw if (notify) 494*5331Samw notify_or_enable_share(share, proto); 495*5331Samw else 496*5331Samw (void) sa_enable_share(share, proto); 4973082Sdougm } 4983082Sdougm } 4993082Sdougm 5003082Sdougm /* 5014241Sdougm * isenabled(group) 5024241Sdougm * 5034241Sdougm * Returns B_TRUE if the group is enabled or B_FALSE if it isn't. 5044241Sdougm * Moved to separate function to reduce clutter in the code. 5054241Sdougm */ 5064241Sdougm 5074241Sdougm static int 5084241Sdougm isenabled(sa_group_t group) 5094241Sdougm { 5104241Sdougm char *state; 5114241Sdougm int ret = B_FALSE; 5124241Sdougm 5134241Sdougm if (group != NULL) { 5144653Sdougm state = sa_get_group_attr(group, "state"); 5154653Sdougm if (state != NULL) { 516*5331Samw 5174653Sdougm if (strcmp(state, "enabled") == 0) 5184653Sdougm ret = B_TRUE; 5194653Sdougm sa_free_attr_string(state); 5204653Sdougm } 5214241Sdougm } 5224241Sdougm return (ret); 5234241Sdougm } 5244241Sdougm 5254241Sdougm /* 5263082Sdougm * enable_all_groups(list, setstate, online, updateproto) 527*5331Samw * 528*5331Samw * Given a list of groups, enable each one found. If updateproto is 529*5331Samw * not NULL, then update all the shares for the protocol that was 530*5331Samw * passed in. If enable is non-zero, tell enable_group to try the 531*5331Samw * notify interface since this is a property change. 5323034Sdougm */ 5333034Sdougm static int 5343910Sdougm enable_all_groups(sa_handle_t handle, struct list *work, int setstate, 535*5331Samw int online, char *updateproto, int enable) 5363034Sdougm { 5374241Sdougm int ret; 5383034Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 5393034Sdougm char *state; 5403034Sdougm char *name; 5413034Sdougm char *zfs = NULL; 5423034Sdougm sa_group_t group; 5433082Sdougm sa_group_t subgroup; 5443034Sdougm 5454241Sdougm for (ret = SA_OK; work != NULL; work = work->next) { 5464653Sdougm group = (sa_group_t)work->item; 5474241Sdougm 5484241Sdougm /* 5494241Sdougm * If setstate == TRUE, then make sure to set 5504241Sdougm * enabled. This needs to be done here in order for 5514241Sdougm * the isenabled check to succeed on a newly enabled 5524241Sdougm * group. 5534241Sdougm */ 5544653Sdougm if (setstate == B_TRUE) { 5554653Sdougm ret = sa_set_group_attr(group, "state", "enabled"); 5564653Sdougm if (ret != SA_OK) 5574653Sdougm break; 5584653Sdougm } 5594241Sdougm 5604241Sdougm /* 5614241Sdougm * Check to see if group is enabled. If it isn't, skip 5624241Sdougm * the rest. We don't want shares starting if the 5634241Sdougm * group is disabled. The properties may have been 5644241Sdougm * updated, but there won't be a change until the 5654241Sdougm * group is enabled. 5664241Sdougm */ 5674653Sdougm if (!isenabled(group)) 5684653Sdougm continue; 5694653Sdougm 5704653Sdougm /* if itemdata != NULL then a single share */ 5714653Sdougm if (work->itemdata != NULL) { 572*5331Samw if (enable) { 573*5331Samw if (work->itemdata != NULL) 574*5331Samw notify_or_enable_share(work->itemdata, 575*5331Samw updateproto); 576*5331Samw else 577*5331Samw ret = SA_CONFIG_ERR; 578*5331Samw } else { 579*5331Samw if (sa_is_share(work->itemdata)) { 580*5331Samw ret = sa_enable_share( 581*5331Samw (sa_share_t)work->itemdata, 582*5331Samw updateproto); 583*5331Samw } else { 584*5331Samw ret = sa_enable_resource( 585*5331Samw (sa_resource_t)work->itemdata, 586*5331Samw updateproto); 587*5331Samw } 588*5331Samw } 5893034Sdougm } 5904653Sdougm if (ret != SA_OK) 5914653Sdougm break; 5924653Sdougm 5934653Sdougm /* if itemdata == NULL then the whole group */ 5944653Sdougm if (work->itemdata == NULL) { 5954653Sdougm zfs = sa_get_group_attr(group, "zfs"); 5964653Sdougm /* 597*5331Samw * If the share is managed by ZFS, don't 5984653Sdougm * update any of the protocols since ZFS is 599*5331Samw * handling this. Updateproto will contain 6004653Sdougm * the name of the protocol that we want to 6014653Sdougm * update legacy files for. 6024653Sdougm */ 603*5331Samw enable_group(group, zfs == NULL ? updateproto : NULL, 604*5331Samw enable, work->proto); 6054653Sdougm for (subgroup = sa_get_sub_group(group); 6064653Sdougm subgroup != NULL; 6074653Sdougm subgroup = sa_get_next_group(subgroup)) { 6084653Sdougm /* never update legacy for ZFS subgroups */ 609*5331Samw enable_group(subgroup, NULL, enable, 610*5331Samw work->proto); 6113034Sdougm } 6123034Sdougm } 6134653Sdougm if (online) { 6144653Sdougm zfs = sa_get_group_attr(group, "zfs"); 6154653Sdougm name = sa_get_group_attr(group, "name"); 6164653Sdougm if (name != NULL) { 6174653Sdougm if (zfs == NULL) { 6184653Sdougm (void) snprintf(instance, 6194653Sdougm sizeof (instance), "%s:%s", 6204653Sdougm SA_SVC_FMRI_BASE, name); 6214653Sdougm state = smf_get_state(instance); 6224653Sdougm if (state == NULL || 6234653Sdougm strcmp(state, "online") != 0) { 6244653Sdougm (void) smf_enable_instance( 6254653Sdougm instance, 0); 6264653Sdougm free(state); 6274653Sdougm } 6284653Sdougm } else { 6294653Sdougm sa_free_attr_string(zfs); 6304653Sdougm zfs = NULL; 6314653Sdougm } 6324653Sdougm if (name != NULL) 6334653Sdougm sa_free_attr_string(name); 6344653Sdougm } 6354653Sdougm } 6363034Sdougm } 6373034Sdougm if (ret == SA_OK) { 6384653Sdougm ret = sa_update_config(handle); 6393034Sdougm } 6403034Sdougm return (ret); 6413034Sdougm } 6423034Sdougm 6433034Sdougm /* 6443034Sdougm * chk_opt(optlistp, security, proto) 6453034Sdougm * 6463034Sdougm * Do a sanity check on the optlist provided for the protocol. This 6473034Sdougm * is a syntax check and verification that the property is either a 6483034Sdougm * general or specific to a names optionset. 6493034Sdougm */ 6503034Sdougm 6513034Sdougm static int 6523034Sdougm chk_opt(struct options *optlistp, int security, char *proto) 6533034Sdougm { 6543034Sdougm struct options *optlist; 6553034Sdougm char *sep = ""; 6563034Sdougm int notfirst = 0; 6573034Sdougm int ret; 6583034Sdougm 6593034Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 6604653Sdougm char *optname; 6614653Sdougm 6624653Sdougm optname = optlist->optname; 6634653Sdougm ret = OPT_ADD_OK; 6644653Sdougm /* extract property/value pair */ 6654653Sdougm if (sa_is_security(optname, proto)) { 6664653Sdougm if (!security) 6674653Sdougm ret = OPT_ADD_SECURITY; 6684653Sdougm } else { 6694653Sdougm if (security) 6704653Sdougm ret = OPT_ADD_PROPERTY; 6714653Sdougm } 6724653Sdougm if (ret != OPT_ADD_OK) { 6734653Sdougm if (notfirst == 0) 6744653Sdougm (void) printf( 6754653Sdougm gettext("Property syntax error: ")); 6764653Sdougm switch (ret) { 6774653Sdougm case OPT_ADD_SYNTAX: 6784653Sdougm (void) printf(gettext("%ssyntax error: %s"), 6793034Sdougm sep, optname); 6804653Sdougm sep = ", "; 6814653Sdougm break; 6824653Sdougm case OPT_ADD_SECURITY: 6834653Sdougm (void) printf(gettext("%s%s requires -S"), 6843034Sdougm optname, sep); 6854653Sdougm sep = ", "; 6864653Sdougm break; 6874653Sdougm case OPT_ADD_PROPERTY: 6884653Sdougm (void) printf( 6894653Sdougm gettext("%s%s not supported with -S"), 6903034Sdougm optname, sep); 6914653Sdougm sep = ", "; 6924653Sdougm break; 6934653Sdougm } 6944653Sdougm notfirst++; 6953034Sdougm } 6963034Sdougm } 6973034Sdougm if (notfirst) { 6984653Sdougm (void) printf("\n"); 6994653Sdougm ret = SA_SYNTAX_ERR; 7003034Sdougm } 7013034Sdougm return (ret); 7023034Sdougm } 7033034Sdougm 7043034Sdougm /* 7053034Sdougm * free_opt(optlist) 7063034Sdougm * Free the specified option list. 7073034Sdougm */ 7083034Sdougm static void 7093034Sdougm free_opt(struct options *optlist) 7103034Sdougm { 7113034Sdougm struct options *nextopt; 7123034Sdougm while (optlist != NULL) { 7133034Sdougm nextopt = optlist->next; 7143034Sdougm free(optlist); 7153034Sdougm optlist = nextopt; 7163034Sdougm } 7173034Sdougm } 7183034Sdougm 7193034Sdougm /* 7203034Sdougm * check property list for valid properties 7213034Sdougm * A null value is a remove which is always valid. 7223034Sdougm */ 7233034Sdougm static int 7243034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec) 7253034Sdougm { 7263034Sdougm int ret = SA_OK; 7273034Sdougm struct options *cur; 7283034Sdougm sa_property_t prop; 7293034Sdougm sa_optionset_t parent = NULL; 7303034Sdougm 7313034Sdougm if (object != NULL) { 7324653Sdougm if (sec == NULL) 7334653Sdougm parent = sa_get_optionset(object, proto); 7344653Sdougm else 7354653Sdougm parent = sa_get_security(object, sec, proto); 7363034Sdougm } 7373034Sdougm 7383034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 7394653Sdougm if (cur->optvalue == NULL) 7404653Sdougm continue; 7413034Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 7423034Sdougm if (prop == NULL) 7434653Sdougm ret = SA_NO_MEMORY; 7443034Sdougm if (ret != SA_OK || 7453034Sdougm (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 7464653Sdougm (void) printf( 7474653Sdougm gettext("Could not add property %s: %s\n"), 7484653Sdougm cur->optname, sa_errorstr(ret)); 7493034Sdougm } 7503034Sdougm (void) sa_remove_property(prop); 7513034Sdougm } 7523034Sdougm return (ret); 7533034Sdougm } 7543034Sdougm 7553034Sdougm /* 7563034Sdougm * add_optionset(group, optlist, protocol, *err) 7573034Sdougm * Add the options in optlist to an optionset and then add the optionset 7583034Sdougm * to the group. 7593034Sdougm * 7603034Sdougm * The return value indicates if there was a "change" while errors are 7613034Sdougm * returned via the *err parameters. 7623034Sdougm */ 7633034Sdougm static int 7643034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 7653034Sdougm { 7663034Sdougm sa_optionset_t optionset; 7673034Sdougm int ret = SA_OK; 768*5331Samw int result = B_FALSE; 7693034Sdougm 7703034Sdougm optionset = sa_get_optionset(group, proto); 7713034Sdougm if (optionset == NULL) { 7724653Sdougm optionset = sa_create_optionset(group, proto); 773*5331Samw if (optionset == NULL) 774*5331Samw ret = SA_NO_MEMORY; 775*5331Samw result = B_TRUE; /* adding a protocol is a change */ 7763034Sdougm } 7774653Sdougm if (optionset == NULL) { 7784653Sdougm ret = SA_NO_MEMORY; 7794653Sdougm goto out; 7804653Sdougm } 7814653Sdougm while (optlist != NULL) { 7823034Sdougm sa_property_t prop; 7833034Sdougm prop = sa_get_property(optionset, optlist->optname); 7843034Sdougm if (prop == NULL) { 7853034Sdougm /* 7863034Sdougm * add the property, but only if it is 7873034Sdougm * a non-NULL or non-zero length value 7883034Sdougm */ 7894653Sdougm if (optlist->optvalue != NULL) { 7904653Sdougm prop = sa_create_property(optlist->optname, 7914653Sdougm optlist->optvalue); 7924653Sdougm if (prop != NULL) { 7934653Sdougm ret = sa_valid_property(optionset, 7944653Sdougm proto, prop); 7954653Sdougm if (ret != SA_OK) { 7964653Sdougm (void) sa_remove_property(prop); 7974653Sdougm (void) printf(gettext("Could " 7984653Sdougm "not add property " 7994653Sdougm "%s: %s\n"), 8004653Sdougm optlist->optname, 8014653Sdougm sa_errorstr(ret)); 8024653Sdougm } 8034653Sdougm } 8044653Sdougm if (ret == SA_OK) { 8054653Sdougm ret = sa_add_property(optionset, prop); 8064653Sdougm if (ret != SA_OK) { 8074653Sdougm (void) printf(gettext( 8084653Sdougm "Could not add property " 8094653Sdougm "%s: %s\n"), 8104653Sdougm optlist->optname, 8114653Sdougm sa_errorstr(ret)); 8124653Sdougm } else { 8134653Sdougm /* there was a change */ 814*5331Samw result = B_TRUE; 8154653Sdougm } 8164653Sdougm } 8173034Sdougm } 8184653Sdougm } else { 8194653Sdougm ret = sa_update_property(prop, optlist->optvalue); 8204653Sdougm /* should check to see if value changed */ 8214653Sdougm if (ret != SA_OK) { 8224653Sdougm (void) printf(gettext("Could not update " 8234653Sdougm "property %s: %s\n"), optlist->optname, 8244653Sdougm sa_errorstr(ret)); 8254653Sdougm } else { 826*5331Samw result = B_TRUE; 8273034Sdougm } 8283034Sdougm } 8293034Sdougm optlist = optlist->next; 8303034Sdougm } 8314653Sdougm ret = sa_commit_properties(optionset, 0); 8324653Sdougm 8334653Sdougm out: 8343034Sdougm if (err != NULL) 8354653Sdougm *err = ret; 8363034Sdougm return (result); 8373034Sdougm } 8383034Sdougm 8393034Sdougm /* 840*5331Samw * resource_compliant(group) 841*5331Samw * 842*5331Samw * Go through all the shares in the group. Assume compliant, but if 843*5331Samw * any share doesn't have at least one resource name, it isn't 844*5331Samw * compliant. 845*5331Samw */ 846*5331Samw static int 847*5331Samw resource_compliant(sa_group_t group) 848*5331Samw { 849*5331Samw sa_share_t share; 850*5331Samw 851*5331Samw for (share = sa_get_share(group, NULL); share != NULL; 852*5331Samw share = sa_get_next_share(share)) { 853*5331Samw if (sa_get_share_resource(share, NULL) == NULL) { 854*5331Samw return (B_FALSE); 855*5331Samw } 856*5331Samw } 857*5331Samw return (B_TRUE); 858*5331Samw } 859*5331Samw 860*5331Samw /* 861*5331Samw * fix_path(path) 862*5331Samw * 863*5331Samw * change all illegal characters to something else. For now, all get 864*5331Samw * converted to '_' and the leading '/' is stripped off. This is used 865*5331Samw * to construct an resource name (SMB share name) that is valid. 866*5331Samw * Caller must pass a valid path. 867*5331Samw */ 868*5331Samw static void 869*5331Samw fix_path(char *path) 870*5331Samw { 871*5331Samw char *cp; 872*5331Samw size_t len; 873*5331Samw 874*5331Samw assert(path != NULL); 875*5331Samw 876*5331Samw /* make sure we are appropriate length */ 877*5331Samw cp = path + 1; /* skip leading slash */ 878*5331Samw while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) { 879*5331Samw cp = strchr(cp, '/'); 880*5331Samw if (cp != NULL) 881*5331Samw cp++; 882*5331Samw } 883*5331Samw /* two cases - cp == NULL and cp is substring of path */ 884*5331Samw if (cp == NULL) { 885*5331Samw /* just take last SA_MAX_RESOURCE_NAME chars */ 886*5331Samw len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME; 887*5331Samw (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME); 888*5331Samw path[SA_MAX_RESOURCE_NAME] = '\0'; 889*5331Samw } else { 890*5331Samw len = strlen(cp) + 1; 891*5331Samw (void) memmove(path, cp, len); 892*5331Samw } 893*5331Samw 894*5331Samw /* 895*5331Samw * Don't want any of the characters that are not allowed 896*5331Samw * in and SMB share name. Replace them with '_'. 897*5331Samw */ 898*5331Samw while (*path) { 899*5331Samw switch (*path) { 900*5331Samw case '/': 901*5331Samw case '"': 902*5331Samw case '\\': 903*5331Samw case '[': 904*5331Samw case ']': 905*5331Samw case ':': 906*5331Samw case '|': 907*5331Samw case '<': 908*5331Samw case '>': 909*5331Samw case '+': 910*5331Samw case ';': 911*5331Samw case ',': 912*5331Samw case '?': 913*5331Samw case '*': 914*5331Samw case '=': 915*5331Samw case '\t': 916*5331Samw *path = '_'; 917*5331Samw break; 918*5331Samw } 919*5331Samw path++; 920*5331Samw } 921*5331Samw } 922*5331Samw 923*5331Samw /* 924*5331Samw * name_adjust(path, count) 925*5331Samw * 926*5331Samw * Add a ~<count> in place of last few characters. The total number of 927*5331Samw * characters is dependent on count. 928*5331Samw */ 929*5331Samw #define MAX_MANGLE_NUMBER 10000 930*5331Samw 931*5331Samw static int 932*5331Samw name_adjust(char *path, int count) 933*5331Samw { 934*5331Samw size_t len; 935*5331Samw 936*5331Samw len = strlen(path) - 2; 937*5331Samw if (count > 10) 938*5331Samw len--; 939*5331Samw if (count > 100) 940*5331Samw len--; 941*5331Samw if (count > 1000) 942*5331Samw len--; 943*5331Samw if (len > 0) 944*5331Samw (void) sprintf(path + len, "~%d", count); 945*5331Samw else 946*5331Samw return (SA_BAD_VALUE); 947*5331Samw 948*5331Samw return (SA_OK); 949*5331Samw } 950*5331Samw 951*5331Samw /* 952*5331Samw * make_resources(group) 953*5331Samw * 954*5331Samw * Go through all the shares in the group and make them have resource 955*5331Samw * names. 956*5331Samw */ 957*5331Samw static void 958*5331Samw make_resources(sa_group_t group) 959*5331Samw { 960*5331Samw sa_share_t share; 961*5331Samw int count; 962*5331Samw int err = SA_OK; 963*5331Samw 964*5331Samw for (share = sa_get_share(group, NULL); share != NULL; 965*5331Samw share = sa_get_next_share(share)) { 966*5331Samw /* Skip those with resources */ 967*5331Samw if (sa_get_share_resource(share, NULL) == NULL) { 968*5331Samw char *path; 969*5331Samw path = sa_get_share_attr(share, "path"); 970*5331Samw if (path == NULL) 971*5331Samw continue; 972*5331Samw fix_path(path); 973*5331Samw count = 0; /* reset for next resource */ 974*5331Samw while (sa_add_resource(share, path, 975*5331Samw SA_SHARE_PERMANENT, &err) == NULL && 976*5331Samw err == SA_DUPLICATE_NAME) { 977*5331Samw int ret; 978*5331Samw ret = name_adjust(path, count); 979*5331Samw count++; 980*5331Samw if (ret != SA_OK || 981*5331Samw count >= MAX_MANGLE_NUMBER) { 982*5331Samw (void) printf(gettext( 983*5331Samw "Cannot create resource name for" 984*5331Samw " path: %s\n"), path); 985*5331Samw break; 986*5331Samw } 987*5331Samw } 988*5331Samw sa_free_attr_string(path); 989*5331Samw } 990*5331Samw } 991*5331Samw } 992*5331Samw 993*5331Samw /* 9943034Sdougm * sa_create(flags, argc, argv) 9953034Sdougm * create a new group 9963034Sdougm * this may or may not have a protocol associated with it. 9973034Sdougm * No protocol means "all" protocols in this case. 9983034Sdougm */ 9993034Sdougm static int 10003910Sdougm sa_create(sa_handle_t handle, int flags, int argc, char *argv[]) 10013034Sdougm { 10023034Sdougm char *groupname; 10033034Sdougm 10043034Sdougm sa_group_t group; 1005*5331Samw int force = 0; 10063034Sdougm int verbose = 0; 10073034Sdougm int dryrun = 0; 10083034Sdougm int c; 10093034Sdougm char *protocol = NULL; 10103034Sdougm int ret = SA_OK; 10113034Sdougm struct options *optlist = NULL; 10123034Sdougm int err = 0; 10133034Sdougm int auth; 10143034Sdougm 1015*5331Samw while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) { 10164653Sdougm switch (c) { 1017*5331Samw case 'f': 1018*5331Samw force++; 1019*5331Samw break; 10204653Sdougm case 'v': 10214653Sdougm verbose++; 10224653Sdougm break; 10234653Sdougm case 'n': 10244653Sdougm dryrun++; 10254653Sdougm break; 10264653Sdougm case 'P': 1027*5331Samw if (protocol != NULL) { 1028*5331Samw (void) printf(gettext("Specifying " 1029*5331Samw "multiple protocols " 1030*5331Samw "not supported: %s\n"), protocol); 1031*5331Samw return (SA_SYNTAX_ERR); 1032*5331Samw } 10334653Sdougm protocol = optarg; 10344653Sdougm if (sa_valid_protocol(protocol)) 10354653Sdougm break; 10364653Sdougm (void) printf(gettext( 10374653Sdougm "Invalid protocol specified: %s\n"), protocol); 10384653Sdougm return (SA_INVALID_PROTOCOL); 10394653Sdougm break; 10404653Sdougm case 'p': 10414653Sdougm ret = add_opt(&optlist, optarg, 0); 10424653Sdougm switch (ret) { 10434653Sdougm case OPT_ADD_SYNTAX: 10444653Sdougm (void) printf(gettext( 10454653Sdougm "Property syntax error for property: %s\n"), 10464653Sdougm optarg); 10474653Sdougm return (SA_SYNTAX_ERR); 10484653Sdougm case OPT_ADD_SECURITY: 10494653Sdougm (void) printf(gettext( 10504653Sdougm "Security properties need " 10514653Sdougm "to be set with set-security: %s\n"), 10524653Sdougm optarg); 10534653Sdougm return (SA_SYNTAX_ERR); 10544653Sdougm default: 10554653Sdougm break; 10564653Sdougm } 10574653Sdougm break; 10584653Sdougm default: 10594653Sdougm case 'h': 10604653Sdougm case '?': 10614653Sdougm (void) printf(gettext("usage: %s\n"), 10624653Sdougm sa_get_usage(USAGE_CREATE)); 10634653Sdougm return (0); 10643034Sdougm } 10653034Sdougm } 10663034Sdougm 10673034Sdougm if (optind >= argc) { 10684653Sdougm (void) printf(gettext("usage: %s\n"), 10694653Sdougm sa_get_usage(USAGE_CREATE)); 10704653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 10714653Sdougm return (SA_BAD_PATH); 10723034Sdougm } 10733034Sdougm 10743034Sdougm if ((optind + 1) < argc) { 10754653Sdougm (void) printf(gettext("usage: %s\n"), 10764653Sdougm sa_get_usage(USAGE_CREATE)); 10774653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 10784653Sdougm return (SA_SYNTAX_ERR); 10793034Sdougm } 10803034Sdougm 10813034Sdougm if (protocol == NULL && optlist != NULL) { 10824653Sdougm /* lookup default protocol */ 10834653Sdougm (void) printf(gettext("usage: %s\n"), 10844653Sdougm sa_get_usage(USAGE_CREATE)); 10854653Sdougm (void) printf(gettext("\tprotocol must be specified " 10864653Sdougm "with properties\n")); 10874653Sdougm return (SA_INVALID_PROTOCOL); 10883034Sdougm } 10893034Sdougm 10903034Sdougm if (optlist != NULL) 10914653Sdougm ret = chk_opt(optlist, 0, protocol); 10923034Sdougm if (ret == OPT_ADD_SECURITY) { 10934653Sdougm (void) printf(gettext("Security properties not " 10944653Sdougm "supported with create\n")); 10954653Sdougm return (SA_SYNTAX_ERR); 10963034Sdougm } 10973034Sdougm 10983034Sdougm /* 10994653Sdougm * If a group already exists, we can only add a new protocol 11003034Sdougm * to it and not create a new one or add the same protocol 11013034Sdougm * again. 11023034Sdougm */ 11033034Sdougm 11043034Sdougm groupname = argv[optind]; 11053034Sdougm 11063034Sdougm auth = check_authorizations(groupname, flags); 11073034Sdougm 11083910Sdougm group = sa_get_group(handle, groupname); 11093034Sdougm if (group != NULL) { 11104653Sdougm /* group exists so must be a protocol add */ 11114653Sdougm if (protocol != NULL) { 11124653Sdougm if (has_protocol(group, protocol)) { 11134653Sdougm (void) printf(gettext( 11144653Sdougm "Group \"%s\" already exists" 11154653Sdougm " with protocol %s\n"), groupname, 11164653Sdougm protocol); 11174653Sdougm ret = SA_DUPLICATE_NAME; 11184653Sdougm } 11194653Sdougm } else { 11204653Sdougm /* must add new protocol */ 11214653Sdougm (void) printf(gettext( 11224653Sdougm "Group already exists and no protocol " 11234653Sdougm "specified.\n")); 11244653Sdougm ret = SA_DUPLICATE_NAME; 11253034Sdougm } 11263034Sdougm } else { 11273034Sdougm /* 11283034Sdougm * is it a valid name? Must comply with SMF instance 11293034Sdougm * name restrictions. 11303034Sdougm */ 11314653Sdougm if (!sa_valid_group_name(groupname)) { 11324653Sdougm ret = SA_INVALID_NAME; 11334653Sdougm (void) printf(gettext("Invalid group name: %s\n"), 11344653Sdougm groupname); 11354653Sdougm } 11363034Sdougm } 11373034Sdougm if (ret == SA_OK) { 11384653Sdougm /* check protocol vs optlist */ 11394653Sdougm if (optlist != NULL) { 11404653Sdougm /* check options, if any, for validity */ 11414653Sdougm ret = valid_options(optlist, protocol, group, NULL); 11424653Sdougm } 11433034Sdougm } 11443034Sdougm if (ret == SA_OK && !dryrun) { 11454653Sdougm if (group == NULL) { 11464653Sdougm group = sa_create_group(handle, (char *)groupname, 11474653Sdougm &err); 11483034Sdougm } 11494653Sdougm if (group != NULL) { 11504653Sdougm sa_optionset_t optionset; 1151*5331Samw /* 1152*5331Samw * First check to see if the new protocol is one that 1153*5331Samw * requires resource names and make sure we are 1154*5331Samw * compliant before proceeding. 1155*5331Samw */ 1156*5331Samw if (protocol != NULL) { 1157*5331Samw uint64_t features; 1158*5331Samw 1159*5331Samw features = sa_proto_get_featureset(protocol); 1160*5331Samw if ((features & SA_FEATURE_RESOURCE) && 1161*5331Samw !resource_compliant(group)) { 1162*5331Samw if (force) { 1163*5331Samw make_resources(group); 1164*5331Samw } else { 1165*5331Samw ret = SA_RESOURCE_REQUIRED; 1166*5331Samw (void) printf( 1167*5331Samw gettext("Protocol " 1168*5331Samw "requires resource " 1169*5331Samw "names to be " 1170*5331Samw "set: %s\n"), 1171*5331Samw protocol); 1172*5331Samw goto err; 1173*5331Samw } 1174*5331Samw } 1175*5331Samw } 11764653Sdougm if (optlist != NULL) { 11774653Sdougm (void) add_optionset(group, optlist, protocol, 11784653Sdougm &ret); 11794653Sdougm } else if (protocol != NULL) { 11804653Sdougm optionset = sa_create_optionset(group, 11814653Sdougm protocol); 11824653Sdougm if (optionset == NULL) 11834653Sdougm ret = SA_NO_MEMORY; 11844653Sdougm } else if (protocol == NULL) { 11854653Sdougm char **protolist; 11864653Sdougm int numprotos, i; 11874653Sdougm numprotos = sa_get_protocols(&protolist); 11884653Sdougm for (i = 0; i < numprotos; i++) { 11894653Sdougm optionset = sa_create_optionset(group, 11904653Sdougm protolist[i]); 11914653Sdougm } 11924653Sdougm if (protolist != NULL) 11934653Sdougm free(protolist); 11944653Sdougm } 11953034Sdougm /* 11964653Sdougm * We have a group and legal additions 11973034Sdougm */ 11984653Sdougm if (ret == SA_OK) { 11994653Sdougm /* 12004653Sdougm * Commit to configuration for protocols that 12014653Sdougm * need to do block updates. For NFS, this 12024653Sdougm * doesn't do anything but it will be run for 12034653Sdougm * all protocols that implement the 12044653Sdougm * appropriate plugin. 12054653Sdougm */ 12064653Sdougm ret = sa_update_config(handle); 12074653Sdougm } else { 12084653Sdougm if (group != NULL) 12094653Sdougm (void) sa_remove_group(group); 12104653Sdougm } 12113034Sdougm } else { 12124653Sdougm ret = err; 12134653Sdougm (void) printf(gettext("Could not create group: %s\n"), 12144653Sdougm sa_errorstr(ret)); 12153034Sdougm } 12163034Sdougm } 12173034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 12184653Sdougm (void) printf(gettext("Command would fail: %s\n"), 12194653Sdougm sa_errorstr(SA_NO_PERMISSION)); 12204653Sdougm ret = SA_NO_PERMISSION; 12213034Sdougm } 1222*5331Samw err: 12233034Sdougm free_opt(optlist); 12243034Sdougm return (ret); 12253034Sdougm } 12263034Sdougm 12273034Sdougm /* 12283034Sdougm * group_status(group) 12293034Sdougm * 12303034Sdougm * return the current status (enabled/disabled) of the group. 12313034Sdougm */ 12323034Sdougm 12333034Sdougm static char * 12343034Sdougm group_status(sa_group_t group) 12353034Sdougm { 12363034Sdougm char *state; 12373034Sdougm int enabled = 0; 12383034Sdougm 12393034Sdougm state = sa_get_group_attr(group, "state"); 12403034Sdougm if (state != NULL) { 12414653Sdougm if (strcmp(state, "enabled") == 0) { 12424653Sdougm enabled = 1; 12434653Sdougm } 12444653Sdougm sa_free_attr_string(state); 12453034Sdougm } 12464255Sdougm return (enabled ? "enabled" : "disabled"); 12473034Sdougm } 12483034Sdougm 12493034Sdougm /* 12503034Sdougm * sa_delete(flags, argc, argv) 12513034Sdougm * 12523034Sdougm * Delete a group. 12533034Sdougm */ 12543034Sdougm 12553034Sdougm static int 12563910Sdougm sa_delete(sa_handle_t handle, int flags, int argc, char *argv[]) 12573034Sdougm { 12583034Sdougm char *groupname; 12593034Sdougm sa_group_t group; 12603034Sdougm sa_share_t share; 12613034Sdougm int verbose = 0; 12623034Sdougm int dryrun = 0; 12633034Sdougm int force = 0; 12643034Sdougm int c; 12653034Sdougm char *protocol = NULL; 12663034Sdougm char *sectype = NULL; 12673034Sdougm int ret = SA_OK; 12683034Sdougm int auth; 12693034Sdougm 12703034Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 12714653Sdougm switch (c) { 12724653Sdougm case 'v': 12734653Sdougm verbose++; 12744653Sdougm break; 12754653Sdougm case 'n': 12764653Sdougm dryrun++; 12774653Sdougm break; 12784653Sdougm case 'P': 1279*5331Samw if (protocol != NULL) { 1280*5331Samw (void) printf(gettext("Specifying " 1281*5331Samw "multiple protocols " 1282*5331Samw "not supported: %s\n"), protocol); 1283*5331Samw return (SA_SYNTAX_ERR); 1284*5331Samw } 12854653Sdougm protocol = optarg; 12864653Sdougm if (!sa_valid_protocol(protocol)) { 12874653Sdougm (void) printf(gettext("Invalid protocol " 1288*5331Samw "specified: %s\n"), protocol); 12894653Sdougm return (SA_INVALID_PROTOCOL); 12904653Sdougm } 12914653Sdougm break; 12924653Sdougm case 'S': 1293*5331Samw if (sectype != NULL) { 1294*5331Samw (void) printf(gettext("Specifying " 1295*5331Samw "multiple property " 1296*5331Samw "spaces not supported: %s\n"), sectype); 1297*5331Samw return (SA_SYNTAX_ERR); 1298*5331Samw } 12994653Sdougm sectype = optarg; 13004653Sdougm break; 13014653Sdougm case 'f': 13024653Sdougm force++; 13034653Sdougm break; 13044653Sdougm default: 13054653Sdougm case 'h': 13064653Sdougm case '?': 13074653Sdougm (void) printf(gettext("usage: %s\n"), 13084653Sdougm sa_get_usage(USAGE_DELETE)); 13094653Sdougm return (0); 13103034Sdougm } 13113034Sdougm } 13123034Sdougm 13133034Sdougm if (optind >= argc) { 13144653Sdougm (void) printf(gettext("usage: %s\n"), 13154653Sdougm sa_get_usage(USAGE_DELETE)); 13164653Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 13174653Sdougm return (SA_SYNTAX_ERR); 13183034Sdougm } 13193034Sdougm 13203034Sdougm if ((optind + 1) < argc) { 13214653Sdougm (void) printf(gettext("usage: %s\n"), 13224653Sdougm sa_get_usage(USAGE_DELETE)); 13234653Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 13244653Sdougm return (SA_SYNTAX_ERR); 13253034Sdougm } 13263034Sdougm 13273034Sdougm if (sectype != NULL && protocol == NULL) { 13284653Sdougm (void) printf(gettext("usage: %s\n"), 13294653Sdougm sa_get_usage(USAGE_DELETE)); 13304653Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 13314653Sdougm "specified.\n")); 13324653Sdougm return (SA_SYNTAX_ERR); 13333034Sdougm } 13343034Sdougm 13353034Sdougm /* 13363034Sdougm * Determine if the group already exists since it must in 13373034Sdougm * order to be removed. 13383034Sdougm * 13393034Sdougm * We can delete when: 13403034Sdougm * 13413034Sdougm * - group is empty 13423034Sdougm * - force flag is set 13433034Sdougm * - if protocol specified, only delete the protocol 13443034Sdougm */ 13453034Sdougm 13463034Sdougm groupname = argv[optind]; 13473910Sdougm group = sa_get_group(handle, groupname); 13483034Sdougm if (group == NULL) { 13493034Sdougm ret = SA_NO_SUCH_GROUP; 13504653Sdougm goto done; 13514653Sdougm } 13524653Sdougm auth = check_authorizations(groupname, flags); 13534653Sdougm if (protocol == NULL) { 13543034Sdougm share = sa_get_share(group, NULL); 13553034Sdougm if (share != NULL) 13564653Sdougm ret = SA_BUSY; 13573034Sdougm if (share == NULL || (share != NULL && force == 1)) { 13584653Sdougm ret = SA_OK; 13594653Sdougm if (!dryrun) { 13604653Sdougm while (share != NULL) { 13614653Sdougm sa_share_t next_share; 13624653Sdougm next_share = sa_get_next_share(share); 13634653Sdougm /* 13644653Sdougm * need to do the disable of 13654653Sdougm * each share, but don't 13664653Sdougm * actually do anything on a 13674653Sdougm * dryrun. 13684653Sdougm */ 13694653Sdougm ret = sa_disable_share(share, NULL); 13704653Sdougm ret = sa_remove_share(share); 13714653Sdougm share = next_share; 13724653Sdougm } 13734653Sdougm ret = sa_remove_group(group); 13743034Sdougm } 13753034Sdougm } 13764653Sdougm /* Commit to configuration if not a dryrun */ 13773034Sdougm if (!dryrun && ret == SA_OK) { 13784653Sdougm ret = sa_update_config(handle); 13793034Sdougm } 13804653Sdougm } else { 13813034Sdougm /* a protocol delete */ 13823034Sdougm sa_optionset_t optionset; 13833034Sdougm sa_security_t security; 1384*5331Samw if (sectype != NULL) { 13854653Sdougm /* only delete specified security */ 13864653Sdougm security = sa_get_security(group, sectype, protocol); 13874653Sdougm if (security != NULL && !dryrun) 13884653Sdougm ret = sa_destroy_security(security); 13894653Sdougm else 13904653Sdougm ret = SA_INVALID_PROTOCOL; 13913034Sdougm } else { 13924653Sdougm optionset = sa_get_optionset(group, protocol); 13934653Sdougm if (optionset != NULL && !dryrun) { 13944653Sdougm /* 13954653Sdougm * have an optionset with 13964653Sdougm * protocol to delete 13974653Sdougm */ 13984653Sdougm ret = sa_destroy_optionset(optionset); 13994653Sdougm /* 14004653Sdougm * Now find all security sets 14014653Sdougm * for the protocol and remove 14024653Sdougm * them. Don't remove other 14034653Sdougm * protocols. 14044653Sdougm */ 14054653Sdougm for (security = 14064653Sdougm sa_get_security(group, NULL, NULL); 14074653Sdougm ret == SA_OK && security != NULL; 14084653Sdougm security = sa_get_next_security(security)) { 14094653Sdougm char *secprot; 14104653Sdougm secprot = sa_get_security_attr(security, 14114653Sdougm "type"); 14124653Sdougm if (secprot != NULL && 14134653Sdougm strcmp(secprot, protocol) == 0) 14144653Sdougm ret = sa_destroy_security( 14154653Sdougm security); 14164653Sdougm if (secprot != NULL) 14174653Sdougm sa_free_attr_string(secprot); 14184653Sdougm } 14194653Sdougm } else { 14204653Sdougm if (!dryrun) 14214653Sdougm ret = SA_INVALID_PROTOCOL; 14223034Sdougm } 14233034Sdougm } 1424*5331Samw /* 1425*5331Samw * With the protocol items removed, make sure that all 1426*5331Samw * the shares are updated in the legacy files, if 1427*5331Samw * necessary. 1428*5331Samw */ 1429*5331Samw for (share = sa_get_share(group, NULL); 1430*5331Samw share != NULL; 1431*5331Samw share = sa_get_next_share(share)) { 1432*5331Samw (void) sa_delete_legacy(share, protocol); 1433*5331Samw } 14343034Sdougm } 14354653Sdougm 14364653Sdougm done: 14373034Sdougm if (ret != SA_OK) { 14384653Sdougm (void) printf(gettext("Could not delete group: %s\n"), 14394653Sdougm sa_errorstr(ret)); 14403034Sdougm } else if (dryrun && !auth && verbose) { 14414653Sdougm (void) printf(gettext("Command would fail: %s\n"), 14424653Sdougm sa_errorstr(SA_NO_PERMISSION)); 14433034Sdougm } 14443034Sdougm return (ret); 14453034Sdougm } 14463034Sdougm 14473034Sdougm /* 14483034Sdougm * strndupr(*buff, str, buffsize) 14493034Sdougm * 14503034Sdougm * used with small strings to duplicate and possibly increase the 14513034Sdougm * buffer size of a string. 14523034Sdougm */ 14533034Sdougm static char * 14543034Sdougm strndupr(char *buff, char *str, int *buffsize) 14553034Sdougm { 14563034Sdougm int limit; 14573034Sdougm char *orig_buff = buff; 14583034Sdougm 14593034Sdougm if (buff == NULL) { 14604653Sdougm buff = (char *)malloc(64); 14614653Sdougm if (buff == NULL) 14624653Sdougm return (NULL); 14634653Sdougm *buffsize = 64; 14644653Sdougm buff[0] = '\0'; 14653034Sdougm } 14663034Sdougm limit = strlen(buff) + strlen(str) + 1; 14673034Sdougm if (limit > *buffsize) { 14684653Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 14694653Sdougm buff = realloc(buff, limit); 14703034Sdougm } 14713034Sdougm if (buff != NULL) { 14724653Sdougm (void) strcat(buff, str); 14733034Sdougm } else { 14744653Sdougm /* if it fails, fail it hard */ 14754653Sdougm if (orig_buff != NULL) 14764653Sdougm free(orig_buff); 14773034Sdougm } 14783034Sdougm return (buff); 14793034Sdougm } 14803034Sdougm 14813034Sdougm /* 14823034Sdougm * group_proto(group) 14833034Sdougm * 14843034Sdougm * return a string of all the protocols (space separated) associated 14853034Sdougm * with this group. 14863034Sdougm */ 14873034Sdougm 14883034Sdougm static char * 14893034Sdougm group_proto(sa_group_t group) 14903034Sdougm { 14913034Sdougm sa_optionset_t optionset; 14923034Sdougm char *proto; 14933034Sdougm char *buff = NULL; 14943034Sdougm int buffsize = 0; 14953034Sdougm int addspace = 0; 14963034Sdougm /* 14973034Sdougm * get the protocol list by finding the optionsets on this 14983034Sdougm * group and extracting the type value. The initial call to 14993034Sdougm * strndupr() initailizes buff. 15003034Sdougm */ 15013034Sdougm buff = strndupr(buff, "", &buffsize); 15023034Sdougm if (buff != NULL) { 15034653Sdougm for (optionset = sa_get_optionset(group, NULL); 15044653Sdougm optionset != NULL && buff != NULL; 15054653Sdougm optionset = sa_get_next_optionset(optionset)) { 15064653Sdougm /* 15074653Sdougm * extract out the protocol type from this optionset 15084653Sdougm * and append it to the buffer "buff". strndupr() will 15094653Sdougm * reallocate space as necessay. 15104653Sdougm */ 15114653Sdougm proto = sa_get_optionset_attr(optionset, "type"); 15124653Sdougm if (proto != NULL) { 15134653Sdougm if (addspace++) 15144653Sdougm buff = strndupr(buff, " ", &buffsize); 15154653Sdougm buff = strndupr(buff, proto, &buffsize); 15164653Sdougm sa_free_attr_string(proto); 15174653Sdougm } 15183034Sdougm } 15193034Sdougm } 15203034Sdougm return (buff); 15213034Sdougm } 15223034Sdougm 15233034Sdougm /* 15243034Sdougm * sa_list(flags, argc, argv) 15253034Sdougm * 15263034Sdougm * implements the "list" subcommand to list groups and optionally 15273034Sdougm * their state and protocols. 15283034Sdougm */ 15293034Sdougm 15303034Sdougm static int 15313910Sdougm sa_list(sa_handle_t handle, int flags, int argc, char *argv[]) 15323034Sdougm { 15333034Sdougm sa_group_t group; 15343034Sdougm int verbose = 0; 15353034Sdougm int c; 15363034Sdougm char *protocol = NULL; 1537*5331Samw #ifdef lint 1538*5331Samw flags = flags; 1539*5331Samw #endif 15403034Sdougm 15413034Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 15424653Sdougm switch (c) { 15434653Sdougm case 'v': 15444653Sdougm verbose++; 15454653Sdougm break; 15464653Sdougm case 'P': 1547*5331Samw if (protocol != NULL) { 1548*5331Samw (void) printf(gettext( 1549*5331Samw "Specifying multiple protocols " 1550*5331Samw "not supported: %s\n"), 1551*5331Samw protocol); 1552*5331Samw return (SA_SYNTAX_ERR); 1553*5331Samw } 15544653Sdougm protocol = optarg; 15554653Sdougm if (!sa_valid_protocol(protocol)) { 15564653Sdougm (void) printf(gettext( 15574653Sdougm "Invalid protocol specified: %s\n"), 15584653Sdougm protocol); 15594653Sdougm return (SA_INVALID_PROTOCOL); 15604653Sdougm } 15614653Sdougm break; 15624653Sdougm default: 15634653Sdougm case 'h': 15644653Sdougm case '?': 15654653Sdougm (void) printf(gettext("usage: %s\n"), 15664653Sdougm sa_get_usage(USAGE_LIST)); 15674653Sdougm return (0); 15683034Sdougm } 15693034Sdougm } 15703034Sdougm 15714653Sdougm for (group = sa_get_group(handle, NULL); 15724653Sdougm group != NULL; 15733034Sdougm group = sa_get_next_group(group)) { 15744653Sdougm char *name; 15754653Sdougm char *proto; 15764653Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 15774653Sdougm name = sa_get_group_attr(group, "name"); 15784653Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 15794653Sdougm (void) printf("%s", (char *)name); 15804653Sdougm if (verbose) { 15814653Sdougm /* 15824653Sdougm * Need the list of protocols 15834653Sdougm * and current status once 15844653Sdougm * available. We do want to 15854653Sdougm * translate the 15864653Sdougm * enabled/disabled text here. 15874653Sdougm */ 15884653Sdougm (void) printf("\t%s", isenabled(group) ? 15894653Sdougm gettext("enabled") : 15904653Sdougm gettext("disabled")); 15914653Sdougm proto = group_proto(group); 15924653Sdougm if (proto != NULL) { 15934653Sdougm (void) printf("\t%s", 15944653Sdougm (char *)proto); 15954653Sdougm free(proto); 15964653Sdougm } 15974653Sdougm } 15984653Sdougm (void) printf("\n"); 15993034Sdougm } 16004653Sdougm if (name != NULL) 16014653Sdougm sa_free_attr_string(name); 16023034Sdougm } 16033034Sdougm } 16043034Sdougm return (0); 16053034Sdougm } 16063034Sdougm 16073034Sdougm /* 16083034Sdougm * out_properties(optionset, proto, sec) 16093034Sdougm * 16103034Sdougm * Format the properties and encode the protocol and optional named 16113034Sdougm * optionset into the string. 16123034Sdougm * 16133034Sdougm * format is protocol[:name]=(property-list) 16143034Sdougm */ 16153034Sdougm 16163034Sdougm static void 16173034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 16183034Sdougm { 16193034Sdougm char *type; 16203034Sdougm char *value; 16213034Sdougm int spacer; 16223034Sdougm sa_property_t prop; 16233034Sdougm 16244653Sdougm if (sec == NULL) 16254653Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 16264653Sdougm else 16274653Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 16283034Sdougm 16293034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 16304653Sdougm prop != NULL; 16314653Sdougm prop = sa_get_next_property(prop)) { 16323034Sdougm 16333034Sdougm /* 16343034Sdougm * extract the property name/value and output with 16353034Sdougm * appropriate spacing. I.e. no prefixed space the 16363034Sdougm * first time through but a space on subsequent 16373034Sdougm * properties. 16383034Sdougm */ 16394653Sdougm type = sa_get_property_attr(prop, "type"); 16404653Sdougm value = sa_get_property_attr(prop, "value"); 16414653Sdougm if (type != NULL) { 16424653Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 16434653Sdougm spacer = 1; 16444653Sdougm if (value != NULL) 16454653Sdougm (void) printf("\"%s\"", value); 16464653Sdougm else 16474653Sdougm (void) printf("\"\""); 16484653Sdougm } 16494653Sdougm if (type != NULL) 16504653Sdougm sa_free_attr_string(type); 16513034Sdougm if (value != NULL) 16524653Sdougm sa_free_attr_string(value); 16533034Sdougm } 16543034Sdougm (void) printf(")"); 16553034Sdougm } 16563034Sdougm 16573034Sdougm /* 16583034Sdougm * show_properties(group, protocol, prefix) 16593034Sdougm * 16603034Sdougm * print the properties for a group. If protocol is NULL, do all 16613034Sdougm * protocols otherwise only the specified protocol. All security 16623034Sdougm * (named groups specific to the protocol) are included. 16633034Sdougm * 16643034Sdougm * The "prefix" is always applied. The caller knows whether it wants 16653034Sdougm * some type of prefix string (white space) or not. Once the prefix 16663034Sdougm * has been output, it is reduced to the zero length string for the 16673034Sdougm * remainder of the property output. 16683034Sdougm */ 16693034Sdougm 16703034Sdougm static void 16713034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 16723034Sdougm { 16733034Sdougm sa_optionset_t optionset; 16743034Sdougm sa_security_t security; 16753034Sdougm char *value; 16763034Sdougm char *secvalue; 16773034Sdougm 16783034Sdougm if (protocol != NULL) { 16794653Sdougm optionset = sa_get_optionset(group, protocol); 16804653Sdougm if (optionset != NULL) { 16814653Sdougm (void) printf("%s", prefix); 16824653Sdougm prefix = ""; 16834653Sdougm out_properties(optionset, protocol, NULL); 16844653Sdougm } 16854653Sdougm security = sa_get_security(group, protocol, NULL); 16864653Sdougm if (security != NULL) { 16874653Sdougm (void) printf("%s", prefix); 16884653Sdougm prefix = ""; 16894653Sdougm out_properties(security, protocol, NULL); 16904653Sdougm } 16913034Sdougm } else { 16924653Sdougm for (optionset = sa_get_optionset(group, protocol); 16934653Sdougm optionset != NULL; 16944653Sdougm optionset = sa_get_next_optionset(optionset)) { 16954653Sdougm 16964653Sdougm value = sa_get_optionset_attr(optionset, "type"); 16974653Sdougm (void) printf("%s", prefix); 16984653Sdougm prefix = ""; 16994653Sdougm out_properties(optionset, value, 0); 17004653Sdougm if (value != NULL) 17014653Sdougm sa_free_attr_string(value); 17024653Sdougm } 17034653Sdougm for (security = sa_get_security(group, NULL, protocol); 17044653Sdougm security != NULL; 17054653Sdougm security = sa_get_next_security(security)) { 17064653Sdougm 17074653Sdougm value = sa_get_security_attr(security, "type"); 17084653Sdougm secvalue = sa_get_security_attr(security, "sectype"); 17094653Sdougm (void) printf("%s", prefix); 17104653Sdougm prefix = ""; 17114653Sdougm out_properties(security, value, secvalue); 17124653Sdougm if (value != NULL) 17134653Sdougm sa_free_attr_string(value); 17144653Sdougm if (secvalue != NULL) 17154653Sdougm sa_free_attr_string(secvalue); 17164653Sdougm } 17173034Sdougm } 17183034Sdougm } 17193034Sdougm 17203034Sdougm /* 1721*5331Samw * get_resource(share) 1722*5331Samw * 1723*5331Samw * Get the first resource name, if any, and fix string to be in 1724*5331Samw * current locale and have quotes if it has embedded spaces. Return 1725*5331Samw * an attr string that must be freed. 1726*5331Samw */ 1727*5331Samw 1728*5331Samw static char * 1729*5331Samw get_resource(sa_share_t share) 1730*5331Samw { 1731*5331Samw sa_resource_t resource; 1732*5331Samw char *resstring = NULL; 1733*5331Samw char *retstring; 1734*5331Samw 1735*5331Samw if ((resource = sa_get_share_resource(share, NULL)) != NULL) { 1736*5331Samw resstring = sa_get_resource_attr(resource, "name"); 1737*5331Samw if (resstring != NULL) { 1738*5331Samw char *cp; 1739*5331Samw int len; 1740*5331Samw 1741*5331Samw retstring = conv_from_utf8(resstring); 1742*5331Samw if (retstring != resstring) { 1743*5331Samw sa_free_attr_string(resstring); 1744*5331Samw resstring = retstring; 1745*5331Samw } 1746*5331Samw if (strpbrk(resstring, " ") != NULL) { 1747*5331Samw /* account for quotes */ 1748*5331Samw len = strlen(resstring) + 3; 1749*5331Samw cp = calloc(len, sizeof (char)); 1750*5331Samw if (cp != NULL) { 1751*5331Samw (void) snprintf(cp, len, 1752*5331Samw "\"%s\"", resstring); 1753*5331Samw sa_free_attr_string(resstring); 1754*5331Samw resstring = cp; 1755*5331Samw } else { 1756*5331Samw sa_free_attr_string(resstring); 1757*5331Samw resstring = NULL; 1758*5331Samw } 1759*5331Samw } 1760*5331Samw } 1761*5331Samw } 1762*5331Samw return (resstring); 1763*5331Samw } 1764*5331Samw 1765*5331Samw /* 1766*5331Samw * has_resource_with_opt(share) 1767*5331Samw * 1768*5331Samw * Check to see if the share has any resource names with optionsets 1769*5331Samw * set. Also indicate if multiple resource names since the syntax 1770*5331Samw * would be about the same. 1771*5331Samw */ 1772*5331Samw static int 1773*5331Samw has_resource_with_opt(sa_share_t share) 1774*5331Samw { 1775*5331Samw sa_resource_t resource; 1776*5331Samw int ret = B_FALSE; 1777*5331Samw 1778*5331Samw for (resource = sa_get_share_resource(share, NULL); 1779*5331Samw resource != NULL; 1780*5331Samw resource = sa_get_next_resource(resource)) { 1781*5331Samw 1782*5331Samw if (sa_get_optionset(resource, NULL) != NULL) { 1783*5331Samw ret = B_TRUE; 1784*5331Samw break; 1785*5331Samw } 1786*5331Samw } 1787*5331Samw return (ret); 1788*5331Samw } 1789*5331Samw 1790*5331Samw /* 1791*5331Samw * has_multiple_resource(share) 1792*5331Samw * 1793*5331Samw * Check to see if the share has any resource names with optionsets 1794*5331Samw * set. Also indicate if multiple resource names since the syntax 1795*5331Samw * would be about the same. 1796*5331Samw */ 1797*5331Samw static int 1798*5331Samw has_multiple_resource(sa_share_t share) 1799*5331Samw { 1800*5331Samw sa_resource_t resource; 1801*5331Samw int num; 1802*5331Samw 1803*5331Samw for (num = 0, resource = sa_get_share_resource(share, NULL); 1804*5331Samw resource != NULL; 1805*5331Samw resource = sa_get_next_resource(resource)) { 1806*5331Samw num++; 1807*5331Samw if (num > 1) 1808*5331Samw return (B_TRUE); 1809*5331Samw } 1810*5331Samw return (B_FALSE); 1811*5331Samw } 1812*5331Samw 1813*5331Samw /* 1814*5331Samw * show_share(share, verbose, properties, proto, iszfs, sharepath) 1815*5331Samw * 1816*5331Samw * print out the share information. With the addition of resource as a 1817*5331Samw * full object that can have multiple instances below the share, we 1818*5331Samw * need to display that as well. 1819*5331Samw */ 1820*5331Samw 1821*5331Samw static void 1822*5331Samw show_share(sa_share_t share, int verbose, int properties, char *proto, 1823*5331Samw int iszfs, char *sharepath) 1824*5331Samw { 1825*5331Samw char *drive; 1826*5331Samw char *exclude; 1827*5331Samw sa_resource_t resource = NULL; 1828*5331Samw char *description; 1829*5331Samw char *desc; 1830*5331Samw char *rsrcname; 1831*5331Samw int rsrcwithopt; 1832*5331Samw int multiple; 1833*5331Samw char *type; 1834*5331Samw 1835*5331Samw rsrcwithopt = has_resource_with_opt(share); 1836*5331Samw 1837*5331Samw if (verbose || (properties && rsrcwithopt)) { 1838*5331Samw /* First, indicate if transient */ 1839*5331Samw type = sa_get_share_attr(share, "type"); 1840*5331Samw if (type != NULL && !iszfs && verbose && 1841*5331Samw strcmp(type, "transient") == 0) 1842*5331Samw (void) printf("\t* "); 1843*5331Samw else 1844*5331Samw (void) printf("\t "); 1845*5331Samw 1846*5331Samw if (type != NULL) 1847*5331Samw sa_free_attr_string(type); 1848*5331Samw 1849*5331Samw /* 1850*5331Samw * If we came in with verbose, we want to handle the case of 1851*5331Samw * multiple resources as though they had properties set. 1852*5331Samw */ 1853*5331Samw multiple = has_multiple_resource(share); 1854*5331Samw 1855*5331Samw /* Next, if not multiple follow old model */ 1856*5331Samw if (!multiple && !rsrcwithopt) { 1857*5331Samw rsrcname = get_resource(share); 1858*5331Samw if (rsrcname != NULL && strlen(rsrcname) > 0) { 1859*5331Samw (void) printf("%s=%s", rsrcname, sharepath); 1860*5331Samw } else { 1861*5331Samw (void) printf("%s", sharepath); 1862*5331Samw } 1863*5331Samw if (rsrcname != NULL) 1864*5331Samw sa_free_attr_string(rsrcname); 1865*5331Samw } else { 1866*5331Samw /* Treat as simple and then resources come later */ 1867*5331Samw (void) printf("%s", sharepath); 1868*5331Samw } 1869*5331Samw drive = sa_get_share_attr(share, "drive-letter"); 1870*5331Samw if (drive != NULL) { 1871*5331Samw if (strlen(drive) > 0) 1872*5331Samw (void) printf(gettext("\tdrive-letter=\"%s:\""), 1873*5331Samw drive); 1874*5331Samw sa_free_attr_string(drive); 1875*5331Samw } 1876*5331Samw if (properties) 1877*5331Samw show_properties(share, proto, "\t"); 1878*5331Samw exclude = sa_get_share_attr(share, "exclude"); 1879*5331Samw if (exclude != NULL) { 1880*5331Samw (void) printf(gettext("\tnot-shared-with=[%s]"), 1881*5331Samw exclude); 1882*5331Samw sa_free_attr_string(exclude); 1883*5331Samw } 1884*5331Samw description = sa_get_share_description(share); 1885*5331Samw if (description != NULL) { 1886*5331Samw if (strlen(description) > 0) { 1887*5331Samw desc = conv_from_utf8(description); 1888*5331Samw if (desc != description) { 1889*5331Samw sa_free_share_description(description); 1890*5331Samw description = desc; 1891*5331Samw } 1892*5331Samw (void) printf("\t\"%s\"", description); 1893*5331Samw } 1894*5331Samw sa_free_share_description(description); 1895*5331Samw } 1896*5331Samw 1897*5331Samw /* 1898*5331Samw * If there are resource names with options, show them 1899*5331Samw * here, with one line per resource. Resource specific 1900*5331Samw * options are at the end of the line followed by 1901*5331Samw * description, if any. 1902*5331Samw */ 1903*5331Samw if (rsrcwithopt || multiple) { 1904*5331Samw for (resource = sa_get_share_resource(share, NULL); 1905*5331Samw resource != NULL; 1906*5331Samw resource = sa_get_next_resource(resource)) { 1907*5331Samw int has_space; 1908*5331Samw char *rsrc; 1909*5331Samw 1910*5331Samw (void) printf("\n\t\t "); 1911*5331Samw rsrcname = sa_get_resource_attr(resource, 1912*5331Samw "name"); 1913*5331Samw if (rsrcname == NULL) 1914*5331Samw continue; 1915*5331Samw 1916*5331Samw rsrc = conv_from_utf8(rsrcname); 1917*5331Samw has_space = strpbrk(rsrc, " ") != NULL; 1918*5331Samw 1919*5331Samw if (has_space) 1920*5331Samw (void) printf("\"%s\"=%s", rsrc, 1921*5331Samw sharepath); 1922*5331Samw else 1923*5331Samw (void) printf("%s=%s", rsrc, 1924*5331Samw sharepath); 1925*5331Samw if (rsrc != rsrcname) 1926*5331Samw sa_free_attr_string(rsrc); 1927*5331Samw sa_free_attr_string(rsrcname); 1928*5331Samw if (properties || rsrcwithopt) 1929*5331Samw show_properties(resource, proto, "\t"); 1930*5331Samw 1931*5331Samw /* Get description string if any */ 1932*5331Samw print_rsrc_desc(resource); 1933*5331Samw } 1934*5331Samw } 1935*5331Samw } else { 1936*5331Samw (void) printf("\t %s", sharepath); 1937*5331Samw if (properties) 1938*5331Samw show_properties(share, proto, "\t"); 1939*5331Samw } 1940*5331Samw (void) printf("\n"); 1941*5331Samw } 1942*5331Samw 1943*5331Samw /* 19443034Sdougm * show_group(group, verbose, properties, proto, subgroup) 19453034Sdougm * 19463034Sdougm * helper function to show the contents of a group. 19473034Sdougm */ 19483034Sdougm 19493034Sdougm static void 19503034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 1951*5331Samw char *subgroup) 19523034Sdougm { 19533034Sdougm sa_share_t share; 19543034Sdougm char *groupname; 19553034Sdougm char *zfs = NULL; 19563034Sdougm int iszfs = 0; 1957*5331Samw char *sharepath; 19583034Sdougm 19593034Sdougm groupname = sa_get_group_attr(group, "name"); 19603034Sdougm if (groupname != NULL) { 19614653Sdougm if (proto != NULL && !has_protocol(group, proto)) { 19624653Sdougm sa_free_attr_string(groupname); 19634653Sdougm return; 19644653Sdougm } 19653034Sdougm /* 19663034Sdougm * check to see if the group is managed by ZFS. If 19673034Sdougm * there is an attribute, then it is. A non-NULL zfs 19683034Sdougm * variable will trigger the different way to display 19693034Sdougm * and will remove the transient property indicator 19703034Sdougm * from the output. 19713034Sdougm */ 19724653Sdougm zfs = sa_get_group_attr(group, "zfs"); 19734653Sdougm if (zfs != NULL) { 19744653Sdougm iszfs = 1; 19754653Sdougm sa_free_attr_string(zfs); 19763034Sdougm } 19774653Sdougm share = sa_get_share(group, NULL); 19784653Sdougm if (subgroup == NULL) 19794653Sdougm (void) printf("%s", groupname); 19804653Sdougm else 19814653Sdougm (void) printf(" %s/%s", subgroup, groupname); 19824653Sdougm if (properties) 19834653Sdougm show_properties(group, proto, ""); 19844653Sdougm (void) printf("\n"); 19854653Sdougm if (strcmp(groupname, "zfs") == 0) { 19864653Sdougm sa_group_t zgroup; 19874653Sdougm 19884653Sdougm for (zgroup = sa_get_sub_group(group); 19894653Sdougm zgroup != NULL; 19904653Sdougm zgroup = sa_get_next_group(zgroup)) { 19914653Sdougm show_group(zgroup, verbose, properties, proto, 19924653Sdougm "zfs"); 19934653Sdougm } 19944653Sdougm sa_free_attr_string(groupname); 19954653Sdougm return; 19964653Sdougm } 19973034Sdougm /* 19984653Sdougm * Have a group, so list the contents. Resource and 19993034Sdougm * description are only listed if verbose is set. 20003034Sdougm */ 20014653Sdougm for (share = sa_get_share(group, NULL); 20024653Sdougm share != NULL; 20034653Sdougm share = sa_get_next_share(share)) { 20044653Sdougm sharepath = sa_get_share_attr(share, "path"); 20054653Sdougm if (sharepath != NULL) { 2006*5331Samw show_share(share, verbose, properties, proto, 2007*5331Samw iszfs, sharepath); 20084653Sdougm sa_free_attr_string(sharepath); 20093034Sdougm } 20103034Sdougm } 20113034Sdougm } 20123034Sdougm if (groupname != NULL) { 20133034Sdougm sa_free_attr_string(groupname); 20143034Sdougm } 20153034Sdougm } 20163034Sdougm 20173034Sdougm /* 20183034Sdougm * show_group_xml_init() 20193034Sdougm * 20203034Sdougm * Create an XML document that will be used to display config info via 20213034Sdougm * XML format. 20223034Sdougm */ 20233034Sdougm 20243034Sdougm xmlDocPtr 20253034Sdougm show_group_xml_init() 20263034Sdougm { 20273034Sdougm xmlDocPtr doc; 20283034Sdougm xmlNodePtr root; 20293034Sdougm 20303034Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 20313034Sdougm if (doc != NULL) { 20324653Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 20334653Sdougm if (root != NULL) 20344653Sdougm xmlDocSetRootElement(doc, root); 20353034Sdougm } 20363034Sdougm return (doc); 20373034Sdougm } 20383034Sdougm 20393034Sdougm /* 20403034Sdougm * show_group_xml(doc, group) 20413034Sdougm * 20423034Sdougm * Copy the group info into the XML doc. 20433034Sdougm */ 20443034Sdougm 20453034Sdougm static void 20463034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 20473034Sdougm { 20483034Sdougm xmlNodePtr node; 20493034Sdougm xmlNodePtr root; 20503034Sdougm 20513034Sdougm root = xmlDocGetRootElement(doc); 20523034Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 20533034Sdougm if (node != NULL && root != NULL) { 20544653Sdougm xmlAddChild(root, node); 20553034Sdougm /* 20563034Sdougm * In the future, we may have interally used tags that 20573034Sdougm * should not appear in the XML output. Remove 20583034Sdougm * anything we don't want to show here. 20593034Sdougm */ 20603034Sdougm } 20613034Sdougm } 20623034Sdougm 20633034Sdougm /* 20643034Sdougm * sa_show(flags, argc, argv) 20653034Sdougm * 20663034Sdougm * Implements the show subcommand. 20673034Sdougm */ 20683034Sdougm 20693034Sdougm int 20703910Sdougm sa_show(sa_handle_t handle, int flags, int argc, char *argv[]) 20713034Sdougm { 20723034Sdougm sa_group_t group; 20733034Sdougm int verbose = 0; 20743034Sdougm int properties = 0; 20753034Sdougm int c; 20763034Sdougm int ret = SA_OK; 20773034Sdougm char *protocol = NULL; 20783034Sdougm int xml = 0; 20793034Sdougm xmlDocPtr doc; 2080*5331Samw #ifdef lint 2081*5331Samw flags = flags; 2082*5331Samw #endif 20833034Sdougm 20843034Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 20854653Sdougm switch (c) { 20864653Sdougm case 'v': 20874653Sdougm verbose++; 20884653Sdougm break; 20894653Sdougm case 'p': 20904653Sdougm properties++; 20914653Sdougm break; 20924653Sdougm case 'P': 2093*5331Samw if (protocol != NULL) { 2094*5331Samw (void) printf(gettext( 2095*5331Samw "Specifying multiple protocols " 2096*5331Samw "not supported: %s\n"), 2097*5331Samw protocol); 2098*5331Samw return (SA_SYNTAX_ERR); 2099*5331Samw } 21004653Sdougm protocol = optarg; 21014653Sdougm if (!sa_valid_protocol(protocol)) { 21024653Sdougm (void) printf(gettext( 21034653Sdougm "Invalid protocol specified: %s\n"), 21044653Sdougm protocol); 21054653Sdougm return (SA_INVALID_PROTOCOL); 21064653Sdougm } 21074653Sdougm break; 21084653Sdougm case 'x': 21094653Sdougm xml++; 21104653Sdougm break; 21114653Sdougm default: 21124653Sdougm case 'h': 21134653Sdougm case '?': 21144653Sdougm (void) printf(gettext("usage: %s\n"), 21154653Sdougm sa_get_usage(USAGE_SHOW)); 21164653Sdougm return (0); 21173034Sdougm } 21183034Sdougm } 21193034Sdougm 21203034Sdougm if (xml) { 21214653Sdougm doc = show_group_xml_init(); 21224653Sdougm if (doc == NULL) 21234653Sdougm ret = SA_NO_MEMORY; 21243034Sdougm } 21253034Sdougm 21263034Sdougm if (optind == argc) { 21274653Sdougm /* No group specified so go through them all */ 21284653Sdougm for (group = sa_get_group(handle, NULL); 21294653Sdougm group != NULL; 21304653Sdougm group = sa_get_next_group(group)) { 21314653Sdougm /* 21324653Sdougm * Have a group so check if one we want and then list 21334653Sdougm * contents with appropriate options. 21344653Sdougm */ 21354653Sdougm if (xml) 21364653Sdougm show_group_xml(doc, group); 21374653Sdougm else 21384653Sdougm show_group(group, verbose, properties, protocol, 21394653Sdougm NULL); 21404653Sdougm } 21413034Sdougm } else { 21424653Sdougm /* Have a specified list of groups */ 21434653Sdougm for (; optind < argc; optind++) { 21444653Sdougm group = sa_get_group(handle, argv[optind]); 21454653Sdougm if (group != NULL) { 21464653Sdougm if (xml) 21474653Sdougm show_group_xml(doc, group); 21484653Sdougm else 21494653Sdougm show_group(group, verbose, properties, 21504653Sdougm protocol, NULL); 21514653Sdougm } else { 21524653Sdougm (void) printf(gettext("%s: not found\n"), 21534653Sdougm argv[optind]); 21544653Sdougm ret = SA_NO_SUCH_GROUP; 21554653Sdougm } 21563034Sdougm } 21573034Sdougm } 21583034Sdougm if (xml && ret == SA_OK) { 21594653Sdougm xmlDocFormatDump(stdout, doc, 1); 21604653Sdougm xmlFreeDoc(doc); 21613034Sdougm } 21623034Sdougm return (ret); 21633034Sdougm 21643034Sdougm } 21653034Sdougm 21663034Sdougm /* 21673034Sdougm * enable_share(group, share, update_legacy) 21683034Sdougm * 21693034Sdougm * helper function to enable a share if the group is enabled. 21703034Sdougm */ 21713034Sdougm 21723034Sdougm static int 21733910Sdougm enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 2174*5331Samw int update_legacy) 21753034Sdougm { 21763034Sdougm char *value; 21773034Sdougm int enabled; 21783034Sdougm sa_optionset_t optionset; 2179*5331Samw int err; 21803034Sdougm int ret = SA_OK; 21813034Sdougm char *zfs = NULL; 21823034Sdougm int iszfs = 0; 2183*5331Samw int isshare; 21843034Sdougm 21853034Sdougm /* 21863034Sdougm * need to enable this share if the group is enabled but not 21873034Sdougm * otherwise. The enable is also done on each protocol 21883034Sdougm * represented in the group. 21893034Sdougm */ 21903034Sdougm value = sa_get_group_attr(group, "state"); 21913034Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 21923034Sdougm if (value != NULL) 21934653Sdougm sa_free_attr_string(value); 21943034Sdougm /* remove legacy config if necessary */ 21953034Sdougm if (update_legacy) 2196*5331Samw ret = sa_delete_legacy(share, NULL); 21973034Sdougm zfs = sa_get_group_attr(group, "zfs"); 21983034Sdougm if (zfs != NULL) { 21994653Sdougm iszfs++; 22004653Sdougm sa_free_attr_string(zfs); 22013034Sdougm } 22023034Sdougm 22033034Sdougm /* 22043034Sdougm * Step through each optionset at the group level and 22053034Sdougm * enable the share based on the protocol type. This 22063034Sdougm * works because protocols must be set on the group 22073034Sdougm * for the protocol to be enabled. 22083034Sdougm */ 2209*5331Samw isshare = sa_is_share(share); 22103034Sdougm for (optionset = sa_get_optionset(group, NULL); 22113034Sdougm optionset != NULL && ret == SA_OK; 22123034Sdougm optionset = sa_get_next_optionset(optionset)) { 22134653Sdougm value = sa_get_optionset_attr(optionset, "type"); 22144653Sdougm if (value != NULL) { 2215*5331Samw if (enabled) { 2216*5331Samw if (isshare) { 2217*5331Samw err = sa_enable_share(share, value); 2218*5331Samw } else { 2219*5331Samw err = sa_enable_resource(share, value); 2220*5331Samw if (err == SA_NOT_SUPPORTED) { 2221*5331Samw sa_share_t parent; 2222*5331Samw parent = sa_get_resource_parent( 2223*5331Samw share); 2224*5331Samw if (parent != NULL) 2225*5331Samw err = sa_enable_share( 2226*5331Samw parent, value); 2227*5331Samw } 2228*5331Samw } 2229*5331Samw if (err != SA_OK) { 2230*5331Samw ret = err; 2231*5331Samw (void) printf(gettext( 2232*5331Samw "Failed to enable share for " 2233*5331Samw "\"%s\": %s\n"), 2234*5331Samw value, sa_errorstr(ret)); 2235*5331Samw } 2236*5331Samw } 2237*5331Samw /* 2238*5331Samw * If we want to update the legacy, use a copy of 2239*5331Samw * share so we can avoid breaking the loop we are in 2240*5331Samw * since we might also need to go up the tree to the 2241*5331Samw * parent. 2242*5331Samw */ 2243*5331Samw if (update_legacy && !iszfs) { 2244*5331Samw sa_share_t update = share; 2245*5331Samw if (!sa_is_share(share)) { 2246*5331Samw update = sa_get_resource_parent(share); 2247*5331Samw } 2248*5331Samw (void) sa_update_legacy(update, value); 2249*5331Samw } 22504653Sdougm sa_free_attr_string(value); 22514653Sdougm } 22523034Sdougm } 22533034Sdougm if (ret == SA_OK) 22544653Sdougm (void) sa_update_config(handle); 22553034Sdougm return (ret); 22563034Sdougm } 22573034Sdougm 22583034Sdougm /* 2259*5331Samw * sa_require_resource(group) 2260*5331Samw * 2261*5331Samw * if any of the defined protocols on the group require resource 2262*5331Samw * names, then all shares must have them. 2263*5331Samw */ 2264*5331Samw 2265*5331Samw static int 2266*5331Samw sa_require_resource(sa_group_t group) 2267*5331Samw { 2268*5331Samw sa_optionset_t optionset; 2269*5331Samw 2270*5331Samw for (optionset = sa_get_optionset(group, NULL); 2271*5331Samw optionset != NULL; 2272*5331Samw optionset = sa_get_next_optionset(optionset)) { 2273*5331Samw char *proto; 2274*5331Samw 2275*5331Samw proto = sa_get_optionset_attr(optionset, "type"); 2276*5331Samw if (proto != NULL) { 2277*5331Samw uint64_t features; 2278*5331Samw 2279*5331Samw features = sa_proto_get_featureset(proto); 2280*5331Samw if (features & SA_FEATURE_RESOURCE) { 2281*5331Samw sa_free_attr_string(proto); 2282*5331Samw return (B_TRUE); 2283*5331Samw } 2284*5331Samw sa_free_attr_string(proto); 2285*5331Samw } 2286*5331Samw } 2287*5331Samw return (B_FALSE); 2288*5331Samw } 2289*5331Samw 2290*5331Samw /* 22913034Sdougm * sa_addshare(flags, argc, argv) 22923034Sdougm * 22933034Sdougm * implements add-share subcommand. 22943034Sdougm */ 22953034Sdougm 2296*5331Samw static int 22973910Sdougm sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[]) 22983034Sdougm { 22993034Sdougm int verbose = 0; 23003034Sdougm int dryrun = 0; 23013034Sdougm int c; 23023034Sdougm int ret = SA_OK; 23033034Sdougm sa_group_t group; 23043034Sdougm sa_share_t share; 2305*5331Samw sa_resource_t resource = NULL; 23063034Sdougm char *sharepath = NULL; 23073034Sdougm char *description = NULL; 2308*5331Samw char *rsrcname = NULL; 2309*5331Samw char *rsrc = NULL; 23103034Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 23113034Sdougm int auth; 23123034Sdougm char dir[MAXPATHLEN]; 23133034Sdougm 23143034Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 23154653Sdougm switch (c) { 23164653Sdougm case 'n': 23174653Sdougm dryrun++; 23184653Sdougm break; 23194653Sdougm case 'v': 23204653Sdougm verbose++; 23214653Sdougm break; 23224653Sdougm case 'd': 23234653Sdougm description = optarg; 23244653Sdougm break; 23254653Sdougm case 'r': 2326*5331Samw if (rsrcname != NULL) { 2327*5331Samw (void) printf(gettext("Adding multiple " 2328*5331Samw "resource names not" 2329*5331Samw " supported\n")); 2330*5331Samw return (SA_SYNTAX_ERR); 2331*5331Samw } 2332*5331Samw rsrcname = optarg; 23334653Sdougm break; 23344653Sdougm case 's': 23354653Sdougm /* 23364653Sdougm * Save share path into group. Currently limit 23374653Sdougm * to one share per command. 23384653Sdougm */ 23394653Sdougm if (sharepath != NULL) { 23404653Sdougm (void) printf(gettext( 23414653Sdougm "Adding multiple shares not supported\n")); 2342*5331Samw return (SA_SYNTAX_ERR); 23434653Sdougm } 23444653Sdougm sharepath = optarg; 23454653Sdougm break; 23464653Sdougm case 't': 23474653Sdougm persist = SA_SHARE_TRANSIENT; 23484653Sdougm break; 23494653Sdougm default: 23504653Sdougm case 'h': 23514653Sdougm case '?': 23524653Sdougm (void) printf(gettext("usage: %s\n"), 23534653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 23544653Sdougm return (0); 23553034Sdougm } 23563034Sdougm } 23573034Sdougm 23583034Sdougm if (optind >= argc) { 23594653Sdougm (void) printf(gettext("usage: %s\n"), 23604653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 23614653Sdougm if (dryrun || sharepath != NULL || description != NULL || 2362*5331Samw rsrcname != NULL || verbose || persist) { 23634653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 23644653Sdougm ret = SA_NO_SUCH_GROUP; 23654653Sdougm } else { 23664653Sdougm ret = SA_OK; 23674653Sdougm } 23683034Sdougm } else { 23694653Sdougm if (sharepath == NULL) { 23704653Sdougm (void) printf(gettext("usage: %s\n"), 23714653Sdougm sa_get_usage(USAGE_ADD_SHARE)); 23724653Sdougm (void) printf(gettext( 23734653Sdougm "\t-s sharepath must be specified\n")); 2374*5331Samw ret = SA_BAD_PATH; 23754653Sdougm } 2376*5331Samw if (ret == SA_OK) { 2377*5331Samw if (realpath(sharepath, dir) == NULL) { 2378*5331Samw ret = SA_BAD_PATH; 2379*5331Samw (void) printf(gettext("Path " 2380*5331Samw "is not valid: %s\n"), 2381*5331Samw sharepath); 2382*5331Samw } else { 2383*5331Samw sharepath = dir; 2384*5331Samw } 23853034Sdougm } 2386*5331Samw if (ret == SA_OK && rsrcname != NULL) { 2387*5331Samw /* check for valid syntax */ 2388*5331Samw if (validresource(rsrcname)) { 2389*5331Samw rsrc = conv_to_utf8(rsrcname); 2390*5331Samw resource = sa_find_resource(handle, rsrc); 2391*5331Samw if (resource != NULL) { 2392*5331Samw /* 2393*5331Samw * Resource names must be 2394*5331Samw * unique in the system 2395*5331Samw */ 2396*5331Samw ret = SA_DUPLICATE_NAME; 2397*5331Samw (void) printf(gettext("usage: %s\n"), 2398*5331Samw sa_get_usage(USAGE_ADD_SHARE)); 2399*5331Samw (void) printf(gettext( 2400*5331Samw "\tresource names must be unique " 2401*5331Samw "in the system\n")); 2402*5331Samw } 2403*5331Samw } else { 2404*5331Samw (void) printf(gettext("usage: %s\n"), 2405*5331Samw sa_get_usage(USAGE_ADD_SHARE)); 2406*5331Samw (void) printf(gettext( 2407*5331Samw "\tresource names use restricted " 2408*5331Samw "character set\n")); 2409*5331Samw ret = SA_INVALID_NAME; 2410*5331Samw } 24113034Sdougm } 2412*5331Samw 2413*5331Samw if (ret != SA_OK) { 2414*5331Samw if (rsrc != NULL && rsrcname != rsrc) 2415*5331Samw sa_free_attr_string(rsrc); 2416*5331Samw return (ret); 24174653Sdougm } 2418*5331Samw 24194653Sdougm share = sa_find_share(handle, sharepath); 24204653Sdougm if (share != NULL) { 2421*5331Samw if (rsrcname == NULL) { 2422*5331Samw /* 2423*5331Samw * Can only have a duplicate share if a new 2424*5331Samw * resource name is being added. 2425*5331Samw */ 2426*5331Samw ret = SA_DUPLICATE_NAME; 2427*5331Samw (void) printf(gettext("Share path already " 2428*5331Samw "shared: %s\n"), sharepath); 2429*5331Samw } 2430*5331Samw } 2431*5331Samw if (ret != SA_OK) 2432*5331Samw return (ret); 2433*5331Samw 2434*5331Samw group = sa_get_group(handle, argv[optind]); 2435*5331Samw if (group != NULL) { 2436*5331Samw if (sa_require_resource(group) == B_TRUE && 2437*5331Samw rsrcname == NULL) { 2438*5331Samw (void) printf(gettext( 2439*5331Samw "Resource name is required " 2440*5331Samw "by at least one enabled protocol " 2441*5331Samw "in group\n")); 2442*5331Samw return (SA_RESOURCE_REQUIRED); 2443*5331Samw } 2444*5331Samw if (share == NULL && ret == SA_OK) { 2445*5331Samw if (dryrun) 2446*5331Samw ret = sa_check_path(group, sharepath, 2447*5331Samw SA_CHECK_NORMAL); 2448*5331Samw else 2449*5331Samw share = sa_add_share(group, sharepath, 2450*5331Samw persist, &ret); 2451*5331Samw } 2452*5331Samw /* 2453*5331Samw * Make sure this isn't an attempt to put a resourced 2454*5331Samw * share into a different group than it already is in. 2455*5331Samw */ 2456*5331Samw if (share != NULL) { 2457*5331Samw sa_group_t parent; 2458*5331Samw parent = sa_get_parent_group(share); 2459*5331Samw if (parent != group) { 2460*5331Samw ret = SA_DUPLICATE_NAME; 24614653Sdougm (void) printf(gettext( 24624653Sdougm "Share path already " 2463*5331Samw "shared: %s\n"), sharepath); 24644653Sdougm } 24653034Sdougm } 24663034Sdougm if (!dryrun && share == NULL) { 24674653Sdougm (void) printf(gettext( 24684653Sdougm "Could not add share: %s\n"), 24694653Sdougm sa_errorstr(ret)); 24703034Sdougm } else { 2471*5331Samw auth = check_authorizations(argv[optind], 2472*5331Samw flags); 24734653Sdougm if (!dryrun && ret == SA_OK) { 2474*5331Samw if (rsrcname != NULL) { 2475*5331Samw resource = sa_add_resource( 2476*5331Samw share, 2477*5331Samw rsrc, 2478*5331Samw SA_SHARE_PERMANENT, 2479*5331Samw &ret); 24804653Sdougm } 24814653Sdougm if (ret == SA_OK && 24824653Sdougm description != NULL) { 2483*5331Samw if (description != NULL) { 2484*5331Samw ret = 2485*5331Samw set_share_desc( 2486*5331Samw share, 2487*5331Samw description); 2488*5331Samw } 24894653Sdougm } 24904653Sdougm if (ret == SA_OK) { 2491*5331Samw /* now enable the share(s) */ 2492*5331Samw if (resource != NULL) { 2493*5331Samw ret = enable_share( 2494*5331Samw handle, 2495*5331Samw group, 2496*5331Samw resource, 2497*5331Samw 1); 2498*5331Samw } else { 2499*5331Samw ret = enable_share( 2500*5331Samw handle, 2501*5331Samw group, 2502*5331Samw share, 2503*5331Samw 1); 2504*5331Samw } 25054653Sdougm ret = sa_update_config(handle); 25064653Sdougm } 25074653Sdougm switch (ret) { 25084653Sdougm case SA_DUPLICATE_NAME: 25094653Sdougm (void) printf(gettext( 25104653Sdougm "Resource name in" 2511*5331Samw "use: %s\n"), 2512*5331Samw rsrcname); 25134653Sdougm break; 25144653Sdougm default: 2515*5331Samw (void) printf(gettext( 2516*5331Samw "Could not set " 25174653Sdougm "attribute: %s\n"), 25184653Sdougm sa_errorstr(ret)); 25194653Sdougm break; 25204653Sdougm case SA_OK: 25214653Sdougm break; 25224653Sdougm } 2523*5331Samw } else if (dryrun && ret == SA_OK && 2524*5331Samw !auth && verbose) { 25254653Sdougm (void) printf(gettext( 25264653Sdougm "Command would fail: %s\n"), 25274653Sdougm sa_errorstr(SA_NO_PERMISSION)); 25284653Sdougm ret = SA_NO_PERMISSION; 25293034Sdougm } 25303034Sdougm } 2531*5331Samw } else { 2532*5331Samw switch (ret) { 2533*5331Samw default: 2534*5331Samw (void) printf(gettext( 2535*5331Samw "Group \"%s\" not found\n"), argv[optind]); 2536*5331Samw ret = SA_NO_SUCH_GROUP; 2537*5331Samw break; 2538*5331Samw case SA_BAD_PATH: 2539*5331Samw case SA_DUPLICATE_NAME: 2540*5331Samw break; 2541*5331Samw } 25423034Sdougm } 25433034Sdougm } 25443034Sdougm return (ret); 25453034Sdougm } 25463034Sdougm 25473034Sdougm /* 25483034Sdougm * sa_moveshare(flags, argc, argv) 25493034Sdougm * 25503034Sdougm * implements move-share subcommand. 25513034Sdougm */ 25523034Sdougm 25533034Sdougm int 25543910Sdougm sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[]) 25553034Sdougm { 25563034Sdougm int verbose = 0; 25573034Sdougm int dryrun = 0; 25583034Sdougm int c; 25593034Sdougm int ret = SA_OK; 25603034Sdougm sa_group_t group; 25613034Sdougm sa_share_t share; 2562*5331Samw char *rsrcname = NULL; 25633034Sdougm char *sharepath = NULL; 25643034Sdougm int authsrc = 0, authdst = 0; 25653034Sdougm 2566*5331Samw while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) { 25674653Sdougm switch (c) { 25684653Sdougm case 'n': 25694653Sdougm dryrun++; 25704653Sdougm break; 25714653Sdougm case 'v': 25724653Sdougm verbose++; 25734653Sdougm break; 2574*5331Samw case 'r': 2575*5331Samw if (rsrcname != NULL) { 2576*5331Samw (void) printf(gettext( 2577*5331Samw "Moving multiple resource names not" 2578*5331Samw " supported\n")); 2579*5331Samw return (SA_SYNTAX_ERR); 2580*5331Samw } 2581*5331Samw rsrcname = optarg; 2582*5331Samw break; 25834653Sdougm case 's': 25844653Sdougm /* 25854653Sdougm * Remove share path from group. Currently limit 25864653Sdougm * to one share per command. 25874653Sdougm */ 25884653Sdougm if (sharepath != NULL) { 25894653Sdougm (void) printf(gettext("Moving multiple shares" 2590*5331Samw " not supported\n")); 2591*5331Samw return (SA_SYNTAX_ERR); 25924653Sdougm } 25934653Sdougm sharepath = optarg; 25944653Sdougm break; 25954653Sdougm default: 25964653Sdougm case 'h': 25974653Sdougm case '?': 25984653Sdougm (void) printf(gettext("usage: %s\n"), 25994653Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 26004653Sdougm return (0); 26013034Sdougm } 26023034Sdougm } 26033034Sdougm 26043034Sdougm if (optind >= argc || sharepath == NULL) { 2605*5331Samw (void) printf(gettext("usage: %s\n"), 2606*5331Samw sa_get_usage(USAGE_MOVE_SHARE)); 2607*5331Samw if (dryrun || verbose || sharepath != NULL) { 2608*5331Samw (void) printf(gettext("\tgroup must be specified\n")); 2609*5331Samw ret = SA_NO_SUCH_GROUP; 2610*5331Samw } else { 2611*5331Samw if (sharepath == NULL) { 2612*5331Samw ret = SA_SYNTAX_ERR; 26134653Sdougm (void) printf(gettext( 2614*5331Samw "\tsharepath must be specified\n")); 26154653Sdougm } else { 2616*5331Samw ret = SA_OK; 26174653Sdougm } 2618*5331Samw } 26194653Sdougm } else { 26204653Sdougm sa_group_t parent; 26214653Sdougm char *zfsold; 26224653Sdougm char *zfsnew; 26234653Sdougm 26243034Sdougm if (sharepath == NULL) { 26254653Sdougm (void) printf(gettext( 26264653Sdougm "sharepath must be specified with the -s " 26274653Sdougm "option\n")); 26284653Sdougm return (SA_BAD_PATH); 26294653Sdougm } 26303910Sdougm group = sa_get_group(handle, argv[optind]); 26314653Sdougm if (group == NULL) { 26324653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 26334653Sdougm argv[optind]); 26344653Sdougm return (SA_NO_SUCH_GROUP); 26354653Sdougm } 26364653Sdougm share = sa_find_share(handle, sharepath); 26374653Sdougm authdst = check_authorizations(argv[optind], flags); 26384653Sdougm if (share == NULL) { 26393034Sdougm (void) printf(gettext("Share not found: %s\n"), 26404653Sdougm sharepath); 26414653Sdougm return (SA_NO_SUCH_PATH); 26424653Sdougm } 26434653Sdougm 26444653Sdougm parent = sa_get_parent_group(share); 26454653Sdougm if (parent != NULL) { 26464653Sdougm char *pname; 26474653Sdougm pname = sa_get_group_attr(parent, "name"); 26484653Sdougm if (pname != NULL) { 26493034Sdougm authsrc = check_authorizations(pname, flags); 26503034Sdougm sa_free_attr_string(pname); 26514653Sdougm } 26524653Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 26534653Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 26544653Sdougm if ((zfsold != NULL && zfsnew == NULL) || 26554653Sdougm (zfsold == NULL && zfsnew != NULL)) { 26563034Sdougm ret = SA_NOT_ALLOWED; 26573034Sdougm } 26584653Sdougm if (zfsold != NULL) 26594653Sdougm sa_free_attr_string(zfsold); 26604653Sdougm if (zfsnew != NULL) 26614653Sdougm sa_free_attr_string(zfsnew); 26624653Sdougm } 26634653Sdougm 26644653Sdougm if (ret == SA_OK && parent != group && !dryrun) { 26654653Sdougm char *oldstate; 26664653Sdougm /* 26674653Sdougm * Note that the share may need to be 2668*5331Samw * "unshared" if the new group is disabled and 2669*5331Samw * the old was enabled or it may need to be 2670*5331Samw * share to update if the new group is 2671*5331Samw * enabled. We disable before the move and 2672*5331Samw * will have to enable after the move in order 2673*5331Samw * to cleanup entries for protocols that 2674*5331Samw * aren't in the new group. 26754653Sdougm */ 26764653Sdougm oldstate = sa_get_group_attr(parent, "state"); 26774653Sdougm 26784653Sdougm /* enable_share determines what to do */ 2679*5331Samw if (strcmp(oldstate, "enabled") == 0) 26803034Sdougm (void) sa_disable_share(share, NULL); 2681*5331Samw 26824653Sdougm if (oldstate != NULL) 26833034Sdougm sa_free_attr_string(oldstate); 26843034Sdougm } 26854653Sdougm 2686*5331Samw if (!dryrun && ret == SA_OK) 2687*5331Samw ret = sa_move_share(group, share); 2688*5331Samw 2689*5331Samw /* 2690*5331Samw * Reenable and update any config information. 2691*5331Samw */ 2692*5331Samw if (ret == SA_OK && parent != group && !dryrun) { 2693*5331Samw ret = sa_update_config(handle); 2694*5331Samw 2695*5331Samw (void) enable_share(handle, group, share, 1); 2696*5331Samw } 2697*5331Samw 26984653Sdougm if (ret != SA_OK) 26994653Sdougm (void) printf(gettext("Could not move share: %s\n"), 27004653Sdougm sa_errorstr(ret)); 27014653Sdougm 27024653Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 27034653Sdougm verbose) { 27044653Sdougm (void) printf(gettext("Command would fail: %s\n"), 27054653Sdougm sa_errorstr(SA_NO_PERMISSION)); 27064653Sdougm } 27073034Sdougm } 27083034Sdougm return (ret); 27093034Sdougm } 27103034Sdougm 27113034Sdougm /* 27123034Sdougm * sa_removeshare(flags, argc, argv) 27133034Sdougm * 27143034Sdougm * implements remove-share subcommand. 27153034Sdougm */ 27163034Sdougm 27173034Sdougm int 27183910Sdougm sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[]) 27193034Sdougm { 27203034Sdougm int verbose = 0; 27213034Sdougm int dryrun = 0; 27223034Sdougm int force = 0; 27233034Sdougm int c; 27243034Sdougm int ret = SA_OK; 27253034Sdougm sa_group_t group; 2726*5331Samw sa_resource_t resource = NULL; 2727*5331Samw sa_share_t share = NULL; 2728*5331Samw char *rsrcname = NULL; 27293034Sdougm char *sharepath = NULL; 27303034Sdougm char dir[MAXPATHLEN]; 27313034Sdougm int auth; 27323034Sdougm 2733*5331Samw while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) { 27344653Sdougm switch (c) { 27354653Sdougm case 'n': 27364653Sdougm dryrun++; 27374653Sdougm break; 27384653Sdougm case 'v': 27394653Sdougm verbose++; 27404653Sdougm break; 27414653Sdougm case 'f': 27424653Sdougm force++; 27434653Sdougm break; 27444653Sdougm case 's': 27454653Sdougm /* 27464653Sdougm * Remove share path from group. Currently limit 27474653Sdougm * to one share per command. 27484653Sdougm */ 27494653Sdougm if (sharepath != NULL) { 27504653Sdougm (void) printf(gettext( 27514653Sdougm "Removing multiple shares not " 27523034Sdougm "supported\n")); 27534653Sdougm return (SA_SYNTAX_ERR); 27544653Sdougm } 27554653Sdougm sharepath = optarg; 27564653Sdougm break; 2757*5331Samw case 'r': 2758*5331Samw /* 2759*5331Samw * Remove share from group if last resource or remove 2760*5331Samw * resource from share if multiple resources. 2761*5331Samw */ 2762*5331Samw if (rsrcname != NULL) { 2763*5331Samw (void) printf(gettext( 2764*5331Samw "Removing multiple resource names not " 2765*5331Samw "supported\n")); 2766*5331Samw return (SA_SYNTAX_ERR); 2767*5331Samw } 2768*5331Samw rsrcname = optarg; 2769*5331Samw break; 27704653Sdougm default: 27714653Sdougm case 'h': 27724653Sdougm case '?': 27734653Sdougm (void) printf(gettext("usage: %s\n"), 27744653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 27754653Sdougm return (0); 27763034Sdougm } 27773034Sdougm } 27783034Sdougm 2779*5331Samw if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) { 2780*5331Samw if (sharepath == NULL && rsrcname == NULL) { 27813034Sdougm (void) printf(gettext("usage: %s\n"), 27824653Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 2783*5331Samw (void) printf(gettext("\t-s sharepath or -r resource" 2784*5331Samw " must be specified\n")); 27854653Sdougm ret = SA_BAD_PATH; 27864653Sdougm } else { 27874653Sdougm ret = SA_OK; 27884653Sdougm } 27893034Sdougm } 27904653Sdougm if (ret != SA_OK) { 27914653Sdougm return (ret); 27924653Sdougm } 27934653Sdougm 27944653Sdougm if (optind < argc) { 27953034Sdougm if ((optind + 1) < argc) { 27964653Sdougm (void) printf(gettext("Extraneous group(s) at end of " 27974653Sdougm "command\n")); 27984653Sdougm ret = SA_SYNTAX_ERR; 27993034Sdougm } else { 28004653Sdougm group = sa_get_group(handle, argv[optind]); 28014653Sdougm if (group == NULL) { 28024653Sdougm (void) printf(gettext( 28034653Sdougm "Group \"%s\" not found\n"), argv[optind]); 28044653Sdougm ret = SA_NO_SUCH_GROUP; 28054653Sdougm } 28063034Sdougm } 28074653Sdougm } else { 28083034Sdougm group = NULL; 28094653Sdougm } 28104653Sdougm 2811*5331Samw if (rsrcname != NULL) { 2812*5331Samw resource = sa_find_resource(handle, rsrcname); 2813*5331Samw if (resource == NULL) { 2814*5331Samw ret = SA_NO_SUCH_RESOURCE; 2815*5331Samw (void) printf(gettext( 2816*5331Samw "Resource name not found for share: %s\n"), 2817*5331Samw rsrcname); 2818*5331Samw } 2819*5331Samw } 2820*5331Samw 28214653Sdougm /* 28224653Sdougm * Lookup the path in the internal configuration. Care 28234653Sdougm * must be taken to handle the case where the 28244653Sdougm * underlying path has been removed since we need to 28254653Sdougm * be able to deal with that as well. 28264653Sdougm */ 28274653Sdougm if (ret == SA_OK) { 2828*5331Samw if (sharepath != NULL) { 2829*5331Samw if (group != NULL) 2830*5331Samw share = sa_get_share(group, sharepath); 2831*5331Samw else 2832*5331Samw share = sa_find_share(handle, sharepath); 2833*5331Samw } 2834*5331Samw 2835*5331Samw if (resource != NULL) { 2836*5331Samw sa_share_t rsrcshare; 2837*5331Samw rsrcshare = sa_get_resource_parent(resource); 2838*5331Samw if (share == NULL) 2839*5331Samw share = rsrcshare; 2840*5331Samw else if (share != rsrcshare) { 2841*5331Samw ret = SA_NO_SUCH_RESOURCE; 2842*5331Samw (void) printf(gettext( 2843*5331Samw "Bad resource name for share: %s\n"), 2844*5331Samw rsrcname); 2845*5331Samw share = NULL; 2846*5331Samw } 2847*5331Samw } 2848*5331Samw 28493663Sdougm /* 28503663Sdougm * If we didn't find the share with the provided path, 28513663Sdougm * it may be a symlink so attempt to resolve it using 28523663Sdougm * realpath and try again. Realpath will resolve any 28533663Sdougm * symlinks and place them in "dir". Note that 28543663Sdougm * sharepath is only used for the lookup the first 28553663Sdougm * time and later for error messages. dir will be used 28563663Sdougm * on the second attempt. Once a share is found, all 28573663Sdougm * operations are based off of the share variable. 28583663Sdougm */ 28593663Sdougm if (share == NULL) { 28604653Sdougm if (realpath(sharepath, dir) == NULL) { 28614653Sdougm ret = SA_BAD_PATH; 28624653Sdougm (void) printf(gettext( 28634653Sdougm "Path is not valid: %s\n"), sharepath); 28644653Sdougm } else { 28654653Sdougm if (group != NULL) 28664653Sdougm share = sa_get_share(group, dir); 28674653Sdougm else 28684653Sdougm share = sa_find_share(handle, dir); 28694653Sdougm } 28703663Sdougm } 28714653Sdougm } 28724653Sdougm 28734653Sdougm /* 28744653Sdougm * If there hasn't been an error, there was likely a 28754653Sdougm * path found. If not, give the appropriate error 28764653Sdougm * message and set the return error. If it was found, 28774653Sdougm * then disable the share and then remove it from the 28784653Sdougm * configuration. 28794653Sdougm */ 28804653Sdougm if (ret != SA_OK) { 28814653Sdougm return (ret); 28824653Sdougm } 28834653Sdougm if (share == NULL) { 28844653Sdougm if (group != NULL) 28853034Sdougm (void) printf(gettext("Share not found in group %s:" 28864653Sdougm " %s\n"), argv[optind], sharepath); 28874653Sdougm else 28883034Sdougm (void) printf(gettext("Share not found: %s\n"), 28894653Sdougm sharepath); 2890*5331Samw ret = SA_NO_SUCH_PATH; 28914653Sdougm } else { 28924653Sdougm if (group == NULL) 28933034Sdougm group = sa_get_parent_group(share); 28944653Sdougm if (!dryrun) { 28953034Sdougm if (ret == SA_OK) { 2896*5331Samw if (resource != NULL) 2897*5331Samw ret = sa_disable_resource(resource, 2898*5331Samw NULL); 2899*5331Samw else 2900*5331Samw ret = sa_disable_share(share, NULL); 29013034Sdougm /* 29024653Sdougm * We don't care if it fails since it 29033663Sdougm * could be disabled already. Some 29043663Sdougm * unexpected errors could occur that 29053663Sdougm * prevent removal, so also check for 29063663Sdougm * force being set. 29073034Sdougm */ 2908*5331Samw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 2909*5331Samw ret == SA_NOT_SUPPORTED || 2910*5331Samw ret == SA_SYSTEM_ERR || force) && 2911*5331Samw resource == NULL) 2912*5331Samw ret = sa_remove_share(share); 2913*5331Samw 2914*5331Samw if ((ret == SA_OK || ret == SA_NO_SUCH_PATH || 29154653Sdougm ret == SA_NOT_SUPPORTED || 2916*5331Samw ret == SA_SYSTEM_ERR || force) && 2917*5331Samw resource != NULL) { 2918*5331Samw ret = sa_remove_resource(resource); 2919*5331Samw if (ret == SA_OK) { 2920*5331Samw /* 2921*5331Samw * If this was the 2922*5331Samw * last one, remove 2923*5331Samw * the share as well. 2924*5331Samw */ 2925*5331Samw resource = 2926*5331Samw sa_get_share_resource( 2927*5331Samw share, NULL); 2928*5331Samw if (resource == NULL) 2929*5331Samw ret = sa_remove_share( 2930*5331Samw share); 2931*5331Samw } 29324653Sdougm } 29334653Sdougm if (ret == SA_OK) 29344653Sdougm ret = sa_update_config(handle); 29353034Sdougm } 29364653Sdougm if (ret != SA_OK) 2937*5331Samw (void) printf(gettext("Could not remove share:" 2938*5331Samw " %s\n"), sa_errorstr(ret)); 29394653Sdougm } else if (ret == SA_OK) { 29403034Sdougm char *pname; 29413034Sdougm pname = sa_get_group_attr(group, "name"); 29423034Sdougm if (pname != NULL) { 29434653Sdougm auth = check_authorizations(pname, flags); 29444653Sdougm sa_free_attr_string(pname); 29453034Sdougm } 29463034Sdougm if (!auth && verbose) { 29474653Sdougm (void) printf(gettext( 29484653Sdougm "Command would fail: %s\n"), 29494653Sdougm sa_errorstr(SA_NO_PERMISSION)); 29503034Sdougm } 29513034Sdougm } 29523034Sdougm } 29533034Sdougm return (ret); 29543034Sdougm } 29553034Sdougm 29563034Sdougm /* 29573034Sdougm * sa_set_share(flags, argc, argv) 29583034Sdougm * 29593034Sdougm * implements set-share subcommand. 29603034Sdougm */ 29613034Sdougm 29623034Sdougm int 29633910Sdougm sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[]) 29643034Sdougm { 29653034Sdougm int dryrun = 0; 29663034Sdougm int c; 29673034Sdougm int ret = SA_OK; 29683034Sdougm sa_group_t group, sharegroup; 29693034Sdougm sa_share_t share; 2970*5331Samw sa_resource_t resource = NULL; 29713034Sdougm char *sharepath = NULL; 29723034Sdougm char *description = NULL; 2973*5331Samw char *desc; 2974*5331Samw char *rsrcname = NULL; 2975*5331Samw char *rsrc = NULL; 2976*5331Samw char *newname = NULL; 2977*5331Samw char *newrsrc; 2978*5331Samw char *groupname = NULL; 29793034Sdougm int auth; 29803034Sdougm int verbose = 0; 29813034Sdougm 29823034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 29834653Sdougm switch (c) { 29844653Sdougm case 'n': 29854653Sdougm dryrun++; 29864653Sdougm break; 29874653Sdougm case 'd': 29884653Sdougm description = optarg; 29894653Sdougm break; 29904653Sdougm case 'v': 29914653Sdougm verbose++; 29924653Sdougm break; 2993*5331Samw case 'r': 2994*5331Samw /* 2995*5331Samw * Update share by resource name 2996*5331Samw */ 2997*5331Samw if (rsrcname != NULL) { 2998*5331Samw (void) printf(gettext( 2999*5331Samw "Updating multiple resource names not " 3000*5331Samw "supported\n")); 3001*5331Samw return (SA_SYNTAX_ERR); 3002*5331Samw } 3003*5331Samw rsrcname = optarg; 3004*5331Samw break; 30054653Sdougm case 's': 30064653Sdougm /* 30074653Sdougm * Save share path into group. Currently limit 30084653Sdougm * to one share per command. 30094653Sdougm */ 30104653Sdougm if (sharepath != NULL) { 30114653Sdougm (void) printf(gettext( 30124653Sdougm "Updating multiple shares not " 30133034Sdougm "supported\n")); 3014*5331Samw return (SA_SYNTAX_ERR); 30154653Sdougm } 30164653Sdougm sharepath = optarg; 30174653Sdougm break; 30184653Sdougm default: 30194653Sdougm case 'h': 30204653Sdougm case '?': 30214653Sdougm (void) printf(gettext("usage: %s\n"), 30224653Sdougm sa_get_usage(USAGE_SET_SHARE)); 30234653Sdougm return (SA_OK); 30243034Sdougm } 30253034Sdougm } 30264653Sdougm 3027*5331Samw if (optind >= argc && sharepath == NULL && rsrcname == NULL) { 30284653Sdougm if (sharepath == NULL) { 30294653Sdougm (void) printf(gettext("usage: %s\n"), 30304653Sdougm sa_get_usage(USAGE_SET_SHARE)); 30314653Sdougm (void) printf(gettext("\tgroup must be specified\n")); 30324653Sdougm ret = SA_BAD_PATH; 30334653Sdougm } else { 30344653Sdougm ret = SA_OK; 30354653Sdougm } 30363034Sdougm } 30373034Sdougm if ((optind + 1) < argc) { 30384653Sdougm (void) printf(gettext("usage: %s\n"), 30394653Sdougm sa_get_usage(USAGE_SET_SHARE)); 30404653Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 30414653Sdougm ret = SA_SYNTAX_ERR; 30423034Sdougm } 30434653Sdougm 3044*5331Samw /* 3045*5331Samw * Must have at least one of sharepath and rsrcrname. 3046*5331Samw * It is a syntax error to be missing both. 3047*5331Samw */ 3048*5331Samw if (sharepath == NULL && rsrcname == NULL) { 3049*5331Samw (void) printf(gettext("usage: %s\n"), 3050*5331Samw sa_get_usage(USAGE_SET_SHARE)); 3051*5331Samw ret = SA_SYNTAX_ERR; 3052*5331Samw } 3053*5331Samw 30544653Sdougm if (ret != SA_OK) 30554653Sdougm return (ret); 30564653Sdougm 30574653Sdougm if (optind < argc) { 30583034Sdougm groupname = argv[optind]; 30593910Sdougm group = sa_get_group(handle, groupname); 30604653Sdougm } else { 30613034Sdougm group = NULL; 30623034Sdougm groupname = NULL; 30634653Sdougm } 3064*5331Samw if (rsrcname != NULL) { 3065*5331Samw /* 3066*5331Samw * If rsrcname exists, split rename syntax and then 3067*5331Samw * convert to utf 8 if no errors. 3068*5331Samw */ 3069*5331Samw newname = strchr(rsrcname, '='); 3070*5331Samw if (newname != NULL) { 3071*5331Samw *newname++ = '\0'; 3072*5331Samw } 3073*5331Samw if (!validresource(rsrcname)) { 3074*5331Samw ret = SA_INVALID_NAME; 3075*5331Samw (void) printf(gettext("Invalid resource name: " 3076*5331Samw "\"%s\"\n"), rsrcname); 3077*5331Samw } else { 3078*5331Samw rsrc = conv_to_utf8(rsrcname); 3079*5331Samw } 3080*5331Samw if (newname != NULL) { 3081*5331Samw if (!validresource(newname)) { 3082*5331Samw ret = SA_INVALID_NAME; 3083*5331Samw (void) printf(gettext("Invalid resource name: " 3084*5331Samw "%s\n"), newname); 3085*5331Samw } else { 3086*5331Samw newrsrc = conv_to_utf8(newname); 3087*5331Samw } 3088*5331Samw } 3089*5331Samw } 3090*5331Samw 3091*5331Samw if (ret != SA_OK) { 3092*5331Samw if (rsrcname != NULL && rsrcname != rsrc) 3093*5331Samw sa_free_attr_string(rsrc); 3094*5331Samw if (newname != NULL && newname != newrsrc) 3095*5331Samw sa_free_attr_string(newrsrc); 3096*5331Samw return (ret); 3097*5331Samw } 3098*5331Samw 3099*5331Samw if (sharepath != NULL) { 3100*5331Samw share = sa_find_share(handle, sharepath); 3101*5331Samw } else if (rsrcname != NULL) { 3102*5331Samw resource = sa_find_resource(handle, rsrc); 3103*5331Samw if (resource != NULL) { 3104*5331Samw share = sa_get_resource_parent(resource); 3105*5331Samw } 3106*5331Samw } 3107*5331Samw if (share != NULL) { 3108*5331Samw sharegroup = sa_get_parent_group(share); 3109*5331Samw if (group != NULL && group != sharegroup) { 3110*5331Samw (void) printf(gettext("Group \"%s\" does not contain " 3111*5331Samw "share %s\n"), 3112*5331Samw argv[optind], sharepath); 3113*5331Samw ret = SA_BAD_PATH; 3114*5331Samw } else { 3115*5331Samw int delgroupname = 0; 3116*5331Samw if (groupname == NULL) { 3117*5331Samw groupname = sa_get_group_attr(sharegroup, 3118*5331Samw "name"); 3119*5331Samw delgroupname = 1; 3120*5331Samw } 3121*5331Samw if (groupname != NULL) { 3122*5331Samw auth = check_authorizations(groupname, flags); 3123*5331Samw if (delgroupname) { 3124*5331Samw sa_free_attr_string(groupname); 3125*5331Samw groupname = NULL; 3126*5331Samw } 3127*5331Samw } else { 3128*5331Samw ret = SA_NO_MEMORY; 3129*5331Samw } 3130*5331Samw if (rsrcname != NULL) { 3131*5331Samw resource = sa_find_resource(handle, rsrc); 3132*5331Samw if (!dryrun) { 3133*5331Samw if (newname != NULL && 3134*5331Samw resource != NULL) 3135*5331Samw ret = sa_rename_resource( 3136*5331Samw resource, newrsrc); 3137*5331Samw else if (newname != NULL) 3138*5331Samw ret = SA_NO_SUCH_RESOURCE; 3139*5331Samw if (newname != NULL && 3140*5331Samw newname != newrsrc) 3141*5331Samw sa_free_attr_string(newrsrc); 3142*5331Samw } 3143*5331Samw if (rsrc != rsrcname) 3144*5331Samw sa_free_attr_string(rsrc); 3145*5331Samw } 3146*5331Samw 3147*5331Samw /* 3148*5331Samw * If the user has set a description, it will be 3149*5331Samw * on the resource if -r was used otherwise it 3150*5331Samw * must be on the share. 3151*5331Samw */ 3152*5331Samw if (ret == SA_OK && description != NULL) { 3153*5331Samw desc = conv_to_utf8(description); 3154*5331Samw if (resource != NULL) 3155*5331Samw ret = sa_set_resource_description( 3156*5331Samw resource, desc); 3157*5331Samw else 3158*5331Samw ret = sa_set_share_description(share, 3159*5331Samw desc); 3160*5331Samw if (desc != description) 3161*5331Samw sa_free_share_description(desc); 3162*5331Samw } 3163*5331Samw } 3164*5331Samw if (!dryrun && ret == SA_OK) { 3165*5331Samw if (resource != NULL) 3166*5331Samw (void) sa_enable_resource(resource, NULL); 3167*5331Samw ret = sa_update_config(handle); 3168*5331Samw } 3169*5331Samw switch (ret) { 3170*5331Samw case SA_DUPLICATE_NAME: 3171*5331Samw (void) printf(gettext("Resource name in use: %s\n"), 3172*5331Samw rsrcname); 3173*5331Samw break; 3174*5331Samw default: 3175*5331Samw (void) printf(gettext("Could not set: %s\n"), 3176*5331Samw sa_errorstr(ret)); 3177*5331Samw break; 3178*5331Samw case SA_OK: 3179*5331Samw if (dryrun && !auth && verbose) { 3180*5331Samw (void) printf(gettext( 3181*5331Samw "Command would fail: %s\n"), 3182*5331Samw sa_errorstr(SA_NO_PERMISSION)); 3183*5331Samw } 3184*5331Samw break; 3185*5331Samw } 3186*5331Samw } else { 31874653Sdougm (void) printf(gettext("Share path \"%s\" not found\n"), 31884653Sdougm sharepath); 3189*5331Samw ret = SA_NO_SUCH_PATH; 31903034Sdougm } 31914653Sdougm 31923034Sdougm return (ret); 31933034Sdougm } 31943034Sdougm 31953034Sdougm /* 31963034Sdougm * add_security(group, sectype, optlist, proto, *err) 31973034Sdougm * 31983034Sdougm * Helper function to add a security option (named optionset) to the 31993034Sdougm * group. 32003034Sdougm */ 32013034Sdougm 32023034Sdougm static int 32033034Sdougm add_security(sa_group_t group, char *sectype, 3204*5331Samw struct options *optlist, char *proto, int *err) 32053034Sdougm { 32063034Sdougm sa_security_t security; 32073034Sdougm int ret = SA_OK; 32083034Sdougm int result = 0; 32093034Sdougm 32103034Sdougm sectype = sa_proto_space_alias(proto, sectype); 32113034Sdougm security = sa_get_security(group, sectype, proto); 32124653Sdougm if (security == NULL) 32134653Sdougm security = sa_create_security(group, sectype, proto); 32144653Sdougm 32153034Sdougm if (sectype != NULL) 32164653Sdougm sa_free_attr_string(sectype); 32174653Sdougm 32184653Sdougm if (security == NULL) 32194653Sdougm return (ret); 32204653Sdougm 32214653Sdougm while (optlist != NULL) { 32223034Sdougm sa_property_t prop; 32233034Sdougm prop = sa_get_property(security, optlist->optname); 32243034Sdougm if (prop == NULL) { 32253034Sdougm /* 32264653Sdougm * Add the property, but only if it is 32273034Sdougm * a non-NULL or non-zero length value 32283034Sdougm */ 32294653Sdougm if (optlist->optvalue != NULL) { 32304653Sdougm prop = sa_create_property(optlist->optname, 32314653Sdougm optlist->optvalue); 32324653Sdougm if (prop != NULL) { 3233*5331Samw ret = sa_valid_property(security, 3234*5331Samw proto, prop); 32354653Sdougm if (ret != SA_OK) { 32364653Sdougm (void) sa_remove_property(prop); 32374653Sdougm (void) printf(gettext( 32384653Sdougm "Could not add " 32394653Sdougm "property %s: %s\n"), 32404653Sdougm optlist->optname, 32414653Sdougm sa_errorstr(ret)); 32424653Sdougm } 32434653Sdougm if (ret == SA_OK) { 32444653Sdougm ret = sa_add_property(security, 32454653Sdougm prop); 32464653Sdougm if (ret != SA_OK) { 32474653Sdougm (void) printf(gettext( 32484653Sdougm "Could not add " 3249*5331Samw "property (%s=%s):" 3250*5331Samw " %s\n"), 32514653Sdougm optlist->optname, 32524653Sdougm optlist->optvalue, 32534653Sdougm sa_errorstr(ret)); 32544653Sdougm } else { 32554653Sdougm result = 1; 32564653Sdougm } 32574653Sdougm } 32583034Sdougm } 32593034Sdougm } 32603034Sdougm } else { 32614653Sdougm ret = sa_update_property(prop, optlist->optvalue); 32624653Sdougm result = 1; /* should check if really changed */ 32633034Sdougm } 32643034Sdougm optlist = optlist->next; 32654653Sdougm } 32664653Sdougm /* 32674653Sdougm * When done, properties may have all been removed but 32684653Sdougm * we need to keep the security type itself until 32694653Sdougm * explicitly removed. 32704653Sdougm */ 32714653Sdougm if (result) 32723034Sdougm ret = sa_commit_properties(security, 0); 32733034Sdougm *err = ret; 32743034Sdougm return (result); 32753034Sdougm } 32763034Sdougm 32773034Sdougm /* 32785089Sdougm * zfscheck(group, share) 32795089Sdougm * 32805089Sdougm * For the special case where a share was provided, make sure it is a 32815089Sdougm * compatible path for a ZFS property change. The only path 32825089Sdougm * acceptable is the path that defines the zfs sub-group (dataset with 32835089Sdougm * the sharenfs property set) and not one of the paths that inherited 32845089Sdougm * the NFS properties. Returns SA_OK if it is usable and 32855089Sdougm * SA_NOT_ALLOWED if it isn't. 32865089Sdougm * 32875089Sdougm * If group is not a ZFS group/subgroup, we assume OK since the check 32885089Sdougm * on return will catch errors for those cases. What we are looking 32895089Sdougm * for here is that the group is ZFS and the share is not the defining 32905089Sdougm * share. All else is SA_OK. 32915089Sdougm */ 32925089Sdougm 32935089Sdougm static int 32945089Sdougm zfscheck(sa_group_t group, sa_share_t share) 32955089Sdougm { 32965089Sdougm int ret = SA_OK; 32975089Sdougm char *attr; 32985089Sdougm 32995089Sdougm if (sa_group_is_zfs(group)) { 33005089Sdougm /* 33015089Sdougm * The group is a ZFS group. Does the share represent 33025089Sdougm * the dataset that defined the group? It is only OK 33035089Sdougm * if the attribute "subgroup" exists on the share and 33045089Sdougm * has a value of "true". 33055089Sdougm */ 33065089Sdougm 33075089Sdougm ret = SA_NOT_ALLOWED; 33085089Sdougm attr = sa_get_share_attr(share, "subgroup"); 33095089Sdougm if (attr != NULL) { 33105089Sdougm if (strcmp(attr, "true") == 0) 33115089Sdougm ret = SA_OK; 33125089Sdougm sa_free_attr_string(attr); 33135089Sdougm } 33145089Sdougm } 33155089Sdougm return (ret); 33165089Sdougm } 33175089Sdougm 33185089Sdougm /* 3319*5331Samw * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 33203034Sdougm * 33213034Sdougm * This function implements "set" when a name space (-S) is not 33223034Sdougm * specified. It is a basic set. Options and other CLI parsing has 33233034Sdougm * already been done. 3324*5331Samw * 3325*5331Samw * "rsrcname" is a "resource name". If it is non-NULL, it must match 3326*5331Samw * the sharepath if present or group if present, otherwise it is used 3327*5331Samw * to set options. 3328*5331Samw * 3329*5331Samw * Resource names may take options if the protocol supports it. If the 3330*5331Samw * protocol doesn't support resource level options, rsrcname is just 3331*5331Samw * an alias for the share. 33323034Sdougm */ 33333034Sdougm 33343034Sdougm static int 33353910Sdougm basic_set(sa_handle_t handle, char *groupname, struct options *optlist, 3336*5331Samw char *protocol, char *sharepath, char *rsrcname, int dryrun) 33373034Sdougm { 33383034Sdougm sa_group_t group; 33393034Sdougm int ret = SA_OK; 33403034Sdougm int change = 0; 33413034Sdougm struct list *worklist = NULL; 33423034Sdougm 33433910Sdougm group = sa_get_group(handle, groupname); 33443034Sdougm if (group != NULL) { 33454653Sdougm sa_share_t share = NULL; 3346*5331Samw sa_resource_t resource = NULL; 3347*5331Samw 3348*5331Samw /* 3349*5331Samw * If there is a sharepath, make sure it belongs to 3350*5331Samw * the group. 3351*5331Samw */ 33524653Sdougm if (sharepath != NULL) { 33534653Sdougm share = sa_get_share(group, sharepath); 33544653Sdougm if (share == NULL) { 33554653Sdougm (void) printf(gettext( 33564653Sdougm "Share does not exist in group %s\n"), 33574653Sdougm groupname, sharepath); 33584653Sdougm ret = SA_NO_SUCH_PATH; 33595089Sdougm } else { 33605089Sdougm /* if ZFS and OK, then only group */ 33615089Sdougm ret = zfscheck(group, share); 33625089Sdougm if (ret == SA_OK && 33635089Sdougm sa_group_is_zfs(group)) 33645089Sdougm share = NULL; 33655089Sdougm if (ret == SA_NOT_ALLOWED) 33665089Sdougm (void) printf(gettext( 33675089Sdougm "Properties on ZFS group shares " 33685089Sdougm "not supported: %s\n"), sharepath); 33694653Sdougm } 33703034Sdougm } 3371*5331Samw 3372*5331Samw /* 3373*5331Samw * If a resource name exists, make sure it belongs to 3374*5331Samw * the share if present else it belongs to the 3375*5331Samw * group. Also check the protocol to see if it 3376*5331Samw * supports resource level properties or not. If not, 3377*5331Samw * use share only. 3378*5331Samw */ 3379*5331Samw if (rsrcname != NULL) { 3380*5331Samw if (share != NULL) { 3381*5331Samw resource = sa_get_share_resource(share, 3382*5331Samw rsrcname); 3383*5331Samw if (resource == NULL) 3384*5331Samw ret = SA_NO_SUCH_RESOURCE; 3385*5331Samw } else { 3386*5331Samw resource = sa_get_resource(group, rsrcname); 3387*5331Samw if (resource != NULL) 3388*5331Samw share = sa_get_resource_parent( 3389*5331Samw resource); 3390*5331Samw else 3391*5331Samw ret = SA_NO_SUCH_RESOURCE; 3392*5331Samw } 3393*5331Samw if (ret == SA_OK && resource != NULL) { 3394*5331Samw uint64_t features; 3395*5331Samw /* 3396*5331Samw * Check to see if the resource can take 3397*5331Samw * properties. If so, stick the resource into 3398*5331Samw * "share" so it will all just work. 3399*5331Samw */ 3400*5331Samw features = sa_proto_get_featureset(protocol); 3401*5331Samw if (features & SA_FEATURE_RESOURCE) 3402*5331Samw share = (sa_share_t)resource; 3403*5331Samw } 3404*5331Samw } 3405*5331Samw 34064653Sdougm if (ret == SA_OK) { 34074653Sdougm /* group must exist */ 34084653Sdougm ret = valid_options(optlist, protocol, 34094653Sdougm share == NULL ? group : share, NULL); 34104653Sdougm if (ret == SA_OK && !dryrun) { 34114653Sdougm if (share != NULL) 34124653Sdougm change |= add_optionset(share, optlist, 34134653Sdougm protocol, &ret); 34144653Sdougm else 34154653Sdougm change |= add_optionset(group, optlist, 34164653Sdougm protocol, &ret); 34174653Sdougm if (ret == SA_OK && change) 34184653Sdougm worklist = add_list(worklist, group, 3419*5331Samw share, protocol); 34204653Sdougm } 34213034Sdougm } 34224653Sdougm free_opt(optlist); 34233034Sdougm } else { 34243034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 34253034Sdougm ret = SA_NO_SUCH_GROUP; 34263034Sdougm } 34273034Sdougm /* 34283034Sdougm * we have a group and potentially legal additions 34293034Sdougm */ 34303034Sdougm 34314653Sdougm /* 34324653Sdougm * Commit to configuration if not a dryrunp and properties 34334653Sdougm * have changed. 34344653Sdougm */ 34354653Sdougm if (!dryrun && ret == SA_OK && change && worklist != NULL) 34363034Sdougm /* properties changed, so update all shares */ 3437*5331Samw (void) enable_all_groups(handle, worklist, 0, 0, protocol, 3438*5331Samw B_TRUE); 34394653Sdougm 34403034Sdougm if (worklist != NULL) 34414653Sdougm free_list(worklist); 34423034Sdougm return (ret); 34433034Sdougm } 34443034Sdougm 34453034Sdougm /* 34463034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 34473034Sdougm * 34483034Sdougm * This function implements "set" when a name space (-S) is 34493034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 34503034Sdougm * already been done. 34513034Sdougm */ 34523034Sdougm 34533034Sdougm static int 34543910Sdougm space_set(sa_handle_t handle, char *groupname, struct options *optlist, 3455*5331Samw char *protocol, char *sharepath, int dryrun, char *sectype) 34563034Sdougm { 34573034Sdougm sa_group_t group; 34583034Sdougm int ret = SA_OK; 34593034Sdougm int change = 0; 34603034Sdougm struct list *worklist = NULL; 34613034Sdougm 34623034Sdougm /* 34633034Sdougm * make sure protcol and sectype are valid 34643034Sdougm */ 34653034Sdougm 34663034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 34674653Sdougm (void) printf(gettext("Option space \"%s\" not valid " 34684653Sdougm "for protocol.\n"), sectype); 34694653Sdougm return (SA_INVALID_SECURITY); 34703034Sdougm } 34713034Sdougm 34723910Sdougm group = sa_get_group(handle, groupname); 34733034Sdougm if (group != NULL) { 34744653Sdougm sa_share_t share = NULL; 34754653Sdougm if (sharepath != NULL) { 34764653Sdougm share = sa_get_share(group, sharepath); 34774653Sdougm if (share == NULL) { 34784653Sdougm (void) printf(gettext( 34794653Sdougm "Share does not exist in group %s\n"), 34804653Sdougm groupname, sharepath); 34814653Sdougm ret = SA_NO_SUCH_PATH; 34825089Sdougm } else { 34835089Sdougm /* if ZFS and OK, then only group */ 34845089Sdougm ret = zfscheck(group, share); 34855089Sdougm if (ret == SA_OK && 34865089Sdougm sa_group_is_zfs(group)) 34875089Sdougm share = NULL; 34885089Sdougm if (ret == SA_NOT_ALLOWED) 34895089Sdougm (void) printf(gettext( 34905089Sdougm "Properties on ZFS group shares " 34915089Sdougm "not supported: %s\n"), sharepath); 34924653Sdougm } 34933034Sdougm } 34944653Sdougm if (ret == SA_OK) { 34954653Sdougm /* group must exist */ 34964653Sdougm ret = valid_options(optlist, protocol, 34974653Sdougm share == NULL ? group : share, sectype); 34984653Sdougm if (ret == SA_OK && !dryrun) { 34994653Sdougm if (share != NULL) 35004653Sdougm change = add_security(share, sectype, 35014653Sdougm optlist, protocol, &ret); 35024653Sdougm else 35034653Sdougm change = add_security(group, sectype, 35044653Sdougm optlist, protocol, &ret); 35054653Sdougm if (ret != SA_OK) 35064653Sdougm (void) printf(gettext( 35074653Sdougm "Could not set property: %s\n"), 35084653Sdougm sa_errorstr(ret)); 35094653Sdougm } 35104653Sdougm if (ret == SA_OK && change) 3511*5331Samw worklist = add_list(worklist, group, share, 3512*5331Samw protocol); 35133034Sdougm } 35144653Sdougm free_opt(optlist); 35153034Sdougm } else { 35163034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 35173034Sdougm ret = SA_NO_SUCH_GROUP; 35183034Sdougm } 3519*5331Samw 35203034Sdougm /* 3521*5331Samw * We have a group and potentially legal additions. 35223034Sdougm */ 35233034Sdougm 35244653Sdougm /* Commit to configuration if not a dryrun */ 35253034Sdougm if (!dryrun && ret == 0) { 35264653Sdougm if (change && worklist != NULL) { 35274653Sdougm /* properties changed, so update all shares */ 35284653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 3529*5331Samw protocol, B_TRUE); 35304653Sdougm } 35314653Sdougm ret = sa_update_config(handle); 35323034Sdougm } 35333034Sdougm if (worklist != NULL) 35344653Sdougm free_list(worklist); 35353034Sdougm return (ret); 35363034Sdougm } 35373034Sdougm 35383034Sdougm /* 35393034Sdougm * sa_set(flags, argc, argv) 35403034Sdougm * 35413034Sdougm * Implements the set subcommand. It keys off of -S to determine which 35423034Sdougm * set of operations to actually do. 35433034Sdougm */ 35443034Sdougm 35453034Sdougm int 35463910Sdougm sa_set(sa_handle_t handle, int flags, int argc, char *argv[]) 35473034Sdougm { 35483034Sdougm char *groupname; 35493034Sdougm int verbose = 0; 35503034Sdougm int dryrun = 0; 35513034Sdougm int c; 35523034Sdougm char *protocol = NULL; 35533034Sdougm int ret = SA_OK; 35543034Sdougm struct options *optlist = NULL; 3555*5331Samw char *rsrcname = NULL; 35563034Sdougm char *sharepath = NULL; 35573034Sdougm char *optset = NULL; 35583034Sdougm int auth; 35593034Sdougm 3560*5331Samw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 35614653Sdougm switch (c) { 35624653Sdougm case 'v': 35634653Sdougm verbose++; 35644653Sdougm break; 35654653Sdougm case 'n': 35664653Sdougm dryrun++; 35674653Sdougm break; 35684653Sdougm case 'P': 3569*5331Samw if (protocol != NULL) { 3570*5331Samw (void) printf(gettext( 3571*5331Samw "Specifying multiple protocols " 3572*5331Samw "not supported: %s\n"), protocol); 3573*5331Samw return (SA_SYNTAX_ERR); 3574*5331Samw } 35754653Sdougm protocol = optarg; 35764653Sdougm if (!sa_valid_protocol(protocol)) { 35774653Sdougm (void) printf(gettext( 35784653Sdougm "Invalid protocol specified: %s\n"), 35794653Sdougm protocol); 35804653Sdougm return (SA_INVALID_PROTOCOL); 35814653Sdougm } 35824653Sdougm break; 35834653Sdougm case 'p': 35844653Sdougm ret = add_opt(&optlist, optarg, 0); 35854653Sdougm switch (ret) { 35864653Sdougm case OPT_ADD_SYNTAX: 35874653Sdougm (void) printf(gettext("Property syntax error:" 35884653Sdougm " %s\n"), optarg); 35894653Sdougm return (SA_SYNTAX_ERR); 35904653Sdougm case OPT_ADD_MEMORY: 35914653Sdougm (void) printf(gettext("No memory to set " 35924653Sdougm "property: %s\n"), optarg); 35934653Sdougm return (SA_NO_MEMORY); 35944653Sdougm default: 35954653Sdougm break; 35964653Sdougm } 35974653Sdougm break; 3598*5331Samw case 'r': 3599*5331Samw if (rsrcname != NULL) { 3600*5331Samw (void) printf(gettext( 3601*5331Samw "Setting multiple resource names not" 3602*5331Samw " supported\n")); 3603*5331Samw return (SA_SYNTAX_ERR); 3604*5331Samw } 3605*5331Samw rsrcname = optarg; 3606*5331Samw break; 36074653Sdougm case 's': 3608*5331Samw if (sharepath != NULL) { 3609*5331Samw (void) printf(gettext( 3610*5331Samw "Setting multiple shares not supported\n")); 3611*5331Samw return (SA_SYNTAX_ERR); 3612*5331Samw } 36134653Sdougm sharepath = optarg; 36144653Sdougm break; 36154653Sdougm case 'S': 3616*5331Samw if (optset != NULL) { 3617*5331Samw (void) printf(gettext( 3618*5331Samw "Specifying multiple property " 3619*5331Samw "spaces not supported: %s\n"), optset); 3620*5331Samw return (SA_SYNTAX_ERR); 3621*5331Samw } 36224653Sdougm optset = optarg; 36234653Sdougm break; 36244653Sdougm default: 36254653Sdougm case 'h': 36264653Sdougm case '?': 36274653Sdougm (void) printf(gettext("usage: %s\n"), 36284653Sdougm sa_get_usage(USAGE_SET)); 36294653Sdougm return (SA_OK); 36303034Sdougm } 36313034Sdougm } 36323034Sdougm 36333034Sdougm if (optlist != NULL) 36344653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 36353034Sdougm 36363034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 36374653Sdougm protocol == NULL || ret != OPT_ADD_OK) { 36384653Sdougm char *sep = "\t"; 36394653Sdougm 36404653Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 36414653Sdougm if (optind >= argc) { 36424653Sdougm (void) printf(gettext("%sgroup must be specified"), 36434653Sdougm sep); 36444653Sdougm sep = ", "; 36454653Sdougm } 36464653Sdougm if (optlist == NULL) { 36474653Sdougm (void) printf(gettext("%sat least one property must be" 36484653Sdougm " specified"), sep); 36494653Sdougm sep = ", "; 36504653Sdougm } 36514653Sdougm if (protocol == NULL) { 36524653Sdougm (void) printf(gettext("%sprotocol must be specified"), 36534653Sdougm sep); 36544653Sdougm sep = ", "; 36554653Sdougm } 36564653Sdougm (void) printf("\n"); 36574653Sdougm ret = SA_SYNTAX_ERR; 36583034Sdougm } else { 36593034Sdougm /* 36605089Sdougm * Group already exists so we can proceed after a few 36615089Sdougm * additional checks related to ZFS handling. 36623034Sdougm */ 36633034Sdougm 36644653Sdougm groupname = argv[optind]; 36655089Sdougm if (strcmp(groupname, "zfs") == 0) { 36665089Sdougm (void) printf(gettext("Changing properties for group " 36675089Sdougm "\"zfs\" not allowed\n")); 36685089Sdougm return (SA_NOT_ALLOWED); 36695089Sdougm } 36705089Sdougm 36714653Sdougm auth = check_authorizations(groupname, flags); 36724653Sdougm if (optset == NULL) 36734653Sdougm ret = basic_set(handle, groupname, optlist, protocol, 3674*5331Samw sharepath, rsrcname, dryrun); 36754653Sdougm else 36764653Sdougm ret = space_set(handle, groupname, optlist, protocol, 36774653Sdougm sharepath, dryrun, optset); 36784653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 36794653Sdougm (void) printf(gettext("Command would fail: %s\n"), 36804653Sdougm sa_errorstr(SA_NO_PERMISSION)); 36814653Sdougm } 36823034Sdougm } 36833034Sdougm return (ret); 36843034Sdougm } 36853034Sdougm 36863034Sdougm /* 36873034Sdougm * remove_options(group, optlist, proto, *err) 36883034Sdougm * 36894653Sdougm * Helper function to actually remove options from a group after all 36903034Sdougm * preprocessing is done. 36913034Sdougm */ 36923034Sdougm 36933034Sdougm static int 36943034Sdougm remove_options(sa_group_t group, struct options *optlist, 3695*5331Samw char *proto, int *err) 36963034Sdougm { 36973034Sdougm struct options *cur; 36983034Sdougm sa_optionset_t optionset; 36993034Sdougm sa_property_t prop; 37003034Sdougm int change = 0; 37013034Sdougm int ret = SA_OK; 37023034Sdougm 37033034Sdougm optionset = sa_get_optionset(group, proto); 37043034Sdougm if (optionset != NULL) { 37054653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 37064653Sdougm prop = sa_get_property(optionset, cur->optname); 37074653Sdougm if (prop != NULL) { 37084653Sdougm ret = sa_remove_property(prop); 37094653Sdougm if (ret != SA_OK) 37104653Sdougm break; 37114653Sdougm change = 1; 37124653Sdougm } 37133034Sdougm } 37143034Sdougm } 37153034Sdougm if (ret == SA_OK && change) 37164653Sdougm ret = sa_commit_properties(optionset, 0); 37173034Sdougm 37183034Sdougm if (err != NULL) 37194653Sdougm *err = ret; 37203034Sdougm return (change); 37213034Sdougm } 37223034Sdougm 37233034Sdougm /* 37243034Sdougm * valid_unset(group, optlist, proto) 37253034Sdougm * 37263034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 37273034Sdougm * error if a property doesn't exist. 37283034Sdougm */ 37293034Sdougm 37303034Sdougm static int 37313034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 37323034Sdougm { 37333034Sdougm struct options *cur; 37343034Sdougm sa_optionset_t optionset; 37353034Sdougm sa_property_t prop; 37363034Sdougm int ret = SA_OK; 37373034Sdougm 37383034Sdougm optionset = sa_get_optionset(group, proto); 37393034Sdougm if (optionset != NULL) { 37404653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 37414653Sdougm prop = sa_get_property(optionset, cur->optname); 37424653Sdougm if (prop == NULL) { 37434653Sdougm (void) printf(gettext( 37444653Sdougm "Could not unset property %s: not set\n"), 37454653Sdougm cur->optname); 37464653Sdougm ret = SA_NO_SUCH_PROP; 37474653Sdougm } 37483034Sdougm } 37493034Sdougm } 37503034Sdougm return (ret); 37513034Sdougm } 37523034Sdougm 37533034Sdougm /* 37543034Sdougm * valid_unset_security(group, optlist, proto) 37553034Sdougm * 37563034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 37573034Sdougm * error if a property doesn't exist. 37583034Sdougm */ 37593034Sdougm 37603034Sdougm static int 37613034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 3762*5331Samw char *sectype) 37633034Sdougm { 37643034Sdougm struct options *cur; 37653034Sdougm sa_security_t security; 37663034Sdougm sa_property_t prop; 37673034Sdougm int ret = SA_OK; 37683034Sdougm char *sec; 37693034Sdougm 37703034Sdougm sec = sa_proto_space_alias(proto, sectype); 37713034Sdougm security = sa_get_security(group, sec, proto); 37723034Sdougm if (security != NULL) { 37734653Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 37744653Sdougm prop = sa_get_property(security, cur->optname); 37754653Sdougm if (prop == NULL) { 37764653Sdougm (void) printf(gettext( 37774653Sdougm "Could not unset property %s: not set\n"), 37784653Sdougm cur->optname); 37794653Sdougm ret = SA_NO_SUCH_PROP; 37804653Sdougm } 37813034Sdougm } 37823034Sdougm } else { 37834653Sdougm (void) printf(gettext( 37844653Sdougm "Could not unset %s: space not defined\n"), sectype); 37854653Sdougm ret = SA_NO_SUCH_SECURITY; 37863034Sdougm } 37873034Sdougm if (sec != NULL) 37884653Sdougm sa_free_attr_string(sec); 37893034Sdougm return (ret); 37903034Sdougm } 37913034Sdougm 37923034Sdougm /* 37933034Sdougm * remove_security(group, optlist, proto) 37943034Sdougm * 37953034Sdougm * Remove the properties since they were checked as valid. 37963034Sdougm */ 37973034Sdougm 37983034Sdougm static int 37993034Sdougm remove_security(sa_group_t group, char *sectype, 3800*5331Samw struct options *optlist, char *proto, int *err) 38013034Sdougm { 38023034Sdougm sa_security_t security; 38033034Sdougm int ret = SA_OK; 38043034Sdougm int change = 0; 38053034Sdougm 38063034Sdougm sectype = sa_proto_space_alias(proto, sectype); 38073034Sdougm security = sa_get_security(group, sectype, proto); 38083034Sdougm if (sectype != NULL) 38094653Sdougm sa_free_attr_string(sectype); 38103034Sdougm 38113034Sdougm if (security != NULL) { 38124653Sdougm while (optlist != NULL) { 38134653Sdougm sa_property_t prop; 38144653Sdougm prop = sa_get_property(security, optlist->optname); 38154653Sdougm if (prop != NULL) { 38164653Sdougm ret = sa_remove_property(prop); 38174653Sdougm if (ret != SA_OK) 38184653Sdougm break; 38194653Sdougm change = 1; 38204653Sdougm } 38214653Sdougm optlist = optlist->next; 38223034Sdougm } 38233034Sdougm /* 38243034Sdougm * when done, properties may have all been removed but 38253034Sdougm * we need to keep the security type itself until 38263034Sdougm * explicitly removed. 38273034Sdougm */ 38284653Sdougm if (ret == SA_OK && change) 38294653Sdougm ret = sa_commit_properties(security, 0); 38303034Sdougm } else { 38314653Sdougm ret = SA_NO_SUCH_PROP; 38323034Sdougm } 38333034Sdougm if (err != NULL) 38344653Sdougm *err = ret; 38353034Sdougm return (change); 38363034Sdougm } 38373034Sdougm 38383034Sdougm /* 3839*5331Samw * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun) 38403034Sdougm * 38414653Sdougm * Unset non-named optionset properties. 38423034Sdougm */ 38433034Sdougm 38443034Sdougm static int 38453910Sdougm basic_unset(sa_handle_t handle, char *groupname, struct options *optlist, 3846*5331Samw char *protocol, char *sharepath, char *rsrcname, int dryrun) 38473034Sdougm { 38483034Sdougm sa_group_t group; 38493034Sdougm int ret = SA_OK; 38503034Sdougm int change = 0; 38513034Sdougm struct list *worklist = NULL; 38524653Sdougm sa_share_t share = NULL; 3853*5331Samw sa_resource_t resource = NULL; 38543034Sdougm 38553910Sdougm group = sa_get_group(handle, groupname); 38564653Sdougm if (group == NULL) 38574653Sdougm return (ret); 38584653Sdougm 3859*5331Samw /* 3860*5331Samw * If there is a sharepath, make sure it belongs to 3861*5331Samw * the group. 3862*5331Samw */ 38634653Sdougm if (sharepath != NULL) { 38643034Sdougm share = sa_get_share(group, sharepath); 38653034Sdougm if (share == NULL) { 38664653Sdougm (void) printf(gettext( 38674653Sdougm "Share does not exist in group %s\n"), 38684653Sdougm groupname, sharepath); 38694653Sdougm ret = SA_NO_SUCH_PATH; 38703034Sdougm } 38714653Sdougm } 3872*5331Samw /* 3873*5331Samw * If a resource name exists, make sure it belongs to 3874*5331Samw * the share if present else it belongs to the 3875*5331Samw * group. Also check the protocol to see if it 3876*5331Samw * supports resource level properties or not. If not, 3877*5331Samw * use share only. 3878*5331Samw */ 3879*5331Samw if (rsrcname != NULL) { 3880*5331Samw if (share != NULL) { 3881*5331Samw resource = sa_get_share_resource(share, rsrcname); 3882*5331Samw if (resource == NULL) 3883*5331Samw ret = SA_NO_SUCH_RESOURCE; 3884*5331Samw } else { 3885*5331Samw resource = sa_get_resource(group, rsrcname); 3886*5331Samw if (resource != NULL) { 3887*5331Samw share = sa_get_resource_parent(resource); 3888*5331Samw } else { 3889*5331Samw ret = SA_NO_SUCH_RESOURCE; 3890*5331Samw } 3891*5331Samw } 3892*5331Samw if (ret == SA_OK && resource != NULL) { 3893*5331Samw uint64_t features; 3894*5331Samw /* 3895*5331Samw * Check to see if the resource can take 3896*5331Samw * properties. If so, stick the resource into 3897*5331Samw * "share" so it will all just work. 3898*5331Samw */ 3899*5331Samw features = sa_proto_get_featureset(protocol); 3900*5331Samw if (features & SA_FEATURE_RESOURCE) 3901*5331Samw share = (sa_share_t)resource; 3902*5331Samw } 3903*5331Samw } 3904*5331Samw 39054653Sdougm if (ret == SA_OK) { 39063034Sdougm /* group must exist */ 39073034Sdougm ret = valid_unset(share != NULL ? share : group, 39084653Sdougm optlist, protocol); 39093034Sdougm if (ret == SA_OK && !dryrun) { 39104653Sdougm if (share != NULL) { 39114653Sdougm sa_optionset_t optionset; 39124653Sdougm sa_property_t prop; 39134653Sdougm change |= remove_options(share, optlist, 39144653Sdougm protocol, &ret); 39154653Sdougm /* 39164653Sdougm * If a share optionset is 39174653Sdougm * empty, remove it. 39184653Sdougm */ 39194653Sdougm optionset = sa_get_optionset((sa_share_t)share, 39204653Sdougm protocol); 39214653Sdougm if (optionset != NULL) { 39224653Sdougm prop = sa_get_property(optionset, NULL); 39234653Sdougm if (prop == NULL) 39244653Sdougm (void) sa_destroy_optionset( 39254653Sdougm optionset); 39264653Sdougm } 39274653Sdougm } else { 39284653Sdougm change |= remove_options(group, 39294653Sdougm optlist, protocol, &ret); 39303034Sdougm } 39314653Sdougm if (ret == SA_OK && change) 3932*5331Samw worklist = add_list(worklist, group, share, 3933*5331Samw protocol); 39344653Sdougm if (ret != SA_OK) 39354653Sdougm (void) printf(gettext( 39364653Sdougm "Could not remove properties: " 39374653Sdougm "%s\n"), sa_errorstr(ret)); 39383034Sdougm } 39394653Sdougm } else { 3940*5331Samw (void) printf(gettext("Group \"%s\" not found\n"), groupname); 39413034Sdougm ret = SA_NO_SUCH_GROUP; 39423034Sdougm } 39434653Sdougm free_opt(optlist); 39443034Sdougm 39453034Sdougm /* 39464653Sdougm * We have a group and potentially legal additions 39474653Sdougm * 39484653Sdougm * Commit to configuration if not a dryrun 39493034Sdougm */ 39503034Sdougm if (!dryrun && ret == SA_OK) { 39514653Sdougm if (change && worklist != NULL) { 39524653Sdougm /* properties changed, so update all shares */ 39534653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 3954*5331Samw protocol, B_TRUE); 39554653Sdougm } 39563034Sdougm } 39573034Sdougm if (worklist != NULL) 39584653Sdougm free_list(worklist); 39593034Sdougm return (ret); 39603034Sdougm } 39613034Sdougm 39623034Sdougm /* 39633034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 39643034Sdougm * 39654653Sdougm * Unset named optionset properties. 39663034Sdougm */ 39673034Sdougm static int 39683910Sdougm space_unset(sa_handle_t handle, char *groupname, struct options *optlist, 3969*5331Samw char *protocol, char *sharepath, int dryrun, char *sectype) 39703034Sdougm { 39713034Sdougm sa_group_t group; 39723034Sdougm int ret = SA_OK; 39733034Sdougm int change = 0; 39743034Sdougm struct list *worklist = NULL; 39754653Sdougm sa_share_t share = NULL; 39763034Sdougm 39773910Sdougm group = sa_get_group(handle, groupname); 39784653Sdougm if (group == NULL) { 39794653Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 39804653Sdougm return (SA_NO_SUCH_GROUP); 39814653Sdougm } 39824653Sdougm if (sharepath != NULL) { 39833034Sdougm share = sa_get_share(group, sharepath); 39843034Sdougm if (share == NULL) { 39854653Sdougm (void) printf(gettext( 39864653Sdougm "Share does not exist in group %s\n"), 39874653Sdougm groupname, sharepath); 39884653Sdougm return (SA_NO_SUCH_PATH); 39893034Sdougm } 39904653Sdougm } 3991*5331Samw ret = valid_unset_security(share != NULL ? share : group, 3992*5331Samw optlist, protocol, sectype); 39934653Sdougm 39944653Sdougm if (ret == SA_OK && !dryrun) { 39954653Sdougm if (optlist != NULL) { 39963034Sdougm if (share != NULL) { 39974653Sdougm sa_security_t optionset; 39984653Sdougm sa_property_t prop; 39994653Sdougm change = remove_security(share, 40004653Sdougm sectype, optlist, protocol, &ret); 40014653Sdougm 40024653Sdougm /* If a share security is empty, remove it */ 40034653Sdougm optionset = sa_get_security((sa_group_t)share, 40044653Sdougm sectype, protocol); 40054653Sdougm if (optionset != NULL) { 40064653Sdougm prop = sa_get_property(optionset, 40074653Sdougm NULL); 40084653Sdougm if (prop == NULL) 40094653Sdougm ret = sa_destroy_security( 40104653Sdougm optionset); 40114653Sdougm } 40123034Sdougm } else { 40134653Sdougm change = remove_security(group, sectype, 40144653Sdougm optlist, protocol, &ret); 40153034Sdougm } 40164653Sdougm } else { 40173034Sdougm sa_security_t security; 40183034Sdougm char *sec; 40193034Sdougm sec = sa_proto_space_alias(protocol, sectype); 40203034Sdougm security = sa_get_security(group, sec, protocol); 40213034Sdougm if (sec != NULL) 40224653Sdougm sa_free_attr_string(sec); 40233034Sdougm if (security != NULL) { 40244653Sdougm ret = sa_destroy_security(security); 40254653Sdougm if (ret == SA_OK) 40264653Sdougm change = 1; 40273034Sdougm } else { 40284653Sdougm ret = SA_NO_SUCH_PROP; 40293034Sdougm } 40304653Sdougm } 40314653Sdougm if (ret != SA_OK) 40323034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 40334653Sdougm sa_errorstr(ret)); 40343034Sdougm } 40354653Sdougm 40364653Sdougm if (ret == SA_OK && change) 4037*5331Samw worklist = add_list(worklist, group, 0, protocol); 40384653Sdougm 40393034Sdougm free_opt(optlist); 40403034Sdougm /* 40414653Sdougm * We have a group and potentially legal additions 40423034Sdougm */ 40433034Sdougm 40444653Sdougm /* Commit to configuration if not a dryrun */ 40453034Sdougm if (!dryrun && ret == 0) { 40463034Sdougm /* properties changed, so update all shares */ 40474653Sdougm if (change && worklist != NULL) 40484653Sdougm (void) enable_all_groups(handle, worklist, 0, 0, 4049*5331Samw protocol, B_TRUE); 40504653Sdougm ret = sa_update_config(handle); 40513034Sdougm } 40523034Sdougm if (worklist != NULL) 40534653Sdougm free_list(worklist); 40543034Sdougm return (ret); 40553034Sdougm } 40563034Sdougm 40573034Sdougm /* 40583034Sdougm * sa_unset(flags, argc, argv) 40593034Sdougm * 40604653Sdougm * Implements the unset subcommand. Parsing done here and then basic 40613034Sdougm * or space versions of the real code are called. 40623034Sdougm */ 40633034Sdougm 40643034Sdougm int 40653910Sdougm sa_unset(sa_handle_t handle, int flags, int argc, char *argv[]) 40663034Sdougm { 40673034Sdougm char *groupname; 40683034Sdougm int verbose = 0; 40693034Sdougm int dryrun = 0; 40703034Sdougm int c; 40713034Sdougm char *protocol = NULL; 40723034Sdougm int ret = SA_OK; 40733034Sdougm struct options *optlist = NULL; 4074*5331Samw char *rsrcname = NULL; 40753034Sdougm char *sharepath = NULL; 40763034Sdougm char *optset = NULL; 40773034Sdougm int auth; 40783034Sdougm 4079*5331Samw while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) { 40804653Sdougm switch (c) { 40814653Sdougm case 'v': 40824653Sdougm verbose++; 40834653Sdougm break; 40844653Sdougm case 'n': 40854653Sdougm dryrun++; 40864653Sdougm break; 40874653Sdougm case 'P': 4088*5331Samw if (protocol != NULL) { 4089*5331Samw (void) printf(gettext( 4090*5331Samw "Specifying multiple protocols " 4091*5331Samw "not supported: %s\n"), protocol); 4092*5331Samw return (SA_SYNTAX_ERR); 4093*5331Samw } 40944653Sdougm protocol = optarg; 40954653Sdougm if (!sa_valid_protocol(protocol)) { 40964653Sdougm (void) printf(gettext( 40974653Sdougm "Invalid protocol specified: %s\n"), 40984653Sdougm protocol); 40994653Sdougm return (SA_INVALID_PROTOCOL); 41004653Sdougm } 41014653Sdougm break; 41024653Sdougm case 'p': 41034653Sdougm ret = add_opt(&optlist, optarg, 1); 41044653Sdougm switch (ret) { 41054653Sdougm case OPT_ADD_SYNTAX: 41064653Sdougm (void) printf(gettext("Property syntax error " 41074653Sdougm "for property %s\n"), optarg); 41084653Sdougm return (SA_SYNTAX_ERR); 41094653Sdougm 41104653Sdougm case OPT_ADD_PROPERTY: 41114653Sdougm (void) printf(gettext("Properties need to be " 41124653Sdougm "set with set command: %s\n"), optarg); 41134653Sdougm return (SA_SYNTAX_ERR); 41144653Sdougm 41154653Sdougm default: 41164653Sdougm break; 41174653Sdougm } 41184653Sdougm break; 4119*5331Samw case 'r': 4120*5331Samw /* 4121*5331Samw * Unset properties on resource if applicable or on 4122*5331Samw * share if resource for this protocol doesn't use 4123*5331Samw * resources. 4124*5331Samw */ 4125*5331Samw if (rsrcname != NULL) { 4126*5331Samw (void) printf(gettext( 4127*5331Samw "Unsetting multiple resource " 4128*5331Samw "names not supported\n")); 4129*5331Samw return (SA_SYNTAX_ERR); 4130*5331Samw } 4131*5331Samw rsrcname = optarg; 4132*5331Samw break; 41334653Sdougm case 's': 4134*5331Samw if (sharepath != NULL) { 4135*5331Samw (void) printf(gettext( 4136*5331Samw "Adding multiple shares not supported\n")); 4137*5331Samw return (SA_SYNTAX_ERR); 4138*5331Samw } 41394653Sdougm sharepath = optarg; 41404653Sdougm break; 41414653Sdougm case 'S': 4142*5331Samw if (optset != NULL) { 4143*5331Samw (void) printf(gettext( 4144*5331Samw "Specifying multiple property " 4145*5331Samw "spaces not supported: %s\n"), optset); 4146*5331Samw return (SA_SYNTAX_ERR); 4147*5331Samw } 41484653Sdougm optset = optarg; 41494653Sdougm break; 41504653Sdougm default: 41514653Sdougm case 'h': 41524653Sdougm case '?': 41534653Sdougm (void) printf(gettext("usage: %s\n"), 41544653Sdougm sa_get_usage(USAGE_UNSET)); 41554653Sdougm return (SA_OK); 41563034Sdougm } 41573034Sdougm } 41583034Sdougm 41593034Sdougm if (optlist != NULL) 41604653Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 41613034Sdougm 41623034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 41633034Sdougm protocol == NULL) { 41644653Sdougm char *sep = "\t"; 41654653Sdougm (void) printf(gettext("usage: %s\n"), 41664653Sdougm sa_get_usage(USAGE_UNSET)); 41674653Sdougm if (optind >= argc) { 41684653Sdougm (void) printf(gettext("%sgroup must be specified"), 41694653Sdougm sep); 41704653Sdougm sep = ", "; 41714653Sdougm } 41724653Sdougm if (optlist == NULL) { 41734653Sdougm (void) printf(gettext("%sat least one property must " 41744653Sdougm "be specified"), sep); 41754653Sdougm sep = ", "; 41764653Sdougm } 41774653Sdougm if (protocol == NULL) { 41784653Sdougm (void) printf(gettext("%sprotocol must be specified"), 41794653Sdougm sep); 41804653Sdougm sep = ", "; 41814653Sdougm } 41824653Sdougm (void) printf("\n"); 41834653Sdougm ret = SA_SYNTAX_ERR; 41843034Sdougm } else { 41853034Sdougm 41863034Sdougm /* 41874653Sdougm * If a group already exists, we can only add a new 41883034Sdougm * protocol to it and not create a new one or add the 41893034Sdougm * same protocol again. 41903034Sdougm */ 41913034Sdougm 41924653Sdougm groupname = argv[optind]; 41934653Sdougm auth = check_authorizations(groupname, flags); 41944653Sdougm if (optset == NULL) 41954653Sdougm ret = basic_unset(handle, groupname, optlist, protocol, 4196*5331Samw sharepath, rsrcname, dryrun); 41974653Sdougm else 41984653Sdougm ret = space_unset(handle, groupname, optlist, protocol, 41994653Sdougm sharepath, dryrun, optset); 42004653Sdougm 42014653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 42024653Sdougm (void) printf(gettext("Command would fail: %s\n"), 42034653Sdougm sa_errorstr(SA_NO_PERMISSION)); 42043034Sdougm } 42053034Sdougm return (ret); 42063034Sdougm } 42073034Sdougm 42083034Sdougm /* 42093034Sdougm * sa_enable_group(flags, argc, argv) 42103034Sdougm * 42113034Sdougm * Implements the enable subcommand 42123034Sdougm */ 42133034Sdougm 42143034Sdougm int 42153910Sdougm sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 42163034Sdougm { 42173034Sdougm int verbose = 0; 42183034Sdougm int dryrun = 0; 42193034Sdougm int all = 0; 42203034Sdougm int c; 42213034Sdougm int ret = SA_OK; 42223034Sdougm char *protocol = NULL; 42233034Sdougm char *state; 42243034Sdougm struct list *worklist = NULL; 42253034Sdougm int auth = 1; 42264653Sdougm sa_group_t group; 42273034Sdougm 42283034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 42294653Sdougm switch (c) { 42304653Sdougm case 'a': 42314653Sdougm all = 1; 42324653Sdougm break; 42334653Sdougm case 'n': 42344653Sdougm dryrun++; 42354653Sdougm break; 42364653Sdougm case 'P': 4237*5331Samw if (protocol != NULL) { 4238*5331Samw (void) printf(gettext( 4239*5331Samw "Specifying multiple protocols " 4240*5331Samw "not supported: %s\n"), protocol); 4241*5331Samw return (SA_SYNTAX_ERR); 4242*5331Samw } 42434653Sdougm protocol = optarg; 42444653Sdougm if (!sa_valid_protocol(protocol)) { 42454653Sdougm (void) printf(gettext( 42464653Sdougm "Invalid protocol specified: %s\n"), 42473034Sdougm protocol); 42484653Sdougm return (SA_INVALID_PROTOCOL); 42494653Sdougm } 42504653Sdougm break; 42514653Sdougm case 'v': 42524653Sdougm verbose++; 42534653Sdougm break; 42544653Sdougm default: 42554653Sdougm case 'h': 42564653Sdougm case '?': 42574653Sdougm (void) printf(gettext("usage: %s\n"), 42584653Sdougm sa_get_usage(USAGE_ENABLE)); 42594653Sdougm return (0); 42603034Sdougm } 42613034Sdougm } 42623034Sdougm 42633034Sdougm if (optind == argc && !all) { 42644653Sdougm (void) printf(gettext("usage: %s\n"), 42654653Sdougm sa_get_usage(USAGE_ENABLE)); 42664653Sdougm (void) printf(gettext("\tmust specify group\n")); 42674653Sdougm return (SA_NO_SUCH_PATH); 42684653Sdougm } 42694653Sdougm if (!all) { 42703034Sdougm while (optind < argc) { 42714653Sdougm group = sa_get_group(handle, argv[optind]); 42724653Sdougm if (group != NULL) { 42734653Sdougm auth &= check_authorizations(argv[optind], 42744653Sdougm flags); 42754653Sdougm state = sa_get_group_attr(group, "state"); 42764653Sdougm if (state != NULL && 42774653Sdougm strcmp(state, "enabled") == 0) { 42784653Sdougm /* already enabled */ 42794653Sdougm if (verbose) 42804653Sdougm (void) printf(gettext( 42814653Sdougm "Group \"%s\" is already " 42824653Sdougm "enabled\n"), 42834653Sdougm argv[optind]); 42844653Sdougm ret = SA_BUSY; /* already enabled */ 42854653Sdougm } else { 42864653Sdougm worklist = add_list(worklist, group, 4287*5331Samw 0, protocol); 42884653Sdougm if (verbose) 42894653Sdougm (void) printf(gettext( 42904653Sdougm "Enabling group \"%s\"\n"), 42914653Sdougm argv[optind]); 42924653Sdougm } 42934653Sdougm if (state != NULL) 42944653Sdougm sa_free_attr_string(state); 42953034Sdougm } else { 42964653Sdougm ret = SA_NO_SUCH_GROUP; 42973034Sdougm } 42984653Sdougm optind++; 42993034Sdougm } 43004653Sdougm } else { 43014653Sdougm for (group = sa_get_group(handle, NULL); 43024653Sdougm group != NULL; 43033034Sdougm group = sa_get_next_group(group)) { 4304*5331Samw worklist = add_list(worklist, group, 0, protocol); 43053034Sdougm } 43064653Sdougm } 43074653Sdougm if (!dryrun && ret == SA_OK) 4308*5331Samw ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE); 43094653Sdougm 43104653Sdougm if (ret != SA_OK && ret != SA_BUSY) 43113034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 43124653Sdougm sa_errorstr(ret)); 43134653Sdougm if (ret == SA_BUSY) 43143034Sdougm ret = SA_OK; 43154653Sdougm 43163034Sdougm if (worklist != NULL) 43174653Sdougm free_list(worklist); 43183034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 43194653Sdougm (void) printf(gettext("Command would fail: %s\n"), 43204653Sdougm sa_errorstr(SA_NO_PERMISSION)); 43213034Sdougm } 43223034Sdougm return (ret); 43233034Sdougm } 43243034Sdougm 43253034Sdougm /* 4326*5331Samw * disable_group(group, proto) 43273034Sdougm * 4328*5331Samw * Disable all the shares in the specified group.. This is a helper 4329*5331Samw * for disable_all_groups in order to simplify regular and subgroup 4330*5331Samw * (zfs) disabling. Group has already been checked for non-NULL. 43313034Sdougm */ 43323034Sdougm 43333034Sdougm static int 4334*5331Samw disable_group(sa_group_t group, char *proto) 43353034Sdougm { 43363034Sdougm sa_share_t share; 43373034Sdougm int ret = SA_OK; 43383034Sdougm 4339*5331Samw /* 4340*5331Samw * If the protocol isn't enabled, skip it and treat as 4341*5331Samw * successful. 4342*5331Samw */ 4343*5331Samw if (!has_protocol(group, proto)) 4344*5331Samw return (ret); 4345*5331Samw 43463034Sdougm for (share = sa_get_share(group, NULL); 43473034Sdougm share != NULL && ret == SA_OK; 43483034Sdougm share = sa_get_next_share(share)) { 4349*5331Samw ret = sa_disable_share(share, proto); 43504653Sdougm if (ret == SA_NO_SUCH_PATH) { 43514653Sdougm /* 43524653Sdougm * this is OK since the path is gone. we can't 43534653Sdougm * re-share it anyway so no error. 43544653Sdougm */ 43554653Sdougm ret = SA_OK; 43564653Sdougm } 43573034Sdougm } 43583034Sdougm return (ret); 43593034Sdougm } 43603034Sdougm 43613034Sdougm /* 43623034Sdougm * disable_all_groups(work, setstate) 43633034Sdougm * 43643034Sdougm * helper function that disables the shares in the list of groups 43653034Sdougm * provided. It optionally marks the group as disabled. Used by both 43663034Sdougm * enable and start subcommands. 43673034Sdougm */ 43683034Sdougm 43693034Sdougm static int 43703910Sdougm disable_all_groups(sa_handle_t handle, struct list *work, int setstate) 43713034Sdougm { 43723034Sdougm int ret = SA_OK; 43733034Sdougm sa_group_t subgroup, group; 43743034Sdougm 43753034Sdougm while (work != NULL && ret == SA_OK) { 43764653Sdougm group = (sa_group_t)work->item; 43774653Sdougm if (setstate) 43784653Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 43794653Sdougm if (ret == SA_OK) { 43804653Sdougm char *name; 43814653Sdougm name = sa_get_group_attr(group, "name"); 43824653Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 43834653Sdougm /* need to get the sub-groups for stopping */ 43844653Sdougm for (subgroup = sa_get_sub_group(group); 43854653Sdougm subgroup != NULL; 43864653Sdougm subgroup = sa_get_next_group(subgroup)) { 4387*5331Samw ret = disable_group(subgroup, 4388*5331Samw work->proto); 43894653Sdougm } 43904653Sdougm } else { 4391*5331Samw ret = disable_group(group, work->proto); 43924653Sdougm } 43934653Sdougm /* 43944653Sdougm * We don't want to "disable" since it won't come 43954653Sdougm * up after a reboot. The SMF framework should do 43964653Sdougm * the right thing. On enable we do want to do 43974653Sdougm * something. 43984653Sdougm */ 43993034Sdougm } 44004653Sdougm work = work->next; 44013034Sdougm } 44023034Sdougm if (ret == SA_OK) 44034653Sdougm ret = sa_update_config(handle); 44043034Sdougm return (ret); 44053034Sdougm } 44063034Sdougm 44073034Sdougm /* 44083034Sdougm * sa_disable_group(flags, argc, argv) 44093034Sdougm * 44103034Sdougm * Implements the disable subcommand 44113034Sdougm */ 44123034Sdougm 44133034Sdougm int 44143910Sdougm sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[]) 44153034Sdougm { 44163034Sdougm int verbose = 0; 44173034Sdougm int dryrun = 0; 44183034Sdougm int all = 0; 44193034Sdougm int c; 44203034Sdougm int ret = SA_OK; 4421*5331Samw char *protocol = NULL; 44223034Sdougm char *state; 44233034Sdougm struct list *worklist = NULL; 44244653Sdougm sa_group_t group; 44253034Sdougm int auth = 1; 44263034Sdougm 44273034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 44284653Sdougm switch (c) { 44294653Sdougm case 'a': 44304653Sdougm all = 1; 44314653Sdougm break; 44324653Sdougm case 'n': 44334653Sdougm dryrun++; 44344653Sdougm break; 44354653Sdougm case 'P': 4436*5331Samw if (protocol != NULL) { 4437*5331Samw (void) printf(gettext( 4438*5331Samw "Specifying multiple protocols " 4439*5331Samw "not supported: %s\n"), protocol); 4440*5331Samw return (SA_SYNTAX_ERR); 4441*5331Samw } 44424653Sdougm protocol = optarg; 44434653Sdougm if (!sa_valid_protocol(protocol)) { 44444653Sdougm (void) printf(gettext( 44454653Sdougm "Invalid protocol specified: %s\n"), 44464653Sdougm protocol); 44474653Sdougm return (SA_INVALID_PROTOCOL); 44484653Sdougm } 44494653Sdougm break; 44504653Sdougm case 'v': 44514653Sdougm verbose++; 44524653Sdougm break; 44534653Sdougm default: 44544653Sdougm case 'h': 44554653Sdougm case '?': 44564653Sdougm (void) printf(gettext("usage: %s\n"), 44574653Sdougm sa_get_usage(USAGE_DISABLE)); 44584653Sdougm return (0); 44593034Sdougm } 44603034Sdougm } 44613034Sdougm 44623034Sdougm if (optind == argc && !all) { 44633034Sdougm (void) printf(gettext("usage: %s\n"), 44644653Sdougm sa_get_usage(USAGE_DISABLE)); 44653034Sdougm (void) printf(gettext("\tmust specify group\n")); 44664653Sdougm return (SA_NO_SUCH_PATH); 44674653Sdougm } 44684653Sdougm if (!all) { 44694653Sdougm while (optind < argc) { 44703910Sdougm group = sa_get_group(handle, argv[optind]); 44713034Sdougm if (group != NULL) { 44724653Sdougm auth &= check_authorizations(argv[optind], 44734653Sdougm flags); 44744653Sdougm state = sa_get_group_attr(group, "state"); 44754653Sdougm if (state == NULL || 44764653Sdougm strcmp(state, "disabled") == 0) { 44774653Sdougm /* already disabled */ 44784653Sdougm if (verbose) 44794653Sdougm (void) printf(gettext( 44804653Sdougm "Group \"%s\" is " 44814653Sdougm "already disabled\n"), 44824653Sdougm argv[optind]); 4483*5331Samw ret = SA_BUSY; /* already disabled */ 44844653Sdougm } else { 4485*5331Samw worklist = add_list(worklist, group, 0, 4486*5331Samw protocol); 44874653Sdougm if (verbose) 44884653Sdougm (void) printf(gettext( 44894653Sdougm "Disabling group " 44904653Sdougm "\"%s\"\n"), argv[optind]); 44914653Sdougm } 44924653Sdougm if (state != NULL) 44934653Sdougm sa_free_attr_string(state); 44943034Sdougm } else { 44954653Sdougm ret = SA_NO_SUCH_GROUP; 44963034Sdougm } 44973034Sdougm optind++; 44984653Sdougm } 44994653Sdougm } else { 45004653Sdougm for (group = sa_get_group(handle, NULL); 45014653Sdougm group != NULL; 45024653Sdougm group = sa_get_next_group(group)) 4503*5331Samw worklist = add_list(worklist, group, 0, protocol); 45043034Sdougm } 45054653Sdougm 45064653Sdougm if (ret == SA_OK && !dryrun) 45074653Sdougm ret = disable_all_groups(handle, worklist, 1); 45084653Sdougm if (ret != SA_OK && ret != SA_BUSY) 45094653Sdougm (void) printf(gettext("Could not disable group: %s\n"), 45104653Sdougm sa_errorstr(ret)); 45114653Sdougm if (ret == SA_BUSY) 45124653Sdougm ret = SA_OK; 45133034Sdougm if (worklist != NULL) 45144653Sdougm free_list(worklist); 45154653Sdougm if (dryrun && ret == SA_OK && !auth && verbose) 45164653Sdougm (void) printf(gettext("Command would fail: %s\n"), 45174653Sdougm sa_errorstr(SA_NO_PERMISSION)); 45183034Sdougm return (ret); 45193034Sdougm } 45203034Sdougm 45213034Sdougm /* 45223034Sdougm * sa_start_group(flags, argc, argv) 45233034Sdougm * 45243034Sdougm * Implements the start command. 45253034Sdougm * This is similar to enable except it doesn't change the state 45263034Sdougm * of the group(s) and only enables shares if the group is already 45273034Sdougm * enabled. 45283034Sdougm */ 4529*5331Samw 45303034Sdougm int 45313910Sdougm sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[]) 45323034Sdougm { 45333034Sdougm int verbose = 0; 45343034Sdougm int all = 0; 45353034Sdougm int c; 45363034Sdougm int ret = SMF_EXIT_OK; 45373034Sdougm char *protocol = NULL; 45383034Sdougm char *state; 45393034Sdougm struct list *worklist = NULL; 45404653Sdougm sa_group_t group; 4541*5331Samw #ifdef lint 4542*5331Samw flags = flags; 4543*5331Samw #endif 45443034Sdougm 45453034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 45464653Sdougm switch (c) { 45474653Sdougm case 'a': 45484653Sdougm all = 1; 45494653Sdougm break; 45504653Sdougm case 'P': 4551*5331Samw if (protocol != NULL) { 4552*5331Samw (void) printf(gettext( 4553*5331Samw "Specifying multiple protocols " 4554*5331Samw "not supported: %s\n"), protocol); 4555*5331Samw return (SA_SYNTAX_ERR); 4556*5331Samw } 45574653Sdougm protocol = optarg; 45584653Sdougm if (!sa_valid_protocol(protocol)) { 45594653Sdougm (void) printf(gettext( 45604653Sdougm "Invalid protocol specified: %s\n"), 45613034Sdougm protocol); 45624653Sdougm return (SA_INVALID_PROTOCOL); 45634653Sdougm } 45644653Sdougm break; 45654653Sdougm case 'v': 45664653Sdougm verbose++; 45674653Sdougm break; 45684653Sdougm default: 45694653Sdougm case 'h': 45704653Sdougm case '?': 45714653Sdougm (void) printf(gettext("usage: %s\n"), 45724653Sdougm sa_get_usage(USAGE_START)); 45734653Sdougm return (SA_OK); 45743034Sdougm } 45753034Sdougm } 45763034Sdougm 45773034Sdougm if (optind == argc && !all) { 45783034Sdougm (void) printf(gettext("usage: %s\n"), 45794653Sdougm sa_get_usage(USAGE_START)); 45804653Sdougm return (SMF_EXIT_ERR_FATAL); 45814653Sdougm } 45824653Sdougm 45834653Sdougm if (!all) { 45844653Sdougm while (optind < argc) { 45853910Sdougm group = sa_get_group(handle, argv[optind]); 45863034Sdougm if (group != NULL) { 45874653Sdougm state = sa_get_group_attr(group, "state"); 45884653Sdougm if (state == NULL || 45894653Sdougm strcmp(state, "enabled") == 0) { 4590*5331Samw worklist = add_list(worklist, group, 0, 4591*5331Samw protocol); 45924653Sdougm if (verbose) 45934653Sdougm (void) printf(gettext( 45944653Sdougm "Starting group \"%s\"\n"), 45954653Sdougm argv[optind]); 45964653Sdougm } else { 45974653Sdougm /* 45984653Sdougm * Determine if there are any 4599*5331Samw * protocols. If there aren't any, 46004653Sdougm * then there isn't anything to do in 46014653Sdougm * any case so no error. 46024653Sdougm */ 46034653Sdougm if (sa_get_optionset(group, 46044653Sdougm protocol) != NULL) { 46054653Sdougm ret = SMF_EXIT_OK; 46064653Sdougm } 46073034Sdougm } 46084653Sdougm if (state != NULL) 46094653Sdougm sa_free_attr_string(state); 46103034Sdougm } 46113034Sdougm optind++; 46124653Sdougm } 46134653Sdougm } else { 4614*5331Samw for (group = sa_get_group(handle, NULL); 4615*5331Samw group != NULL; 46164653Sdougm group = sa_get_next_group(group)) { 46173034Sdougm state = sa_get_group_attr(group, "state"); 46183034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 4619*5331Samw worklist = add_list(worklist, group, 0, 4620*5331Samw protocol); 46213034Sdougm if (state != NULL) 46224653Sdougm sa_free_attr_string(state); 46233034Sdougm } 46243034Sdougm } 46254653Sdougm 4626*5331Samw (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE); 46274653Sdougm 46283034Sdougm if (worklist != NULL) 46294653Sdougm free_list(worklist); 46303034Sdougm return (ret); 46313034Sdougm } 46323034Sdougm 46333034Sdougm /* 46343034Sdougm * sa_stop_group(flags, argc, argv) 46353034Sdougm * 46363034Sdougm * Implements the stop command. 46373034Sdougm * This is similar to disable except it doesn't change the state 46383034Sdougm * of the group(s) and only disables shares if the group is already 46393034Sdougm * enabled. 46403034Sdougm */ 46413034Sdougm int 46423910Sdougm sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[]) 46433034Sdougm { 46443034Sdougm int verbose = 0; 46453034Sdougm int all = 0; 46463034Sdougm int c; 46473034Sdougm int ret = SMF_EXIT_OK; 46483034Sdougm char *protocol = NULL; 46493034Sdougm char *state; 46503034Sdougm struct list *worklist = NULL; 46514653Sdougm sa_group_t group; 4652*5331Samw #ifdef lint 4653*5331Samw flags = flags; 4654*5331Samw #endif 46553034Sdougm 46563034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 46574653Sdougm switch (c) { 46584653Sdougm case 'a': 46594653Sdougm all = 1; 46604653Sdougm break; 46614653Sdougm case 'P': 4662*5331Samw if (protocol != NULL) { 4663*5331Samw (void) printf(gettext( 4664*5331Samw "Specifying multiple protocols " 4665*5331Samw "not supported: %s\n"), protocol); 4666*5331Samw return (SA_SYNTAX_ERR); 4667*5331Samw } 46684653Sdougm protocol = optarg; 46694653Sdougm if (!sa_valid_protocol(protocol)) { 46704653Sdougm (void) printf(gettext( 46714653Sdougm "Invalid protocol specified: %s\n"), 46724653Sdougm protocol); 46734653Sdougm return (SA_INVALID_PROTOCOL); 46744653Sdougm } 46754653Sdougm break; 46764653Sdougm case 'v': 46774653Sdougm verbose++; 46784653Sdougm break; 46794653Sdougm default: 46804653Sdougm case 'h': 46814653Sdougm case '?': 46824653Sdougm (void) printf(gettext("usage: %s\n"), 46834653Sdougm sa_get_usage(USAGE_STOP)); 46844653Sdougm return (0); 46853034Sdougm } 46863034Sdougm } 46873034Sdougm 46883034Sdougm if (optind == argc && !all) { 46894653Sdougm (void) printf(gettext("usage: %s\n"), 46904653Sdougm sa_get_usage(USAGE_STOP)); 46914653Sdougm return (SMF_EXIT_ERR_FATAL); 46924653Sdougm } else if (!all) { 46934653Sdougm while (optind < argc) { 46943910Sdougm group = sa_get_group(handle, argv[optind]); 46953034Sdougm if (group != NULL) { 46964653Sdougm state = sa_get_group_attr(group, "state"); 46974653Sdougm if (state == NULL || 46984653Sdougm strcmp(state, "enabled") == 0) { 4699*5331Samw worklist = add_list(worklist, group, 0, 4700*5331Samw protocol); 47014653Sdougm if (verbose) 47024653Sdougm (void) printf(gettext( 47034653Sdougm "Stopping group \"%s\"\n"), 47044653Sdougm argv[optind]); 47054653Sdougm } else { 47064653Sdougm ret = SMF_EXIT_OK; 47074653Sdougm } 47084653Sdougm if (state != NULL) 47094653Sdougm sa_free_attr_string(state); 47103034Sdougm } 47113034Sdougm optind++; 47124653Sdougm } 47134653Sdougm } else { 4714*5331Samw for (group = sa_get_group(handle, NULL); 4715*5331Samw group != NULL; 47164653Sdougm group = sa_get_next_group(group)) { 47173034Sdougm state = sa_get_group_attr(group, "state"); 47183034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 4719*5331Samw worklist = add_list(worklist, group, 0, 4720*5331Samw protocol); 47213034Sdougm if (state != NULL) 47224653Sdougm sa_free_attr_string(state); 47233034Sdougm } 47243034Sdougm } 47254653Sdougm (void) disable_all_groups(handle, worklist, 0); 47264653Sdougm ret = sa_update_config(handle); 47274653Sdougm 47283034Sdougm if (worklist != NULL) 47294653Sdougm free_list(worklist); 47303034Sdougm return (ret); 47313034Sdougm } 47323034Sdougm 47333034Sdougm /* 47343034Sdougm * remove_all_options(share, proto) 47353034Sdougm * 47363034Sdougm * Removes all options on a share. 47373034Sdougm */ 47383034Sdougm 47393034Sdougm static void 47403034Sdougm remove_all_options(sa_share_t share, char *proto) 47413034Sdougm { 47423034Sdougm sa_optionset_t optionset; 47433034Sdougm sa_security_t security; 47443034Sdougm sa_security_t prevsec = NULL; 47453034Sdougm 47463034Sdougm optionset = sa_get_optionset(share, proto); 47473034Sdougm if (optionset != NULL) 47484653Sdougm (void) sa_destroy_optionset(optionset); 47493034Sdougm for (security = sa_get_security(share, NULL, NULL); 47503034Sdougm security != NULL; 47513034Sdougm security = sa_get_next_security(security)) { 47524653Sdougm char *type; 47533034Sdougm /* 47544653Sdougm * We walk through the list. prevsec keeps the 47553034Sdougm * previous security so we can delete it without 47563034Sdougm * destroying the list. 47573034Sdougm */ 47584653Sdougm if (prevsec != NULL) { 47594653Sdougm /* remove the previously seen security */ 47604653Sdougm (void) sa_destroy_security(prevsec); 47614653Sdougm /* set to NULL so we don't try multiple times */ 47624653Sdougm prevsec = NULL; 47634653Sdougm } 47644653Sdougm type = sa_get_security_attr(security, "type"); 47654653Sdougm if (type != NULL) { 47664653Sdougm /* 47674653Sdougm * if the security matches the specified protocol, we 47684653Sdougm * want to remove it. prevsec holds it until either 47694653Sdougm * the next pass or we fall out of the loop. 47704653Sdougm */ 47714653Sdougm if (strcmp(type, proto) == 0) 47724653Sdougm prevsec = security; 47734653Sdougm sa_free_attr_string(type); 47744653Sdougm } 47753034Sdougm } 47763034Sdougm /* in case there is one left */ 47773034Sdougm if (prevsec != NULL) 47784653Sdougm (void) sa_destroy_security(prevsec); 47793034Sdougm } 47803034Sdougm 47813034Sdougm 47823034Sdougm /* 47833034Sdougm * for legacy support, we need to handle the old syntax. This is what 47843034Sdougm * we get if sharemgr is called with the name "share" rather than 47853034Sdougm * sharemgr. 47863034Sdougm */ 47873034Sdougm 47883034Sdougm static int 47893034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 47903034Sdougm { 47913034Sdougm int err; 47923034Sdougm 47933034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 47943034Sdougm if (err > buffsize) 47954653Sdougm return (-1); 47963034Sdougm return (0); 47973034Sdougm } 47983034Sdougm 47993034Sdougm 48003034Sdougm /* 48013034Sdougm * check_legacy_cmd(proto, cmd) 48023034Sdougm * 48033034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 48043034Sdougm * executable. 48053034Sdougm */ 48063034Sdougm 48073034Sdougm static int 48083034Sdougm check_legacy_cmd(char *path) 48093034Sdougm { 48103034Sdougm struct stat st; 48113034Sdougm int ret = 0; 48123034Sdougm 48133034Sdougm if (stat(path, &st) == 0) { 48144653Sdougm if (S_ISREG(st.st_mode) && 48154653Sdougm st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 48164653Sdougm ret = 1; 48173034Sdougm } 48183034Sdougm return (ret); 48193034Sdougm } 48203034Sdougm 48213034Sdougm /* 48223034Sdougm * run_legacy_command(proto, cmd, argv) 48233034Sdougm * 48244653Sdougm * We know the command exists, so attempt to execute it with all the 48253034Sdougm * arguments. This implements full legacy share support for those 48263034Sdougm * protocols that don't have plugin providers. 48273034Sdougm */ 48283034Sdougm 48293034Sdougm static int 48303034Sdougm run_legacy_command(char *path, char *argv[]) 48313034Sdougm { 48323034Sdougm int ret; 48333034Sdougm 48343034Sdougm ret = execv(path, argv); 48353034Sdougm if (ret < 0) { 48364653Sdougm switch (errno) { 48374653Sdougm case EACCES: 48384653Sdougm ret = SA_NO_PERMISSION; 48394653Sdougm break; 48404653Sdougm default: 48414653Sdougm ret = SA_SYSTEM_ERR; 48424653Sdougm break; 48434653Sdougm } 48443034Sdougm } 48453034Sdougm return (ret); 48463034Sdougm } 48473034Sdougm 48483034Sdougm /* 48493348Sdougm * out_share(out, group, proto) 48503034Sdougm * 48513034Sdougm * Display the share information in the format that the "share" 48523034Sdougm * command has traditionally used. 48533034Sdougm */ 48543034Sdougm 48553034Sdougm static void 48563348Sdougm out_share(FILE *out, sa_group_t group, char *proto) 48573034Sdougm { 48583034Sdougm sa_share_t share; 48593034Sdougm char resfmt[128]; 4860*5331Samw char *defprop; 4861*5331Samw 4862*5331Samw /* 4863*5331Samw * The original share command defaulted to displaying NFS 4864*5331Samw * shares or allowed a protocol to be specified. We want to 4865*5331Samw * skip those shares that are not the specified protocol. 4866*5331Samw */ 4867*5331Samw if (proto != NULL && sa_get_optionset(group, proto) == NULL) 4868*5331Samw return; 4869*5331Samw 4870*5331Samw if (proto == NULL) 4871*5331Samw proto = "nfs"; 4872*5331Samw 4873*5331Samw /* 4874*5331Samw * get the default property string. NFS uses "rw" but 4875*5331Samw * everything else will use "". 4876*5331Samw */ 4877*5331Samw if (proto != NULL && strcmp(proto, "nfs") != 0) 4878*5331Samw defprop = "\"\""; 4879*5331Samw else 4880*5331Samw defprop = "rw"; 48813034Sdougm 48824653Sdougm for (share = sa_get_share(group, NULL); 48834653Sdougm share != NULL; 48844653Sdougm share = sa_get_next_share(share)) { 48854653Sdougm char *path; 48864653Sdougm char *type; 48874653Sdougm char *resource; 48884653Sdougm char *description; 48894653Sdougm char *groupname; 48904653Sdougm char *sharedstate; 48914653Sdougm int shared = 1; 48924653Sdougm char *soptions; 4893*5331Samw char shareopts[MAXNAMLEN]; 48944653Sdougm 48954653Sdougm sharedstate = sa_get_share_attr(share, "shared"); 48964653Sdougm path = sa_get_share_attr(share, "path"); 48974653Sdougm type = sa_get_share_attr(share, "type"); 4898*5331Samw resource = get_resource(share); 48994653Sdougm groupname = sa_get_group_attr(group, "name"); 49004653Sdougm 49014653Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 49024653Sdougm sa_free_attr_string(groupname); 49034653Sdougm groupname = NULL; 49044653Sdougm } 49054653Sdougm description = sa_get_share_description(share); 49064653Sdougm 4907*5331Samw /* 4908*5331Samw * Want the sharetab version if it exists, defaulting 4909*5331Samw * to NFS if no protocol specified. 4910*5331Samw */ 4911*5331Samw (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto); 4912*5331Samw soptions = sa_get_share_attr(share, shareopts); 49134653Sdougm 49144653Sdougm if (sharedstate == NULL) 49154653Sdougm shared = 0; 49164653Sdougm 49174653Sdougm if (soptions == NULL) 49184653Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 49194653Sdougm 49204653Sdougm if (shared) { 49214653Sdougm /* only active shares go here */ 49224653Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 49234653Sdougm resource != NULL ? resource : "-", 49244653Sdougm groupname != NULL ? "@" : "", 49254653Sdougm groupname != NULL ? groupname : ""); 49264653Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 49274653Sdougm resfmt, path, 49284653Sdougm (soptions != NULL && strlen(soptions) > 0) ? 4929*5331Samw soptions : defprop, 49304653Sdougm (description != NULL) ? description : ""); 49314653Sdougm } 49324653Sdougm 49334653Sdougm if (path != NULL) 49344653Sdougm sa_free_attr_string(path); 49354653Sdougm if (type != NULL) 49364653Sdougm sa_free_attr_string(type); 49374653Sdougm if (resource != NULL) 49384653Sdougm sa_free_attr_string(resource); 49394653Sdougm if (groupname != NULL) 49404653Sdougm sa_free_attr_string(groupname); 49414653Sdougm if (description != NULL) 49424653Sdougm sa_free_share_description(description); 49434653Sdougm if (sharedstate != NULL) 49444653Sdougm sa_free_attr_string(sharedstate); 49454653Sdougm if (soptions != NULL) 49464653Sdougm sa_format_free(soptions); 49473034Sdougm } 49483034Sdougm } 49493034Sdougm 49503034Sdougm /* 49513034Sdougm * output_legacy_file(out, proto) 49523034Sdougm * 49533034Sdougm * Walk all of the groups for the specified protocol and call 49543034Sdougm * out_share() to format and write in the format displayed by the 49553034Sdougm * "share" command with no arguments. 49563034Sdougm */ 49573034Sdougm 49583034Sdougm static void 49593910Sdougm output_legacy_file(FILE *out, char *proto, sa_handle_t handle) 49603034Sdougm { 49613034Sdougm sa_group_t group; 49623034Sdougm 4963*5331Samw for (group = sa_get_group(handle, NULL); 4964*5331Samw group != NULL; 49654653Sdougm group = sa_get_next_group(group)) { 49664653Sdougm char *zfs; 49673034Sdougm 49683034Sdougm /* 4969*5331Samw * Go through all the groups and ZFS 4970*5331Samw * sub-groups. out_share() will format the shares in 4971*5331Samw * the group appropriately. 49723034Sdougm */ 49733034Sdougm 49744653Sdougm zfs = sa_get_group_attr(group, "zfs"); 49754653Sdougm if (zfs != NULL) { 49764653Sdougm sa_group_t zgroup; 49774653Sdougm sa_free_attr_string(zfs); 49784653Sdougm for (zgroup = sa_get_sub_group(group); 49794653Sdougm zgroup != NULL; 49804653Sdougm zgroup = sa_get_next_group(zgroup)) { 49814653Sdougm 49824653Sdougm /* got a group, so display it */ 49834653Sdougm out_share(out, zgroup, proto); 49844653Sdougm } 49854653Sdougm } else { 49864653Sdougm out_share(out, group, proto); 49873034Sdougm } 49883034Sdougm } 49893034Sdougm } 49903034Sdougm 49913034Sdougm int 49923910Sdougm sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[]) 49933034Sdougm { 49943034Sdougm char *protocol = "nfs"; 49953034Sdougm char *options = NULL; 49963034Sdougm char *description = NULL; 49973034Sdougm char *groupname = NULL; 49983034Sdougm char *sharepath = NULL; 49993034Sdougm char *resource = NULL; 50003034Sdougm char *groupstatus = NULL; 50013034Sdougm int persist = SA_SHARE_TRANSIENT; 50023034Sdougm int argsused = 0; 50033034Sdougm int c; 50043034Sdougm int ret = SA_OK; 50053034Sdougm int zfs = 0; 50063034Sdougm int true_legacy = 0; 50073034Sdougm int curtype = SA_SHARE_TRANSIENT; 50083034Sdougm char cmd[MAXPATHLEN]; 50094653Sdougm sa_group_t group = NULL; 5010*5331Samw sa_resource_t rsrc = NULL; 50114653Sdougm sa_share_t share; 50124653Sdougm char dir[MAXPATHLEN]; 5013*5331Samw uint64_t features; 5014*5331Samw #ifdef lint 5015*5331Samw flags = flags; 5016*5331Samw #endif 50173034Sdougm 50183034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 50194653Sdougm switch (c) { 50204653Sdougm case 'd': 50214653Sdougm description = optarg; 50224653Sdougm argsused++; 50234653Sdougm break; 50244653Sdougm case 'F': 50254653Sdougm protocol = optarg; 50264653Sdougm if (!sa_valid_protocol(protocol)) { 50274653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 50284653Sdougm protocol, "share") == 0 && 50294653Sdougm check_legacy_cmd(cmd)) { 50304653Sdougm true_legacy++; 50314653Sdougm } else { 50324653Sdougm (void) fprintf(stderr, gettext( 50334653Sdougm "Invalid protocol specified: " 50344653Sdougm "%s\n"), protocol); 50354653Sdougm return (SA_INVALID_PROTOCOL); 50364653Sdougm } 50374653Sdougm } 50384653Sdougm break; 50394653Sdougm case 'o': 50404653Sdougm options = optarg; 50414653Sdougm argsused++; 50424653Sdougm break; 50434653Sdougm case 'p': 50444653Sdougm persist = SA_SHARE_PERMANENT; 50454653Sdougm argsused++; 50464653Sdougm break; 50474653Sdougm case 'h': 50484653Sdougm case '?': 50494653Sdougm default: 50504653Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 50514653Sdougm sa_get_usage(USAGE_SHARE)); 50524653Sdougm return (SA_OK); 50533034Sdougm } 50544653Sdougm } 50554653Sdougm 50564653Sdougm /* Have the info so construct what is needed */ 50574653Sdougm if (!argsused && optind == argc) { 50584653Sdougm /* display current info in share format */ 5059*5331Samw (void) output_legacy_file(stdout, protocol, handle); 50604653Sdougm return (ret); 50613034Sdougm } 50623034Sdougm 50634653Sdougm /* We are modifying the configuration */ 50644653Sdougm if (optind == argc) { 50653034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 50664653Sdougm sa_get_usage(USAGE_SHARE)); 50673034Sdougm return (SA_LEGACY_ERR); 50684653Sdougm } 50694653Sdougm if (true_legacy) { 50704653Sdougm /* If still using legacy share/unshare, exec it */ 50713034Sdougm ret = run_legacy_command(cmd, argv); 50723034Sdougm return (ret); 50734653Sdougm } 50744653Sdougm 50754653Sdougm sharepath = argv[optind++]; 50764653Sdougm if (optind < argc) { 50773034Sdougm resource = argv[optind]; 50783034Sdougm groupname = strchr(resource, '@'); 50793034Sdougm if (groupname != NULL) 50804653Sdougm *groupname++ = '\0'; 50814653Sdougm } 50824653Sdougm if (realpath(sharepath, dir) == NULL) 50833034Sdougm ret = SA_BAD_PATH; 50844653Sdougm else 50853034Sdougm sharepath = dir; 50864653Sdougm if (ret == SA_OK) 50873910Sdougm share = sa_find_share(handle, sharepath); 50884653Sdougm else 50893034Sdougm share = NULL; 50904653Sdougm 5091*5331Samw features = sa_proto_get_featureset(protocol); 5092*5331Samw 50934653Sdougm if (groupname != NULL) { 50944653Sdougm ret = SA_NOT_ALLOWED; 50954653Sdougm } else if (ret == SA_OK) { 5096*5331Samw char *legacygroup; 50973034Sdougm /* 50984653Sdougm * The legacy group is always present and zfs groups 50993034Sdougm * come and go. zfs shares may be in sub-groups and 51003034Sdougm * the zfs share will already be in that group so it 5101*5331Samw * isn't an error. If the protocol is "smb", the group 5102*5331Samw * "smb" is used when "default" would otherwise be 5103*5331Samw * used. "default" is NFS only and "smb" is SMB only. 51043034Sdougm */ 5105*5331Samw if (strcmp(protocol, "smb") == 0) 5106*5331Samw legacygroup = "smb"; 5107*5331Samw else 5108*5331Samw legacygroup = "default"; 5109*5331Samw 51103034Sdougm /* 51114653Sdougm * If the share exists (not NULL), then make sure it 51124653Sdougm * is one we want to handle by getting the parent 51134653Sdougm * group. 51143034Sdougm */ 5115*5331Samw if (share != NULL) { 51164653Sdougm group = sa_get_parent_group(share); 5117*5331Samw } else { 51184653Sdougm group = sa_get_group(handle, legacygroup); 5119*5331Samw if (group == NULL && strcmp(legacygroup, "smb") == 0) { 5120*5331Samw /* 5121*5331Samw * This group may not exist, so create 5122*5331Samw * as necessary. It only contains the 5123*5331Samw * "smb" protocol. 5124*5331Samw */ 5125*5331Samw group = sa_create_group(handle, legacygroup, 5126*5331Samw &ret); 5127*5331Samw if (group != NULL) 5128*5331Samw (void) sa_create_optionset(group, 5129*5331Samw protocol); 5130*5331Samw } 5131*5331Samw } 5132*5331Samw 5133*5331Samw if (group == NULL) { 5134*5331Samw ret = SA_SYSTEM_ERR; 5135*5331Samw goto err; 5136*5331Samw } 5137*5331Samw 5138*5331Samw groupstatus = group_status(group); 5139*5331Samw if (share == NULL) { 5140*5331Samw share = sa_add_share(group, sharepath, 5141*5331Samw persist, &ret); 5142*5331Samw if (share == NULL && 5143*5331Samw ret == SA_DUPLICATE_NAME) { 5144*5331Samw /* 5145*5331Samw * Could be a ZFS path being started 5146*5331Samw */ 5147*5331Samw if (sa_zfs_is_shared(handle, 5148*5331Samw sharepath)) { 5149*5331Samw ret = SA_OK; 5150*5331Samw group = sa_get_group(handle, 5151*5331Samw "zfs"); 5152*5331Samw if (group == NULL) { 5153*5331Samw /* 5154*5331Samw * This shouldn't 5155*5331Samw * happen. 5156*5331Samw */ 5157*5331Samw ret = SA_CONFIG_ERR; 5158*5331Samw } else { 5159*5331Samw share = sa_add_share( 5160*5331Samw group, sharepath, 5161*5331Samw persist, &ret); 51624653Sdougm } 51633034Sdougm } 5164*5331Samw } 5165*5331Samw } else { 5166*5331Samw char *type; 5167*5331Samw /* 5168*5331Samw * May want to change persist state, but the 5169*5331Samw * important thing is to change options. We 5170*5331Samw * need to change them regardless of the 5171*5331Samw * source. 5172*5331Samw */ 5173*5331Samw 5174*5331Samw if (sa_zfs_is_shared(handle, sharepath)) { 5175*5331Samw zfs = 1; 5176*5331Samw } 5177*5331Samw remove_all_options(share, protocol); 5178*5331Samw type = sa_get_share_attr(share, "type"); 5179*5331Samw if (type != NULL && 5180*5331Samw strcmp(type, "transient") != 0) { 5181*5331Samw curtype = SA_SHARE_PERMANENT; 5182*5331Samw } 5183*5331Samw if (type != NULL) 5184*5331Samw sa_free_attr_string(type); 5185*5331Samw if (curtype != persist) { 5186*5331Samw (void) sa_set_share_attr(share, "type", 5187*5331Samw persist == SA_SHARE_PERMANENT ? 5188*5331Samw "persist" : "transient"); 5189*5331Samw } 5190*5331Samw } 5191*5331Samw 5192*5331Samw /* 5193*5331Samw * If there is a resource name, we may 5194*5331Samw * actually care about it if this is share for 5195*5331Samw * a protocol that uses resource level sharing 5196*5331Samw * (SMB). We need to find the resource and, if 5197*5331Samw * it exists, make sure it belongs to the 5198*5331Samw * current share. If it doesn't exist, attempt 5199*5331Samw * to create it. 5200*5331Samw */ 5201*5331Samw 5202*5331Samw if (ret == SA_OK && resource != NULL) { 5203*5331Samw rsrc = sa_find_resource(handle, resource); 5204*5331Samw if (rsrc != NULL) { 5205*5331Samw if (share != sa_get_resource_parent(rsrc)) 5206*5331Samw ret = SA_DUPLICATE_NAME; 5207*5331Samw } else { 5208*5331Samw rsrc = sa_add_resource(share, resource, 5209*5331Samw persist, &ret); 52103034Sdougm } 5211*5331Samw if (features & SA_FEATURE_RESOURCE) 5212*5331Samw share = rsrc; 52133108Sdougm } 5214*5331Samw 52154653Sdougm /* Have a group to hold this share path */ 52164653Sdougm if (ret == SA_OK && options != NULL && 52174653Sdougm strlen(options) > 0) { 52184653Sdougm ret = sa_parse_legacy_options(share, 52194653Sdougm options, 52204653Sdougm protocol); 52213034Sdougm } 52224653Sdougm if (!zfs) { 52234653Sdougm /* 5224*5331Samw * ZFS shares never have a description 5225*5331Samw * and we can't store the values so 5226*5331Samw * don't try. 52274653Sdougm */ 52284653Sdougm if (ret == SA_OK && description != NULL) 52294653Sdougm ret = sa_set_share_description(share, 52304653Sdougm description); 52313034Sdougm } 5232*5331Samw if (ret == SA_OK && 5233*5331Samw strcmp(groupstatus, "enabled") == 0) { 5234*5331Samw if (rsrc != share) 52354653Sdougm ret = sa_enable_share(share, protocol); 5236*5331Samw else 5237*5331Samw ret = sa_enable_resource(rsrc, 5238*5331Samw protocol); 52394653Sdougm if (ret == SA_OK && 52404653Sdougm persist == SA_SHARE_PERMANENT) { 52414653Sdougm (void) sa_update_legacy(share, 52424653Sdougm protocol); 52434653Sdougm } 52444653Sdougm if (ret == SA_OK) 52454653Sdougm ret = sa_update_config(handle); 52464653Sdougm } 52473034Sdougm } 5248*5331Samw err: 52493034Sdougm if (ret != SA_OK) { 52504653Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 52514653Sdougm sharepath, sa_errorstr(ret)); 52524653Sdougm ret = SA_LEGACY_ERR; 52533034Sdougm } 52543034Sdougm return (ret); 52553034Sdougm } 52563034Sdougm 52573034Sdougm /* 52583034Sdougm * sa_legacy_unshare(flags, argc, argv) 52593034Sdougm * 52603034Sdougm * Implements the original unshare command. 52613034Sdougm */ 52623034Sdougm int 52633910Sdougm sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[]) 52643034Sdougm { 52653034Sdougm char *protocol = "nfs"; /* for now */ 52663034Sdougm char *options = NULL; 52673034Sdougm char *sharepath = NULL; 52683034Sdougm int persist = SA_SHARE_TRANSIENT; 52693034Sdougm int argsused = 0; 52703034Sdougm int c; 52713034Sdougm int ret = SA_OK; 52723034Sdougm int true_legacy = 0; 5273*5331Samw uint64_t features = 0; 5274*5331Samw sa_resource_t resource = NULL; 52753034Sdougm char cmd[MAXPATHLEN]; 5276*5331Samw #ifdef lint 5277*5331Samw flags = flags; 5278*5331Samw options = options; 5279*5331Samw #endif 52803034Sdougm 52813034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 52824653Sdougm switch (c) { 52834653Sdougm case 'h': 52844653Sdougm case '?': 52854653Sdougm break; 52864653Sdougm case 'F': 52874653Sdougm protocol = optarg; 52884653Sdougm if (!sa_valid_protocol(protocol)) { 52894653Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 52904653Sdougm protocol, "unshare") == 0 && 52914653Sdougm check_legacy_cmd(cmd)) { 52924653Sdougm true_legacy++; 52934653Sdougm } else { 52944653Sdougm (void) printf(gettext( 52954653Sdougm "Invalid file system name\n")); 52964653Sdougm return (SA_INVALID_PROTOCOL); 52974653Sdougm } 52984653Sdougm } 52994653Sdougm break; 53004653Sdougm case 'o': 53014653Sdougm options = optarg; 53024653Sdougm argsused++; 53034653Sdougm break; 53044653Sdougm case 'p': 53054653Sdougm persist = SA_SHARE_PERMANENT; 53064653Sdougm argsused++; 53074653Sdougm break; 53084653Sdougm default: 53094653Sdougm (void) printf(gettext("usage: %s\n"), 53104653Sdougm sa_get_usage(USAGE_UNSHARE)); 53114653Sdougm return (SA_OK); 53123034Sdougm } 53133034Sdougm } 53143034Sdougm 53154653Sdougm /* Have the info so construct what is needed */ 53164653Sdougm if (optind == argc || (optind + 1) < argc || options != NULL) { 53174653Sdougm ret = SA_SYNTAX_ERR; 53183034Sdougm } else { 53194653Sdougm sa_share_t share; 53204653Sdougm char dir[MAXPATHLEN]; 53214653Sdougm if (true_legacy) { 53224653Sdougm /* if still using legacy share/unshare, exec it */ 53234653Sdougm ret = run_legacy_command(cmd, argv); 53244653Sdougm return (ret); 53254653Sdougm } 53263663Sdougm /* 53273663Sdougm * Find the path in the internal configuration. If it 53283663Sdougm * isn't found, attempt to resolve the path via 53293663Sdougm * realpath() and try again. 53303663Sdougm */ 53314653Sdougm sharepath = argv[optind++]; 53324653Sdougm share = sa_find_share(handle, sharepath); 53334653Sdougm if (share == NULL) { 53344653Sdougm if (realpath(sharepath, dir) == NULL) { 53354653Sdougm ret = SA_NO_SUCH_PATH; 53364653Sdougm } else { 53374653Sdougm share = sa_find_share(handle, dir); 53384653Sdougm } 53393663Sdougm } 5340*5331Samw if (share == NULL) { 5341*5331Samw /* Could be a resource name so check that next */ 5342*5331Samw features = sa_proto_get_featureset(protocol); 5343*5331Samw resource = sa_find_resource(handle, sharepath); 5344*5331Samw if (resource != NULL) { 5345*5331Samw share = sa_get_resource_parent(resource); 5346*5331Samw if (features & SA_FEATURE_RESOURCE) 5347*5331Samw (void) sa_disable_resource(resource, 5348*5331Samw protocol); 5349*5331Samw if (persist == SA_SHARE_PERMANENT) { 5350*5331Samw ret = sa_remove_resource(resource); 5351*5331Samw if (ret == SA_OK) 5352*5331Samw ret = sa_update_config(handle); 5353*5331Samw } 5354*5331Samw /* 5355*5331Samw * If we still have a resource on the 5356*5331Samw * share, we don't disable the share 5357*5331Samw * itself. IF there aren't anymore, we 5358*5331Samw * need to remove the share. The 5359*5331Samw * removal will be done in the next 5360*5331Samw * section if appropriate. 5361*5331Samw */ 5362*5331Samw resource = sa_get_share_resource(share, NULL); 5363*5331Samw if (resource != NULL) 5364*5331Samw share = NULL; 5365*5331Samw } else if (ret == SA_OK) { 5366*5331Samw /* Didn't find path and no resource */ 5367*5331Samw ret = SA_BAD_PATH; 5368*5331Samw } 5369*5331Samw } 5370*5331Samw if (share != NULL && resource == NULL) { 53714653Sdougm ret = sa_disable_share(share, protocol); 53724653Sdougm /* 53734653Sdougm * Errors are ok and removal should still occur. The 53744653Sdougm * legacy unshare is more forgiving of errors than the 53754653Sdougm * remove-share subcommand which may need the force 53764653Sdougm * flag set for some error conditions. That is, the 53774653Sdougm * "unshare" command will always unshare if it can 53784653Sdougm * while "remove-share" might require the force option. 53794653Sdougm */ 53804653Sdougm if (persist == SA_SHARE_PERMANENT) { 53814653Sdougm ret = sa_remove_share(share); 53824653Sdougm if (ret == SA_OK) 53834653Sdougm ret = sa_update_config(handle); 53844653Sdougm } 5385*5331Samw } else if (ret == SA_OK && share == NULL && resource == NULL) { 5386*5331Samw /* 5387*5331Samw * If both share and resource are NULL, then 5388*5331Samw * share not found. If one or the other was 5389*5331Samw * found or there was an earlier error, we 5390*5331Samw * assume it was handled earlier. 5391*5331Samw */ 53924653Sdougm ret = SA_NOT_SHARED; 53933663Sdougm } 53943034Sdougm } 53953034Sdougm switch (ret) { 53963034Sdougm default: 53974653Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 53984653Sdougm ret = SA_LEGACY_ERR; 53994653Sdougm break; 54003034Sdougm case SA_SYNTAX_ERR: 54014653Sdougm (void) printf(gettext("usage: %s\n"), 54024653Sdougm sa_get_usage(USAGE_UNSHARE)); 54034653Sdougm break; 54043034Sdougm case SA_OK: 54054653Sdougm break; 54063034Sdougm } 54073034Sdougm return (ret); 54083034Sdougm } 54093034Sdougm 54103034Sdougm /* 54114653Sdougm * Common commands that implement the sub-commands used by all 5412*5331Samw * protocols. The entries are found via the lookup command 54133034Sdougm */ 54143034Sdougm 54153034Sdougm static sa_command_t commands[] = { 54163034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 54173034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 54183034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 54193034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 54203034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 54213034Sdougm {"list", 0, sa_list, USAGE_LIST}, 54223034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 54233034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 54243034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 54253034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 54263034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 54273034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 54283034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 5429*5331Samw SVC_SET|SVC_ACTION}, 54303034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 54313034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 54323034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 54333034Sdougm {NULL, 0, NULL, NULL} 54343034Sdougm }; 54353034Sdougm 54363034Sdougm static char * 54373034Sdougm sa_get_usage(sa_usage_t index) 54383034Sdougm { 54393034Sdougm char *ret = NULL; 54403034Sdougm switch (index) { 54413034Sdougm case USAGE_ADD_SHARE: 54424653Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 54434653Sdougm "[-d \"description text\"] -s sharepath group"); 54444653Sdougm break; 54453034Sdougm case USAGE_CREATE: 54464653Sdougm ret = gettext( 54474653Sdougm "create [-nvh] [-P proto [-p property=value]] group"); 54484653Sdougm break; 54493034Sdougm case USAGE_DELETE: 54504653Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 54514653Sdougm break; 54523034Sdougm case USAGE_DISABLE: 54534653Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 54544653Sdougm break; 54553034Sdougm case USAGE_ENABLE: 54564653Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 54574653Sdougm break; 54583034Sdougm case USAGE_LIST: 54594653Sdougm ret = gettext("list [-vh] [-P proto]"); 54604653Sdougm break; 54613034Sdougm case USAGE_MOVE_SHARE: 54624653Sdougm ret = gettext( 54634653Sdougm "move-share [-nvh] -s sharepath destination-group"); 54644653Sdougm break; 54653034Sdougm case USAGE_REMOVE_SHARE: 5466*5331Samw ret = gettext( 5467*5331Samw "remove-share [-fnvh] {-s sharepath | -r resource} " 5468*5331Samw "group"); 54694653Sdougm break; 54703034Sdougm case USAGE_SET: 54714653Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 5472*5331Samw "[-p property=value]* [-s sharepath] [-r resource]] " 5473*5331Samw "group"); 54744653Sdougm break; 54753034Sdougm case USAGE_SET_SECURITY: 54764653Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 54774653Sdougm "[-p property=value]* group"); 54784653Sdougm break; 54793034Sdougm case USAGE_SET_SHARE: 54804653Sdougm ret = gettext("set-share [-nh] [-r resource] " 54814653Sdougm "[-d \"description text\"] -s sharepath group"); 54824653Sdougm break; 54833034Sdougm case USAGE_SHOW: 54844653Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 54854653Sdougm break; 54863034Sdougm case USAGE_SHARE: 54874653Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 54884653Sdougm "[-d description] [pathname [resourcename]]"); 54894653Sdougm break; 54903034Sdougm case USAGE_START: 54914653Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 54924653Sdougm break; 54933034Sdougm case USAGE_STOP: 54944653Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 54954653Sdougm break; 54963034Sdougm case USAGE_UNSET: 54974653Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 54984653Sdougm "[-p property]* group"); 54994653Sdougm break; 55003034Sdougm case USAGE_UNSET_SECURITY: 5501*5331Samw ret = gettext("unset-security [-nvh] -P proto " 5502*5331Samw "-S security-type [-p property]* group"); 55034653Sdougm break; 55043034Sdougm case USAGE_UNSHARE: 55054653Sdougm ret = gettext( 5506*5331Samw "unshare [-F fstype] [-p] [-o optionlist] sharepath"); 55074653Sdougm break; 55083034Sdougm } 55093034Sdougm return (ret); 55103034Sdougm } 55113034Sdougm 55123034Sdougm /* 55133034Sdougm * sa_lookup(cmd, proto) 55143034Sdougm * 55153034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 55163034Sdougm * eventually provide a way to provide protocol specific sub-commands. 55173034Sdougm */ 55183034Sdougm sa_command_t * 55193034Sdougm sa_lookup(char *cmd, char *proto) 55203034Sdougm { 55213034Sdougm int i; 55223034Sdougm size_t len; 5523*5331Samw #ifdef lint 5524*5331Samw proto = proto; 5525*5331Samw #endif 55263034Sdougm 55273034Sdougm len = strlen(cmd); 55283034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 55294653Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 55304653Sdougm return (&commands[i]); 55313034Sdougm } 55323034Sdougm return (NULL); 55333034Sdougm } 55343034Sdougm 55353034Sdougm void 55363034Sdougm sub_command_help(char *proto) 55373034Sdougm { 55383034Sdougm int i; 5539*5331Samw #ifdef lint 5540*5331Samw proto = proto; 5541*5331Samw #endif 55423034Sdougm 55433034Sdougm (void) printf(gettext("\tsub-commands:\n")); 55443034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 55454653Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 55464653Sdougm (void) printf("\t%s\n", 55474653Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 55483034Sdougm } 55493034Sdougm } 5550