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 /* 233034Sdougm * Copyright 2006 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> 513034Sdougm 523034Sdougm static char *sa_get_usage(sa_usage_t); 533034Sdougm 543034Sdougm /* 553034Sdougm * Implementation of the common sub-commands supported by sharemgr. 563034Sdougm * A number of helper functions are also included. 573034Sdougm */ 583034Sdougm 593034Sdougm /* 603034Sdougm * has_protocol(group, proto) 613034Sdougm * If the group has an optionset with the specified protocol, 623034Sdougm * return true (1) otherwise false (0). 633034Sdougm */ 643034Sdougm static int 653034Sdougm has_protocol(sa_group_t group, char *protocol) 663034Sdougm { 673034Sdougm sa_optionset_t optionset; 683034Sdougm int result = 0; 693034Sdougm 703034Sdougm optionset = sa_get_optionset(group, protocol); 713034Sdougm if (optionset != NULL) { 723034Sdougm result++; 733034Sdougm } 743034Sdougm return (result); 753034Sdougm } 763034Sdougm 773034Sdougm /* 783034Sdougm * add_list(list, item) 793034Sdougm * Adds a new list member that points to item to the list. 803034Sdougm * If list is NULL, it starts a new list. The function returns 813034Sdougm * the first member of the list. 823034Sdougm */ 833034Sdougm struct list * 843034Sdougm add_list(struct list *listp, void *item, void *data) 853034Sdougm { 863034Sdougm struct list *new, *tmp; 873034Sdougm 883034Sdougm new = malloc(sizeof (struct list)); 893034Sdougm if (new != NULL) { 903034Sdougm new->next = NULL; 913034Sdougm new->item = item; 923034Sdougm new->itemdata = data; 933034Sdougm } else { 943034Sdougm return (listp); 953034Sdougm } 963034Sdougm 973034Sdougm if (listp == NULL) 983034Sdougm return (new); 993034Sdougm 1003034Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 1013034Sdougm /* get to end of list */ 1023034Sdougm } 1033034Sdougm tmp->next = new; 1043034Sdougm return (listp); 1053034Sdougm } 1063034Sdougm 1073034Sdougm /* 1083034Sdougm * free_list(list) 1093034Sdougm * Given a list, free all the members of the list; 1103034Sdougm */ 1113034Sdougm static void 1123034Sdougm free_list(struct list *listp) 1133034Sdougm { 1143034Sdougm struct list *tmp; 1153034Sdougm while (listp != NULL) { 1163034Sdougm tmp = listp; 1173034Sdougm listp = listp->next; 1183034Sdougm free(tmp); 1193034Sdougm } 1203034Sdougm } 1213034Sdougm 1223034Sdougm /* 1233034Sdougm * check_authorization(instname, which) 1243034Sdougm * 1253034Sdougm * Checks to see if the specific type of authorization in which is 1263034Sdougm * enabled for the user in this SMF service instance. 1273034Sdougm */ 1283034Sdougm 1293034Sdougm static int 1303034Sdougm check_authorization(char *instname, int which) 1313034Sdougm { 1323034Sdougm scf_handle_t *handle = NULL; 1333034Sdougm scf_simple_prop_t *prop = NULL; 1343034Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 1353034Sdougm char *authstr = NULL; 1363034Sdougm ssize_t numauths; 1373034Sdougm int ret = 1; 1383034Sdougm uid_t uid; 1393034Sdougm struct passwd *pw = NULL; 1403034Sdougm 1413034Sdougm uid = getuid(); 1423034Sdougm pw = getpwuid(uid); 1433034Sdougm if (pw == NULL) 1443034Sdougm ret = 0; 1453034Sdougm 1463034Sdougm if (ret == 1) { 1473034Sdougm /* since names are restricted to SA_MAX_NAME_LEN won't overflow */ 1483034Sdougm (void) snprintf(svcstring, sizeof (svcstring), 1493034Sdougm "%s:%s", SA_SVC_FMRI_BASE, instname); 1503034Sdougm handle = scf_handle_create(SCF_VERSION); 1513034Sdougm if (handle != NULL) { 1523034Sdougm if (scf_handle_bind(handle) == 0) { 1533034Sdougm switch (which) { 1543034Sdougm case SVC_SET: 1553034Sdougm prop = scf_simple_prop_get(handle, svcstring, 1563034Sdougm "general", 1573034Sdougm SVC_AUTH_VALUE); 1583034Sdougm break; 1593034Sdougm case SVC_ACTION: 1603034Sdougm prop = scf_simple_prop_get(handle, svcstring, 1613034Sdougm "general", 1623034Sdougm SVC_AUTH_ACTION); 1633034Sdougm break; 1643034Sdougm } 1653034Sdougm } 1663034Sdougm } 1673034Sdougm } 1683034Sdougm /* make sure we have an authorization string property */ 1693034Sdougm if (prop != NULL) { 1703034Sdougm int i; 1713034Sdougm numauths = scf_simple_prop_numvalues(prop); 1723034Sdougm for (ret = 0, i = 0; i < numauths; i++) { 1733034Sdougm authstr = scf_simple_prop_next_astring(prop); 1743034Sdougm if (authstr != NULL) { 1753034Sdougm /* check if this user has one of the strings */ 1763034Sdougm if (chkauthattr(authstr, pw->pw_name)) { 1773034Sdougm ret = 1; 1783034Sdougm break; 1793034Sdougm } 1803034Sdougm } 1813034Sdougm } 1823034Sdougm endauthattr(); 1833034Sdougm scf_simple_prop_free(prop); 1843034Sdougm } else { 1853034Sdougm /* no authorization string defined */ 1863034Sdougm ret = 0; 1873034Sdougm } 1883034Sdougm if (handle != NULL) 1893034Sdougm scf_handle_destroy(handle); 1903034Sdougm return (ret); 1913034Sdougm } 1923034Sdougm 1933034Sdougm /* 1943034Sdougm * check_authorizations(instname, flags) 1953034Sdougm * 1963034Sdougm * check all the needed authorizations for the user in this service 1973034Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 1983034Sdougm * there are authorizations for the user or not. 1993034Sdougm */ 2003034Sdougm 2013034Sdougm static int 2023034Sdougm check_authorizations(char *instname, int flags) 2033034Sdougm { 2043034Sdougm int ret1 = 0; 2053034Sdougm int ret2 = 0; 2063034Sdougm int ret; 2073034Sdougm 2083034Sdougm if (flags & SVC_SET) 2093034Sdougm ret1 = check_authorization(instname, SVC_SET); 2103034Sdougm if (flags & SVC_ACTION) 2113034Sdougm ret2 = check_authorization(instname, SVC_ACTION); 2123034Sdougm switch (flags) { 2133034Sdougm case SVC_ACTION: 2143034Sdougm ret = ret2; 2153034Sdougm break; 2163034Sdougm case SVC_SET: 2173034Sdougm ret = ret1; 2183034Sdougm break; 2193034Sdougm case SVC_ACTION|SVC_SET: 2203034Sdougm ret = ret1 & ret2; 2213034Sdougm break; 2223034Sdougm default: 2233034Sdougm /* if not flags set, we assume we don't need authorizations */ 2243034Sdougm ret = 1; 2253034Sdougm } 2263034Sdougm return (ret); 2273034Sdougm } 2283034Sdougm 2293034Sdougm /* 230*3082Sdougm * enable_group(group, updateproto) 231*3082Sdougm * 232*3082Sdougm * enable all the shares in the specified group. This is a helper for 233*3082Sdougm * enable_all_groups in order to simplify regular and subgroup (zfs) 234*3082Sdougm * disabling. Group has already been checked for non-NULL. 235*3082Sdougm */ 236*3082Sdougm 237*3082Sdougm static void 238*3082Sdougm enable_group(sa_group_t group, char *updateproto) 239*3082Sdougm { 240*3082Sdougm sa_share_t share; 241*3082Sdougm 242*3082Sdougm for (share = sa_get_share(group, NULL); 243*3082Sdougm share != NULL; 244*3082Sdougm share = sa_get_next_share(share)) { 245*3082Sdougm if (updateproto != NULL) 246*3082Sdougm (void) sa_update_legacy(share, updateproto); 247*3082Sdougm (void) sa_enable_share(share, NULL); 248*3082Sdougm } 249*3082Sdougm } 250*3082Sdougm 251*3082Sdougm /* 252*3082Sdougm * enable_all_groups(list, setstate, online, updateproto) 253*3082Sdougm * Given a list of groups, enable each one found. If updateproto 254*3082Sdougm * is not NULL, then update all the shares for the protocol that 255*3082Sdougm * was passed in. 2563034Sdougm */ 2573034Sdougm static int 258*3082Sdougm enable_all_groups(struct list *work, int setstate, int online, 259*3082Sdougm char *updateproto) 2603034Sdougm { 2613034Sdougm int ret = SA_OK; 2623034Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 2633034Sdougm char *state; 2643034Sdougm char *name; 2653034Sdougm char *zfs = NULL; 2663034Sdougm sa_group_t group; 267*3082Sdougm sa_group_t subgroup; 2683034Sdougm 2693034Sdougm while (work != NULL && ret == SA_OK) { 2703034Sdougm group = (sa_group_t)work->item; 2713034Sdougm /* if itemdata != NULL then a single share */ 2723034Sdougm if (work->itemdata != NULL) { 2733034Sdougm ret = sa_enable_share((sa_share_t)work->itemdata, NULL); 2743034Sdougm } 2753034Sdougm if (setstate) 2763034Sdougm ret = sa_set_group_attr(group, "state", 2773034Sdougm "enabled"); 2783034Sdougm if (ret == SA_OK) { 2793034Sdougm /* if itemdata == NULL then the whole group */ 2803034Sdougm if (work->itemdata == NULL) { 281*3082Sdougm zfs = sa_get_group_attr(group, "zfs"); 282*3082Sdougm /* 283*3082Sdougm * if the share is managed by ZFS, don't 284*3082Sdougm * update any of the protocols since ZFS is 285*3082Sdougm * handling this. updateproto will contain 286*3082Sdougm * the name of the protocol that we want to 287*3082Sdougm * update legacy files for. 288*3082Sdougm */ 289*3082Sdougm enable_group(group, zfs == NULL ? updateproto : NULL); 290*3082Sdougm for (subgroup = sa_get_sub_group(group); subgroup != NULL; 291*3082Sdougm subgroup = sa_get_next_group(subgroup)) { 292*3082Sdougm /* never update legacy for ZFS subgroups */ 293*3082Sdougm enable_group(subgroup, NULL); 2943034Sdougm } 2953034Sdougm } 2963034Sdougm if (online) { 297*3082Sdougm zfs = sa_get_group_attr(group, "zfs"); 2983034Sdougm name = sa_get_group_attr(group, "name"); 2993034Sdougm if (name != NULL) { 3003034Sdougm if (zfs == NULL) { 3013034Sdougm (void) snprintf(instance, sizeof (instance), 3023034Sdougm "%s:%s", 3033034Sdougm SA_SVC_FMRI_BASE, name); 3043034Sdougm state = smf_get_state(instance); 3053034Sdougm if (state == NULL || 3063034Sdougm strcmp(state, "online") != 0) { 3073034Sdougm (void) smf_enable_instance(instance, 0); 3083034Sdougm free(state); 3093034Sdougm } 3103034Sdougm } else { 3113034Sdougm sa_free_attr_string(zfs); 3123034Sdougm zfs = NULL; 3133034Sdougm } 3143034Sdougm if (name != NULL) 3153034Sdougm sa_free_attr_string(name); 3163034Sdougm } 3173034Sdougm } 3183034Sdougm work = work->next; 3193034Sdougm } 3203034Sdougm } 3213034Sdougm if (ret == SA_OK) { 3223034Sdougm ret = sa_update_config(); 3233034Sdougm } 3243034Sdougm return (ret); 3253034Sdougm } 3263034Sdougm 3273034Sdougm /* 3283034Sdougm * chk_opt(optlistp, security, proto) 3293034Sdougm * 3303034Sdougm * Do a sanity check on the optlist provided for the protocol. This 3313034Sdougm * is a syntax check and verification that the property is either a 3323034Sdougm * general or specific to a names optionset. 3333034Sdougm */ 3343034Sdougm 3353034Sdougm static int 3363034Sdougm chk_opt(struct options *optlistp, int security, char *proto) 3373034Sdougm { 3383034Sdougm struct options *optlist; 3393034Sdougm char *sep = ""; 3403034Sdougm int notfirst = 0; 3413034Sdougm int ret; 3423034Sdougm 3433034Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 3443034Sdougm char *optname; 3453034Sdougm 3463034Sdougm optname = optlist->optname; 3473034Sdougm ret = OPT_ADD_OK; 3483034Sdougm /* extract property/value pair */ 3493034Sdougm if (sa_is_security(optname, proto)) { 3503034Sdougm if (!security) 3513034Sdougm ret = OPT_ADD_SECURITY; 3523034Sdougm } else { 3533034Sdougm if (security) 3543034Sdougm ret = OPT_ADD_PROPERTY; 3553034Sdougm } 3563034Sdougm if (ret != OPT_ADD_OK) { 3573034Sdougm if (notfirst == 0) 3583034Sdougm (void) printf(gettext("Property syntax error: ")); 3593034Sdougm switch (ret) { 3603034Sdougm case OPT_ADD_SYNTAX: 3613034Sdougm (void) printf(gettext("%ssyntax error: %s"), 3623034Sdougm sep, optname); 3633034Sdougm sep = ", "; 3643034Sdougm break; 3653034Sdougm case OPT_ADD_SECURITY: 3663034Sdougm (void) printf(gettext("%s%s requires -S"), 3673034Sdougm optname, sep); 3683034Sdougm sep = ", "; 3693034Sdougm break; 3703034Sdougm case OPT_ADD_PROPERTY: 3713034Sdougm (void) printf(gettext("%s%s not supported with -S"), 3723034Sdougm optname, sep); 3733034Sdougm sep = ", "; 3743034Sdougm break; 3753034Sdougm } 3763034Sdougm notfirst++; 3773034Sdougm } 3783034Sdougm } 3793034Sdougm if (notfirst) { 3803034Sdougm (void) printf("\n"); 3813034Sdougm ret = SA_SYNTAX_ERR; 3823034Sdougm } 3833034Sdougm return (ret); 3843034Sdougm } 3853034Sdougm 3863034Sdougm /* 3873034Sdougm * free_opt(optlist) 3883034Sdougm * Free the specified option list. 3893034Sdougm */ 3903034Sdougm static void 3913034Sdougm free_opt(struct options *optlist) 3923034Sdougm { 3933034Sdougm struct options *nextopt; 3943034Sdougm while (optlist != NULL) { 3953034Sdougm nextopt = optlist->next; 3963034Sdougm free(optlist); 3973034Sdougm optlist = nextopt; 3983034Sdougm } 3993034Sdougm } 4003034Sdougm 4013034Sdougm /* 4023034Sdougm * check property list for valid properties 4033034Sdougm * A null value is a remove which is always valid. 4043034Sdougm */ 4053034Sdougm static int 4063034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec) 4073034Sdougm { 4083034Sdougm int ret = SA_OK; 4093034Sdougm struct options *cur; 4103034Sdougm sa_property_t prop; 4113034Sdougm sa_optionset_t parent = NULL; 4123034Sdougm 4133034Sdougm if (object != NULL) { 4143034Sdougm if (sec == NULL) 4153034Sdougm parent = sa_get_optionset(object, proto); 4163034Sdougm else 4173034Sdougm parent = sa_get_security(object, sec, proto); 4183034Sdougm } 4193034Sdougm 4203034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 4213034Sdougm if (cur->optvalue != NULL) { 4223034Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 4233034Sdougm if (prop == NULL) 4243034Sdougm ret = SA_NO_MEMORY; 4253034Sdougm if (ret != SA_OK || 4263034Sdougm (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 4273034Sdougm (void) printf(gettext("Could not add property %s: %s\n"), 4283034Sdougm cur->optname, 4293034Sdougm sa_errorstr(ret)); 4303034Sdougm } 4313034Sdougm (void) sa_remove_property(prop); 4323034Sdougm } 4333034Sdougm } 4343034Sdougm return (ret); 4353034Sdougm } 4363034Sdougm 4373034Sdougm /* 4383034Sdougm * add_optionset(group, optlist, protocol, *err) 4393034Sdougm * Add the options in optlist to an optionset and then add the optionset 4403034Sdougm * to the group. 4413034Sdougm * 4423034Sdougm * The return value indicates if there was a "change" while errors are 4433034Sdougm * returned via the *err parameters. 4443034Sdougm */ 4453034Sdougm static int 4463034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 4473034Sdougm { 4483034Sdougm sa_optionset_t optionset; 4493034Sdougm int ret = SA_OK; 4503034Sdougm int result = 0; 4513034Sdougm 4523034Sdougm optionset = sa_get_optionset(group, proto); 4533034Sdougm if (optionset == NULL) { 4543034Sdougm optionset = sa_create_optionset(group, proto); 4553034Sdougm result = 1; /* adding a protocol is a change */ 4563034Sdougm } 4573034Sdougm if (optionset != NULL) { 4583034Sdougm while (optlist != NULL) { 4593034Sdougm sa_property_t prop; 4603034Sdougm prop = sa_get_property(optionset, optlist->optname); 4613034Sdougm if (prop == NULL) { 4623034Sdougm /* 4633034Sdougm * add the property, but only if it is 4643034Sdougm * a non-NULL or non-zero length value 4653034Sdougm */ 4663034Sdougm if (optlist->optvalue != NULL) { 4673034Sdougm prop = sa_create_property(optlist->optname, 4683034Sdougm optlist->optvalue); 4693034Sdougm if (prop != NULL) { 4703034Sdougm ret = sa_valid_property(optionset, proto, prop); 4713034Sdougm if (ret != SA_OK) { 4723034Sdougm (void) sa_remove_property(prop); 4733034Sdougm (void) printf(gettext("Could not add property " 4743034Sdougm "%s: %s\n"), 4753034Sdougm optlist->optname, 4763034Sdougm sa_errorstr(ret)); 4773034Sdougm } 4783034Sdougm } 4793034Sdougm if (ret == SA_OK) { 4803034Sdougm ret = sa_add_property(optionset, prop); 4813034Sdougm if (ret != SA_OK) { 4823034Sdougm (void) printf(gettext("Could not add property" 4833034Sdougm " %s: %s\n"), 4843034Sdougm optlist->optname, 4853034Sdougm sa_errorstr(ret)); 4863034Sdougm } else { 4873034Sdougm /* there was a change */ 4883034Sdougm result = 1; 4893034Sdougm } 4903034Sdougm } 4913034Sdougm } 4923034Sdougm } else { 4933034Sdougm ret = sa_update_property(prop, optlist->optvalue); 4943034Sdougm /* should check to see if value changed */ 4953034Sdougm if (ret != SA_OK) { 4963034Sdougm (void) printf(gettext("Could not update " 4973034Sdougm "property %s: %s\n"), 4983034Sdougm optlist->optname, 4993034Sdougm sa_errorstr(ret)); 5003034Sdougm } else { 5013034Sdougm result = 1; 5023034Sdougm } 5033034Sdougm } 5043034Sdougm optlist = optlist->next; 5053034Sdougm } 5063034Sdougm ret = sa_commit_properties(optionset, 0); 5073034Sdougm } 5083034Sdougm if (err != NULL) 5093034Sdougm *err = ret; 5103034Sdougm return (result); 5113034Sdougm } 5123034Sdougm 5133034Sdougm /* 5143034Sdougm * sa_create(flags, argc, argv) 5153034Sdougm * create a new group 5163034Sdougm * this may or may not have a protocol associated with it. 5173034Sdougm * No protocol means "all" protocols in this case. 5183034Sdougm */ 5193034Sdougm static int 5203034Sdougm sa_create(int flags, int argc, char *argv[]) 5213034Sdougm { 5223034Sdougm char *groupname; 5233034Sdougm 5243034Sdougm sa_group_t group; 5253034Sdougm int verbose = 0; 5263034Sdougm int dryrun = 0; 5273034Sdougm int c; 5283034Sdougm char *protocol = NULL; 5293034Sdougm int ret = SA_OK; 5303034Sdougm struct options *optlist = NULL; 5313034Sdougm int err = 0; 5323034Sdougm int auth; 5333034Sdougm 5343034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) { 5353034Sdougm switch (c) { 5363034Sdougm case 'v': 5373034Sdougm verbose++; 5383034Sdougm break; 5393034Sdougm case 'n': 5403034Sdougm dryrun++; 5413034Sdougm break; 5423034Sdougm case 'P': 5433034Sdougm protocol = optarg; 5443034Sdougm if (!sa_valid_protocol(protocol)) { 5453034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 5463034Sdougm protocol); 5473034Sdougm return (SA_INVALID_PROTOCOL); 5483034Sdougm } 5493034Sdougm break; 5503034Sdougm case 'p': 5513034Sdougm ret = add_opt(&optlist, optarg, 0); 5523034Sdougm switch (ret) { 5533034Sdougm case OPT_ADD_SYNTAX: 5543034Sdougm (void) printf(gettext("Property syntax error for " 5553034Sdougm "property: %s\n"), 5563034Sdougm optarg); 5573034Sdougm return (SA_SYNTAX_ERR); 5583034Sdougm case OPT_ADD_SECURITY: 5593034Sdougm (void) printf(gettext("Security properties need " 5603034Sdougm "to be set with set-security: %s\n"), 5613034Sdougm optarg); 5623034Sdougm return (SA_SYNTAX_ERR); 5633034Sdougm default: 5643034Sdougm break; 5653034Sdougm } 5663034Sdougm 5673034Sdougm break; 5683034Sdougm default: 5693034Sdougm case 'h': 5703034Sdougm case '?': 5713034Sdougm (void) printf(gettext("usage: %s\n"), 5723034Sdougm sa_get_usage(USAGE_CREATE)); 5733034Sdougm return (0); 5743034Sdougm } 5753034Sdougm } 5763034Sdougm 5773034Sdougm if (optind >= argc) { 5783034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 5793034Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 5803034Sdougm return (SA_BAD_PATH); 5813034Sdougm } 5823034Sdougm 5833034Sdougm if ((optind + 1) < argc) { 5843034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 5853034Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 5863034Sdougm return (SA_SYNTAX_ERR); 5873034Sdougm } 5883034Sdougm 5893034Sdougm if (protocol == NULL && optlist != NULL) { 5903034Sdougm /* lookup default protocol */ 5913034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 5923034Sdougm (void) printf(gettext("\tprotocol must be specified " 5933034Sdougm "with properties\n")); 5943034Sdougm return (SA_INVALID_PROTOCOL); 5953034Sdougm } 5963034Sdougm 5973034Sdougm if (optlist != NULL) 5983034Sdougm ret = chk_opt(optlist, 0, protocol); 5993034Sdougm if (ret == OPT_ADD_SECURITY) { 6003034Sdougm (void) printf(gettext("Security properties not " 6013034Sdougm "supported with create\n")); 6023034Sdougm return (SA_SYNTAX_ERR); 6033034Sdougm } 6043034Sdougm 6053034Sdougm /* 6063034Sdougm * if a group already exists, we can only add a new protocol 6073034Sdougm * to it and not create a new one or add the same protocol 6083034Sdougm * again. 6093034Sdougm */ 6103034Sdougm 6113034Sdougm groupname = argv[optind]; 6123034Sdougm 6133034Sdougm auth = check_authorizations(groupname, flags); 6143034Sdougm 6153034Sdougm group = sa_get_group(groupname); 6163034Sdougm if (group != NULL) { 6173034Sdougm /* group exists so must be a protocol add */ 6183034Sdougm if (protocol != NULL) { 6193034Sdougm if (has_protocol(group, protocol)) { 6203034Sdougm (void) printf(gettext("Group \"%s\" already exists" 6213034Sdougm " with protocol %s\n"), 6223034Sdougm groupname, protocol); 6233034Sdougm ret = SA_DUPLICATE_NAME; 6243034Sdougm } 6253034Sdougm } else { 6263034Sdougm /* must add new protocol */ 6273034Sdougm (void) printf(gettext("Group already exists and no protocol" 6283034Sdougm " specified.\n")); 6293034Sdougm ret = SA_DUPLICATE_NAME; 6303034Sdougm } 6313034Sdougm } else { 6323034Sdougm /* 6333034Sdougm * is it a valid name? Must comply with SMF instance 6343034Sdougm * name restrictions. 6353034Sdougm */ 6363034Sdougm if (!sa_valid_group_name(groupname)) { 6373034Sdougm ret = SA_INVALID_NAME; 6383034Sdougm (void) printf(gettext("Invalid group name: %s\n"), groupname); 6393034Sdougm } 6403034Sdougm } 6413034Sdougm if (ret == SA_OK) { 6423034Sdougm /* check protocol vs optlist */ 6433034Sdougm if (optlist != NULL) { 6443034Sdougm /* check options, if any, for validity */ 6453034Sdougm ret = valid_options(optlist, protocol, group, NULL); 6463034Sdougm } 6473034Sdougm } 6483034Sdougm if (ret == SA_OK && !dryrun) { 6493034Sdougm if (group == NULL) { 6503034Sdougm group = sa_create_group((char *)groupname, &err); 6513034Sdougm } 6523034Sdougm if (group != NULL) { 6533034Sdougm sa_optionset_t optionset; 6543034Sdougm if (optlist != NULL) { 6553034Sdougm (void) add_optionset(group, optlist, protocol, &ret); 6563034Sdougm } else if (protocol != NULL) { 6573034Sdougm optionset = sa_create_optionset(group, protocol); 6583034Sdougm if (optionset == NULL) 6593034Sdougm ret = SA_NO_MEMORY; 6603034Sdougm } else if (protocol == NULL) { 6613034Sdougm char **protolist; 6623034Sdougm int numprotos, i; 6633034Sdougm numprotos = sa_get_protocols(&protolist); 6643034Sdougm for (i = 0; i < numprotos; i++) { 6653034Sdougm optionset = sa_create_optionset(group, protolist[i]); 6663034Sdougm } 6673034Sdougm if (protolist != NULL) 6683034Sdougm free(protolist); 6693034Sdougm } 6703034Sdougm /* 6713034Sdougm * we have a group and legal additions 6723034Sdougm */ 6733034Sdougm if (ret == SA_OK) { 6743034Sdougm /* 6753034Sdougm * commit to configuration for protocols that 6763034Sdougm * need to do block updates. For NFS, this 6773034Sdougm * doesn't do anything but it will be run for 6783034Sdougm * all protocols that implement the 6793034Sdougm * appropriate plugin. 6803034Sdougm */ 6813034Sdougm ret = sa_update_config(); 6823034Sdougm } else { 6833034Sdougm if (group != NULL) 6843034Sdougm (void) sa_remove_group(group); 6853034Sdougm } 6863034Sdougm } else { 6873034Sdougm ret = err; 6883034Sdougm (void) printf(gettext("Could not create group: %s\n"), 6893034Sdougm sa_errorstr(ret)); 6903034Sdougm } 6913034Sdougm } 6923034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 6933034Sdougm (void) printf(gettext("Command would fail: %s\n"), 6943034Sdougm sa_errorstr(SA_NO_PERMISSION)); 6953034Sdougm ret = SA_NO_PERMISSION; 6963034Sdougm } 6973034Sdougm free_opt(optlist); 6983034Sdougm return (ret); 6993034Sdougm } 7003034Sdougm 7013034Sdougm /* 7023034Sdougm * group_status(group) 7033034Sdougm * 7043034Sdougm * return the current status (enabled/disabled) of the group. 7053034Sdougm */ 7063034Sdougm 7073034Sdougm static char * 7083034Sdougm group_status(sa_group_t group) 7093034Sdougm { 7103034Sdougm char *state; 7113034Sdougm int enabled = 0; 7123034Sdougm 7133034Sdougm state = sa_get_group_attr(group, "state"); 7143034Sdougm if (state != NULL) { 7153034Sdougm if (strcmp(state, "enabled") == 0) { 7163034Sdougm enabled = 1; 7173034Sdougm } 7183034Sdougm sa_free_attr_string(state); 7193034Sdougm } 7203034Sdougm return (enabled ? gettext("enabled") : gettext("disabled")); 7213034Sdougm } 7223034Sdougm 7233034Sdougm /* 7243034Sdougm * sa_delete(flags, argc, argv) 7253034Sdougm * 7263034Sdougm * Delete a group. 7273034Sdougm */ 7283034Sdougm 7293034Sdougm static int 7303034Sdougm sa_delete(int flags, int argc, char *argv[]) 7313034Sdougm { 7323034Sdougm char *groupname; 7333034Sdougm sa_group_t group; 7343034Sdougm sa_share_t share; 7353034Sdougm int verbose = 0; 7363034Sdougm int dryrun = 0; 7373034Sdougm int force = 0; 7383034Sdougm int c; 7393034Sdougm char *protocol = NULL; 7403034Sdougm char *sectype = NULL; 7413034Sdougm int ret = SA_OK; 7423034Sdougm int auth; 7433034Sdougm 7443034Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 7453034Sdougm switch (c) { 7463034Sdougm case 'v': 7473034Sdougm verbose++; 7483034Sdougm break; 7493034Sdougm case 'n': 7503034Sdougm dryrun++; 7513034Sdougm break; 7523034Sdougm case 'P': 7533034Sdougm protocol = optarg; 7543034Sdougm if (!sa_valid_protocol(protocol)) { 7553034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 7563034Sdougm protocol); 7573034Sdougm return (SA_INVALID_PROTOCOL); 7583034Sdougm } 7593034Sdougm break; 7603034Sdougm case 'S': 7613034Sdougm sectype = optarg; 7623034Sdougm break; 7633034Sdougm case 'f': 7643034Sdougm force++; 7653034Sdougm break; 7663034Sdougm default: 7673034Sdougm case 'h': 7683034Sdougm case '?': 7693034Sdougm (void) printf(gettext("usage: %s\n"), 7703034Sdougm sa_get_usage(USAGE_DELETE)); 7713034Sdougm return (0); 7723034Sdougm } 7733034Sdougm } 7743034Sdougm 7753034Sdougm if (optind >= argc) { 7763034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 7773034Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 7783034Sdougm return (SA_SYNTAX_ERR); 7793034Sdougm } 7803034Sdougm 7813034Sdougm if ((optind + 1) < argc) { 7823034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 7833034Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 7843034Sdougm return (SA_SYNTAX_ERR); 7853034Sdougm } 7863034Sdougm 7873034Sdougm if (sectype != NULL && protocol == NULL) { 7883034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 7893034Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 7903034Sdougm "specified.\n")); 7913034Sdougm return (SA_SYNTAX_ERR); 7923034Sdougm } 7933034Sdougm 7943034Sdougm /* 7953034Sdougm * Determine if the group already exists since it must in 7963034Sdougm * order to be removed. 7973034Sdougm * 7983034Sdougm * We can delete when: 7993034Sdougm * 8003034Sdougm * - group is empty 8013034Sdougm * - force flag is set 8023034Sdougm * - if protocol specified, only delete the protocol 8033034Sdougm */ 8043034Sdougm 8053034Sdougm groupname = argv[optind]; 8063034Sdougm group = sa_get_group(groupname); 8073034Sdougm if (group == NULL) { 8083034Sdougm ret = SA_NO_SUCH_GROUP; 8093034Sdougm } else { 8103034Sdougm auth = check_authorizations(groupname, flags); 8113034Sdougm if (protocol == NULL) { 8123034Sdougm share = sa_get_share(group, NULL); 8133034Sdougm if (share != NULL) 8143034Sdougm ret = SA_BUSY; 8153034Sdougm if (share == NULL || (share != NULL && force == 1)) { 8163034Sdougm ret = SA_OK; 8173034Sdougm if (!dryrun) { 8183034Sdougm while (share != NULL) { 8193034Sdougm sa_share_t next_share; 8203034Sdougm next_share = sa_get_next_share(share); 8213034Sdougm /* 8223034Sdougm * need to do the disable of each 8233034Sdougm * share, but don't actually do 8243034Sdougm * anything on a dryrun. 8253034Sdougm */ 8263034Sdougm ret = sa_disable_share(share, NULL); 8273034Sdougm ret = sa_remove_share(share); 8283034Sdougm share = next_share; 8293034Sdougm } 8303034Sdougm ret = sa_remove_group(group); 8313034Sdougm } 8323034Sdougm } 8333034Sdougm /* commit to configuration if not a dryrun */ 8343034Sdougm if (!dryrun && ret == SA_OK) { 8353034Sdougm ret = sa_update_config(); 8363034Sdougm } 8373034Sdougm } else { 8383034Sdougm /* a protocol delete */ 8393034Sdougm sa_optionset_t optionset; 8403034Sdougm sa_security_t security; 8413034Sdougm if (sectype != NULL) { 8423034Sdougm /* only delete specified security */ 8433034Sdougm security = sa_get_security(group, sectype, protocol); 8443034Sdougm if (security != NULL && !dryrun) { 8453034Sdougm ret = sa_destroy_security(security); 8463034Sdougm } else { 8473034Sdougm ret = SA_INVALID_PROTOCOL; 8483034Sdougm } 8493034Sdougm } else { 8503034Sdougm optionset = sa_get_optionset(group, protocol); 8513034Sdougm if (optionset != NULL && !dryrun) { 8523034Sdougm /* have an optionset with protocol to delete */ 8533034Sdougm ret = sa_destroy_optionset(optionset); 8543034Sdougm /* 8553034Sdougm * now find all security sets for the protocol 8563034Sdougm * and remove them. Don't remove other 8573034Sdougm * protocols. 8583034Sdougm */ 8593034Sdougm for (security = sa_get_security(group, NULL, NULL); 8603034Sdougm ret == SA_OK && security != NULL; 8613034Sdougm security = sa_get_next_security(security)) { 8623034Sdougm char *secprot; 8633034Sdougm 8643034Sdougm secprot = sa_get_security_attr(security, "type"); 8653034Sdougm if (secprot != NULL && 8663034Sdougm strcmp(secprot, protocol) == 0) 8673034Sdougm ret = sa_destroy_security(security); 8683034Sdougm if (secprot != NULL) 8693034Sdougm sa_free_attr_string(secprot); 8703034Sdougm } 8713034Sdougm } else { 8723034Sdougm if (!dryrun) 8733034Sdougm ret = SA_INVALID_PROTOCOL; 8743034Sdougm } 8753034Sdougm } 8763034Sdougm } 8773034Sdougm } 8783034Sdougm if (ret != SA_OK) { 8793034Sdougm (void) printf(gettext("Could not delete group: %s\n"), 8803034Sdougm sa_errorstr(ret)); 8813034Sdougm } else if (dryrun && !auth && verbose) { 8823034Sdougm (void) printf(gettext("Command would fail: %s\n"), 8833034Sdougm sa_errorstr(SA_NO_PERMISSION)); 8843034Sdougm } 8853034Sdougm return (ret); 8863034Sdougm } 8873034Sdougm 8883034Sdougm /* 8893034Sdougm * strndupr(*buff, str, buffsize) 8903034Sdougm * 8913034Sdougm * used with small strings to duplicate and possibly increase the 8923034Sdougm * buffer size of a string. 8933034Sdougm */ 8943034Sdougm static char * 8953034Sdougm strndupr(char *buff, char *str, int *buffsize) 8963034Sdougm { 8973034Sdougm int limit; 8983034Sdougm char *orig_buff = buff; 8993034Sdougm 9003034Sdougm if (buff == NULL) { 9013034Sdougm buff = (char *)malloc(64); 9023034Sdougm if (buff == NULL) 9033034Sdougm return (NULL); 9043034Sdougm *buffsize = 64; 9053034Sdougm buff[0] = '\0'; 9063034Sdougm } 9073034Sdougm limit = strlen(buff) + strlen(str) + 1; 9083034Sdougm if (limit > *buffsize) { 9093034Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 9103034Sdougm buff = realloc(buff, limit); 9113034Sdougm } 9123034Sdougm if (buff != NULL) { 9133034Sdougm (void) strcat(buff, str); 9143034Sdougm } else { 9153034Sdougm /* if it fails, fail it hard */ 9163034Sdougm if (orig_buff != NULL) 9173034Sdougm free(orig_buff); 9183034Sdougm } 9193034Sdougm return (buff); 9203034Sdougm } 9213034Sdougm 9223034Sdougm /* 9233034Sdougm * group_proto(group) 9243034Sdougm * 9253034Sdougm * return a string of all the protocols (space separated) associated 9263034Sdougm * with this group. 9273034Sdougm */ 9283034Sdougm 9293034Sdougm static char * 9303034Sdougm group_proto(sa_group_t group) 9313034Sdougm { 9323034Sdougm sa_optionset_t optionset; 9333034Sdougm char *proto; 9343034Sdougm char *buff = NULL; 9353034Sdougm int buffsize = 0; 9363034Sdougm int addspace = 0; 9373034Sdougm /* 9383034Sdougm * get the protocol list by finding the optionsets on this 9393034Sdougm * group and extracting the type value. The initial call to 9403034Sdougm * strndupr() initailizes buff. 9413034Sdougm */ 9423034Sdougm buff = strndupr(buff, "", &buffsize); 9433034Sdougm if (buff != NULL) { 9443034Sdougm for (optionset = sa_get_optionset(group, NULL); 9453034Sdougm optionset != NULL && buff != NULL; 9463034Sdougm optionset = sa_get_next_optionset(optionset)) { 9473034Sdougm /* 9483034Sdougm * extract out the protocol type from this optionset 9493034Sdougm * and append it to the buffer "buff". strndupr() will 9503034Sdougm * reallocate space as necessay. 9513034Sdougm */ 9523034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 9533034Sdougm if (proto != NULL) { 9543034Sdougm if (addspace++) 9553034Sdougm buff = strndupr(buff, " ", &buffsize); 9563034Sdougm buff = strndupr(buff, proto, &buffsize); 9573034Sdougm sa_free_attr_string(proto); 9583034Sdougm } 9593034Sdougm } 9603034Sdougm } 9613034Sdougm return (buff); 9623034Sdougm } 9633034Sdougm 9643034Sdougm /* 9653034Sdougm * sa_list(flags, argc, argv) 9663034Sdougm * 9673034Sdougm * implements the "list" subcommand to list groups and optionally 9683034Sdougm * their state and protocols. 9693034Sdougm */ 9703034Sdougm 9713034Sdougm static int 9723034Sdougm sa_list(int flags, int argc, char *argv[]) 9733034Sdougm { 9743034Sdougm sa_group_t group; 9753034Sdougm int verbose = 0; 9763034Sdougm int c; 9773034Sdougm char *protocol = NULL; 9783034Sdougm #ifdef lint 9793034Sdougm flags = flags; 9803034Sdougm #endif 9813034Sdougm 9823034Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 9833034Sdougm switch (c) { 9843034Sdougm case 'v': 9853034Sdougm verbose++; 9863034Sdougm break; 9873034Sdougm case 'P': 9883034Sdougm protocol = optarg; 9893034Sdougm if (!sa_valid_protocol(protocol)) { 9903034Sdougm (void) printf(gettext("Invalid protocol specified:" 9913034Sdougm "%s\n"), 9923034Sdougm protocol); 9933034Sdougm return (SA_INVALID_PROTOCOL); 9943034Sdougm } 9953034Sdougm break; 9963034Sdougm default: 9973034Sdougm case 'h': 9983034Sdougm case '?': 9993034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_LIST)); 10003034Sdougm return (0); 10013034Sdougm } 10023034Sdougm } 10033034Sdougm 10043034Sdougm for (group = sa_get_group(NULL); group != NULL; 10053034Sdougm group = sa_get_next_group(group)) { 10063034Sdougm char *name; 10073034Sdougm char *proto; 10083034Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 10093034Sdougm name = sa_get_group_attr(group, "name"); 10103034Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 10113034Sdougm (void) printf("%s", (char *)name); 10123034Sdougm if (verbose) { 10133034Sdougm /* 10143034Sdougm * need the list of protocols 10153034Sdougm * and current status once 10163034Sdougm * available. 10173034Sdougm */ 10183034Sdougm (void) printf("\t%s", group_status(group)); 10193034Sdougm proto = group_proto(group); 10203034Sdougm if (proto != NULL) { 10213034Sdougm (void) printf("\t%s", (char *)proto); 10223034Sdougm free(proto); 10233034Sdougm } 10243034Sdougm } 10253034Sdougm (void) printf("\n"); 10263034Sdougm } 10273034Sdougm if (name != NULL) 10283034Sdougm sa_free_attr_string(name); 10293034Sdougm } 10303034Sdougm } 10313034Sdougm return (0); 10323034Sdougm } 10333034Sdougm 10343034Sdougm /* 10353034Sdougm * out_properties(optionset, proto, sec) 10363034Sdougm * 10373034Sdougm * Format the properties and encode the protocol and optional named 10383034Sdougm * optionset into the string. 10393034Sdougm * 10403034Sdougm * format is protocol[:name]=(property-list) 10413034Sdougm */ 10423034Sdougm 10433034Sdougm static void 10443034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 10453034Sdougm { 10463034Sdougm char *type; 10473034Sdougm char *value; 10483034Sdougm int spacer; 10493034Sdougm sa_property_t prop; 10503034Sdougm 10513034Sdougm if (sec == NULL) { 10523034Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 10533034Sdougm } else { 10543034Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 10553034Sdougm } 10563034Sdougm 10573034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 10583034Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 10593034Sdougm 10603034Sdougm /* 10613034Sdougm * extract the property name/value and output with 10623034Sdougm * appropriate spacing. I.e. no prefixed space the 10633034Sdougm * first time through but a space on subsequent 10643034Sdougm * properties. 10653034Sdougm */ 10663034Sdougm type = sa_get_property_attr(prop, "type"); 10673034Sdougm value = sa_get_property_attr(prop, "value"); 10683034Sdougm if (type != NULL) { 10693034Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 10703034Sdougm spacer = 1; 10713034Sdougm if (value != NULL) 10723034Sdougm (void) printf("\"%s\"", value); 10733034Sdougm else 10743034Sdougm (void) printf("\"\""); 10753034Sdougm } 10763034Sdougm if (type != NULL) 10773034Sdougm sa_free_attr_string(type); 10783034Sdougm if (value != NULL) 10793034Sdougm sa_free_attr_string(value); 10803034Sdougm } 10813034Sdougm (void) printf(")"); 10823034Sdougm } 10833034Sdougm 10843034Sdougm /* 10853034Sdougm * show_properties(group, protocol, prefix) 10863034Sdougm * 10873034Sdougm * print the properties for a group. If protocol is NULL, do all 10883034Sdougm * protocols otherwise only the specified protocol. All security 10893034Sdougm * (named groups specific to the protocol) are included. 10903034Sdougm * 10913034Sdougm * The "prefix" is always applied. The caller knows whether it wants 10923034Sdougm * some type of prefix string (white space) or not. Once the prefix 10933034Sdougm * has been output, it is reduced to the zero length string for the 10943034Sdougm * remainder of the property output. 10953034Sdougm */ 10963034Sdougm 10973034Sdougm static void 10983034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 10993034Sdougm { 11003034Sdougm sa_optionset_t optionset; 11013034Sdougm sa_security_t security; 11023034Sdougm char *value; 11033034Sdougm char *secvalue; 11043034Sdougm 11053034Sdougm if (protocol != NULL) { 11063034Sdougm optionset = sa_get_optionset(group, protocol); 11073034Sdougm if (optionset != NULL) { 11083034Sdougm (void) printf("%s", prefix); 11093034Sdougm prefix = ""; 11103034Sdougm out_properties(optionset, protocol, NULL); 11113034Sdougm } 11123034Sdougm security = sa_get_security(group, protocol, NULL); 11133034Sdougm if (security != NULL) { 11143034Sdougm (void) printf("%s", prefix); 11153034Sdougm prefix = ""; 11163034Sdougm out_properties(security, protocol, NULL); 11173034Sdougm } 11183034Sdougm } else { 11193034Sdougm for (optionset = sa_get_optionset(group, protocol); 11203034Sdougm optionset != NULL; 11213034Sdougm optionset = sa_get_next_optionset(optionset)) { 11223034Sdougm 11233034Sdougm value = sa_get_optionset_attr(optionset, "type"); 11243034Sdougm (void) printf("%s", prefix); 11253034Sdougm prefix = ""; 11263034Sdougm out_properties(optionset, value, 0); 11273034Sdougm if (value != NULL) 11283034Sdougm sa_free_attr_string(value); 11293034Sdougm } 11303034Sdougm for (security = sa_get_security(group, NULL, protocol); 11313034Sdougm security != NULL; 11323034Sdougm security = sa_get_next_security(security)) { 11333034Sdougm 11343034Sdougm value = sa_get_security_attr(security, "type"); 11353034Sdougm secvalue = sa_get_security_attr(security, "sectype"); 11363034Sdougm (void) printf("%s", prefix); 11373034Sdougm prefix = ""; 11383034Sdougm out_properties(security, value, secvalue); 11393034Sdougm if (value != NULL) 11403034Sdougm sa_free_attr_string(value); 11413034Sdougm if (secvalue != NULL) 11423034Sdougm sa_free_attr_string(secvalue); 11433034Sdougm } 11443034Sdougm } 11453034Sdougm } 11463034Sdougm 11473034Sdougm /* 11483034Sdougm * show_group(group, verbose, properties, proto, subgroup) 11493034Sdougm * 11503034Sdougm * helper function to show the contents of a group. 11513034Sdougm */ 11523034Sdougm 11533034Sdougm static void 11543034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 11553034Sdougm char *subgroup) 11563034Sdougm { 11573034Sdougm sa_share_t share; 11583034Sdougm char *groupname; 11593034Sdougm char *sharepath; 11603034Sdougm char *resource; 11613034Sdougm char *description; 11623034Sdougm char *type; 11633034Sdougm char *zfs = NULL; 11643034Sdougm int iszfs = 0; 11653034Sdougm 11663034Sdougm groupname = sa_get_group_attr(group, "name"); 11673034Sdougm if (groupname != NULL) { 11683034Sdougm if (proto != NULL && !has_protocol(group, proto)) { 11693034Sdougm sa_free_attr_string(groupname); 11703034Sdougm return; 11713034Sdougm } 11723034Sdougm /* 11733034Sdougm * check to see if the group is managed by ZFS. If 11743034Sdougm * there is an attribute, then it is. A non-NULL zfs 11753034Sdougm * variable will trigger the different way to display 11763034Sdougm * and will remove the transient property indicator 11773034Sdougm * from the output. 11783034Sdougm */ 11793034Sdougm zfs = sa_get_group_attr(group, "zfs"); 11803034Sdougm if (zfs != NULL) { 11813034Sdougm iszfs = 1; 11823034Sdougm sa_free_attr_string(zfs); 11833034Sdougm } 11843034Sdougm share = sa_get_share(group, NULL); 11853034Sdougm if (subgroup == NULL) 11863034Sdougm (void) printf("%s", groupname); 11873034Sdougm else 11883034Sdougm (void) printf(" %s/%s", subgroup, groupname); 11893034Sdougm if (properties) { 11903034Sdougm show_properties(group, proto, ""); 11913034Sdougm } 11923034Sdougm (void) printf("\n"); 11933034Sdougm if (strcmp(groupname, "zfs") == 0) { 11943034Sdougm sa_group_t zgroup; 11953034Sdougm 11963034Sdougm for (zgroup = sa_get_sub_group(group); zgroup != NULL; 11973034Sdougm zgroup = sa_get_next_group(zgroup)) { 11983034Sdougm show_group(zgroup, verbose, properties, proto, "zfs"); 11993034Sdougm } 12003034Sdougm sa_free_attr_string(groupname); 12013034Sdougm return; 12023034Sdougm } 12033034Sdougm /* 12043034Sdougm * have a group, so list the contents. Resource and 12053034Sdougm * description are only listed if verbose is set. 12063034Sdougm */ 12073034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12083034Sdougm share = sa_get_next_share(share)) { 12093034Sdougm sharepath = sa_get_share_attr(share, "path"); 12103034Sdougm if (sharepath != NULL) { 12113034Sdougm if (verbose) { 12123034Sdougm resource = sa_get_share_attr(share, "resource"); 12133034Sdougm description = sa_get_share_description(share); 12143034Sdougm type = sa_get_share_attr(share, "type"); 12153034Sdougm if (type != NULL && !iszfs && 12163034Sdougm strcmp(type, "transient") == 0) 12173034Sdougm (void) printf("\t* "); 12183034Sdougm else 12193034Sdougm (void) printf("\t "); 12203034Sdougm if (resource != NULL && strlen(resource) > 0) { 12213034Sdougm (void) printf("%s=%s", resource, sharepath); 12223034Sdougm } else { 12233034Sdougm (void) printf("%s", sharepath); 12243034Sdougm } 12253034Sdougm if (resource != NULL) 12263034Sdougm sa_free_attr_string(resource); 12273034Sdougm if (properties) 12283034Sdougm show_properties(share, NULL, "\t"); 12293034Sdougm if (description != NULL) { 12303034Sdougm if (strlen(description) > 0) { 12313034Sdougm (void) printf("\t\"%s\"", description); 12323034Sdougm } 12333034Sdougm sa_free_share_description(description); 12343034Sdougm } 12353034Sdougm if (type != NULL) 12363034Sdougm sa_free_attr_string(type); 12373034Sdougm } else { 12383034Sdougm (void) printf("\t%s", sharepath); 12393034Sdougm if (properties) 12403034Sdougm show_properties(share, NULL, "\t"); 12413034Sdougm } 12423034Sdougm (void) printf("\n"); 12433034Sdougm sa_free_attr_string(sharepath); 12443034Sdougm } 12453034Sdougm } 12463034Sdougm } 12473034Sdougm if (groupname != NULL) { 12483034Sdougm sa_free_attr_string(groupname); 12493034Sdougm } 12503034Sdougm } 12513034Sdougm 12523034Sdougm /* 12533034Sdougm * show_group_xml_init() 12543034Sdougm * 12553034Sdougm * Create an XML document that will be used to display config info via 12563034Sdougm * XML format. 12573034Sdougm */ 12583034Sdougm 12593034Sdougm xmlDocPtr 12603034Sdougm show_group_xml_init() 12613034Sdougm { 12623034Sdougm xmlDocPtr doc; 12633034Sdougm xmlNodePtr root; 12643034Sdougm 12653034Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 12663034Sdougm if (doc != NULL) { 12673034Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 12683034Sdougm if (root != NULL) 12693034Sdougm xmlDocSetRootElement(doc, root); 12703034Sdougm } 12713034Sdougm return (doc); 12723034Sdougm } 12733034Sdougm 12743034Sdougm /* 12753034Sdougm * show_group_xml(doc, group) 12763034Sdougm * 12773034Sdougm * Copy the group info into the XML doc. 12783034Sdougm */ 12793034Sdougm 12803034Sdougm static void 12813034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 12823034Sdougm { 12833034Sdougm xmlNodePtr node; 12843034Sdougm xmlNodePtr root; 12853034Sdougm 12863034Sdougm root = xmlDocGetRootElement(doc); 12873034Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 12883034Sdougm if (node != NULL && root != NULL) { 12893034Sdougm xmlAddChild(root, node); 12903034Sdougm /* 12913034Sdougm * In the future, we may have interally used tags that 12923034Sdougm * should not appear in the XML output. Remove 12933034Sdougm * anything we don't want to show here. 12943034Sdougm */ 12953034Sdougm } 12963034Sdougm } 12973034Sdougm 12983034Sdougm /* 12993034Sdougm * sa_show(flags, argc, argv) 13003034Sdougm * 13013034Sdougm * Implements the show subcommand. 13023034Sdougm */ 13033034Sdougm 13043034Sdougm int 13053034Sdougm sa_show(int flags, int argc, char *argv[]) 13063034Sdougm { 13073034Sdougm sa_group_t group; 13083034Sdougm int verbose = 0; 13093034Sdougm int properties = 0; 13103034Sdougm int c; 13113034Sdougm int ret = SA_OK; 13123034Sdougm char *protocol = NULL; 13133034Sdougm int xml = 0; 13143034Sdougm xmlDocPtr doc; 13153034Sdougm #ifdef lint 13163034Sdougm flags = flags; 13173034Sdougm #endif 13183034Sdougm 13193034Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 13203034Sdougm switch (c) { 13213034Sdougm case 'v': 13223034Sdougm verbose++; 13233034Sdougm break; 13243034Sdougm case 'p': 13253034Sdougm properties++; 13263034Sdougm break; 13273034Sdougm case 'P': 13283034Sdougm protocol = optarg; 13293034Sdougm if (!sa_valid_protocol(protocol)) { 13303034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 13313034Sdougm protocol); 13323034Sdougm return (SA_INVALID_PROTOCOL); 13333034Sdougm } 13343034Sdougm break; 13353034Sdougm case 'x': 13363034Sdougm xml++; 13373034Sdougm break; 13383034Sdougm default: 13393034Sdougm case 'h': 13403034Sdougm case '?': 13413034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SHOW)); 13423034Sdougm return (0); 13433034Sdougm } 13443034Sdougm } 13453034Sdougm 13463034Sdougm if (xml) { 13473034Sdougm doc = show_group_xml_init(); 13483034Sdougm if (doc == NULL) 13493034Sdougm ret = SA_NO_MEMORY; 13503034Sdougm } 13513034Sdougm 13523034Sdougm if (optind == argc) { 13533034Sdougm /* no group specified so go through them all */ 13543034Sdougm for (group = sa_get_group(NULL); group != NULL; 13553034Sdougm group = sa_get_next_group(group)) { 13563034Sdougm /* 13573034Sdougm * have a group so check if one we want and then list 13583034Sdougm * contents with appropriate options. 13593034Sdougm */ 13603034Sdougm if (xml) 13613034Sdougm show_group_xml(doc, group); 13623034Sdougm else 13633034Sdougm show_group(group, verbose, properties, protocol, NULL); 13643034Sdougm } 13653034Sdougm } else { 13663034Sdougm /* have a specified list of groups */ 13673034Sdougm for (; optind < argc; optind++) { 13683034Sdougm group = sa_get_group(argv[optind]); 13693034Sdougm if (group != NULL) { 13703034Sdougm if (xml) 13713034Sdougm show_group_xml(doc, group); 13723034Sdougm else 13733034Sdougm show_group(group, verbose, properties, protocol, NULL); 13743034Sdougm } else { 13753034Sdougm (void) printf(gettext("%s: not found\n"), argv[optind]); 13763034Sdougm ret = SA_NO_SUCH_GROUP; 13773034Sdougm } 13783034Sdougm } 13793034Sdougm } 13803034Sdougm if (xml && ret == SA_OK) { 13813034Sdougm xmlDocFormatDump(stdout, doc, 1); 13823034Sdougm xmlFreeDoc(doc); 13833034Sdougm } 13843034Sdougm return (ret); 13853034Sdougm 13863034Sdougm } 13873034Sdougm 13883034Sdougm /* 13893034Sdougm * enable_share(group, share, update_legacy) 13903034Sdougm * 13913034Sdougm * helper function to enable a share if the group is enabled. 13923034Sdougm */ 13933034Sdougm 13943034Sdougm static int 13953034Sdougm enable_share(sa_group_t group, sa_share_t share, int update_legacy) 13963034Sdougm { 13973034Sdougm char *value; 13983034Sdougm int enabled; 13993034Sdougm sa_optionset_t optionset; 14003034Sdougm int ret = SA_OK; 14013034Sdougm char *zfs = NULL; 14023034Sdougm int iszfs = 0; 14033034Sdougm 14043034Sdougm /* 14053034Sdougm * need to enable this share if the group is enabled but not 14063034Sdougm * otherwise. The enable is also done on each protocol 14073034Sdougm * represented in the group. 14083034Sdougm */ 14093034Sdougm value = sa_get_group_attr(group, "state"); 14103034Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 14113034Sdougm if (value != NULL) 14123034Sdougm sa_free_attr_string(value); 14133034Sdougm /* remove legacy config if necessary */ 14143034Sdougm if (update_legacy) 14153034Sdougm ret = sa_delete_legacy(share); 14163034Sdougm zfs = sa_get_group_attr(group, "zfs"); 14173034Sdougm if (zfs != NULL) { 14183034Sdougm iszfs++; 14193034Sdougm sa_free_attr_string(zfs); 14203034Sdougm } 14213034Sdougm 14223034Sdougm /* 14233034Sdougm * Step through each optionset at the group level and 14243034Sdougm * enable the share based on the protocol type. This 14253034Sdougm * works because protocols must be set on the group 14263034Sdougm * for the protocol to be enabled. 14273034Sdougm */ 14283034Sdougm for (optionset = sa_get_optionset(group, NULL); 14293034Sdougm optionset != NULL && ret == SA_OK; 14303034Sdougm optionset = sa_get_next_optionset(optionset)) { 14313034Sdougm value = sa_get_optionset_attr(optionset, "type"); 14323034Sdougm if (value != NULL) { 14333034Sdougm if (enabled) 14343034Sdougm ret = sa_enable_share(share, value); 14353034Sdougm if (update_legacy && !iszfs) 14363034Sdougm (void) sa_update_legacy(share, value); 14373034Sdougm sa_free_attr_string(value); 14383034Sdougm } 14393034Sdougm } 14403034Sdougm if (ret == SA_OK) 14413034Sdougm (void) sa_update_config(); 14423034Sdougm return (ret); 14433034Sdougm } 14443034Sdougm 14453034Sdougm /* 14463034Sdougm * sa_addshare(flags, argc, argv) 14473034Sdougm * 14483034Sdougm * implements add-share subcommand. 14493034Sdougm */ 14503034Sdougm 14513034Sdougm int 14523034Sdougm sa_addshare(int flags, int argc, char *argv[]) 14533034Sdougm { 14543034Sdougm int verbose = 0; 14553034Sdougm int dryrun = 0; 14563034Sdougm int c; 14573034Sdougm int ret = SA_OK; 14583034Sdougm sa_group_t group; 14593034Sdougm sa_share_t share; 14603034Sdougm char *sharepath = NULL; 14613034Sdougm char *description = NULL; 14623034Sdougm char *resource = NULL; 14633034Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 14643034Sdougm int auth; 14653034Sdougm char dir[MAXPATHLEN]; 14663034Sdougm 14673034Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 14683034Sdougm switch (c) { 14693034Sdougm case 'n': 14703034Sdougm dryrun++; 14713034Sdougm break; 14723034Sdougm case 'v': 14733034Sdougm verbose++; 14743034Sdougm break; 14753034Sdougm case 'd': 14763034Sdougm description = optarg; 14773034Sdougm break; 14783034Sdougm case 'r': 14793034Sdougm resource = optarg; 14803034Sdougm break; 14813034Sdougm case 's': 14823034Sdougm /* 14833034Sdougm * save share path into group. Currently limit 14843034Sdougm * to one share per command. 14853034Sdougm */ 14863034Sdougm if (sharepath != NULL) { 14873034Sdougm (void) printf(gettext("Adding multiple shares not" 14883034Sdougm "supported\n")); 14893034Sdougm return (1); 14903034Sdougm } 14913034Sdougm sharepath = optarg; 14923034Sdougm break; 14933034Sdougm case 't': 14943034Sdougm persist = SA_SHARE_TRANSIENT; 14953034Sdougm break; 14963034Sdougm default: 14973034Sdougm case 'h': 14983034Sdougm case '?': 14993034Sdougm (void) printf(gettext("usage: %s\n"), 15003034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 15013034Sdougm return (0); 15023034Sdougm } 15033034Sdougm } 15043034Sdougm 15053034Sdougm if (optind >= argc) { 15063034Sdougm (void) printf(gettext("usage: %s\n"), 15073034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 15083034Sdougm if (dryrun || sharepath != NULL || description != NULL || 15093034Sdougm resource != NULL || verbose || persist) { 15103034Sdougm (void) printf(gettext("\tgroup must be specified\n")); 15113034Sdougm ret = SA_NO_SUCH_GROUP; 15123034Sdougm } else { 15133034Sdougm ret = SA_OK; 15143034Sdougm } 15153034Sdougm } else { 15163034Sdougm if (sharepath == NULL) { 15173034Sdougm (void) printf(gettext("usage: %s\n"), 15183034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 15193034Sdougm (void) printf(gettext("\t-s sharepath must be specified\n")); 15203034Sdougm ret = SA_BAD_PATH; 15213034Sdougm } 15223034Sdougm if (ret == SA_OK) { 15233034Sdougm if (realpath(sharepath, dir) == NULL) { 15243034Sdougm ret = SA_BAD_PATH; 15253034Sdougm (void) printf(gettext("Path is not valid: %s\n"), 15263034Sdougm sharepath); 15273034Sdougm } else { 15283034Sdougm sharepath = dir; 15293034Sdougm } 15303034Sdougm } 15313034Sdougm if (ret == SA_OK && resource != NULL) { 15323034Sdougm /* check for valid syntax */ 15333034Sdougm if (strpbrk(resource, " \t/") != NULL) { 15343034Sdougm (void) printf(gettext("usage: %s\n"), 15353034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 15363034Sdougm (void) printf(gettext("\tresource must not contain white" 15373034Sdougm "space or '/' characters\n")); 15383034Sdougm ret = SA_BAD_PATH; 15393034Sdougm } 15403034Sdougm } 15413034Sdougm if (ret == SA_OK) { 15423034Sdougm group = sa_get_group(argv[optind]); 15433034Sdougm if (group != NULL) { 15443034Sdougm auth = check_authorizations(argv[optind], flags); 15453034Sdougm share = sa_find_share(sharepath); 15463034Sdougm if (share != NULL) { 15473034Sdougm group = sa_get_parent_group(share); 15483034Sdougm if (group != NULL) { 15493034Sdougm char *groupname; 15503034Sdougm groupname = sa_get_group_attr(group, "name"); 15513034Sdougm if (groupname != NULL) { 15523034Sdougm (void) printf(gettext("Share path already " 15533034Sdougm "shared in group " 15543034Sdougm "\"%s\": %s\n"), 15553034Sdougm groupname, sharepath); 15563034Sdougm sa_free_attr_string(groupname); 15573034Sdougm } else { 15583034Sdougm (void) printf(gettext("Share path already" 15593034Sdougm "shared: %s\n"), 15603034Sdougm groupname, sharepath); 15613034Sdougm } 15623034Sdougm } else { 15633034Sdougm (void) printf(gettext("Share path %s already " 15643034Sdougm "shared\n"), 15653034Sdougm sharepath); 15663034Sdougm } 15673034Sdougm ret = SA_DUPLICATE_NAME; 15683034Sdougm } else { 15693034Sdougm /* 15703034Sdougm * need to check that resource name is unique 15713034Sdougm * at some point. 15723034Sdougm */ 15733034Sdougm if (dryrun) 15743034Sdougm ret = sa_check_path(group, sharepath); 15753034Sdougm else 15763034Sdougm share = sa_add_share(group, sharepath, 15773034Sdougm persist, &ret); 15783034Sdougm if (!dryrun && share == NULL) { 15793034Sdougm (void) printf(gettext("Could not add share: " 15803034Sdougm "%s\n"), 15813034Sdougm sa_errorstr(ret)); 15823034Sdougm } else { 15833034Sdougm if (!dryrun && ret == SA_OK) { 15843034Sdougm if (resource != NULL) { 15853034Sdougm if (strpbrk(resource, " \t/") == NULL) { 15863034Sdougm ret = sa_set_share_attr(share, 15873034Sdougm "resource", 15883034Sdougm resource); 15893034Sdougm } 15903034Sdougm } 15913034Sdougm if (ret == SA_OK && description != NULL) { 15923034Sdougm ret = sa_set_share_description(share, 15933034Sdougm description); 15943034Sdougm } 15953034Sdougm if (ret == SA_OK) { 15963034Sdougm /* now enable the share(s) */ 15973034Sdougm ret = enable_share(group, share, 1); 15983034Sdougm ret = sa_update_config(); 15993034Sdougm } 16003034Sdougm switch (ret) { 16013034Sdougm case SA_DUPLICATE_NAME: 16023034Sdougm (void) printf(gettext("Resource name in" 16033034Sdougm "use: %s\n"), 16043034Sdougm resource); 16053034Sdougm break; 16063034Sdougm default: 16073034Sdougm (void) printf(gettext("Could not set " 16083034Sdougm "attribute: %s\n"), 16093034Sdougm sa_errorstr(ret)); 16103034Sdougm break; 16113034Sdougm case SA_OK: 16123034Sdougm break; 16133034Sdougm } 16143034Sdougm } else if (dryrun && ret == SA_OK && 16153034Sdougm !auth && verbose) { 16163034Sdougm (void) printf(gettext("Command would fail: " 16173034Sdougm "%s\n"), 16183034Sdougm sa_errorstr(SA_NO_PERMISSION)); 16193034Sdougm ret = SA_NO_PERMISSION; 16203034Sdougm } 16213034Sdougm } 16223034Sdougm } 16233034Sdougm } else { 16243034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 16253034Sdougm argv[optind]); 16263034Sdougm ret = SA_NO_SUCH_GROUP; 16273034Sdougm } 16283034Sdougm } 16293034Sdougm } 16303034Sdougm return (ret); 16313034Sdougm } 16323034Sdougm 16333034Sdougm /* 16343034Sdougm * sa_moveshare(flags, argc, argv) 16353034Sdougm * 16363034Sdougm * implements move-share subcommand. 16373034Sdougm */ 16383034Sdougm 16393034Sdougm int 16403034Sdougm sa_moveshare(int flags, int argc, char *argv[]) 16413034Sdougm { 16423034Sdougm int verbose = 0; 16433034Sdougm int dryrun = 0; 16443034Sdougm int c; 16453034Sdougm int ret = SA_OK; 16463034Sdougm sa_group_t group; 16473034Sdougm sa_share_t share; 16483034Sdougm char *sharepath = NULL; 16493034Sdougm int authsrc = 0, authdst = 0; 16503034Sdougm 16513034Sdougm while ((c = getopt(argc, argv, "?hvns:")) != EOF) { 16523034Sdougm switch (c) { 16533034Sdougm case 'n': 16543034Sdougm dryrun++; 16553034Sdougm break; 16563034Sdougm case 'v': 16573034Sdougm verbose++; 16583034Sdougm break; 16593034Sdougm case 's': 16603034Sdougm /* 16613034Sdougm * remove share path from group. Currently limit 16623034Sdougm * to one share per command. 16633034Sdougm */ 16643034Sdougm if (sharepath != NULL) { 16653034Sdougm (void) printf(gettext("Moving multiple shares not" 16663034Sdougm "supported\n")); 16673034Sdougm return (SA_BAD_PATH); 16683034Sdougm } 16693034Sdougm sharepath = optarg; 16703034Sdougm break; 16713034Sdougm default: 16723034Sdougm case 'h': 16733034Sdougm case '?': 16743034Sdougm (void) printf(gettext("usage: %s\n"), 16753034Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 16763034Sdougm return (0); 16773034Sdougm } 16783034Sdougm } 16793034Sdougm 16803034Sdougm if (optind >= argc || sharepath == NULL) { 16813034Sdougm (void) printf(gettext("usage: %s\n"), 16823034Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 16833034Sdougm if (dryrun || verbose || sharepath != NULL) { 16843034Sdougm (void) printf(gettext("\tgroup must be specified\n")); 16853034Sdougm ret = SA_NO_SUCH_GROUP; 16863034Sdougm } else { 16873034Sdougm if (sharepath == NULL) { 16883034Sdougm ret = SA_SYNTAX_ERR; 16893034Sdougm (void) printf(gettext("\tsharepath must be specified\n")); 16903034Sdougm } else 16913034Sdougm ret = SA_OK; 16923034Sdougm } 16933034Sdougm } else { 16943034Sdougm if (sharepath == NULL) { 16953034Sdougm (void) printf(gettext("sharepath must be specified with " 16963034Sdougm "the -s option\n")); 16973034Sdougm ret = SA_BAD_PATH; 16983034Sdougm } else { 16993034Sdougm group = sa_get_group(argv[optind]); 17003034Sdougm if (group != NULL) { 17013034Sdougm share = sa_find_share(sharepath); 17023034Sdougm authdst = check_authorizations(argv[optind], flags); 17033034Sdougm if (share == NULL) { 17043034Sdougm (void) printf(gettext("Share not found: %s\n"), 17053034Sdougm sharepath); 17063034Sdougm ret = SA_NO_SUCH_PATH; 17073034Sdougm } else { 17083034Sdougm sa_group_t parent; 17093034Sdougm char *zfsold; 17103034Sdougm char *zfsnew; 17113034Sdougm 17123034Sdougm parent = sa_get_parent_group(share); 17133034Sdougm if (parent != NULL) { 17143034Sdougm char *pname; 17153034Sdougm pname = sa_get_group_attr(parent, "name"); 17163034Sdougm if (pname != NULL) { 17173034Sdougm authsrc = check_authorizations(pname, flags); 17183034Sdougm sa_free_attr_string(pname); 17193034Sdougm } 17203034Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 17213034Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 17223034Sdougm if ((zfsold != NULL && zfsnew == NULL) || 17233034Sdougm (zfsold == NULL && zfsnew != NULL)) { 17243034Sdougm ret = SA_NOT_ALLOWED; 17253034Sdougm } 17263034Sdougm if (zfsold != NULL) 17273034Sdougm sa_free_attr_string(zfsold); 17283034Sdougm if (zfsnew != NULL) 17293034Sdougm sa_free_attr_string(zfsnew); 17303034Sdougm } 17313034Sdougm if (!dryrun && ret == SA_OK) { 17323034Sdougm ret = sa_move_share(group, share); 17333034Sdougm } 17343034Sdougm if (ret == SA_OK && parent != group && !dryrun) { 17353034Sdougm char *oldstate; 17363034Sdougm ret = sa_update_config(); 17373034Sdougm /* 17383034Sdougm * note that the share may need to be 17393034Sdougm * "unshared" if the new group is 17403034Sdougm * disabled and the old was enabled or 17413034Sdougm * it may need to be share to update 17423034Sdougm * if the new group is enabled. 17433034Sdougm */ 17443034Sdougm oldstate = sa_get_group_attr(parent, "state"); 17453034Sdougm /* enable_share determines what to do */ 17463034Sdougm if (strcmp(oldstate, "enabled") == 0) { 17473034Sdougm (void) sa_disable_share(share, NULL); 17483034Sdougm } 17493034Sdougm (void) enable_share(group, share, 1); 17503034Sdougm if (oldstate != NULL) 17513034Sdougm sa_free_attr_string(oldstate); 17523034Sdougm } 17533034Sdougm if (ret != SA_OK) { 17543034Sdougm (void) printf(gettext("Could not move share: %s\n"), 17553034Sdougm sa_errorstr(ret)); 17563034Sdougm } 17573034Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 17583034Sdougm verbose) { 17593034Sdougm (void) printf(gettext("Command would fail: %s\n"), 17603034Sdougm sa_errorstr(SA_NO_PERMISSION)); 17613034Sdougm } 17623034Sdougm } 17633034Sdougm } else { 17643034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 17653034Sdougm argv[optind]); 17663034Sdougm ret = SA_NO_SUCH_GROUP; 17673034Sdougm } 17683034Sdougm } 17693034Sdougm } 17703034Sdougm return (ret); 17713034Sdougm } 17723034Sdougm 17733034Sdougm /* 17743034Sdougm * sa_removeshare(flags, argc, argv) 17753034Sdougm * 17763034Sdougm * implements remove-share subcommand. 17773034Sdougm */ 17783034Sdougm 17793034Sdougm int 17803034Sdougm sa_removeshare(int flags, int argc, char *argv[]) 17813034Sdougm { 17823034Sdougm int verbose = 0; 17833034Sdougm int dryrun = 0; 17843034Sdougm int force = 0; 17853034Sdougm int c; 17863034Sdougm int ret = SA_OK; 17873034Sdougm sa_group_t group; 17883034Sdougm sa_share_t share; 17893034Sdougm char *sharepath = NULL; 17903034Sdougm char dir[MAXPATHLEN]; 17913034Sdougm int auth; 17923034Sdougm 17933034Sdougm while ((c = getopt(argc, argv, "?hfns:v")) != EOF) { 17943034Sdougm switch (c) { 17953034Sdougm case 'n': 17963034Sdougm dryrun++; 17973034Sdougm break; 17983034Sdougm case 'v': 17993034Sdougm verbose++; 18003034Sdougm break; 18013034Sdougm case 'f': 18023034Sdougm force++; 18033034Sdougm break; 18043034Sdougm case 's': 18053034Sdougm /* 18063034Sdougm * remove share path from group. Currently limit 18073034Sdougm * to one share per command. 18083034Sdougm */ 18093034Sdougm if (sharepath != NULL) { 18103034Sdougm (void) printf(gettext("Removing multiple shares not" 18113034Sdougm "supported\n")); 18123034Sdougm return (SA_SYNTAX_ERR); 18133034Sdougm } 18143034Sdougm sharepath = optarg; 18153034Sdougm break; 18163034Sdougm default: 18173034Sdougm case 'h': 18183034Sdougm case '?': 18193034Sdougm (void) printf(gettext("usage: %s\n"), 18203034Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 18213034Sdougm return (0); 18223034Sdougm } 18233034Sdougm } 18243034Sdougm 18253034Sdougm if (optind >= argc || sharepath == NULL) { 18263034Sdougm if (sharepath == NULL) { 18273034Sdougm (void) printf(gettext("usage: %s\n"), 18283034Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 18293034Sdougm (void) printf(gettext("\t-s sharepath must be specified\n")); 18303034Sdougm ret = SA_BAD_PATH; 18313034Sdougm } else { 18323034Sdougm ret = SA_OK; 18333034Sdougm } 18343034Sdougm } 18353034Sdougm if (ret == SA_OK) { 18363034Sdougm if (optind < argc) { 18373034Sdougm if ((optind + 1) < argc) { 18383034Sdougm (void) printf(gettext("Extraneous group(s) at end of " 18393034Sdougm "command\n")); 18403034Sdougm ret = SA_SYNTAX_ERR; 18413034Sdougm } else { 18423034Sdougm group = sa_get_group(argv[optind]); 18433034Sdougm if (group == NULL) { 18443034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 18453034Sdougm argv[optind]); 18463034Sdougm ret = SA_NO_SUCH_GROUP; 18473034Sdougm } 18483034Sdougm } 18493034Sdougm } else { 18503034Sdougm group = NULL; 18513034Sdougm } 18523034Sdougm if (ret == SA_OK) { 18533034Sdougm if (realpath(sharepath, dir) == NULL) { 18543034Sdougm ret = SA_BAD_PATH; 18553034Sdougm (void) printf(gettext("Path is not valid: %s\n"), 18563034Sdougm sharepath); 18573034Sdougm } else { 18583034Sdougm sharepath = dir; 18593034Sdougm } 18603034Sdougm } 18613034Sdougm if (ret == SA_OK) { 18623034Sdougm if (group != NULL) 18633034Sdougm share = sa_get_share(group, sharepath); 18643034Sdougm else 18653034Sdougm share = sa_find_share(sharepath); 18663034Sdougm if (share == NULL) { 18673034Sdougm if (group != NULL) 18683034Sdougm (void) printf(gettext("Share not found in group %s:" 18693034Sdougm "%s\n"), 18703034Sdougm argv[optind], sharepath); 18713034Sdougm else 18723034Sdougm (void) printf(gettext("Share not found: %s\n"), 18733034Sdougm sharepath); 18743034Sdougm ret = SA_NO_SUCH_PATH; 18753034Sdougm } else { 18763034Sdougm if (group == NULL) 18773034Sdougm group = sa_get_parent_group(share); 18783034Sdougm if (!dryrun) { 18793034Sdougm if (ret == SA_OK) { 18803034Sdougm ret = sa_disable_share(share, NULL); 18813034Sdougm /* 18823034Sdougm * we don't care if it fails since it 18833034Sdougm * could be disabled already. 18843034Sdougm */ 18853034Sdougm if (ret == SA_OK || ret == SA_NO_SUCH_PATH || 18863034Sdougm ret == SA_NOT_SUPPORTED) { 18873034Sdougm ret = sa_remove_share(share); 18883034Sdougm } 18893034Sdougm if (ret == SA_OK) 18903034Sdougm ret = sa_update_config(); 18913034Sdougm } 18923034Sdougm if (ret != SA_OK) { 18933034Sdougm (void) printf(gettext("Could not remove share:" 18943034Sdougm " %s\n"), 18953034Sdougm sa_errorstr(ret)); 18963034Sdougm } 18973034Sdougm } else if (ret == SA_OK) { 18983034Sdougm char *pname; 18993034Sdougm pname = sa_get_group_attr(group, "name"); 19003034Sdougm if (pname != NULL) { 19013034Sdougm auth = check_authorizations(pname, flags); 19023034Sdougm sa_free_attr_string(pname); 19033034Sdougm } 19043034Sdougm if (!auth && verbose) { 19053034Sdougm (void) printf(gettext("Command would fail: %s\n"), 19063034Sdougm sa_errorstr(SA_NO_PERMISSION)); 19073034Sdougm } 19083034Sdougm } 19093034Sdougm } 19103034Sdougm } 19113034Sdougm } 19123034Sdougm return (ret); 19133034Sdougm } 19143034Sdougm 19153034Sdougm /* 19163034Sdougm * sa_set_share(flags, argc, argv) 19173034Sdougm * 19183034Sdougm * implements set-share subcommand. 19193034Sdougm */ 19203034Sdougm 19213034Sdougm int 19223034Sdougm sa_set_share(int flags, int argc, char *argv[]) 19233034Sdougm { 19243034Sdougm int dryrun = 0; 19253034Sdougm int c; 19263034Sdougm int ret = SA_OK; 19273034Sdougm sa_group_t group, sharegroup; 19283034Sdougm sa_share_t share; 19293034Sdougm char *sharepath = NULL; 19303034Sdougm char *description = NULL; 19313034Sdougm char *resource = NULL; 19323034Sdougm int auth; 19333034Sdougm int verbose = 0; 19343034Sdougm 19353034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 19363034Sdougm switch (c) { 19373034Sdougm case 'n': 19383034Sdougm dryrun++; 19393034Sdougm break; 19403034Sdougm case 'd': 19413034Sdougm description = optarg; 19423034Sdougm break; 19433034Sdougm case 'r': 19443034Sdougm resource = optarg; 19453034Sdougm break; 19463034Sdougm case 'v': 19473034Sdougm verbose++; 19483034Sdougm break; 19493034Sdougm case 's': 19503034Sdougm /* 19513034Sdougm * save share path into group. Currently limit 19523034Sdougm * to one share per command. 19533034Sdougm */ 19543034Sdougm if (sharepath != NULL) { 19553034Sdougm (void) printf(gettext("Updating multiple shares not" 19563034Sdougm "supported\n")); 19573034Sdougm return (SA_BAD_PATH); 19583034Sdougm } 19593034Sdougm sharepath = optarg; 19603034Sdougm break; 19613034Sdougm default: 19623034Sdougm case 'h': 19633034Sdougm case '?': 19643034Sdougm (void) printf(gettext("usage: %s\n"), 19653034Sdougm sa_get_usage(USAGE_SET_SHARE)); 19663034Sdougm return (SA_OK); 19673034Sdougm } 19683034Sdougm } 19693034Sdougm if (optind >= argc || sharepath == NULL) { 19703034Sdougm if (sharepath == NULL) { 19713034Sdougm (void) printf(gettext("usage: %s\n"), 19723034Sdougm sa_get_usage(USAGE_SET_SHARE)); 19733034Sdougm (void) printf(gettext("\tgroup must be specified\n")); 19743034Sdougm ret = SA_BAD_PATH; 19753034Sdougm } else { 19763034Sdougm ret = SA_OK; 19773034Sdougm } 19783034Sdougm } 19793034Sdougm if ((optind + 1) < argc) { 19803034Sdougm (void) printf(gettext("usage: %s\n"), 19813034Sdougm sa_get_usage(USAGE_SET_SHARE)); 19823034Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 19833034Sdougm ret = SA_SYNTAX_ERR; 19843034Sdougm } 19853034Sdougm if (ret == SA_OK) { 19863034Sdougm char *groupname; 19873034Sdougm if (optind < argc) { 19883034Sdougm groupname = argv[optind]; 19893034Sdougm group = sa_get_group(groupname); 19903034Sdougm } else { 19913034Sdougm group = NULL; 19923034Sdougm groupname = NULL; 19933034Sdougm } 19943034Sdougm share = sa_find_share(sharepath); 19953034Sdougm if (share != NULL) { 19963034Sdougm sharegroup = sa_get_parent_group(share); 19973034Sdougm if (group != NULL && group != sharegroup) { 19983034Sdougm (void) printf(gettext("Group \"%s\" does not contain " 19993034Sdougm "share %s\n"), 20003034Sdougm argv[optind], sharepath); 20013034Sdougm ret = SA_BAD_PATH; 20023034Sdougm } else { 20033034Sdougm int delgroupname = 0; 20043034Sdougm if (groupname == NULL) { 20053034Sdougm groupname = sa_get_group_attr(sharegroup, "name"); 20063034Sdougm delgroupname = 1; 20073034Sdougm } 20083034Sdougm if (groupname != NULL) { 20093034Sdougm auth = check_authorizations(groupname, flags); 20103034Sdougm if (delgroupname) { 20113034Sdougm sa_free_attr_string(groupname); 20123034Sdougm groupname = NULL; 20133034Sdougm } 20143034Sdougm } else { 20153034Sdougm ret = SA_NO_MEMORY; 20163034Sdougm } 20173034Sdougm if (resource != NULL) { 20183034Sdougm if (strpbrk(resource, " \t/") == NULL) { 20193034Sdougm if (!dryrun) { 20203034Sdougm ret = sa_set_share_attr(share, "resource", 20213034Sdougm resource); 20223034Sdougm } else { 20233034Sdougm sa_share_t resshare; 20243034Sdougm resshare = sa_get_resource(sharegroup, 20253034Sdougm resource); 20263034Sdougm if (resshare != NULL && resshare != share) 20273034Sdougm ret = SA_DUPLICATE_NAME; 20283034Sdougm } 20293034Sdougm } else { 20303034Sdougm ret = SA_BAD_PATH; 20313034Sdougm (void) printf(gettext("Resource must not contain " 20323034Sdougm "white space or '/'\n")); 20333034Sdougm } 20343034Sdougm } 20353034Sdougm if (ret == SA_OK && description != NULL) { 20363034Sdougm ret = sa_set_share_description(share, description); 20373034Sdougm } 20383034Sdougm } 20393034Sdougm if (!dryrun && ret == SA_OK) { 20403034Sdougm ret = sa_update_config(); 20413034Sdougm } 20423034Sdougm switch (ret) { 20433034Sdougm case SA_DUPLICATE_NAME: 20443034Sdougm (void) printf(gettext("Resource name in use: %s\n"), 20453034Sdougm resource); 20463034Sdougm break; 20473034Sdougm default: 20483034Sdougm (void) printf(gettext("Could not set attribute: %s\n"), 20493034Sdougm sa_errorstr(ret)); 20503034Sdougm break; 20513034Sdougm case SA_OK: 20523034Sdougm if (dryrun && !auth && verbose) { 20533034Sdougm (void) printf(gettext("Command would fail: %s\n"), 20543034Sdougm sa_errorstr(SA_NO_PERMISSION)); 20553034Sdougm } 20563034Sdougm break; 20573034Sdougm } 20583034Sdougm } else { 20593034Sdougm (void) printf(gettext("Share path \"%s\" not found\n"), 20603034Sdougm sharepath); 20613034Sdougm ret = SA_NO_SUCH_PATH; 20623034Sdougm } 20633034Sdougm } 20643034Sdougm return (ret); 20653034Sdougm } 20663034Sdougm 20673034Sdougm /* 20683034Sdougm * add_security(group, sectype, optlist, proto, *err) 20693034Sdougm * 20703034Sdougm * Helper function to add a security option (named optionset) to the 20713034Sdougm * group. 20723034Sdougm */ 20733034Sdougm 20743034Sdougm static int 20753034Sdougm add_security(sa_group_t group, char *sectype, 20763034Sdougm struct options *optlist, char *proto, int *err) 20773034Sdougm { 20783034Sdougm sa_security_t security; 20793034Sdougm int ret = SA_OK; 20803034Sdougm int result = 0; 20813034Sdougm 20823034Sdougm sectype = sa_proto_space_alias(proto, sectype); 20833034Sdougm security = sa_get_security(group, sectype, proto); 20843034Sdougm if (security == NULL) { 20853034Sdougm security = sa_create_security(group, sectype, proto); 20863034Sdougm } 20873034Sdougm if (sectype != NULL) 20883034Sdougm sa_free_attr_string(sectype); 20893034Sdougm if (security != NULL) { 20903034Sdougm while (optlist != NULL) { 20913034Sdougm sa_property_t prop; 20923034Sdougm prop = sa_get_property(security, optlist->optname); 20933034Sdougm if (prop == NULL) { 20943034Sdougm /* 20953034Sdougm * add the property, but only if it is 20963034Sdougm * a non-NULL or non-zero length value 20973034Sdougm */ 20983034Sdougm if (optlist->optvalue != NULL) { 20993034Sdougm prop = sa_create_property(optlist->optname, 21003034Sdougm optlist->optvalue); 21013034Sdougm if (prop != NULL) { 21023034Sdougm ret = sa_valid_property(security, proto, prop); 21033034Sdougm if (ret != SA_OK) { 21043034Sdougm (void) sa_remove_property(prop); 21053034Sdougm (void) printf(gettext("Could not add " 21063034Sdougm "property %s: %s\n"), 21073034Sdougm optlist->optname, 21083034Sdougm sa_errorstr(ret)); 21093034Sdougm } 21103034Sdougm if (ret == SA_OK) { 21113034Sdougm ret = sa_add_property(security, prop); 21123034Sdougm if (ret != SA_OK) { 21133034Sdougm (void) printf(gettext("Could not add " 21143034Sdougm "property (%s=%s): %s\n"), 21153034Sdougm optlist->optname, 21163034Sdougm optlist->optvalue, 21173034Sdougm sa_errorstr(ret)); 21183034Sdougm } else { 21193034Sdougm result = 1; 21203034Sdougm } 21213034Sdougm } 21223034Sdougm } 21233034Sdougm } 21243034Sdougm } else { 21253034Sdougm ret = sa_update_property(prop, optlist->optvalue); 21263034Sdougm result = 1; /* should check if really changed */ 21273034Sdougm } 21283034Sdougm optlist = optlist->next; 21293034Sdougm } 21303034Sdougm /* 21313034Sdougm * when done, properties may have all been removed but 21323034Sdougm * we need to keep the security type itself until 21333034Sdougm * explicitly removed. 21343034Sdougm */ 21353034Sdougm if (result) 21363034Sdougm ret = sa_commit_properties(security, 0); 21373034Sdougm } 21383034Sdougm *err = ret; 21393034Sdougm return (result); 21403034Sdougm } 21413034Sdougm 21423034Sdougm /* 21433034Sdougm * basic_set(groupname, optlist, protocol, sharepath, dryrun) 21443034Sdougm * 21453034Sdougm * This function implements "set" when a name space (-S) is not 21463034Sdougm * specified. It is a basic set. Options and other CLI parsing has 21473034Sdougm * already been done. 21483034Sdougm */ 21493034Sdougm 21503034Sdougm static int 21513034Sdougm basic_set(char *groupname, struct options *optlist, char *protocol, 21523034Sdougm char *sharepath, int dryrun) 21533034Sdougm { 21543034Sdougm sa_group_t group; 21553034Sdougm int ret = SA_OK; 21563034Sdougm int change = 0; 21573034Sdougm struct list *worklist = NULL; 21583034Sdougm 21593034Sdougm group = sa_get_group(groupname); 21603034Sdougm if (group != NULL) { 21613034Sdougm sa_share_t share = NULL; 21623034Sdougm if (sharepath != NULL) { 21633034Sdougm share = sa_get_share(group, sharepath); 21643034Sdougm if (share == NULL) { 21653034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 21663034Sdougm groupname, sharepath); 21673034Sdougm ret = SA_NO_SUCH_PATH; 21683034Sdougm } 21693034Sdougm } 21703034Sdougm if (ret == SA_OK) { 21713034Sdougm /* group must exist */ 21723034Sdougm ret = valid_options(optlist, protocol, 21733034Sdougm share == NULL ? group : share, NULL); 21743034Sdougm if (ret == SA_OK && !dryrun) { 21753034Sdougm if (share != NULL) 21763034Sdougm change |= add_optionset(share, optlist, protocol, 21773034Sdougm &ret); 21783034Sdougm else 21793034Sdougm change |= add_optionset(group, optlist, protocol, 21803034Sdougm &ret); 21813034Sdougm if (ret == SA_OK && change) { 21823034Sdougm worklist = add_list(worklist, group, share); 21833034Sdougm } 21843034Sdougm } 21853034Sdougm } 21863034Sdougm free_opt(optlist); 21873034Sdougm } else { 21883034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 21893034Sdougm ret = SA_NO_SUCH_GROUP; 21903034Sdougm } 21913034Sdougm /* 21923034Sdougm * we have a group and potentially legal additions 21933034Sdougm */ 21943034Sdougm 21953034Sdougm /* commit to configuration if not a dryrun */ 21963034Sdougm if (!dryrun && ret == SA_OK) { 21973034Sdougm if (change && worklist != NULL) { 21983034Sdougm /* properties changed, so update all shares */ 21993034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 22003034Sdougm } 22013034Sdougm } 22023034Sdougm if (worklist != NULL) 22033034Sdougm free_list(worklist); 22043034Sdougm return (ret); 22053034Sdougm } 22063034Sdougm 22073034Sdougm /* 22083034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 22093034Sdougm * 22103034Sdougm * This function implements "set" when a name space (-S) is 22113034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 22123034Sdougm * already been done. 22133034Sdougm */ 22143034Sdougm 22153034Sdougm static int 22163034Sdougm space_set(char *groupname, struct options *optlist, char *protocol, 22173034Sdougm char *sharepath, int dryrun, char *sectype) 22183034Sdougm { 22193034Sdougm sa_group_t group; 22203034Sdougm int ret = SA_OK; 22213034Sdougm int change = 0; 22223034Sdougm struct list *worklist = NULL; 22233034Sdougm 22243034Sdougm /* 22253034Sdougm * make sure protcol and sectype are valid 22263034Sdougm */ 22273034Sdougm 22283034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 22293034Sdougm (void) printf(gettext("Option space \"%s\" not valid " 22303034Sdougm "for protocol.\n"), 22313034Sdougm sectype); 22323034Sdougm return (SA_INVALID_SECURITY); 22333034Sdougm } 22343034Sdougm 22353034Sdougm group = sa_get_group(groupname); 22363034Sdougm if (group != NULL) { 22373034Sdougm sa_share_t share = NULL; 22383034Sdougm if (sharepath != NULL) { 22393034Sdougm share = sa_get_share(group, sharepath); 22403034Sdougm if (share == NULL) { 22413034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 22423034Sdougm groupname, sharepath); 22433034Sdougm ret = SA_NO_SUCH_PATH; 22443034Sdougm } 22453034Sdougm } 22463034Sdougm if (ret == SA_OK) { 22473034Sdougm /* group must exist */ 22483034Sdougm ret = valid_options(optlist, protocol, 22493034Sdougm share == NULL ? group : share, sectype); 22503034Sdougm if (ret == SA_OK && !dryrun) { 22513034Sdougm if (share != NULL) 22523034Sdougm change = add_security(share, sectype, optlist, 22533034Sdougm protocol, 22543034Sdougm &ret); 22553034Sdougm else 22563034Sdougm change = add_security(group, sectype, optlist, 22573034Sdougm protocol, 22583034Sdougm &ret); 22593034Sdougm if (ret != SA_OK) 22603034Sdougm (void) printf(gettext("Could not set property: %s\n"), 22613034Sdougm sa_errorstr(ret)); 22623034Sdougm } 22633034Sdougm if (ret == SA_OK && change) 22643034Sdougm worklist = add_list(worklist, group, share); 22653034Sdougm } 22663034Sdougm free_opt(optlist); 22673034Sdougm } else { 22683034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 22693034Sdougm ret = SA_NO_SUCH_GROUP; 22703034Sdougm } 22713034Sdougm /* 22723034Sdougm * we have a group and potentially legal additions 22733034Sdougm */ 22743034Sdougm 22753034Sdougm /* commit to configuration if not a dryrun */ 22763034Sdougm if (!dryrun && ret == 0) { 22773034Sdougm if (change && worklist != NULL) { 22783034Sdougm /* properties changed, so update all shares */ 22793034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 22803034Sdougm } 22813034Sdougm ret = sa_update_config(); 22823034Sdougm } 22833034Sdougm if (worklist != NULL) 22843034Sdougm free_list(worklist); 22853034Sdougm return (ret); 22863034Sdougm } 22873034Sdougm 22883034Sdougm /* 22893034Sdougm * sa_set(flags, argc, argv) 22903034Sdougm * 22913034Sdougm * Implements the set subcommand. It keys off of -S to determine which 22923034Sdougm * set of operations to actually do. 22933034Sdougm */ 22943034Sdougm 22953034Sdougm int 22963034Sdougm sa_set(int flags, int argc, char *argv[]) 22973034Sdougm { 22983034Sdougm char *groupname; 22993034Sdougm int verbose = 0; 23003034Sdougm int dryrun = 0; 23013034Sdougm int c; 23023034Sdougm char *protocol = NULL; 23033034Sdougm int ret = SA_OK; 23043034Sdougm struct options *optlist = NULL; 23053034Sdougm char *sharepath = NULL; 23063034Sdougm char *optset = NULL; 23073034Sdougm int auth; 23083034Sdougm 23093034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 23103034Sdougm switch (c) { 23113034Sdougm case 'v': 23123034Sdougm verbose++; 23133034Sdougm break; 23143034Sdougm case 'n': 23153034Sdougm dryrun++; 23163034Sdougm break; 23173034Sdougm case 'P': 23183034Sdougm protocol = optarg; 23193034Sdougm if (!sa_valid_protocol(protocol)) { 23203034Sdougm (void) printf(gettext("Invalid protocol specified:" 23213034Sdougm "%s\n"), 23223034Sdougm protocol); 23233034Sdougm return (SA_INVALID_PROTOCOL); 23243034Sdougm } 23253034Sdougm break; 23263034Sdougm case 'p': 23273034Sdougm ret = add_opt(&optlist, optarg, 0); 23283034Sdougm switch (ret) { 23293034Sdougm case OPT_ADD_SYNTAX: 23303034Sdougm (void) printf(gettext("Property syntax error: %s\n"), 23313034Sdougm optarg); 23323034Sdougm return (SA_SYNTAX_ERR); 23333034Sdougm case OPT_ADD_MEMORY: 23343034Sdougm (void) printf(gettext("No memory to set property: %s\n"), 23353034Sdougm optarg); 23363034Sdougm return (SA_NO_MEMORY); 23373034Sdougm default: 23383034Sdougm break; 23393034Sdougm } 23403034Sdougm break; 23413034Sdougm case 's': 23423034Sdougm sharepath = optarg; 23433034Sdougm break; 23443034Sdougm case 'S': 23453034Sdougm optset = optarg; 23463034Sdougm break; 23473034Sdougm default: 23483034Sdougm case 'h': 23493034Sdougm case '?': 23503034Sdougm (void) printf(gettext("usage: %s\n"), 23513034Sdougm sa_get_usage(USAGE_SET)); 23523034Sdougm return (SA_OK); 23533034Sdougm } 23543034Sdougm } 23553034Sdougm 23563034Sdougm if (optlist != NULL) 23573034Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 23583034Sdougm 23593034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 23603034Sdougm protocol == NULL || 23613034Sdougm ret != OPT_ADD_OK) { 23623034Sdougm char *sep = "\t"; 23633034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 23643034Sdougm if (optind >= argc) { 23653034Sdougm (void) printf(gettext("%sgroup must be specified"), sep); 23663034Sdougm sep = ", "; 23673034Sdougm } 23683034Sdougm if (optlist == NULL) { 23693034Sdougm (void) printf(gettext("%sat least one property must be" 23703034Sdougm " specified"), sep); 23713034Sdougm sep = ", "; 23723034Sdougm } 23733034Sdougm if (protocol == NULL) { 23743034Sdougm (void) printf(gettext("%sprotocol must be specified"), sep); 23753034Sdougm sep = ", "; 23763034Sdougm } 23773034Sdougm (void) printf("\n"); 23783034Sdougm ret = SA_SYNTAX_ERR; 23793034Sdougm } else { 23803034Sdougm /* 23813034Sdougm * if a group already exists, we can only add a new 23823034Sdougm * protocol to it and not create a new one or add the 23833034Sdougm * same protocol again. 23843034Sdougm */ 23853034Sdougm 23863034Sdougm groupname = argv[optind]; 23873034Sdougm auth = check_authorizations(groupname, flags); 23883034Sdougm if (optset == NULL) 23893034Sdougm ret = basic_set(groupname, optlist, protocol, 23903034Sdougm sharepath, dryrun); 23913034Sdougm else 23923034Sdougm ret = space_set(groupname, optlist, protocol, 23933034Sdougm sharepath, dryrun, optset); 23943034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 23953034Sdougm (void) printf(gettext("Command would fail: %s\n"), 23963034Sdougm sa_errorstr(SA_NO_PERMISSION)); 23973034Sdougm } 23983034Sdougm } 23993034Sdougm return (ret); 24003034Sdougm } 24013034Sdougm 24023034Sdougm /* 24033034Sdougm * remove_options(group, optlist, proto, *err) 24043034Sdougm * 24053034Sdougm * helper function to actually remove options from a group after all 24063034Sdougm * preprocessing is done. 24073034Sdougm */ 24083034Sdougm 24093034Sdougm static int 24103034Sdougm remove_options(sa_group_t group, struct options *optlist, 24113034Sdougm char *proto, int *err) 24123034Sdougm { 24133034Sdougm struct options *cur; 24143034Sdougm sa_optionset_t optionset; 24153034Sdougm sa_property_t prop; 24163034Sdougm int change = 0; 24173034Sdougm int ret = SA_OK; 24183034Sdougm 24193034Sdougm optionset = sa_get_optionset(group, proto); 24203034Sdougm if (optionset != NULL) { 24213034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 24223034Sdougm prop = sa_get_property(optionset, cur->optname); 24233034Sdougm if (prop != NULL) { 24243034Sdougm ret = sa_remove_property(prop); 24253034Sdougm if (ret != SA_OK) 24263034Sdougm break; 24273034Sdougm change = 1; 24283034Sdougm } 24293034Sdougm } 24303034Sdougm } 24313034Sdougm if (ret == SA_OK && change) 24323034Sdougm ret = sa_commit_properties(optionset, 0); 24333034Sdougm 24343034Sdougm if (err != NULL) 24353034Sdougm *err = ret; 24363034Sdougm return (change); 24373034Sdougm } 24383034Sdougm 24393034Sdougm /* 24403034Sdougm * valid_unset(group, optlist, proto) 24413034Sdougm * 24423034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 24433034Sdougm * error if a property doesn't exist. 24443034Sdougm */ 24453034Sdougm 24463034Sdougm static int 24473034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 24483034Sdougm { 24493034Sdougm struct options *cur; 24503034Sdougm sa_optionset_t optionset; 24513034Sdougm sa_property_t prop; 24523034Sdougm int ret = SA_OK; 24533034Sdougm 24543034Sdougm optionset = sa_get_optionset(group, proto); 24553034Sdougm if (optionset != NULL) { 24563034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 24573034Sdougm prop = sa_get_property(optionset, cur->optname); 24583034Sdougm if (prop == NULL) { 24593034Sdougm (void) printf(gettext("Could not unset property %s:" 24603034Sdougm " not set\n"), 24613034Sdougm cur->optname); 24623034Sdougm ret = SA_NO_SUCH_PROP; 24633034Sdougm } 24643034Sdougm } 24653034Sdougm } 24663034Sdougm return (ret); 24673034Sdougm } 24683034Sdougm 24693034Sdougm /* 24703034Sdougm * valid_unset_security(group, optlist, proto) 24713034Sdougm * 24723034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 24733034Sdougm * error if a property doesn't exist. 24743034Sdougm */ 24753034Sdougm 24763034Sdougm static int 24773034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 24783034Sdougm char *sectype) 24793034Sdougm { 24803034Sdougm struct options *cur; 24813034Sdougm sa_security_t security; 24823034Sdougm sa_property_t prop; 24833034Sdougm int ret = SA_OK; 24843034Sdougm char *sec; 24853034Sdougm 24863034Sdougm sec = sa_proto_space_alias(proto, sectype); 24873034Sdougm security = sa_get_security(group, sec, proto); 24883034Sdougm if (security != NULL) { 24893034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 24903034Sdougm prop = sa_get_property(security, cur->optname); 24913034Sdougm if (prop == NULL) { 24923034Sdougm (void) printf(gettext("Could not unset property %s:" 24933034Sdougm " not set\n"), 24943034Sdougm cur->optname); 24953034Sdougm ret = SA_NO_SUCH_PROP; 24963034Sdougm } 24973034Sdougm } 24983034Sdougm } else { 24993034Sdougm (void) printf(gettext("Could not unset %s: space not defined\n"), 25003034Sdougm sectype); 25013034Sdougm ret = SA_NO_SUCH_SECURITY; 25023034Sdougm } 25033034Sdougm if (sec != NULL) 25043034Sdougm sa_free_attr_string(sec); 25053034Sdougm return (ret); 25063034Sdougm } 25073034Sdougm 25083034Sdougm /* 25093034Sdougm * remove_security(group, optlist, proto) 25103034Sdougm * 25113034Sdougm * Remove the properties since they were checked as valid. 25123034Sdougm */ 25133034Sdougm 25143034Sdougm static int 25153034Sdougm remove_security(sa_group_t group, char *sectype, 25163034Sdougm struct options *optlist, char *proto, int *err) 25173034Sdougm { 25183034Sdougm sa_security_t security; 25193034Sdougm int ret = SA_OK; 25203034Sdougm int change = 0; 25213034Sdougm 25223034Sdougm sectype = sa_proto_space_alias(proto, sectype); 25233034Sdougm security = sa_get_security(group, sectype, proto); 25243034Sdougm if (sectype != NULL) 25253034Sdougm sa_free_attr_string(sectype); 25263034Sdougm 25273034Sdougm if (security != NULL) { 25283034Sdougm while (optlist != NULL) { 25293034Sdougm sa_property_t prop; 25303034Sdougm prop = sa_get_property(security, optlist->optname); 25313034Sdougm if (prop != NULL) { 25323034Sdougm ret = sa_remove_property(prop); 25333034Sdougm if (ret != SA_OK) 25343034Sdougm break; 25353034Sdougm change = 1; 25363034Sdougm } 25373034Sdougm optlist = optlist->next; 25383034Sdougm } 25393034Sdougm /* 25403034Sdougm * when done, properties may have all been removed but 25413034Sdougm * we need to keep the security type itself until 25423034Sdougm * explicitly removed. 25433034Sdougm */ 25443034Sdougm if (ret == SA_OK && change) 25453034Sdougm ret = sa_commit_properties(security, 0); 25463034Sdougm } else { 25473034Sdougm ret = SA_NO_SUCH_PROP; 25483034Sdougm } 25493034Sdougm if (err != NULL) 25503034Sdougm *err = ret; 25513034Sdougm return (change); 25523034Sdougm } 25533034Sdougm 25543034Sdougm /* 25553034Sdougm * basic_unset(groupname, optlist, protocol, sharepath, dryrun) 25563034Sdougm * 25573034Sdougm * unset non-named optionset properties. 25583034Sdougm */ 25593034Sdougm 25603034Sdougm static int 25613034Sdougm basic_unset(char *groupname, struct options *optlist, char *protocol, 25623034Sdougm char *sharepath, int dryrun) 25633034Sdougm { 25643034Sdougm sa_group_t group; 25653034Sdougm int ret = SA_OK; 25663034Sdougm int change = 0; 25673034Sdougm struct list *worklist = NULL; 25683034Sdougm 25693034Sdougm group = sa_get_group(groupname); 25703034Sdougm if (group != NULL) { 25713034Sdougm sa_share_t share = NULL; 25723034Sdougm if (sharepath != NULL) { 25733034Sdougm share = sa_get_share(group, sharepath); 25743034Sdougm if (share == NULL) { 25753034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 25763034Sdougm groupname, sharepath); 25773034Sdougm ret = SA_NO_SUCH_PATH; 25783034Sdougm } 25793034Sdougm } 25803034Sdougm if (ret == SA_OK) { 25813034Sdougm /* group must exist */ 25823034Sdougm ret = valid_unset(share != NULL ? share : group, 25833034Sdougm optlist, protocol); 25843034Sdougm if (ret == SA_OK && !dryrun) { 25853034Sdougm if (share != NULL) { 25863034Sdougm sa_optionset_t optionset; 25873034Sdougm sa_property_t prop; 25883034Sdougm change |= remove_options(share, optlist, protocol, 25893034Sdougm &ret); 25903034Sdougm /* if a share optionset is empty, remove it */ 25913034Sdougm optionset = sa_get_optionset((sa_share_t)share, 25923034Sdougm protocol); 25933034Sdougm if (optionset != NULL) { 25943034Sdougm prop = sa_get_property(optionset, NULL); 25953034Sdougm if (prop == NULL) 25963034Sdougm (void) sa_destroy_optionset(optionset); 25973034Sdougm } 25983034Sdougm } else { 25993034Sdougm change |= remove_options(group, optlist, protocol, 26003034Sdougm &ret); 26013034Sdougm } 26023034Sdougm if (ret == SA_OK && change) 26033034Sdougm worklist = add_list(worklist, group, share); 26043034Sdougm if (ret != SA_OK) 26053034Sdougm (void) printf(gettext("Could not remove properties:" 26063034Sdougm "%s\n"), 26073034Sdougm sa_errorstr(ret)); 26083034Sdougm } 26093034Sdougm } else { 26103034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 26113034Sdougm ret = SA_NO_SUCH_GROUP; 26123034Sdougm } 26133034Sdougm free_opt(optlist); 26143034Sdougm } 26153034Sdougm 26163034Sdougm /* 26173034Sdougm * we have a group and potentially legal additions 26183034Sdougm */ 26193034Sdougm /* commit to configuration if not a dryrun */ 26203034Sdougm if (!dryrun && ret == SA_OK) { 26213034Sdougm if (change && worklist != NULL) { 26223034Sdougm /* properties changed, so update all shares */ 26233034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 26243034Sdougm } 26253034Sdougm } 26263034Sdougm if (worklist != NULL) 26273034Sdougm free_list(worklist); 26283034Sdougm return (ret); 26293034Sdougm } 26303034Sdougm 26313034Sdougm /* 26323034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 26333034Sdougm * 26343034Sdougm * unset named optionset properties. 26353034Sdougm */ 26363034Sdougm static int 26373034Sdougm space_unset(char *groupname, struct options *optlist, char *protocol, 26383034Sdougm char *sharepath, int dryrun, char *sectype) 26393034Sdougm { 26403034Sdougm sa_group_t group; 26413034Sdougm int ret = SA_OK; 26423034Sdougm int change = 0; 26433034Sdougm struct list *worklist = NULL; 26443034Sdougm 26453034Sdougm group = sa_get_group(groupname); 26463034Sdougm if (group != NULL) { 26473034Sdougm sa_share_t share = NULL; 26483034Sdougm if (sharepath != NULL) { 26493034Sdougm share = sa_get_share(group, sharepath); 26503034Sdougm if (share == NULL) { 26513034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 26523034Sdougm groupname, sharepath); 26533034Sdougm ret = SA_NO_SUCH_PATH; 26543034Sdougm } 26553034Sdougm } 26563034Sdougm if (ret == SA_OK) { 26573034Sdougm ret = valid_unset_security(share != NULL ? share : group, 26583034Sdougm optlist, protocol, sectype); 26593034Sdougm if (ret == SA_OK && !dryrun) { 26603034Sdougm if (optlist != NULL) { 26613034Sdougm if (share != NULL) { 26623034Sdougm sa_security_t optionset; 26633034Sdougm sa_property_t prop; 26643034Sdougm change = remove_security(share, sectype, 26653034Sdougm optlist, protocol, 26663034Sdougm &ret); 26673034Sdougm /* if a share security is empty, remove it */ 26683034Sdougm optionset = sa_get_security((sa_group_t)share, 26693034Sdougm sectype, 26703034Sdougm protocol); 26713034Sdougm if (optionset != NULL) { 26723034Sdougm prop = sa_get_property(optionset, NULL); 26733034Sdougm if (prop == NULL) 26743034Sdougm ret = sa_destroy_security(optionset); 26753034Sdougm } 26763034Sdougm } else { 26773034Sdougm change = remove_security(group, sectype, 26783034Sdougm optlist, protocol, 26793034Sdougm &ret); 26803034Sdougm } 26813034Sdougm } else { 26823034Sdougm sa_security_t security; 26833034Sdougm char *sec; 26843034Sdougm sec = sa_proto_space_alias(protocol, sectype); 26853034Sdougm security = sa_get_security(group, sec, protocol); 26863034Sdougm if (sec != NULL) 26873034Sdougm sa_free_attr_string(sec); 26883034Sdougm if (security != NULL) { 26893034Sdougm ret = sa_destroy_security(security); 26903034Sdougm if (ret == SA_OK) 26913034Sdougm change = 1; 26923034Sdougm } else { 26933034Sdougm ret = SA_NO_SUCH_PROP; 26943034Sdougm } 26953034Sdougm } 26963034Sdougm if (ret != SA_OK) 26973034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 26983034Sdougm sa_errorstr(ret)); 26993034Sdougm } 27003034Sdougm 27013034Sdougm if (ret == SA_OK && change) 27023034Sdougm worklist = add_list(worklist, group, 0); 27033034Sdougm } 27043034Sdougm } else { 27053034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 27063034Sdougm ret = SA_NO_SUCH_GROUP; 27073034Sdougm } 27083034Sdougm free_opt(optlist); 27093034Sdougm /* 27103034Sdougm * we have a group and potentially legal additions 27113034Sdougm */ 27123034Sdougm 27133034Sdougm /* commit to configuration if not a dryrun */ 27143034Sdougm if (!dryrun && ret == 0) { 27153034Sdougm if (change && worklist != NULL) { 27163034Sdougm /* properties changed, so update all shares */ 27173034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 27183034Sdougm } 27193034Sdougm ret = sa_update_config(); 27203034Sdougm } 27213034Sdougm if (worklist != NULL) 27223034Sdougm free_list(worklist); 27233034Sdougm return (ret); 27243034Sdougm } 27253034Sdougm 27263034Sdougm /* 27273034Sdougm * sa_unset(flags, argc, argv) 27283034Sdougm * 27293034Sdougm * implements the unset subcommand. Parsing done here and then basic 27303034Sdougm * or space versions of the real code are called. 27313034Sdougm */ 27323034Sdougm 27333034Sdougm int 27343034Sdougm sa_unset(int flags, int argc, char *argv[]) 27353034Sdougm { 27363034Sdougm char *groupname; 27373034Sdougm int verbose = 0; 27383034Sdougm int dryrun = 0; 27393034Sdougm int c; 27403034Sdougm char *protocol = NULL; 27413034Sdougm int ret = SA_OK; 27423034Sdougm struct options *optlist = NULL; 27433034Sdougm char *sharepath = NULL; 27443034Sdougm char *optset = NULL; 27453034Sdougm int auth; 27463034Sdougm 27473034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 27483034Sdougm switch (c) { 27493034Sdougm case 'v': 27503034Sdougm verbose++; 27513034Sdougm break; 27523034Sdougm case 'n': 27533034Sdougm dryrun++; 27543034Sdougm break; 27553034Sdougm case 'P': 27563034Sdougm protocol = optarg; 27573034Sdougm if (!sa_valid_protocol(protocol)) { 27583034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 27593034Sdougm protocol); 27603034Sdougm return (SA_INVALID_PROTOCOL); 27613034Sdougm } 27623034Sdougm break; 27633034Sdougm case 'p': 27643034Sdougm ret = add_opt(&optlist, optarg, 1); 27653034Sdougm switch (ret) { 27663034Sdougm case OPT_ADD_SYNTAX: 27673034Sdougm (void) printf(gettext("Property syntax error for " 27683034Sdougm "property %s\n"), 27693034Sdougm optarg); 27703034Sdougm return (SA_SYNTAX_ERR); 27713034Sdougm case OPT_ADD_PROPERTY: 27723034Sdougm (void) printf(gettext("Properties need to be set" 27733034Sdougm " with set command: %s\n"), 27743034Sdougm optarg); 27753034Sdougm return (SA_SYNTAX_ERR); 27763034Sdougm default: 27773034Sdougm break; 27783034Sdougm } 27793034Sdougm break; 27803034Sdougm case 's': 27813034Sdougm sharepath = optarg; 27823034Sdougm break; 27833034Sdougm case 'S': 27843034Sdougm optset = optarg; 27853034Sdougm break; 27863034Sdougm default: 27873034Sdougm case 'h': 27883034Sdougm case '?': 27893034Sdougm (void) printf(gettext("usage: %s\n"), 27903034Sdougm sa_get_usage(USAGE_UNSET)); 27913034Sdougm return (SA_OK); 27923034Sdougm } 27933034Sdougm } 27943034Sdougm 27953034Sdougm if (optlist != NULL) 27963034Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 27973034Sdougm 27983034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 27993034Sdougm protocol == NULL) { 28003034Sdougm char *sep = "\t"; 28013034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET)); 28023034Sdougm if (optind >= argc) { 28033034Sdougm (void) printf(gettext("%sgroup must be specified"), sep); 28043034Sdougm sep = ", "; 28053034Sdougm } 28063034Sdougm if (optlist == NULL) { 28073034Sdougm (void) printf(gettext("%sat least one property must be " 28083034Sdougm "specified"), 28093034Sdougm sep); 28103034Sdougm sep = ", "; 28113034Sdougm } 28123034Sdougm if (protocol == NULL) { 28133034Sdougm (void) printf(gettext("%sprotocol must be specified"), sep); 28143034Sdougm sep = ", "; 28153034Sdougm } 28163034Sdougm (void) printf("\n"); 28173034Sdougm ret = SA_SYNTAX_ERR; 28183034Sdougm } else { 28193034Sdougm 28203034Sdougm /* 28213034Sdougm * if a group already exists, we can only add a new 28223034Sdougm * protocol to it and not create a new one or add the 28233034Sdougm * same protocol again. 28243034Sdougm */ 28253034Sdougm 28263034Sdougm groupname = argv[optind]; 28273034Sdougm auth = check_authorizations(groupname, flags); 28283034Sdougm if (optset == NULL) 28293034Sdougm ret = basic_unset(groupname, optlist, protocol, 28303034Sdougm sharepath, dryrun); 28313034Sdougm else 28323034Sdougm ret = space_unset(groupname, optlist, protocol, 28333034Sdougm sharepath, dryrun, optset); 28343034Sdougm 28353034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 28363034Sdougm (void) printf(gettext("Command would fail: %s\n"), 28373034Sdougm sa_errorstr(SA_NO_PERMISSION)); 28383034Sdougm } 28393034Sdougm } 28403034Sdougm return (ret); 28413034Sdougm } 28423034Sdougm 28433034Sdougm /* 28443034Sdougm * sa_enable_group(flags, argc, argv) 28453034Sdougm * 28463034Sdougm * Implements the enable subcommand 28473034Sdougm */ 28483034Sdougm 28493034Sdougm int 28503034Sdougm sa_enable_group(int flags, int argc, char *argv[]) 28513034Sdougm { 28523034Sdougm int verbose = 0; 28533034Sdougm int dryrun = 0; 28543034Sdougm int all = 0; 28553034Sdougm int c; 28563034Sdougm int ret = SA_OK; 28573034Sdougm char *protocol = NULL; 28583034Sdougm char *state; 28593034Sdougm struct list *worklist = NULL; 28603034Sdougm int auth = 1; 28613034Sdougm 28623034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 28633034Sdougm switch (c) { 28643034Sdougm case 'a': 28653034Sdougm all = 1; 28663034Sdougm break; 28673034Sdougm case 'n': 28683034Sdougm dryrun++; 28693034Sdougm break; 28703034Sdougm case 'P': 28713034Sdougm protocol = optarg; 28723034Sdougm if (!sa_valid_protocol(protocol)) { 28733034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 28743034Sdougm protocol); 28753034Sdougm return (SA_INVALID_PROTOCOL); 28763034Sdougm } 28773034Sdougm break; 28783034Sdougm case 'v': 28793034Sdougm verbose++; 28803034Sdougm break; 28813034Sdougm default: 28823034Sdougm case 'h': 28833034Sdougm case '?': 28843034Sdougm (void) printf(gettext("usage: %s\n"), 28853034Sdougm sa_get_usage(USAGE_ENABLE)); 28863034Sdougm return (0); 28873034Sdougm } 28883034Sdougm } 28893034Sdougm 28903034Sdougm if (optind == argc && !all) { 28913034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE)); 28923034Sdougm (void) printf(gettext("\tmust specify group\n")); 28933034Sdougm ret = SA_NO_SUCH_PATH; 28943034Sdougm } else { 28953034Sdougm sa_group_t group; 28963034Sdougm if (!all) { 28973034Sdougm while (optind < argc) { 28983034Sdougm group = sa_get_group(argv[optind]); 28993034Sdougm if (group != NULL) { 29003034Sdougm auth &= check_authorizations(argv[optind], flags); 29013034Sdougm state = sa_get_group_attr(group, "state"); 29023034Sdougm if (state != NULL && 29033034Sdougm strcmp(state, "enabled") == 0) { 29043034Sdougm /* already enabled */ 29053034Sdougm if (verbose) 29063034Sdougm (void) printf(gettext("Group \"%s\" is already " 29073034Sdougm "enabled\n"), 29083034Sdougm argv[optind]); 29093034Sdougm ret = SA_BUSY; /* already enabled */ 29103034Sdougm } else { 29113034Sdougm worklist = add_list(worklist, group, 0); 29123034Sdougm if (verbose) 29133034Sdougm (void) printf(gettext("Enabling group " 29143034Sdougm "\"%s\"\n"), 29153034Sdougm argv[optind]); 29163034Sdougm } 29173034Sdougm if (state != NULL) 29183034Sdougm sa_free_attr_string(state); 29193034Sdougm } else { 29203034Sdougm ret = SA_NO_SUCH_GROUP; 29213034Sdougm } 29223034Sdougm optind++; 29233034Sdougm } 29243034Sdougm } else { 29253034Sdougm for (group = sa_get_group(NULL); group != NULL; 29263034Sdougm group = sa_get_next_group(group)) { 29273034Sdougm worklist = add_list(worklist, group, 0); 29283034Sdougm } 29293034Sdougm } 29303034Sdougm if (!dryrun && ret == SA_OK) { 29313034Sdougm ret = enable_all_groups(worklist, 1, 0, NULL); 29323034Sdougm } 29333034Sdougm if (ret != SA_OK && ret != SA_BUSY) 29343034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 29353034Sdougm sa_errorstr(ret)); 29363034Sdougm if (ret == SA_BUSY) 29373034Sdougm ret = SA_OK; 29383034Sdougm } 29393034Sdougm if (worklist != NULL) 29403034Sdougm free_list(worklist); 29413034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 29423034Sdougm (void) printf(gettext("Command would fail: %s\n"), 29433034Sdougm sa_errorstr(SA_NO_PERMISSION)); 29443034Sdougm } 29453034Sdougm return (ret); 29463034Sdougm } 29473034Sdougm 29483034Sdougm /* 29493034Sdougm * disable_group(group, setstate) 29503034Sdougm * 29513034Sdougm * disable all the shares in the specified group honoring the setstate 29523034Sdougm * argument. This is a helper for disable_all_groups in order to 29533034Sdougm * simplify regular and subgroup (zfs) disabling. Group has already 29543034Sdougm * been checked for non-NULL. 29553034Sdougm */ 29563034Sdougm 29573034Sdougm static int 29583034Sdougm disable_group(sa_group_t group) 29593034Sdougm { 29603034Sdougm sa_share_t share; 29613034Sdougm int ret = SA_OK; 29623034Sdougm 29633034Sdougm for (share = sa_get_share(group, NULL); 29643034Sdougm share != NULL && ret == SA_OK; 29653034Sdougm share = sa_get_next_share(share)) { 29663034Sdougm ret = sa_disable_share(share, NULL); 29673034Sdougm if (ret == SA_NO_SUCH_PATH) { 29683034Sdougm /* 29693034Sdougm * this is OK since the path is gone. we can't 29703034Sdougm * re-share it anyway so no error. 29713034Sdougm */ 29723034Sdougm ret = SA_OK; 29733034Sdougm } 29743034Sdougm } 29753034Sdougm return (ret); 29763034Sdougm } 29773034Sdougm 29783034Sdougm 29793034Sdougm /* 29803034Sdougm * disable_all_groups(work, setstate) 29813034Sdougm * 29823034Sdougm * helper function that disables the shares in the list of groups 29833034Sdougm * provided. It optionally marks the group as disabled. Used by both 29843034Sdougm * enable and start subcommands. 29853034Sdougm */ 29863034Sdougm 29873034Sdougm static int 29883034Sdougm disable_all_groups(struct list *work, int setstate) 29893034Sdougm { 29903034Sdougm int ret = SA_OK; 29913034Sdougm sa_group_t subgroup, group; 29923034Sdougm 29933034Sdougm while (work != NULL && ret == SA_OK) { 29943034Sdougm group = (sa_group_t)work->item; 29953034Sdougm if (setstate) 29963034Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 29973034Sdougm if (ret == SA_OK) { 29983034Sdougm char *name; 29993034Sdougm name = sa_get_group_attr(group, "name"); 30003034Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 30013034Sdougm /* need to get the sub-groups for stopping */ 30023034Sdougm for (subgroup = sa_get_sub_group(group); subgroup != NULL; 30033034Sdougm subgroup = sa_get_next_group(subgroup)) { 30043034Sdougm ret = disable_group(subgroup); 30053034Sdougm } 30063034Sdougm } else { 30073034Sdougm ret = disable_group(group); 30083034Sdougm } 30093034Sdougm /* 30103034Sdougm * we don't want to "disable" since it won't come 30113034Sdougm * up after a reboot. The SMF framework should do 30123034Sdougm * the right thing. On enable we do want to do 30133034Sdougm * something. 30143034Sdougm */ 30153034Sdougm } 30163034Sdougm work = work->next; 30173034Sdougm } 30183034Sdougm if (ret == SA_OK) 30193034Sdougm ret = sa_update_config(); 30203034Sdougm return (ret); 30213034Sdougm } 30223034Sdougm 30233034Sdougm /* 30243034Sdougm * sa_disable_group(flags, argc, argv) 30253034Sdougm * 30263034Sdougm * Implements the disable subcommand 30273034Sdougm */ 30283034Sdougm 30293034Sdougm int 30303034Sdougm sa_disable_group(int flags, int argc, char *argv[]) 30313034Sdougm { 30323034Sdougm int verbose = 0; 30333034Sdougm int dryrun = 0; 30343034Sdougm int all = 0; 30353034Sdougm int c; 30363034Sdougm int ret = SA_OK; 30373034Sdougm char *protocol; 30383034Sdougm char *state; 30393034Sdougm struct list *worklist = NULL; 30403034Sdougm int auth = 1; 30413034Sdougm 30423034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 30433034Sdougm switch (c) { 30443034Sdougm case 'a': 30453034Sdougm all = 1; 30463034Sdougm break; 30473034Sdougm case 'n': 30483034Sdougm dryrun++; 30493034Sdougm break; 30503034Sdougm case 'P': 30513034Sdougm protocol = optarg; 30523034Sdougm if (!sa_valid_protocol(protocol)) { 30533034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 30543034Sdougm protocol); 30553034Sdougm return (SA_INVALID_PROTOCOL); 30563034Sdougm } 30573034Sdougm break; 30583034Sdougm case 'v': 30593034Sdougm verbose++; 30603034Sdougm break; 30613034Sdougm default: 30623034Sdougm case 'h': 30633034Sdougm case '?': 30643034Sdougm (void) printf(gettext("usage: %s\n"), 30653034Sdougm sa_get_usage(USAGE_DISABLE)); 30663034Sdougm return (0); 30673034Sdougm } 30683034Sdougm } 30693034Sdougm 30703034Sdougm if (optind == argc && !all) { 30713034Sdougm (void) printf(gettext("usage: %s\n"), 30723034Sdougm sa_get_usage(USAGE_DISABLE)); 30733034Sdougm (void) printf(gettext("\tmust specify group\n")); 30743034Sdougm ret = SA_NO_SUCH_PATH; 30753034Sdougm } else { 30763034Sdougm sa_group_t group; 30773034Sdougm if (!all) { 30783034Sdougm while (optind < argc) { 30793034Sdougm group = sa_get_group(argv[optind]); 30803034Sdougm if (group != NULL) { 30813034Sdougm auth &= check_authorizations(argv[optind], flags); 30823034Sdougm state = sa_get_group_attr(group, "state"); 30833034Sdougm if (state == NULL || 30843034Sdougm strcmp(state, "disabled") == 0) { 30853034Sdougm /* already disabled */ 30863034Sdougm if (verbose) 30873034Sdougm (void) printf(gettext("Group \"%s\" is " 30883034Sdougm "already disabled\n"), 30893034Sdougm argv[optind]); 30903034Sdougm ret = SA_BUSY; /* already disable */ 30913034Sdougm } else { 30923034Sdougm worklist = add_list(worklist, group, 0); 30933034Sdougm if (verbose) 30943034Sdougm (void) printf(gettext("Disabling group " 30953034Sdougm "\"%s\"\n"), 30963034Sdougm argv[optind]); 30973034Sdougm } 30983034Sdougm if (state != NULL) 30993034Sdougm sa_free_attr_string(state); 31003034Sdougm } else { 31013034Sdougm ret = SA_NO_SUCH_GROUP; 31023034Sdougm } 31033034Sdougm optind++; 31043034Sdougm } 31053034Sdougm } else { 31063034Sdougm for (group = sa_get_group(NULL); group != NULL; 31073034Sdougm group = sa_get_next_group(group)) { 31083034Sdougm worklist = add_list(worklist, group, 0); 31093034Sdougm } 31103034Sdougm } 31113034Sdougm if (ret == SA_OK && !dryrun) { 31123034Sdougm ret = disable_all_groups(worklist, 1); 31133034Sdougm } 31143034Sdougm if (ret != SA_OK && ret != SA_BUSY) 31153034Sdougm (void) printf(gettext("Could not disable group: %s\n"), 31163034Sdougm sa_errorstr(ret)); 31173034Sdougm if (ret == SA_BUSY) 31183034Sdougm ret = SA_OK; 31193034Sdougm } 31203034Sdougm if (worklist != NULL) 31213034Sdougm free_list(worklist); 31223034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 31233034Sdougm (void) printf(gettext("Command would fail: %s\n"), 31243034Sdougm sa_errorstr(SA_NO_PERMISSION)); 31253034Sdougm } 31263034Sdougm return (ret); 31273034Sdougm } 31283034Sdougm 31293034Sdougm /* 31303034Sdougm * check_sharetab() 31313034Sdougm * 31323034Sdougm * Checks to see if the /etc/dfs/sharetab file is stale (exists from 31333034Sdougm * before the current boot). If it is, truncate it since nothing is 31343034Sdougm * really shared. 31353034Sdougm */ 31363034Sdougm 31373034Sdougm static void 31383034Sdougm check_sharetab() 31393034Sdougm { 31403034Sdougm int fd; 31413034Sdougm struct utmpx *utmpxp; 31423034Sdougm struct stat st; 31433034Sdougm 31443034Sdougm fd = open(SA_LEGACY_SHARETAB, O_RDWR); 31453034Sdougm if (fd >= 0) { 31463034Sdougm /* 31473034Sdougm * Attempt to get a lock on the file. Whgen we get 31483034Sdougm * one, then check to see if it is older than the boot 31493034Sdougm * time. Truncate if older than boot. 31503034Sdougm */ 31513034Sdougm (void) lockf(fd, F_LOCK, 0); 31523034Sdougm if ((fstat(fd, &st) == 0) && /* does sharetab exist? */ 31533034Sdougm (utmpxp = getutxent()) != NULL && /* does utmpx exist? */ 31543034Sdougm (utmpxp->ut_xtime > st.st_mtime)) /* sharetab older? */ 31553034Sdougm (void) ftruncate(fd, 0); 31563034Sdougm 31573034Sdougm (void) lockf(fd, F_ULOCK, 0); 31583034Sdougm (void) close(fd); 31593034Sdougm endutxent(); 31603034Sdougm } 31613034Sdougm } 31623034Sdougm 31633034Sdougm /* 31643034Sdougm * sa_start_group(flags, argc, argv) 31653034Sdougm * 31663034Sdougm * Implements the start command. 31673034Sdougm * This is similar to enable except it doesn't change the state 31683034Sdougm * of the group(s) and only enables shares if the group is already 31693034Sdougm * enabled. 31703034Sdougm */ 31713034Sdougm 31723034Sdougm int 31733034Sdougm sa_start_group(int flags, int argc, char *argv[]) 31743034Sdougm { 31753034Sdougm int verbose = 0; 31763034Sdougm int all = 0; 31773034Sdougm int c; 31783034Sdougm int ret = SMF_EXIT_OK; 31793034Sdougm char *protocol = NULL; 31803034Sdougm char *state; 31813034Sdougm struct list *worklist = NULL; 31823034Sdougm #ifdef lint 31833034Sdougm flags = flags; 31843034Sdougm #endif 31853034Sdougm 31863034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 31873034Sdougm switch (c) { 31883034Sdougm case 'a': 31893034Sdougm all = 1; 31903034Sdougm break; 31913034Sdougm case 'P': 31923034Sdougm protocol = optarg; 31933034Sdougm if (!sa_valid_protocol(protocol)) { 31943034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 31953034Sdougm protocol); 31963034Sdougm return (SA_INVALID_PROTOCOL); 31973034Sdougm } 31983034Sdougm break; 31993034Sdougm case 'v': 32003034Sdougm verbose++; 32013034Sdougm break; 32023034Sdougm default: 32033034Sdougm case 'h': 32043034Sdougm case '?': 32053034Sdougm (void) printf(gettext("usage: %s\n"), 32063034Sdougm sa_get_usage(USAGE_START)); 32073034Sdougm return (SA_OK); 32083034Sdougm } 32093034Sdougm } 32103034Sdougm 32113034Sdougm if (optind == argc && !all) { 32123034Sdougm (void) printf(gettext("usage: %s\n"), 32133034Sdougm sa_get_usage(USAGE_START)); 32143034Sdougm ret = SMF_EXIT_ERR_FATAL; 32153034Sdougm } else { 32163034Sdougm sa_group_t group; 32173034Sdougm 32183034Sdougm check_sharetab(); 32193034Sdougm 32203034Sdougm if (!all) { 32213034Sdougm while (optind < argc) { 32223034Sdougm group = sa_get_group(argv[optind]); 32233034Sdougm if (group != NULL) { 32243034Sdougm state = sa_get_group_attr(group, "state"); 32253034Sdougm if (state == NULL || 32263034Sdougm strcmp(state, "enabled") == 0) { 32273034Sdougm worklist = add_list(worklist, group, 0); 32283034Sdougm if (verbose) 32293034Sdougm (void) printf(gettext("Starting group " 32303034Sdougm "\"%s\"\n"), 32313034Sdougm argv[optind]); 32323034Sdougm } else { 32333034Sdougm /* 32343034Sdougm * determine if there are any 32353034Sdougm * protocols. if there aren't any, 32363034Sdougm * then there isn't anything to do in 32373034Sdougm * any case so no error. 32383034Sdougm */ 32393034Sdougm if (sa_get_optionset(group, protocol) != NULL) { 32403034Sdougm ret = SMF_EXIT_OK; 32413034Sdougm } 32423034Sdougm } 32433034Sdougm if (state != NULL) 32443034Sdougm sa_free_attr_string(state); 32453034Sdougm } 32463034Sdougm optind++; 32473034Sdougm } 32483034Sdougm } else { 32493034Sdougm for (group = sa_get_group(NULL); group != NULL; 32503034Sdougm group = sa_get_next_group(group)) { 32513034Sdougm state = sa_get_group_attr(group, "state"); 32523034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 32533034Sdougm worklist = add_list(worklist, group, 0); 32543034Sdougm if (state != NULL) 32553034Sdougm sa_free_attr_string(state); 32563034Sdougm } 32573034Sdougm } 32583034Sdougm (void) enable_all_groups(worklist, 0, 1, NULL); 32593034Sdougm } 32603034Sdougm if (worklist != NULL) 32613034Sdougm free_list(worklist); 32623034Sdougm return (ret); 32633034Sdougm } 32643034Sdougm 32653034Sdougm /* 32663034Sdougm * sa_stop_group(flags, argc, argv) 32673034Sdougm * 32683034Sdougm * Implements the stop command. 32693034Sdougm * This is similar to disable except it doesn't change the state 32703034Sdougm * of the group(s) and only disables shares if the group is already 32713034Sdougm * enabled. 32723034Sdougm */ 32733034Sdougm 32743034Sdougm int 32753034Sdougm sa_stop_group(int flags, int argc, char *argv[]) 32763034Sdougm { 32773034Sdougm int verbose = 0; 32783034Sdougm int all = 0; 32793034Sdougm int c; 32803034Sdougm int ret = SMF_EXIT_OK; 32813034Sdougm char *protocol = NULL; 32823034Sdougm char *state; 32833034Sdougm struct list *worklist = NULL; 32843034Sdougm #ifdef lint 32853034Sdougm flags = flags; 32863034Sdougm #endif 32873034Sdougm 32883034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 32893034Sdougm switch (c) { 32903034Sdougm case 'a': 32913034Sdougm all = 1; 32923034Sdougm break; 32933034Sdougm case 'P': 32943034Sdougm protocol = optarg; 32953034Sdougm if (!sa_valid_protocol(protocol)) { 32963034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 32973034Sdougm protocol); 32983034Sdougm return (SA_INVALID_PROTOCOL); 32993034Sdougm } 33003034Sdougm break; 33013034Sdougm case 'v': 33023034Sdougm verbose++; 33033034Sdougm break; 33043034Sdougm default: 33053034Sdougm case 'h': 33063034Sdougm case '?': 33073034Sdougm (void) printf(gettext("usage: %s\n"), 33083034Sdougm sa_get_usage(USAGE_STOP)); 33093034Sdougm return (0); 33103034Sdougm } 33113034Sdougm } 33123034Sdougm 33133034Sdougm if (optind == argc && !all) { 33143034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP)); 33153034Sdougm ret = SMF_EXIT_ERR_FATAL; 33163034Sdougm } else { 33173034Sdougm sa_group_t group; 33183034Sdougm if (!all) { 33193034Sdougm while (optind < argc) { 33203034Sdougm group = sa_get_group(argv[optind]); 33213034Sdougm if (group != NULL) { 33223034Sdougm state = sa_get_group_attr(group, "state"); 33233034Sdougm if (state == NULL || 33243034Sdougm strcmp(state, "enabled") == 0) { 33253034Sdougm worklist = add_list(worklist, group, 0); 33263034Sdougm if (verbose) 33273034Sdougm (void) printf(gettext("Stopping group " 33283034Sdougm "\"%s\"\n"), 33293034Sdougm argv[optind]); 33303034Sdougm } else { 33313034Sdougm ret = SMF_EXIT_OK; 33323034Sdougm } 33333034Sdougm if (state != NULL) 33343034Sdougm sa_free_attr_string(state); 33353034Sdougm } 33363034Sdougm optind++; 33373034Sdougm } 33383034Sdougm } else { 33393034Sdougm for (group = sa_get_group(NULL); group != NULL; 33403034Sdougm group = sa_get_next_group(group)) { 33413034Sdougm state = sa_get_group_attr(group, "state"); 33423034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 33433034Sdougm worklist = add_list(worklist, group, 0); 33443034Sdougm if (state != NULL) 33453034Sdougm sa_free_attr_string(state); 33463034Sdougm } 33473034Sdougm } 33483034Sdougm (void) disable_all_groups(worklist, 0); 33493034Sdougm ret = sa_update_config(); 33503034Sdougm } 33513034Sdougm if (worklist != NULL) 33523034Sdougm free_list(worklist); 33533034Sdougm return (ret); 33543034Sdougm } 33553034Sdougm 33563034Sdougm /* 33573034Sdougm * remove_all_options(share, proto) 33583034Sdougm * 33593034Sdougm * Removes all options on a share. 33603034Sdougm */ 33613034Sdougm 33623034Sdougm static void 33633034Sdougm remove_all_options(sa_share_t share, char *proto) 33643034Sdougm { 33653034Sdougm sa_optionset_t optionset; 33663034Sdougm sa_security_t security; 33673034Sdougm sa_security_t prevsec = NULL; 33683034Sdougm 33693034Sdougm optionset = sa_get_optionset(share, proto); 33703034Sdougm if (optionset != NULL) 33713034Sdougm (void) sa_destroy_optionset(optionset); 33723034Sdougm for (security = sa_get_security(share, NULL, NULL); 33733034Sdougm security != NULL; 33743034Sdougm security = sa_get_next_security(security)) { 33753034Sdougm char *type; 33763034Sdougm /* 33773034Sdougm * we walk through the list. prevsec keeps the 33783034Sdougm * previous security so we can delete it without 33793034Sdougm * destroying the list. 33803034Sdougm */ 33813034Sdougm if (prevsec != NULL) { 33823034Sdougm /* remove the previously seen security */ 33833034Sdougm (void) sa_destroy_security(prevsec); 33843034Sdougm /* set to NULL so we don't try multiple times */ 33853034Sdougm prevsec = NULL; 33863034Sdougm } 33873034Sdougm type = sa_get_security_attr(security, "type"); 33883034Sdougm if (type != NULL) { 33893034Sdougm /* 33903034Sdougm * if the security matches the specified protocol, we 33913034Sdougm * want to remove it. prevsec holds it until either 33923034Sdougm * the next pass or we fall out of the loop. 33933034Sdougm */ 33943034Sdougm if (strcmp(type, proto) == 0) 33953034Sdougm prevsec = security; 33963034Sdougm sa_free_attr_string(type); 33973034Sdougm } 33983034Sdougm } 33993034Sdougm /* in case there is one left */ 34003034Sdougm if (prevsec != NULL) 34013034Sdougm (void) sa_destroy_security(prevsec); 34023034Sdougm } 34033034Sdougm 34043034Sdougm 34053034Sdougm /* 34063034Sdougm * for legacy support, we need to handle the old syntax. This is what 34073034Sdougm * we get if sharemgr is called with the name "share" rather than 34083034Sdougm * sharemgr. 34093034Sdougm */ 34103034Sdougm 34113034Sdougm static int 34123034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 34133034Sdougm { 34143034Sdougm int err; 34153034Sdougm 34163034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 34173034Sdougm if (err > buffsize) 34183034Sdougm return (-1); 34193034Sdougm return (0); 34203034Sdougm } 34213034Sdougm 34223034Sdougm 34233034Sdougm /* 34243034Sdougm * check_legacy_cmd(proto, cmd) 34253034Sdougm * 34263034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 34273034Sdougm * executable. 34283034Sdougm */ 34293034Sdougm 34303034Sdougm static int 34313034Sdougm check_legacy_cmd(char *path) 34323034Sdougm { 34333034Sdougm struct stat st; 34343034Sdougm int ret = 0; 34353034Sdougm 34363034Sdougm if (stat(path, &st) == 0) { 34373034Sdougm if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 34383034Sdougm ret = 1; 34393034Sdougm } 34403034Sdougm return (ret); 34413034Sdougm } 34423034Sdougm 34433034Sdougm /* 34443034Sdougm * run_legacy_command(proto, cmd, argv) 34453034Sdougm * 34463034Sdougm * we know the command exists, so attempt to execute it with all the 34473034Sdougm * arguments. This implements full legacy share support for those 34483034Sdougm * protocols that don't have plugin providers. 34493034Sdougm */ 34503034Sdougm 34513034Sdougm static int 34523034Sdougm run_legacy_command(char *path, char *argv[]) 34533034Sdougm { 34543034Sdougm int ret; 34553034Sdougm 34563034Sdougm ret = execv(path, argv); 34573034Sdougm if (ret < 0) { 34583034Sdougm switch (errno) { 34593034Sdougm case EACCES: 34603034Sdougm ret = SA_NO_PERMISSION; 34613034Sdougm break; 34623034Sdougm default: 34633034Sdougm ret = SA_SYSTEM_ERR; 34643034Sdougm break; 34653034Sdougm } 34663034Sdougm } 34673034Sdougm return (ret); 34683034Sdougm } 34693034Sdougm 34703034Sdougm /* 34713034Sdougm * out_share(out, group, proto, options) 34723034Sdougm * 34733034Sdougm * Display the share information in the format that the "share" 34743034Sdougm * command has traditionally used. 34753034Sdougm */ 34763034Sdougm 34773034Sdougm static void 34783034Sdougm out_share(FILE *out, sa_group_t group, char *proto, char *options) 34793034Sdougm { 34803034Sdougm sa_share_t share; 34813034Sdougm char resfmt[128]; 34823034Sdougm 34833034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 34843034Sdougm share = sa_get_next_share(share)) { 34853034Sdougm char *path; 34863034Sdougm char *type; 34873034Sdougm char *resource; 34883034Sdougm char *description; 34893034Sdougm char *groupname; 34903034Sdougm char *sharedstate; 34913034Sdougm int shared = 1; 34923034Sdougm char *soptions; 34933034Sdougm 34943034Sdougm sharedstate = sa_get_share_attr(share, "shared"); 34953034Sdougm path = sa_get_share_attr(share, "path"); 34963034Sdougm type = sa_get_share_attr(share, "type"); 34973034Sdougm resource = sa_get_share_attr(share, "resource"); 34983034Sdougm groupname = sa_get_group_attr(group, "name"); 34993034Sdougm 35003034Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 35013034Sdougm sa_free_attr_string(groupname); 35023034Sdougm groupname = NULL; 35033034Sdougm } 35043034Sdougm description = sa_get_share_description(share); 35053034Sdougm soptions = options; 35063034Sdougm 35073034Sdougm if (sharedstate == NULL) 35083034Sdougm shared = 0; 35093034Sdougm 35103034Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 35113034Sdougm 35123034Sdougm if (shared) { 35133034Sdougm /* only persisting share go here */ 35143034Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 35153034Sdougm resource != NULL ? resource : "-", 35163034Sdougm groupname != NULL ? "@" : "", 35173034Sdougm groupname != NULL ? groupname : ""); 35183034Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 35193034Sdougm resfmt, 35203034Sdougm path, 35213034Sdougm (soptions != NULL && strlen(soptions) > 0) ? 35223034Sdougm soptions : "rw", 35233034Sdougm (description != NULL) ? description : ""); 35243034Sdougm } 35253034Sdougm 35263034Sdougm if (path != NULL) 35273034Sdougm sa_free_attr_string(path); 35283034Sdougm if (type != NULL) 35293034Sdougm sa_free_attr_string(type); 35303034Sdougm if (resource != NULL) 35313034Sdougm sa_free_attr_string(resource); 35323034Sdougm if (groupname != NULL) 35333034Sdougm sa_free_attr_string(groupname); 35343034Sdougm if (description != NULL) 35353034Sdougm sa_free_share_description(description); 35363034Sdougm if (sharedstate != NULL) 35373034Sdougm sa_free_attr_string(sharedstate); 35383034Sdougm if (soptions != NULL && soptions != options) 35393034Sdougm sa_format_free(soptions); 35403034Sdougm } 35413034Sdougm } 35423034Sdougm 35433034Sdougm /* 35443034Sdougm * output_legacy_file(out, proto) 35453034Sdougm * 35463034Sdougm * Walk all of the groups for the specified protocol and call 35473034Sdougm * out_share() to format and write in the format displayed by the 35483034Sdougm * "share" command with no arguments. 35493034Sdougm */ 35503034Sdougm 35513034Sdougm static void 35523034Sdougm output_legacy_file(FILE *out, char *proto) 35533034Sdougm { 35543034Sdougm sa_group_t group; 35553034Sdougm 35563034Sdougm for (group = sa_get_group(NULL); group != NULL; 35573034Sdougm group = sa_get_next_group(group)) { 35583034Sdougm char *options; 35593034Sdougm char *zfs; 35603034Sdougm 35613034Sdougm /* 35623034Sdougm * get default options preformated, being careful to 35633034Sdougm * handle legacy shares differently from new style 35643034Sdougm * shares. Legacy share have options on the share. 35653034Sdougm */ 35663034Sdougm 35673034Sdougm zfs = sa_get_group_attr(group, "zfs"); 35683034Sdougm if (zfs != NULL) { 35693034Sdougm sa_group_t zgroup; 35703034Sdougm sa_free_attr_string(zfs); 35713034Sdougm options = sa_proto_legacy_format(proto, group, 1); 35723034Sdougm for (zgroup = sa_get_sub_group(group); zgroup != NULL; 35733034Sdougm zgroup = sa_get_next_group(zgroup)) { 35743034Sdougm 35753034Sdougm /* got a group, so display it */ 35763034Sdougm out_share(out, zgroup, proto, options); 35773034Sdougm } 35783034Sdougm } else { 35793034Sdougm options = sa_proto_legacy_format(proto, group, 1); 35803034Sdougm out_share(out, group, proto, options); 35813034Sdougm } 35823034Sdougm if (options != NULL) 35833034Sdougm free(options); 35843034Sdougm } 35853034Sdougm } 35863034Sdougm 35873034Sdougm int 35883034Sdougm sa_legacy_share(int flags, int argc, char *argv[]) 35893034Sdougm { 35903034Sdougm char *protocol = "nfs"; 35913034Sdougm char *options = NULL; 35923034Sdougm char *description = NULL; 35933034Sdougm char *groupname = NULL; 35943034Sdougm char *sharepath = NULL; 35953034Sdougm char *resource = NULL; 35963034Sdougm char *groupstatus = NULL; 35973034Sdougm int persist = SA_SHARE_TRANSIENT; 35983034Sdougm int argsused = 0; 35993034Sdougm int c; 36003034Sdougm int ret = SA_OK; 36013034Sdougm int zfs = 0; 36023034Sdougm int true_legacy = 0; 36033034Sdougm int curtype = SA_SHARE_TRANSIENT; 36043034Sdougm char cmd[MAXPATHLEN]; 36053034Sdougm #ifdef lint 36063034Sdougm flags = flags; 36073034Sdougm #endif 36083034Sdougm 36093034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 36103034Sdougm switch (c) { 36113034Sdougm case 'd': 36123034Sdougm description = optarg; 36133034Sdougm argsused++; 36143034Sdougm break; 36153034Sdougm case 'F': 36163034Sdougm protocol = optarg; 36173034Sdougm if (!sa_valid_protocol(protocol)) { 36183034Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 36193034Sdougm protocol, "share") == 0 && check_legacy_cmd(cmd)) { 36203034Sdougm true_legacy++; 36213034Sdougm } else { 36223034Sdougm (void) fprintf(stderr, 36233034Sdougm gettext("Invalid protocol specified:" 36243034Sdougm "%s\n"), 36253034Sdougm protocol); 36263034Sdougm return (SA_INVALID_PROTOCOL); 36273034Sdougm } 36283034Sdougm } 36293034Sdougm break; 36303034Sdougm case 'o': 36313034Sdougm options = optarg; 36323034Sdougm argsused++; 36333034Sdougm break; 36343034Sdougm case 'p': 36353034Sdougm persist = SA_SHARE_PERMANENT; 36363034Sdougm argsused++; 36373034Sdougm break; 36383034Sdougm case 'h': 36393034Sdougm case '?': 36403034Sdougm default: 36413034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 36423034Sdougm sa_get_usage(USAGE_SHARE)); 36433034Sdougm return (SA_OK); 36443034Sdougm } 36453034Sdougm } 36463034Sdougm 36473034Sdougm /* have the info so construct what is needed */ 36483034Sdougm if (!argsused && optind == argc) { 36493034Sdougm /* display current info in share format */ 36503034Sdougm (void) output_legacy_file(stdout, "nfs"); 36513034Sdougm } else { 36523034Sdougm sa_group_t group = NULL; 36533034Sdougm sa_share_t share; 36543034Sdougm char dir[MAXPATHLEN]; 36553034Sdougm 36563034Sdougm /* we are modifying the configuration */ 36573034Sdougm if (optind == argc) { 36583034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 36593034Sdougm sa_get_usage(USAGE_SHARE)); 36603034Sdougm return (SA_LEGACY_ERR); 36613034Sdougm } 36623034Sdougm 36633034Sdougm if (true_legacy) { 36643034Sdougm /* if still using legacy share/unshare, exec it */ 36653034Sdougm ret = run_legacy_command(cmd, argv); 36663034Sdougm return (ret); 36673034Sdougm } 36683034Sdougm 36693034Sdougm sharepath = argv[optind++]; 36703034Sdougm if (optind < argc) { 36713034Sdougm resource = argv[optind]; 36723034Sdougm groupname = strchr(resource, '@'); 36733034Sdougm if (groupname != NULL) 36743034Sdougm *groupname++ = '\0'; 36753034Sdougm } 36763034Sdougm if (realpath(sharepath, dir) == NULL) 36773034Sdougm ret = SA_BAD_PATH; 36783034Sdougm else 36793034Sdougm sharepath = dir; 36803034Sdougm if (ret == SA_OK) { 36813034Sdougm share = sa_find_share(sharepath); 36823034Sdougm } else { 36833034Sdougm share = NULL; 36843034Sdougm } 36853034Sdougm if (groupname != NULL) { 36863034Sdougm ret = SA_NOT_ALLOWED; 36873034Sdougm } else if (ret == SA_OK) { 36883034Sdougm char *legacygroup = "default"; 36893034Sdougm /* 36903034Sdougm * the legacy group is always present and zfs groups 36913034Sdougm * come and go. zfs shares may be in sub-groups and 36923034Sdougm * the zfs share will already be in that group so it 36933034Sdougm * isn't an error. 36943034Sdougm */ 36953034Sdougm if (share != NULL) { 36963034Sdougm /* 36973034Sdougm * if the share exists, then make sure it is one we 36983034Sdougm * want to handle. 36993034Sdougm */ 37003034Sdougm group = sa_get_parent_group(share); 37013034Sdougm } else { 37023034Sdougm group = sa_get_group(legacygroup); 37033034Sdougm } 37043034Sdougm if (group != NULL) { 37053034Sdougm groupstatus = group_status(group); 37063034Sdougm if (share == NULL) { 37073034Sdougm share = sa_add_share(group, sharepath, persist, &ret); 37083034Sdougm if (share == NULL && ret == SA_DUPLICATE_NAME) { 37093034Sdougm /* could be a ZFS path being started */ 37103034Sdougm if (sa_zfs_is_shared(sharepath)) { 37113034Sdougm ret = SA_OK; 37123034Sdougm group = sa_get_group("zfs"); 37133034Sdougm if (group == NULL) { 37143034Sdougm /* this shouldn't happen */ 37153034Sdougm ret = SA_CONFIG_ERR; 37163034Sdougm } 37173034Sdougm if (group != NULL) { 37183034Sdougm share = sa_add_share(group, sharepath, 37193034Sdougm persist, &ret); 37203034Sdougm } 37213034Sdougm } 37223034Sdougm } 37233034Sdougm } else { 37243034Sdougm /* 37253034Sdougm * may want to change persist state, but the 37263034Sdougm * important thing is to change options unless 37273034Sdougm * this is ZFS where we just want to do the 37283034Sdougm * enable since everything is current. 37293034Sdougm */ 37303034Sdougm if (!sa_zfs_is_shared(sharepath)) { 37313034Sdougm char *type; 37323034Sdougm remove_all_options(share, protocol); 37333034Sdougm type = sa_get_share_attr(share, "type"); 37343034Sdougm if (type != NULL && 37353034Sdougm strcmp(type, "transient") != 0) { 37363034Sdougm curtype = SA_SHARE_PERMANENT; 37373034Sdougm } 37383034Sdougm if (type != NULL) 37393034Sdougm sa_free_attr_string(type); 37403034Sdougm if (curtype != persist) { 37413034Sdougm (void) sa_set_share_attr(share, "type", 37423034Sdougm persist == SA_SHARE_PERMANENT ? 37433034Sdougm "persist" : "transient"); 37443034Sdougm } 37453034Sdougm } else { 37463034Sdougm zfs++; 37473034Sdougm } 37483034Sdougm } 37493034Sdougm if (!zfs) { 37503034Sdougm /* have a group to hold this share path */ 37513034Sdougm if (ret == SA_OK && options != NULL && 37523034Sdougm strlen(options) > 0) { 37533034Sdougm ret = sa_parse_legacy_options(share, 37543034Sdougm options, 37553034Sdougm protocol); 37563034Sdougm } 37573034Sdougm if (ret == SA_OK && description != NULL) 37583034Sdougm ret = sa_set_share_description(share, description); 37593034Sdougm if (ret == SA_OK && resource != NULL) 37603034Sdougm ret = sa_set_share_attr(share, "resource", 37613034Sdougm resource); 37623034Sdougm } 37633034Sdougm if (ret == SA_OK) { 37643034Sdougm if (strcmp(groupstatus, "enabled") == 0) 37653034Sdougm ret = sa_enable_share(share, protocol); 37663034Sdougm if (ret == SA_OK && persist == SA_SHARE_PERMANENT) { 37673034Sdougm (void) sa_update_legacy(share, protocol); 37683034Sdougm } 37693034Sdougm if (ret == SA_OK) 37703034Sdougm ret = sa_update_config(); 37713034Sdougm } 37723034Sdougm } else { 37733034Sdougm ret = SA_SYSTEM_ERR; 37743034Sdougm } 37753034Sdougm } 37763034Sdougm } 37773034Sdougm if (ret != SA_OK) { 37783034Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 37793034Sdougm sharepath, sa_errorstr(ret)); 37803034Sdougm ret = SA_LEGACY_ERR; 37813034Sdougm 37823034Sdougm } 37833034Sdougm return (ret); 37843034Sdougm } 37853034Sdougm 37863034Sdougm /* 37873034Sdougm * sa_legacy_unshare(flags, argc, argv) 37883034Sdougm * 37893034Sdougm * Implements the original unshare command. 37903034Sdougm */ 37913034Sdougm 37923034Sdougm int 37933034Sdougm sa_legacy_unshare(int flags, int argc, char *argv[]) 37943034Sdougm { 37953034Sdougm char *protocol = "nfs"; /* for now */ 37963034Sdougm char *options = NULL; 37973034Sdougm char *sharepath = NULL; 37983034Sdougm int persist = SA_SHARE_TRANSIENT; 37993034Sdougm int argsused = 0; 38003034Sdougm int c; 38013034Sdougm int ret = SA_OK; 38023034Sdougm int true_legacy = 0; 38033034Sdougm char cmd[MAXPATHLEN]; 38043034Sdougm #ifdef lint 38053034Sdougm flags = flags; 38063034Sdougm options = options; 38073034Sdougm #endif 38083034Sdougm 38093034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 38103034Sdougm switch (c) { 38113034Sdougm case 'h': 38123034Sdougm case '?': 38133034Sdougm break; 38143034Sdougm case 'F': 38153034Sdougm protocol = optarg; 38163034Sdougm if (!sa_valid_protocol(protocol)) { 38173034Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 38183034Sdougm protocol, "unshare") == 0 && 38193034Sdougm check_legacy_cmd(cmd)) { 38203034Sdougm true_legacy++; 38213034Sdougm } else { 38223034Sdougm (void) printf(gettext("Invalid file system name\n")); 38233034Sdougm return (SA_INVALID_PROTOCOL); 38243034Sdougm } 38253034Sdougm } 38263034Sdougm break; 38273034Sdougm case 'o': 38283034Sdougm options = optarg; 38293034Sdougm argsused++; 38303034Sdougm break; 38313034Sdougm case 'p': 38323034Sdougm persist = SA_SHARE_PERMANENT; 38333034Sdougm argsused++; 38343034Sdougm break; 38353034Sdougm default: 38363034Sdougm (void) printf(gettext("usage: %s\n"), 38373034Sdougm sa_get_usage(USAGE_UNSHARE)); 38383034Sdougm return (SA_OK); 38393034Sdougm } 38403034Sdougm } 38413034Sdougm 38423034Sdougm /* have the info so construct what is needed */ 38433034Sdougm if (optind == argc || (optind + 1) < argc) { 38443034Sdougm ret = SA_SYNTAX_ERR; 38453034Sdougm } else { 38463034Sdougm sa_share_t share; 38473034Sdougm char dir[MAXPATHLEN]; 38483034Sdougm if (true_legacy) { 38493034Sdougm /* if still using legacy share/unshare, exec it */ 38503034Sdougm ret = run_legacy_command(cmd, argv); 38513034Sdougm return (ret); 38523034Sdougm } 38533034Sdougm sharepath = argv[optind++]; 38543034Sdougm if (realpath(sharepath, dir) == NULL) { 38553034Sdougm ret = SA_NO_SUCH_PATH; 38563034Sdougm } else { 38573034Sdougm sharepath = dir; 38583034Sdougm share = sa_find_share(sharepath); 38593034Sdougm if (share != NULL) { 38603034Sdougm ret = sa_disable_share(share, protocol); 38613034Sdougm if (ret == SA_OK) { 38623034Sdougm if (persist == SA_SHARE_PERMANENT) 38633034Sdougm ret = sa_remove_share(share); 38643034Sdougm ret = sa_update_config(); 38653034Sdougm } 38663034Sdougm } else { 38673034Sdougm ret = SA_NOT_SHARED; 38683034Sdougm } 38693034Sdougm } 38703034Sdougm } 38713034Sdougm switch (ret) { 38723034Sdougm default: 38733034Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 38743034Sdougm ret = SA_LEGACY_ERR; 38753034Sdougm break; 38763034Sdougm case SA_SYNTAX_ERR: 38773034Sdougm (void) printf(gettext("usage: %s\n"), 38783034Sdougm sa_get_usage(USAGE_UNSHARE)); 38793034Sdougm break; 38803034Sdougm case SA_OK: 38813034Sdougm break; 38823034Sdougm } 38833034Sdougm return (ret); 38843034Sdougm } 38853034Sdougm 38863034Sdougm /* 38873034Sdougm * common commands that implement the sub-commands used by all 38883034Sdougm * protcols. The entries are found via the lookup command 38893034Sdougm */ 38903034Sdougm 38913034Sdougm static sa_command_t commands[] = { 38923034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 38933034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 38943034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 38953034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 38963034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 38973034Sdougm {"list", 0, sa_list, USAGE_LIST}, 38983034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 38993034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 39003034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 39013034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 39023034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 39033034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 39043034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 39053034Sdougm SVC_SET|SVC_ACTION}, 39063034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 39073034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 39083034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 39093034Sdougm {NULL, 0, NULL, NULL} 39103034Sdougm }; 39113034Sdougm 39123034Sdougm static char * 39133034Sdougm sa_get_usage(sa_usage_t index) 39143034Sdougm { 39153034Sdougm char *ret = NULL; 39163034Sdougm switch (index) { 39173034Sdougm case USAGE_ADD_SHARE: 39183034Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 39193034Sdougm "[-d \"description text\"] -s sharepath group"); 39203034Sdougm break; 39213034Sdougm case USAGE_CREATE: 39223034Sdougm ret = gettext("create [-nvh] [-P proto [-p property=value]] group"); 39233034Sdougm break; 39243034Sdougm case USAGE_DELETE: 39253034Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 39263034Sdougm break; 39273034Sdougm case USAGE_DISABLE: 39283034Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 39293034Sdougm break; 39303034Sdougm case USAGE_ENABLE: 39313034Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 39323034Sdougm break; 39333034Sdougm case USAGE_LIST: 39343034Sdougm ret = gettext("list [-vh] [-P proto]"); 39353034Sdougm break; 39363034Sdougm case USAGE_MOVE_SHARE: 39373034Sdougm ret = gettext("move-share [-nvh] -s sharepath destination-group"); 39383034Sdougm break; 39393034Sdougm case USAGE_REMOVE_SHARE: 39403034Sdougm ret = gettext("remove-share [-fnvh] -s sharepath group"); 39413034Sdougm break; 39423034Sdougm case USAGE_SET: 39433034Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 39443034Sdougm "[-p property=value]* [-s sharepath] group"); 39453034Sdougm break; 39463034Sdougm case USAGE_SET_SECURITY: 39473034Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 39483034Sdougm "[-p property=value]* group"); 39493034Sdougm break; 39503034Sdougm case USAGE_SET_SHARE: 39513034Sdougm ret = gettext("set-share [-nh] [-r resource] " 39523034Sdougm "[-d \"description text\"] -s sharepath group"); 39533034Sdougm break; 39543034Sdougm case USAGE_SHOW: 39553034Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 39563034Sdougm break; 39573034Sdougm case USAGE_SHARE: 39583034Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 39593034Sdougm "[-d description] [pathname [resourcename]]"); 39603034Sdougm break; 39613034Sdougm case USAGE_START: 39623034Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 39633034Sdougm break; 39643034Sdougm case USAGE_STOP: 39653034Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 39663034Sdougm break; 39673034Sdougm case USAGE_UNSET: 39683034Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 39693034Sdougm "[-p property]* group"); 39703034Sdougm break; 39713034Sdougm case USAGE_UNSET_SECURITY: 39723034Sdougm ret = gettext("unset-security [-nvh] -P proto -S security-type " 39733034Sdougm "[-p property]* group"); 39743034Sdougm break; 39753034Sdougm case USAGE_UNSHARE: 39763034Sdougm ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath"); 39773034Sdougm break; 39783034Sdougm } 39793034Sdougm return (ret); 39803034Sdougm } 39813034Sdougm 39823034Sdougm /* 39833034Sdougm * sa_lookup(cmd, proto) 39843034Sdougm * 39853034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 39863034Sdougm * eventually provide a way to provide protocol specific sub-commands. 39873034Sdougm */ 39883034Sdougm 39893034Sdougm sa_command_t * 39903034Sdougm sa_lookup(char *cmd, char *proto) 39913034Sdougm { 39923034Sdougm int i; 39933034Sdougm size_t len; 39943034Sdougm #ifdef lint 39953034Sdougm proto = proto; 39963034Sdougm #endif 39973034Sdougm 39983034Sdougm len = strlen(cmd); 39993034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 40003034Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 40013034Sdougm return (&commands[i]); 40023034Sdougm } 40033034Sdougm return (NULL); 40043034Sdougm } 40053034Sdougm 40063034Sdougm void 40073034Sdougm sub_command_help(char *proto) 40083034Sdougm { 40093034Sdougm int i; 40103034Sdougm #ifdef lint 40113034Sdougm proto = proto; 40123034Sdougm #endif 40133034Sdougm 40143034Sdougm (void) printf(gettext("\tsub-commands:\n")); 40153034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 40163034Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 40173034Sdougm (void) printf("\t%s\n", 40183034Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 40193034Sdougm } 40203034Sdougm } 4021