1*3034Sdougm /* 2*3034Sdougm * CDDL HEADER START 3*3034Sdougm * 4*3034Sdougm * The contents of this file are subject to the terms of the 5*3034Sdougm * Common Development and Distribution License (the "License"). 6*3034Sdougm * You may not use this file except in compliance with the License. 7*3034Sdougm * 8*3034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3034Sdougm * or http://www.opensolaris.org/os/licensing. 10*3034Sdougm * See the License for the specific language governing permissions 11*3034Sdougm * and limitations under the License. 12*3034Sdougm * 13*3034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 14*3034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3034Sdougm * If applicable, add the following below this CDDL HEADER, with the 16*3034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 17*3034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 18*3034Sdougm * 19*3034Sdougm * CDDL HEADER END 20*3034Sdougm */ 21*3034Sdougm 22*3034Sdougm /* 23*3034Sdougm * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*3034Sdougm * Use is subject to license terms. 25*3034Sdougm */ 26*3034Sdougm 27*3034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 28*3034Sdougm 29*3034Sdougm #include <sys/types.h> 30*3034Sdougm #include <sys/stat.h> 31*3034Sdougm #include <fcntl.h> 32*3034Sdougm #include <stdlib.h> 33*3034Sdougm #include <stdio.h> 34*3034Sdougm #include <string.h> 35*3034Sdougm #include <ctype.h> 36*3034Sdougm #include <unistd.h> 37*3034Sdougm #include <getopt.h> 38*3034Sdougm #include <utmpx.h> 39*3034Sdougm #include <pwd.h> 40*3034Sdougm #include <auth_attr.h> 41*3034Sdougm #include <secdb.h> 42*3034Sdougm #include <sys/param.h> 43*3034Sdougm #include <sys/stat.h> 44*3034Sdougm #include <errno.h> 45*3034Sdougm 46*3034Sdougm #include <libshare.h> 47*3034Sdougm #include "sharemgr.h" 48*3034Sdougm #include <libscf.h> 49*3034Sdougm #include <libxml/tree.h> 50*3034Sdougm #include <libintl.h> 51*3034Sdougm 52*3034Sdougm static char *sa_get_usage(sa_usage_t); 53*3034Sdougm 54*3034Sdougm /* 55*3034Sdougm * Implementation of the common sub-commands supported by sharemgr. 56*3034Sdougm * A number of helper functions are also included. 57*3034Sdougm */ 58*3034Sdougm 59*3034Sdougm /* 60*3034Sdougm * has_protocol(group, proto) 61*3034Sdougm * If the group has an optionset with the specified protocol, 62*3034Sdougm * return true (1) otherwise false (0). 63*3034Sdougm */ 64*3034Sdougm static int 65*3034Sdougm has_protocol(sa_group_t group, char *protocol) 66*3034Sdougm { 67*3034Sdougm sa_optionset_t optionset; 68*3034Sdougm int result = 0; 69*3034Sdougm 70*3034Sdougm optionset = sa_get_optionset(group, protocol); 71*3034Sdougm if (optionset != NULL) { 72*3034Sdougm result++; 73*3034Sdougm } 74*3034Sdougm return (result); 75*3034Sdougm } 76*3034Sdougm 77*3034Sdougm /* 78*3034Sdougm * add_list(list, item) 79*3034Sdougm * Adds a new list member that points to item to the list. 80*3034Sdougm * If list is NULL, it starts a new list. The function returns 81*3034Sdougm * the first member of the list. 82*3034Sdougm */ 83*3034Sdougm struct list * 84*3034Sdougm add_list(struct list *listp, void *item, void *data) 85*3034Sdougm { 86*3034Sdougm struct list *new, *tmp; 87*3034Sdougm 88*3034Sdougm new = malloc(sizeof (struct list)); 89*3034Sdougm if (new != NULL) { 90*3034Sdougm new->next = NULL; 91*3034Sdougm new->item = item; 92*3034Sdougm new->itemdata = data; 93*3034Sdougm } else { 94*3034Sdougm return (listp); 95*3034Sdougm } 96*3034Sdougm 97*3034Sdougm if (listp == NULL) 98*3034Sdougm return (new); 99*3034Sdougm 100*3034Sdougm for (tmp = listp; tmp->next != NULL; tmp = tmp->next) { 101*3034Sdougm /* get to end of list */ 102*3034Sdougm } 103*3034Sdougm tmp->next = new; 104*3034Sdougm return (listp); 105*3034Sdougm } 106*3034Sdougm 107*3034Sdougm /* 108*3034Sdougm * free_list(list) 109*3034Sdougm * Given a list, free all the members of the list; 110*3034Sdougm */ 111*3034Sdougm static void 112*3034Sdougm free_list(struct list *listp) 113*3034Sdougm { 114*3034Sdougm struct list *tmp; 115*3034Sdougm while (listp != NULL) { 116*3034Sdougm tmp = listp; 117*3034Sdougm listp = listp->next; 118*3034Sdougm free(tmp); 119*3034Sdougm } 120*3034Sdougm } 121*3034Sdougm 122*3034Sdougm /* 123*3034Sdougm * check_authorization(instname, which) 124*3034Sdougm * 125*3034Sdougm * Checks to see if the specific type of authorization in which is 126*3034Sdougm * enabled for the user in this SMF service instance. 127*3034Sdougm */ 128*3034Sdougm 129*3034Sdougm static int 130*3034Sdougm check_authorization(char *instname, int which) 131*3034Sdougm { 132*3034Sdougm scf_handle_t *handle = NULL; 133*3034Sdougm scf_simple_prop_t *prop = NULL; 134*3034Sdougm char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 135*3034Sdougm char *authstr = NULL; 136*3034Sdougm ssize_t numauths; 137*3034Sdougm int ret = 1; 138*3034Sdougm uid_t uid; 139*3034Sdougm struct passwd *pw = NULL; 140*3034Sdougm 141*3034Sdougm uid = getuid(); 142*3034Sdougm pw = getpwuid(uid); 143*3034Sdougm if (pw == NULL) 144*3034Sdougm ret = 0; 145*3034Sdougm 146*3034Sdougm if (ret == 1) { 147*3034Sdougm /* since names are restricted to SA_MAX_NAME_LEN won't overflow */ 148*3034Sdougm (void) snprintf(svcstring, sizeof (svcstring), 149*3034Sdougm "%s:%s", SA_SVC_FMRI_BASE, instname); 150*3034Sdougm handle = scf_handle_create(SCF_VERSION); 151*3034Sdougm if (handle != NULL) { 152*3034Sdougm if (scf_handle_bind(handle) == 0) { 153*3034Sdougm switch (which) { 154*3034Sdougm case SVC_SET: 155*3034Sdougm prop = scf_simple_prop_get(handle, svcstring, 156*3034Sdougm "general", 157*3034Sdougm SVC_AUTH_VALUE); 158*3034Sdougm break; 159*3034Sdougm case SVC_ACTION: 160*3034Sdougm prop = scf_simple_prop_get(handle, svcstring, 161*3034Sdougm "general", 162*3034Sdougm SVC_AUTH_ACTION); 163*3034Sdougm break; 164*3034Sdougm } 165*3034Sdougm } 166*3034Sdougm } 167*3034Sdougm } 168*3034Sdougm /* make sure we have an authorization string property */ 169*3034Sdougm if (prop != NULL) { 170*3034Sdougm int i; 171*3034Sdougm numauths = scf_simple_prop_numvalues(prop); 172*3034Sdougm for (ret = 0, i = 0; i < numauths; i++) { 173*3034Sdougm authstr = scf_simple_prop_next_astring(prop); 174*3034Sdougm if (authstr != NULL) { 175*3034Sdougm /* check if this user has one of the strings */ 176*3034Sdougm if (chkauthattr(authstr, pw->pw_name)) { 177*3034Sdougm ret = 1; 178*3034Sdougm break; 179*3034Sdougm } 180*3034Sdougm } 181*3034Sdougm } 182*3034Sdougm endauthattr(); 183*3034Sdougm scf_simple_prop_free(prop); 184*3034Sdougm } else { 185*3034Sdougm /* no authorization string defined */ 186*3034Sdougm ret = 0; 187*3034Sdougm } 188*3034Sdougm if (handle != NULL) 189*3034Sdougm scf_handle_destroy(handle); 190*3034Sdougm return (ret); 191*3034Sdougm } 192*3034Sdougm 193*3034Sdougm /* 194*3034Sdougm * check_authorizations(instname, flags) 195*3034Sdougm * 196*3034Sdougm * check all the needed authorizations for the user in this service 197*3034Sdougm * instance. Return value of 1(true) or 0(false) indicates whether 198*3034Sdougm * there are authorizations for the user or not. 199*3034Sdougm */ 200*3034Sdougm 201*3034Sdougm static int 202*3034Sdougm check_authorizations(char *instname, int flags) 203*3034Sdougm { 204*3034Sdougm int ret1 = 0; 205*3034Sdougm int ret2 = 0; 206*3034Sdougm int ret; 207*3034Sdougm 208*3034Sdougm if (flags & SVC_SET) 209*3034Sdougm ret1 = check_authorization(instname, SVC_SET); 210*3034Sdougm if (flags & SVC_ACTION) 211*3034Sdougm ret2 = check_authorization(instname, SVC_ACTION); 212*3034Sdougm switch (flags) { 213*3034Sdougm case SVC_ACTION: 214*3034Sdougm ret = ret2; 215*3034Sdougm break; 216*3034Sdougm case SVC_SET: 217*3034Sdougm ret = ret1; 218*3034Sdougm break; 219*3034Sdougm case SVC_ACTION|SVC_SET: 220*3034Sdougm ret = ret1 & ret2; 221*3034Sdougm break; 222*3034Sdougm default: 223*3034Sdougm /* if not flags set, we assume we don't need authorizations */ 224*3034Sdougm ret = 1; 225*3034Sdougm } 226*3034Sdougm return (ret); 227*3034Sdougm } 228*3034Sdougm 229*3034Sdougm /* 230*3034Sdougm * enable_all_groups(list, setstate, online, update) 231*3034Sdougm * Given a list of groups, enable each one found. If update is 232*3034Sdougm * not NULL, then update all the shares for the protocol that was 233*3034Sdougm * passed in. 234*3034Sdougm */ 235*3034Sdougm static int 236*3034Sdougm enable_all_groups(struct list *work, int setstate, int online, char *update) 237*3034Sdougm { 238*3034Sdougm sa_share_t share; 239*3034Sdougm int ret = SA_OK; 240*3034Sdougm char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1]; 241*3034Sdougm char *state; 242*3034Sdougm char *name; 243*3034Sdougm char *zfs = NULL; 244*3034Sdougm int dozfs = 0; 245*3034Sdougm sa_group_t group; 246*3034Sdougm 247*3034Sdougm while (work != NULL && ret == SA_OK) { 248*3034Sdougm group = (sa_group_t)work->item; 249*3034Sdougm /* if itemdata != NULL then a single share */ 250*3034Sdougm if (work->itemdata != NULL) { 251*3034Sdougm ret = sa_enable_share((sa_share_t)work->itemdata, NULL); 252*3034Sdougm } 253*3034Sdougm if (setstate) 254*3034Sdougm ret = sa_set_group_attr(group, "state", 255*3034Sdougm "enabled"); 256*3034Sdougm if (ret == SA_OK) { 257*3034Sdougm /* if itemdata == NULL then the whole group */ 258*3034Sdougm if (work->itemdata == NULL) { 259*3034Sdougm for (share = sa_get_share(group, NULL); 260*3034Sdougm share != NULL; share = sa_get_next_share(share)) { 261*3034Sdougm if (update != NULL) 262*3034Sdougm (void) sa_update_legacy(share, update); 263*3034Sdougm ret = sa_enable_share(share, NULL); 264*3034Sdougm } 265*3034Sdougm } 266*3034Sdougm if (online) { 267*3034Sdougm name = sa_get_group_attr(group, "name"); 268*3034Sdougm zfs = sa_get_group_attr(group, "zfs"); 269*3034Sdougm if (name != NULL) { 270*3034Sdougm if (zfs == NULL) { 271*3034Sdougm (void) snprintf(instance, sizeof (instance), 272*3034Sdougm "%s:%s", 273*3034Sdougm SA_SVC_FMRI_BASE, name); 274*3034Sdougm state = smf_get_state(instance); 275*3034Sdougm if (state == NULL || 276*3034Sdougm strcmp(state, "online") != 0) { 277*3034Sdougm (void) smf_enable_instance(instance, 0); 278*3034Sdougm free(state); 279*3034Sdougm } 280*3034Sdougm } else { 281*3034Sdougm dozfs++; 282*3034Sdougm sa_free_attr_string(zfs); 283*3034Sdougm zfs = NULL; 284*3034Sdougm } 285*3034Sdougm if (name != NULL) 286*3034Sdougm sa_free_attr_string(name); 287*3034Sdougm } 288*3034Sdougm } else { 289*3034Sdougm zfs = sa_get_group_attr(group, "zfs"); 290*3034Sdougm if (zfs != NULL) { 291*3034Sdougm dozfs++; 292*3034Sdougm sa_free_attr_string(zfs); 293*3034Sdougm zfs = NULL; 294*3034Sdougm } 295*3034Sdougm } 296*3034Sdougm work = work->next; 297*3034Sdougm } 298*3034Sdougm } 299*3034Sdougm if (ret == SA_OK) { 300*3034Sdougm ret = sa_update_config(); 301*3034Sdougm } 302*3034Sdougm /* do ZFS last to allow everything to get updated */ 303*3034Sdougm if (ret == SA_OK && dozfs) { 304*3034Sdougm FILE *sys; 305*3034Sdougm int err; 306*3034Sdougm sys = popen(ZFS_SHAREALL, "r"); 307*3034Sdougm if (sys != NULL) { 308*3034Sdougm err = pclose(sys); 309*3034Sdougm if (err != 0) 310*3034Sdougm ret = SA_SYSTEM_ERR; 311*3034Sdougm } else { 312*3034Sdougm ret = SA_SYSTEM_ERR; 313*3034Sdougm } 314*3034Sdougm } 315*3034Sdougm return (ret); 316*3034Sdougm } 317*3034Sdougm 318*3034Sdougm /* 319*3034Sdougm * chk_opt(optlistp, security, proto) 320*3034Sdougm * 321*3034Sdougm * Do a sanity check on the optlist provided for the protocol. This 322*3034Sdougm * is a syntax check and verification that the property is either a 323*3034Sdougm * general or specific to a names optionset. 324*3034Sdougm */ 325*3034Sdougm 326*3034Sdougm static int 327*3034Sdougm chk_opt(struct options *optlistp, int security, char *proto) 328*3034Sdougm { 329*3034Sdougm struct options *optlist; 330*3034Sdougm char *sep = ""; 331*3034Sdougm int notfirst = 0; 332*3034Sdougm int ret; 333*3034Sdougm 334*3034Sdougm for (optlist = optlistp; optlist != NULL; optlist = optlist->next) { 335*3034Sdougm char *optname; 336*3034Sdougm 337*3034Sdougm optname = optlist->optname; 338*3034Sdougm ret = OPT_ADD_OK; 339*3034Sdougm /* extract property/value pair */ 340*3034Sdougm if (sa_is_security(optname, proto)) { 341*3034Sdougm if (!security) 342*3034Sdougm ret = OPT_ADD_SECURITY; 343*3034Sdougm } else { 344*3034Sdougm if (security) 345*3034Sdougm ret = OPT_ADD_PROPERTY; 346*3034Sdougm } 347*3034Sdougm if (ret != OPT_ADD_OK) { 348*3034Sdougm if (notfirst == 0) 349*3034Sdougm (void) printf(gettext("Property syntax error: ")); 350*3034Sdougm switch (ret) { 351*3034Sdougm case OPT_ADD_SYNTAX: 352*3034Sdougm (void) printf(gettext("%ssyntax error: %s"), 353*3034Sdougm sep, optname); 354*3034Sdougm sep = ", "; 355*3034Sdougm break; 356*3034Sdougm case OPT_ADD_SECURITY: 357*3034Sdougm (void) printf(gettext("%s%s requires -S"), 358*3034Sdougm optname, sep); 359*3034Sdougm sep = ", "; 360*3034Sdougm break; 361*3034Sdougm case OPT_ADD_PROPERTY: 362*3034Sdougm (void) printf(gettext("%s%s not supported with -S"), 363*3034Sdougm optname, sep); 364*3034Sdougm sep = ", "; 365*3034Sdougm break; 366*3034Sdougm } 367*3034Sdougm notfirst++; 368*3034Sdougm } 369*3034Sdougm } 370*3034Sdougm if (notfirst) { 371*3034Sdougm (void) printf("\n"); 372*3034Sdougm ret = SA_SYNTAX_ERR; 373*3034Sdougm } 374*3034Sdougm return (ret); 375*3034Sdougm } 376*3034Sdougm 377*3034Sdougm /* 378*3034Sdougm * free_opt(optlist) 379*3034Sdougm * Free the specified option list. 380*3034Sdougm */ 381*3034Sdougm static void 382*3034Sdougm free_opt(struct options *optlist) 383*3034Sdougm { 384*3034Sdougm struct options *nextopt; 385*3034Sdougm while (optlist != NULL) { 386*3034Sdougm nextopt = optlist->next; 387*3034Sdougm free(optlist); 388*3034Sdougm optlist = nextopt; 389*3034Sdougm } 390*3034Sdougm } 391*3034Sdougm 392*3034Sdougm /* 393*3034Sdougm * check property list for valid properties 394*3034Sdougm * A null value is a remove which is always valid. 395*3034Sdougm */ 396*3034Sdougm static int 397*3034Sdougm valid_options(struct options *optlist, char *proto, void *object, char *sec) 398*3034Sdougm { 399*3034Sdougm int ret = SA_OK; 400*3034Sdougm struct options *cur; 401*3034Sdougm sa_property_t prop; 402*3034Sdougm sa_optionset_t parent = NULL; 403*3034Sdougm 404*3034Sdougm if (object != NULL) { 405*3034Sdougm if (sec == NULL) 406*3034Sdougm parent = sa_get_optionset(object, proto); 407*3034Sdougm else 408*3034Sdougm parent = sa_get_security(object, sec, proto); 409*3034Sdougm } 410*3034Sdougm 411*3034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 412*3034Sdougm if (cur->optvalue != NULL) { 413*3034Sdougm prop = sa_create_property(cur->optname, cur->optvalue); 414*3034Sdougm if (prop == NULL) 415*3034Sdougm ret = SA_NO_MEMORY; 416*3034Sdougm if (ret != SA_OK || 417*3034Sdougm (ret = sa_valid_property(parent, proto, prop)) != SA_OK) { 418*3034Sdougm (void) printf(gettext("Could not add property %s: %s\n"), 419*3034Sdougm cur->optname, 420*3034Sdougm sa_errorstr(ret)); 421*3034Sdougm } 422*3034Sdougm (void) sa_remove_property(prop); 423*3034Sdougm } 424*3034Sdougm } 425*3034Sdougm return (ret); 426*3034Sdougm } 427*3034Sdougm 428*3034Sdougm /* 429*3034Sdougm * add_optionset(group, optlist, protocol, *err) 430*3034Sdougm * Add the options in optlist to an optionset and then add the optionset 431*3034Sdougm * to the group. 432*3034Sdougm * 433*3034Sdougm * The return value indicates if there was a "change" while errors are 434*3034Sdougm * returned via the *err parameters. 435*3034Sdougm */ 436*3034Sdougm static int 437*3034Sdougm add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err) 438*3034Sdougm { 439*3034Sdougm sa_optionset_t optionset; 440*3034Sdougm int ret = SA_OK; 441*3034Sdougm int result = 0; 442*3034Sdougm 443*3034Sdougm optionset = sa_get_optionset(group, proto); 444*3034Sdougm if (optionset == NULL) { 445*3034Sdougm optionset = sa_create_optionset(group, proto); 446*3034Sdougm result = 1; /* adding a protocol is a change */ 447*3034Sdougm } 448*3034Sdougm if (optionset != NULL) { 449*3034Sdougm while (optlist != NULL) { 450*3034Sdougm sa_property_t prop; 451*3034Sdougm prop = sa_get_property(optionset, optlist->optname); 452*3034Sdougm if (prop == NULL) { 453*3034Sdougm /* 454*3034Sdougm * add the property, but only if it is 455*3034Sdougm * a non-NULL or non-zero length value 456*3034Sdougm */ 457*3034Sdougm if (optlist->optvalue != NULL) { 458*3034Sdougm prop = sa_create_property(optlist->optname, 459*3034Sdougm optlist->optvalue); 460*3034Sdougm if (prop != NULL) { 461*3034Sdougm ret = sa_valid_property(optionset, proto, prop); 462*3034Sdougm if (ret != SA_OK) { 463*3034Sdougm (void) sa_remove_property(prop); 464*3034Sdougm (void) printf(gettext("Could not add property " 465*3034Sdougm "%s: %s\n"), 466*3034Sdougm optlist->optname, 467*3034Sdougm sa_errorstr(ret)); 468*3034Sdougm } 469*3034Sdougm } 470*3034Sdougm if (ret == SA_OK) { 471*3034Sdougm ret = sa_add_property(optionset, prop); 472*3034Sdougm if (ret != SA_OK) { 473*3034Sdougm (void) printf(gettext("Could not add property" 474*3034Sdougm " %s: %s\n"), 475*3034Sdougm optlist->optname, 476*3034Sdougm sa_errorstr(ret)); 477*3034Sdougm } else { 478*3034Sdougm /* there was a change */ 479*3034Sdougm result = 1; 480*3034Sdougm } 481*3034Sdougm } 482*3034Sdougm } 483*3034Sdougm } else { 484*3034Sdougm ret = sa_update_property(prop, optlist->optvalue); 485*3034Sdougm /* should check to see if value changed */ 486*3034Sdougm if (ret != SA_OK) { 487*3034Sdougm (void) printf(gettext("Could not update " 488*3034Sdougm "property %s: %s\n"), 489*3034Sdougm optlist->optname, 490*3034Sdougm sa_errorstr(ret)); 491*3034Sdougm } else { 492*3034Sdougm result = 1; 493*3034Sdougm } 494*3034Sdougm } 495*3034Sdougm optlist = optlist->next; 496*3034Sdougm } 497*3034Sdougm ret = sa_commit_properties(optionset, 0); 498*3034Sdougm } 499*3034Sdougm if (err != NULL) 500*3034Sdougm *err = ret; 501*3034Sdougm return (result); 502*3034Sdougm } 503*3034Sdougm 504*3034Sdougm /* 505*3034Sdougm * sa_create(flags, argc, argv) 506*3034Sdougm * create a new group 507*3034Sdougm * this may or may not have a protocol associated with it. 508*3034Sdougm * No protocol means "all" protocols in this case. 509*3034Sdougm */ 510*3034Sdougm static int 511*3034Sdougm sa_create(int flags, int argc, char *argv[]) 512*3034Sdougm { 513*3034Sdougm char *groupname; 514*3034Sdougm 515*3034Sdougm sa_group_t group; 516*3034Sdougm int verbose = 0; 517*3034Sdougm int dryrun = 0; 518*3034Sdougm int c; 519*3034Sdougm char *protocol = NULL; 520*3034Sdougm int ret = SA_OK; 521*3034Sdougm struct options *optlist = NULL; 522*3034Sdougm int err = 0; 523*3034Sdougm int auth; 524*3034Sdougm 525*3034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:")) != EOF) { 526*3034Sdougm switch (c) { 527*3034Sdougm case 'v': 528*3034Sdougm verbose++; 529*3034Sdougm break; 530*3034Sdougm case 'n': 531*3034Sdougm dryrun++; 532*3034Sdougm break; 533*3034Sdougm case 'P': 534*3034Sdougm protocol = optarg; 535*3034Sdougm if (!sa_valid_protocol(protocol)) { 536*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 537*3034Sdougm protocol); 538*3034Sdougm return (SA_INVALID_PROTOCOL); 539*3034Sdougm } 540*3034Sdougm break; 541*3034Sdougm case 'p': 542*3034Sdougm ret = add_opt(&optlist, optarg, 0); 543*3034Sdougm switch (ret) { 544*3034Sdougm case OPT_ADD_SYNTAX: 545*3034Sdougm (void) printf(gettext("Property syntax error for " 546*3034Sdougm "property: %s\n"), 547*3034Sdougm optarg); 548*3034Sdougm return (SA_SYNTAX_ERR); 549*3034Sdougm case OPT_ADD_SECURITY: 550*3034Sdougm (void) printf(gettext("Security properties need " 551*3034Sdougm "to be set with set-security: %s\n"), 552*3034Sdougm optarg); 553*3034Sdougm return (SA_SYNTAX_ERR); 554*3034Sdougm default: 555*3034Sdougm break; 556*3034Sdougm } 557*3034Sdougm 558*3034Sdougm break; 559*3034Sdougm default: 560*3034Sdougm case 'h': 561*3034Sdougm case '?': 562*3034Sdougm (void) printf(gettext("usage: %s\n"), 563*3034Sdougm sa_get_usage(USAGE_CREATE)); 564*3034Sdougm return (0); 565*3034Sdougm } 566*3034Sdougm } 567*3034Sdougm 568*3034Sdougm if (optind >= argc) { 569*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 570*3034Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 571*3034Sdougm return (SA_BAD_PATH); 572*3034Sdougm } 573*3034Sdougm 574*3034Sdougm if ((optind + 1) < argc) { 575*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 576*3034Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 577*3034Sdougm return (SA_SYNTAX_ERR); 578*3034Sdougm } 579*3034Sdougm 580*3034Sdougm if (protocol == NULL && optlist != NULL) { 581*3034Sdougm /* lookup default protocol */ 582*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_CREATE)); 583*3034Sdougm (void) printf(gettext("\tprotocol must be specified " 584*3034Sdougm "with properties\n")); 585*3034Sdougm return (SA_INVALID_PROTOCOL); 586*3034Sdougm } 587*3034Sdougm 588*3034Sdougm if (optlist != NULL) 589*3034Sdougm ret = chk_opt(optlist, 0, protocol); 590*3034Sdougm if (ret == OPT_ADD_SECURITY) { 591*3034Sdougm (void) printf(gettext("Security properties not " 592*3034Sdougm "supported with create\n")); 593*3034Sdougm return (SA_SYNTAX_ERR); 594*3034Sdougm } 595*3034Sdougm 596*3034Sdougm /* 597*3034Sdougm * if a group already exists, we can only add a new protocol 598*3034Sdougm * to it and not create a new one or add the same protocol 599*3034Sdougm * again. 600*3034Sdougm */ 601*3034Sdougm 602*3034Sdougm groupname = argv[optind]; 603*3034Sdougm 604*3034Sdougm auth = check_authorizations(groupname, flags); 605*3034Sdougm 606*3034Sdougm group = sa_get_group(groupname); 607*3034Sdougm if (group != NULL) { 608*3034Sdougm /* group exists so must be a protocol add */ 609*3034Sdougm if (protocol != NULL) { 610*3034Sdougm if (has_protocol(group, protocol)) { 611*3034Sdougm (void) printf(gettext("Group \"%s\" already exists" 612*3034Sdougm " with protocol %s\n"), 613*3034Sdougm groupname, protocol); 614*3034Sdougm ret = SA_DUPLICATE_NAME; 615*3034Sdougm } 616*3034Sdougm } else { 617*3034Sdougm /* must add new protocol */ 618*3034Sdougm (void) printf(gettext("Group already exists and no protocol" 619*3034Sdougm " specified.\n")); 620*3034Sdougm ret = SA_DUPLICATE_NAME; 621*3034Sdougm } 622*3034Sdougm } else { 623*3034Sdougm /* 624*3034Sdougm * is it a valid name? Must comply with SMF instance 625*3034Sdougm * name restrictions. 626*3034Sdougm */ 627*3034Sdougm if (!sa_valid_group_name(groupname)) { 628*3034Sdougm ret = SA_INVALID_NAME; 629*3034Sdougm (void) printf(gettext("Invalid group name: %s\n"), groupname); 630*3034Sdougm } 631*3034Sdougm } 632*3034Sdougm if (ret == SA_OK) { 633*3034Sdougm /* check protocol vs optlist */ 634*3034Sdougm if (optlist != NULL) { 635*3034Sdougm /* check options, if any, for validity */ 636*3034Sdougm ret = valid_options(optlist, protocol, group, NULL); 637*3034Sdougm } 638*3034Sdougm } 639*3034Sdougm if (ret == SA_OK && !dryrun) { 640*3034Sdougm if (group == NULL) { 641*3034Sdougm group = sa_create_group((char *)groupname, &err); 642*3034Sdougm } 643*3034Sdougm if (group != NULL) { 644*3034Sdougm sa_optionset_t optionset; 645*3034Sdougm if (optlist != NULL) { 646*3034Sdougm (void) add_optionset(group, optlist, protocol, &ret); 647*3034Sdougm } else if (protocol != NULL) { 648*3034Sdougm optionset = sa_create_optionset(group, protocol); 649*3034Sdougm if (optionset == NULL) 650*3034Sdougm ret = SA_NO_MEMORY; 651*3034Sdougm } else if (protocol == NULL) { 652*3034Sdougm char **protolist; 653*3034Sdougm int numprotos, i; 654*3034Sdougm numprotos = sa_get_protocols(&protolist); 655*3034Sdougm for (i = 0; i < numprotos; i++) { 656*3034Sdougm optionset = sa_create_optionset(group, protolist[i]); 657*3034Sdougm } 658*3034Sdougm if (protolist != NULL) 659*3034Sdougm free(protolist); 660*3034Sdougm } 661*3034Sdougm /* 662*3034Sdougm * we have a group and legal additions 663*3034Sdougm */ 664*3034Sdougm if (ret == SA_OK) { 665*3034Sdougm /* 666*3034Sdougm * commit to configuration for protocols that 667*3034Sdougm * need to do block updates. For NFS, this 668*3034Sdougm * doesn't do anything but it will be run for 669*3034Sdougm * all protocols that implement the 670*3034Sdougm * appropriate plugin. 671*3034Sdougm */ 672*3034Sdougm ret = sa_update_config(); 673*3034Sdougm } else { 674*3034Sdougm if (group != NULL) 675*3034Sdougm (void) sa_remove_group(group); 676*3034Sdougm } 677*3034Sdougm } else { 678*3034Sdougm ret = err; 679*3034Sdougm (void) printf(gettext("Could not create group: %s\n"), 680*3034Sdougm sa_errorstr(ret)); 681*3034Sdougm } 682*3034Sdougm } 683*3034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 684*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 685*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 686*3034Sdougm ret = SA_NO_PERMISSION; 687*3034Sdougm } 688*3034Sdougm free_opt(optlist); 689*3034Sdougm return (ret); 690*3034Sdougm } 691*3034Sdougm 692*3034Sdougm /* 693*3034Sdougm * group_status(group) 694*3034Sdougm * 695*3034Sdougm * return the current status (enabled/disabled) of the group. 696*3034Sdougm */ 697*3034Sdougm 698*3034Sdougm static char * 699*3034Sdougm group_status(sa_group_t group) 700*3034Sdougm { 701*3034Sdougm char *state; 702*3034Sdougm int enabled = 0; 703*3034Sdougm 704*3034Sdougm state = sa_get_group_attr(group, "state"); 705*3034Sdougm if (state != NULL) { 706*3034Sdougm if (strcmp(state, "enabled") == 0) { 707*3034Sdougm enabled = 1; 708*3034Sdougm } 709*3034Sdougm sa_free_attr_string(state); 710*3034Sdougm } 711*3034Sdougm return (enabled ? gettext("enabled") : gettext("disabled")); 712*3034Sdougm } 713*3034Sdougm 714*3034Sdougm /* 715*3034Sdougm * sa_delete(flags, argc, argv) 716*3034Sdougm * 717*3034Sdougm * Delete a group. 718*3034Sdougm */ 719*3034Sdougm 720*3034Sdougm static int 721*3034Sdougm sa_delete(int flags, int argc, char *argv[]) 722*3034Sdougm { 723*3034Sdougm char *groupname; 724*3034Sdougm sa_group_t group; 725*3034Sdougm sa_share_t share; 726*3034Sdougm int verbose = 0; 727*3034Sdougm int dryrun = 0; 728*3034Sdougm int force = 0; 729*3034Sdougm int c; 730*3034Sdougm char *protocol = NULL; 731*3034Sdougm char *sectype = NULL; 732*3034Sdougm int ret = SA_OK; 733*3034Sdougm int auth; 734*3034Sdougm 735*3034Sdougm while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) { 736*3034Sdougm switch (c) { 737*3034Sdougm case 'v': 738*3034Sdougm verbose++; 739*3034Sdougm break; 740*3034Sdougm case 'n': 741*3034Sdougm dryrun++; 742*3034Sdougm break; 743*3034Sdougm case 'P': 744*3034Sdougm protocol = optarg; 745*3034Sdougm if (!sa_valid_protocol(protocol)) { 746*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 747*3034Sdougm protocol); 748*3034Sdougm return (SA_INVALID_PROTOCOL); 749*3034Sdougm } 750*3034Sdougm break; 751*3034Sdougm case 'S': 752*3034Sdougm sectype = optarg; 753*3034Sdougm break; 754*3034Sdougm case 'f': 755*3034Sdougm force++; 756*3034Sdougm break; 757*3034Sdougm default: 758*3034Sdougm case 'h': 759*3034Sdougm case '?': 760*3034Sdougm (void) printf(gettext("usage: %s\n"), 761*3034Sdougm sa_get_usage(USAGE_DELETE)); 762*3034Sdougm return (0); 763*3034Sdougm } 764*3034Sdougm } 765*3034Sdougm 766*3034Sdougm if (optind >= argc) { 767*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 768*3034Sdougm (void) printf(gettext("\tgroup must be specified.\n")); 769*3034Sdougm return (SA_SYNTAX_ERR); 770*3034Sdougm } 771*3034Sdougm 772*3034Sdougm if ((optind + 1) < argc) { 773*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 774*3034Sdougm (void) printf(gettext("\textraneous group(s) at end\n")); 775*3034Sdougm return (SA_SYNTAX_ERR); 776*3034Sdougm } 777*3034Sdougm 778*3034Sdougm if (sectype != NULL && protocol == NULL) { 779*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_DELETE)); 780*3034Sdougm (void) printf(gettext("\tsecurity requires protocol to be " 781*3034Sdougm "specified.\n")); 782*3034Sdougm return (SA_SYNTAX_ERR); 783*3034Sdougm } 784*3034Sdougm 785*3034Sdougm /* 786*3034Sdougm * Determine if the group already exists since it must in 787*3034Sdougm * order to be removed. 788*3034Sdougm * 789*3034Sdougm * We can delete when: 790*3034Sdougm * 791*3034Sdougm * - group is empty 792*3034Sdougm * - force flag is set 793*3034Sdougm * - if protocol specified, only delete the protocol 794*3034Sdougm */ 795*3034Sdougm 796*3034Sdougm groupname = argv[optind]; 797*3034Sdougm group = sa_get_group(groupname); 798*3034Sdougm if (group == NULL) { 799*3034Sdougm ret = SA_NO_SUCH_GROUP; 800*3034Sdougm } else { 801*3034Sdougm auth = check_authorizations(groupname, flags); 802*3034Sdougm if (protocol == NULL) { 803*3034Sdougm share = sa_get_share(group, NULL); 804*3034Sdougm if (share != NULL) 805*3034Sdougm ret = SA_BUSY; 806*3034Sdougm if (share == NULL || (share != NULL && force == 1)) { 807*3034Sdougm ret = SA_OK; 808*3034Sdougm if (!dryrun) { 809*3034Sdougm while (share != NULL) { 810*3034Sdougm sa_share_t next_share; 811*3034Sdougm next_share = sa_get_next_share(share); 812*3034Sdougm /* 813*3034Sdougm * need to do the disable of each 814*3034Sdougm * share, but don't actually do 815*3034Sdougm * anything on a dryrun. 816*3034Sdougm */ 817*3034Sdougm ret = sa_disable_share(share, NULL); 818*3034Sdougm ret = sa_remove_share(share); 819*3034Sdougm share = next_share; 820*3034Sdougm } 821*3034Sdougm ret = sa_remove_group(group); 822*3034Sdougm } 823*3034Sdougm } 824*3034Sdougm /* commit to configuration if not a dryrun */ 825*3034Sdougm if (!dryrun && ret == SA_OK) { 826*3034Sdougm ret = sa_update_config(); 827*3034Sdougm } 828*3034Sdougm } else { 829*3034Sdougm /* a protocol delete */ 830*3034Sdougm sa_optionset_t optionset; 831*3034Sdougm sa_security_t security; 832*3034Sdougm if (sectype != NULL) { 833*3034Sdougm /* only delete specified security */ 834*3034Sdougm security = sa_get_security(group, sectype, protocol); 835*3034Sdougm if (security != NULL && !dryrun) { 836*3034Sdougm ret = sa_destroy_security(security); 837*3034Sdougm } else { 838*3034Sdougm ret = SA_INVALID_PROTOCOL; 839*3034Sdougm } 840*3034Sdougm } else { 841*3034Sdougm optionset = sa_get_optionset(group, protocol); 842*3034Sdougm if (optionset != NULL && !dryrun) { 843*3034Sdougm /* have an optionset with protocol to delete */ 844*3034Sdougm ret = sa_destroy_optionset(optionset); 845*3034Sdougm /* 846*3034Sdougm * now find all security sets for the protocol 847*3034Sdougm * and remove them. Don't remove other 848*3034Sdougm * protocols. 849*3034Sdougm */ 850*3034Sdougm for (security = sa_get_security(group, NULL, NULL); 851*3034Sdougm ret == SA_OK && security != NULL; 852*3034Sdougm security = sa_get_next_security(security)) { 853*3034Sdougm char *secprot; 854*3034Sdougm 855*3034Sdougm secprot = sa_get_security_attr(security, "type"); 856*3034Sdougm if (secprot != NULL && 857*3034Sdougm strcmp(secprot, protocol) == 0) 858*3034Sdougm ret = sa_destroy_security(security); 859*3034Sdougm if (secprot != NULL) 860*3034Sdougm sa_free_attr_string(secprot); 861*3034Sdougm } 862*3034Sdougm } else { 863*3034Sdougm if (!dryrun) 864*3034Sdougm ret = SA_INVALID_PROTOCOL; 865*3034Sdougm } 866*3034Sdougm } 867*3034Sdougm } 868*3034Sdougm } 869*3034Sdougm if (ret != SA_OK) { 870*3034Sdougm (void) printf(gettext("Could not delete group: %s\n"), 871*3034Sdougm sa_errorstr(ret)); 872*3034Sdougm } else if (dryrun && !auth && verbose) { 873*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 874*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 875*3034Sdougm } 876*3034Sdougm return (ret); 877*3034Sdougm } 878*3034Sdougm 879*3034Sdougm /* 880*3034Sdougm * strndupr(*buff, str, buffsize) 881*3034Sdougm * 882*3034Sdougm * used with small strings to duplicate and possibly increase the 883*3034Sdougm * buffer size of a string. 884*3034Sdougm */ 885*3034Sdougm static char * 886*3034Sdougm strndupr(char *buff, char *str, int *buffsize) 887*3034Sdougm { 888*3034Sdougm int limit; 889*3034Sdougm char *orig_buff = buff; 890*3034Sdougm 891*3034Sdougm if (buff == NULL) { 892*3034Sdougm buff = (char *)malloc(64); 893*3034Sdougm if (buff == NULL) 894*3034Sdougm return (NULL); 895*3034Sdougm *buffsize = 64; 896*3034Sdougm buff[0] = '\0'; 897*3034Sdougm } 898*3034Sdougm limit = strlen(buff) + strlen(str) + 1; 899*3034Sdougm if (limit > *buffsize) { 900*3034Sdougm limit = *buffsize = *buffsize + ((limit / 64) + 64); 901*3034Sdougm buff = realloc(buff, limit); 902*3034Sdougm } 903*3034Sdougm if (buff != NULL) { 904*3034Sdougm (void) strcat(buff, str); 905*3034Sdougm } else { 906*3034Sdougm /* if it fails, fail it hard */ 907*3034Sdougm if (orig_buff != NULL) 908*3034Sdougm free(orig_buff); 909*3034Sdougm } 910*3034Sdougm return (buff); 911*3034Sdougm } 912*3034Sdougm 913*3034Sdougm /* 914*3034Sdougm * group_proto(group) 915*3034Sdougm * 916*3034Sdougm * return a string of all the protocols (space separated) associated 917*3034Sdougm * with this group. 918*3034Sdougm */ 919*3034Sdougm 920*3034Sdougm static char * 921*3034Sdougm group_proto(sa_group_t group) 922*3034Sdougm { 923*3034Sdougm sa_optionset_t optionset; 924*3034Sdougm char *proto; 925*3034Sdougm char *buff = NULL; 926*3034Sdougm int buffsize = 0; 927*3034Sdougm int addspace = 0; 928*3034Sdougm /* 929*3034Sdougm * get the protocol list by finding the optionsets on this 930*3034Sdougm * group and extracting the type value. The initial call to 931*3034Sdougm * strndupr() initailizes buff. 932*3034Sdougm */ 933*3034Sdougm buff = strndupr(buff, "", &buffsize); 934*3034Sdougm if (buff != NULL) { 935*3034Sdougm for (optionset = sa_get_optionset(group, NULL); 936*3034Sdougm optionset != NULL && buff != NULL; 937*3034Sdougm optionset = sa_get_next_optionset(optionset)) { 938*3034Sdougm /* 939*3034Sdougm * extract out the protocol type from this optionset 940*3034Sdougm * and append it to the buffer "buff". strndupr() will 941*3034Sdougm * reallocate space as necessay. 942*3034Sdougm */ 943*3034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 944*3034Sdougm if (proto != NULL) { 945*3034Sdougm if (addspace++) 946*3034Sdougm buff = strndupr(buff, " ", &buffsize); 947*3034Sdougm buff = strndupr(buff, proto, &buffsize); 948*3034Sdougm sa_free_attr_string(proto); 949*3034Sdougm } 950*3034Sdougm } 951*3034Sdougm } 952*3034Sdougm return (buff); 953*3034Sdougm } 954*3034Sdougm 955*3034Sdougm /* 956*3034Sdougm * sa_list(flags, argc, argv) 957*3034Sdougm * 958*3034Sdougm * implements the "list" subcommand to list groups and optionally 959*3034Sdougm * their state and protocols. 960*3034Sdougm */ 961*3034Sdougm 962*3034Sdougm static int 963*3034Sdougm sa_list(int flags, int argc, char *argv[]) 964*3034Sdougm { 965*3034Sdougm sa_group_t group; 966*3034Sdougm int verbose = 0; 967*3034Sdougm int c; 968*3034Sdougm char *protocol = NULL; 969*3034Sdougm #ifdef lint 970*3034Sdougm flags = flags; 971*3034Sdougm #endif 972*3034Sdougm 973*3034Sdougm while ((c = getopt(argc, argv, "?hvP:")) != EOF) { 974*3034Sdougm switch (c) { 975*3034Sdougm case 'v': 976*3034Sdougm verbose++; 977*3034Sdougm break; 978*3034Sdougm case 'P': 979*3034Sdougm protocol = optarg; 980*3034Sdougm if (!sa_valid_protocol(protocol)) { 981*3034Sdougm (void) printf(gettext("Invalid protocol specified:" 982*3034Sdougm "%s\n"), 983*3034Sdougm protocol); 984*3034Sdougm return (SA_INVALID_PROTOCOL); 985*3034Sdougm } 986*3034Sdougm break; 987*3034Sdougm default: 988*3034Sdougm case 'h': 989*3034Sdougm case '?': 990*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_LIST)); 991*3034Sdougm return (0); 992*3034Sdougm } 993*3034Sdougm } 994*3034Sdougm 995*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 996*3034Sdougm group = sa_get_next_group(group)) { 997*3034Sdougm char *name; 998*3034Sdougm char *proto; 999*3034Sdougm if (protocol == NULL || has_protocol(group, protocol)) { 1000*3034Sdougm name = sa_get_group_attr(group, "name"); 1001*3034Sdougm if (name != NULL && (verbose > 1 || name[0] != '#')) { 1002*3034Sdougm (void) printf("%s", (char *)name); 1003*3034Sdougm if (verbose) { 1004*3034Sdougm /* 1005*3034Sdougm * need the list of protocols 1006*3034Sdougm * and current status once 1007*3034Sdougm * available. 1008*3034Sdougm */ 1009*3034Sdougm (void) printf("\t%s", group_status(group)); 1010*3034Sdougm proto = group_proto(group); 1011*3034Sdougm if (proto != NULL) { 1012*3034Sdougm (void) printf("\t%s", (char *)proto); 1013*3034Sdougm free(proto); 1014*3034Sdougm } 1015*3034Sdougm } 1016*3034Sdougm (void) printf("\n"); 1017*3034Sdougm } 1018*3034Sdougm if (name != NULL) 1019*3034Sdougm sa_free_attr_string(name); 1020*3034Sdougm } 1021*3034Sdougm } 1022*3034Sdougm return (0); 1023*3034Sdougm } 1024*3034Sdougm 1025*3034Sdougm /* 1026*3034Sdougm * out_properties(optionset, proto, sec) 1027*3034Sdougm * 1028*3034Sdougm * Format the properties and encode the protocol and optional named 1029*3034Sdougm * optionset into the string. 1030*3034Sdougm * 1031*3034Sdougm * format is protocol[:name]=(property-list) 1032*3034Sdougm */ 1033*3034Sdougm 1034*3034Sdougm static void 1035*3034Sdougm out_properties(sa_optionset_t optionset, char *proto, char *sec) 1036*3034Sdougm { 1037*3034Sdougm char *type; 1038*3034Sdougm char *value; 1039*3034Sdougm int spacer; 1040*3034Sdougm sa_property_t prop; 1041*3034Sdougm 1042*3034Sdougm if (sec == NULL) { 1043*3034Sdougm (void) printf(" %s=(", proto ? proto : gettext("all")); 1044*3034Sdougm } else { 1045*3034Sdougm (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec); 1046*3034Sdougm } 1047*3034Sdougm 1048*3034Sdougm for (spacer = 0, prop = sa_get_property(optionset, NULL); 1049*3034Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 1050*3034Sdougm 1051*3034Sdougm /* 1052*3034Sdougm * extract the property name/value and output with 1053*3034Sdougm * appropriate spacing. I.e. no prefixed space the 1054*3034Sdougm * first time through but a space on subsequent 1055*3034Sdougm * properties. 1056*3034Sdougm */ 1057*3034Sdougm type = sa_get_property_attr(prop, "type"); 1058*3034Sdougm value = sa_get_property_attr(prop, "value"); 1059*3034Sdougm if (type != NULL) { 1060*3034Sdougm (void) printf("%s%s=", spacer ? " " : "", type); 1061*3034Sdougm spacer = 1; 1062*3034Sdougm if (value != NULL) 1063*3034Sdougm (void) printf("\"%s\"", value); 1064*3034Sdougm else 1065*3034Sdougm (void) printf("\"\""); 1066*3034Sdougm } 1067*3034Sdougm if (type != NULL) 1068*3034Sdougm sa_free_attr_string(type); 1069*3034Sdougm if (value != NULL) 1070*3034Sdougm sa_free_attr_string(value); 1071*3034Sdougm } 1072*3034Sdougm (void) printf(")"); 1073*3034Sdougm } 1074*3034Sdougm 1075*3034Sdougm /* 1076*3034Sdougm * show_properties(group, protocol, prefix) 1077*3034Sdougm * 1078*3034Sdougm * print the properties for a group. If protocol is NULL, do all 1079*3034Sdougm * protocols otherwise only the specified protocol. All security 1080*3034Sdougm * (named groups specific to the protocol) are included. 1081*3034Sdougm * 1082*3034Sdougm * The "prefix" is always applied. The caller knows whether it wants 1083*3034Sdougm * some type of prefix string (white space) or not. Once the prefix 1084*3034Sdougm * has been output, it is reduced to the zero length string for the 1085*3034Sdougm * remainder of the property output. 1086*3034Sdougm */ 1087*3034Sdougm 1088*3034Sdougm static void 1089*3034Sdougm show_properties(sa_group_t group, char *protocol, char *prefix) 1090*3034Sdougm { 1091*3034Sdougm sa_optionset_t optionset; 1092*3034Sdougm sa_security_t security; 1093*3034Sdougm char *value; 1094*3034Sdougm char *secvalue; 1095*3034Sdougm 1096*3034Sdougm if (protocol != NULL) { 1097*3034Sdougm optionset = sa_get_optionset(group, protocol); 1098*3034Sdougm if (optionset != NULL) { 1099*3034Sdougm (void) printf("%s", prefix); 1100*3034Sdougm prefix = ""; 1101*3034Sdougm out_properties(optionset, protocol, NULL); 1102*3034Sdougm } 1103*3034Sdougm security = sa_get_security(group, protocol, NULL); 1104*3034Sdougm if (security != NULL) { 1105*3034Sdougm (void) printf("%s", prefix); 1106*3034Sdougm prefix = ""; 1107*3034Sdougm out_properties(security, protocol, NULL); 1108*3034Sdougm } 1109*3034Sdougm } else { 1110*3034Sdougm for (optionset = sa_get_optionset(group, protocol); 1111*3034Sdougm optionset != NULL; 1112*3034Sdougm optionset = sa_get_next_optionset(optionset)) { 1113*3034Sdougm 1114*3034Sdougm value = sa_get_optionset_attr(optionset, "type"); 1115*3034Sdougm (void) printf("%s", prefix); 1116*3034Sdougm prefix = ""; 1117*3034Sdougm out_properties(optionset, value, 0); 1118*3034Sdougm if (value != NULL) 1119*3034Sdougm sa_free_attr_string(value); 1120*3034Sdougm } 1121*3034Sdougm for (security = sa_get_security(group, NULL, protocol); 1122*3034Sdougm security != NULL; 1123*3034Sdougm security = sa_get_next_security(security)) { 1124*3034Sdougm 1125*3034Sdougm value = sa_get_security_attr(security, "type"); 1126*3034Sdougm secvalue = sa_get_security_attr(security, "sectype"); 1127*3034Sdougm (void) printf("%s", prefix); 1128*3034Sdougm prefix = ""; 1129*3034Sdougm out_properties(security, value, secvalue); 1130*3034Sdougm if (value != NULL) 1131*3034Sdougm sa_free_attr_string(value); 1132*3034Sdougm if (secvalue != NULL) 1133*3034Sdougm sa_free_attr_string(secvalue); 1134*3034Sdougm } 1135*3034Sdougm } 1136*3034Sdougm } 1137*3034Sdougm 1138*3034Sdougm /* 1139*3034Sdougm * show_group(group, verbose, properties, proto, subgroup) 1140*3034Sdougm * 1141*3034Sdougm * helper function to show the contents of a group. 1142*3034Sdougm */ 1143*3034Sdougm 1144*3034Sdougm static void 1145*3034Sdougm show_group(sa_group_t group, int verbose, int properties, char *proto, 1146*3034Sdougm char *subgroup) 1147*3034Sdougm { 1148*3034Sdougm sa_share_t share; 1149*3034Sdougm char *groupname; 1150*3034Sdougm char *sharepath; 1151*3034Sdougm char *resource; 1152*3034Sdougm char *description; 1153*3034Sdougm char *type; 1154*3034Sdougm char *zfs = NULL; 1155*3034Sdougm int iszfs = 0; 1156*3034Sdougm 1157*3034Sdougm groupname = sa_get_group_attr(group, "name"); 1158*3034Sdougm if (groupname != NULL) { 1159*3034Sdougm if (proto != NULL && !has_protocol(group, proto)) { 1160*3034Sdougm sa_free_attr_string(groupname); 1161*3034Sdougm return; 1162*3034Sdougm } 1163*3034Sdougm /* 1164*3034Sdougm * check to see if the group is managed by ZFS. If 1165*3034Sdougm * there is an attribute, then it is. A non-NULL zfs 1166*3034Sdougm * variable will trigger the different way to display 1167*3034Sdougm * and will remove the transient property indicator 1168*3034Sdougm * from the output. 1169*3034Sdougm */ 1170*3034Sdougm zfs = sa_get_group_attr(group, "zfs"); 1171*3034Sdougm if (zfs != NULL) { 1172*3034Sdougm iszfs = 1; 1173*3034Sdougm sa_free_attr_string(zfs); 1174*3034Sdougm } 1175*3034Sdougm share = sa_get_share(group, NULL); 1176*3034Sdougm if (subgroup == NULL) 1177*3034Sdougm (void) printf("%s", groupname); 1178*3034Sdougm else 1179*3034Sdougm (void) printf(" %s/%s", subgroup, groupname); 1180*3034Sdougm if (properties) { 1181*3034Sdougm show_properties(group, proto, ""); 1182*3034Sdougm } 1183*3034Sdougm (void) printf("\n"); 1184*3034Sdougm if (strcmp(groupname, "zfs") == 0) { 1185*3034Sdougm sa_group_t zgroup; 1186*3034Sdougm 1187*3034Sdougm for (zgroup = sa_get_sub_group(group); zgroup != NULL; 1188*3034Sdougm zgroup = sa_get_next_group(zgroup)) { 1189*3034Sdougm show_group(zgroup, verbose, properties, proto, "zfs"); 1190*3034Sdougm } 1191*3034Sdougm sa_free_attr_string(groupname); 1192*3034Sdougm return; 1193*3034Sdougm } 1194*3034Sdougm /* 1195*3034Sdougm * have a group, so list the contents. Resource and 1196*3034Sdougm * description are only listed if verbose is set. 1197*3034Sdougm */ 1198*3034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 1199*3034Sdougm share = sa_get_next_share(share)) { 1200*3034Sdougm sharepath = sa_get_share_attr(share, "path"); 1201*3034Sdougm if (sharepath != NULL) { 1202*3034Sdougm if (verbose) { 1203*3034Sdougm resource = sa_get_share_attr(share, "resource"); 1204*3034Sdougm description = sa_get_share_description(share); 1205*3034Sdougm type = sa_get_share_attr(share, "type"); 1206*3034Sdougm if (type != NULL && !iszfs && 1207*3034Sdougm strcmp(type, "transient") == 0) 1208*3034Sdougm (void) printf("\t* "); 1209*3034Sdougm else 1210*3034Sdougm (void) printf("\t "); 1211*3034Sdougm if (resource != NULL && strlen(resource) > 0) { 1212*3034Sdougm (void) printf("%s=%s", resource, sharepath); 1213*3034Sdougm } else { 1214*3034Sdougm (void) printf("%s", sharepath); 1215*3034Sdougm } 1216*3034Sdougm if (resource != NULL) 1217*3034Sdougm sa_free_attr_string(resource); 1218*3034Sdougm if (properties) 1219*3034Sdougm show_properties(share, NULL, "\t"); 1220*3034Sdougm if (description != NULL) { 1221*3034Sdougm if (strlen(description) > 0) { 1222*3034Sdougm (void) printf("\t\"%s\"", description); 1223*3034Sdougm } 1224*3034Sdougm sa_free_share_description(description); 1225*3034Sdougm } 1226*3034Sdougm if (type != NULL) 1227*3034Sdougm sa_free_attr_string(type); 1228*3034Sdougm } else { 1229*3034Sdougm (void) printf("\t%s", sharepath); 1230*3034Sdougm if (properties) 1231*3034Sdougm show_properties(share, NULL, "\t"); 1232*3034Sdougm } 1233*3034Sdougm (void) printf("\n"); 1234*3034Sdougm sa_free_attr_string(sharepath); 1235*3034Sdougm } 1236*3034Sdougm } 1237*3034Sdougm } 1238*3034Sdougm if (groupname != NULL) { 1239*3034Sdougm sa_free_attr_string(groupname); 1240*3034Sdougm } 1241*3034Sdougm } 1242*3034Sdougm 1243*3034Sdougm /* 1244*3034Sdougm * show_group_xml_init() 1245*3034Sdougm * 1246*3034Sdougm * Create an XML document that will be used to display config info via 1247*3034Sdougm * XML format. 1248*3034Sdougm */ 1249*3034Sdougm 1250*3034Sdougm xmlDocPtr 1251*3034Sdougm show_group_xml_init() 1252*3034Sdougm { 1253*3034Sdougm xmlDocPtr doc; 1254*3034Sdougm xmlNodePtr root; 1255*3034Sdougm 1256*3034Sdougm doc = xmlNewDoc((xmlChar *)"1.0"); 1257*3034Sdougm if (doc != NULL) { 1258*3034Sdougm root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 1259*3034Sdougm if (root != NULL) 1260*3034Sdougm xmlDocSetRootElement(doc, root); 1261*3034Sdougm } 1262*3034Sdougm return (doc); 1263*3034Sdougm } 1264*3034Sdougm 1265*3034Sdougm /* 1266*3034Sdougm * show_group_xml(doc, group) 1267*3034Sdougm * 1268*3034Sdougm * Copy the group info into the XML doc. 1269*3034Sdougm */ 1270*3034Sdougm 1271*3034Sdougm static void 1272*3034Sdougm show_group_xml(xmlDocPtr doc, sa_group_t group) 1273*3034Sdougm { 1274*3034Sdougm xmlNodePtr node; 1275*3034Sdougm xmlNodePtr root; 1276*3034Sdougm 1277*3034Sdougm root = xmlDocGetRootElement(doc); 1278*3034Sdougm node = xmlCopyNode((xmlNodePtr)group, 1); 1279*3034Sdougm if (node != NULL && root != NULL) { 1280*3034Sdougm xmlAddChild(root, node); 1281*3034Sdougm /* 1282*3034Sdougm * In the future, we may have interally used tags that 1283*3034Sdougm * should not appear in the XML output. Remove 1284*3034Sdougm * anything we don't want to show here. 1285*3034Sdougm */ 1286*3034Sdougm } 1287*3034Sdougm } 1288*3034Sdougm 1289*3034Sdougm /* 1290*3034Sdougm * sa_show(flags, argc, argv) 1291*3034Sdougm * 1292*3034Sdougm * Implements the show subcommand. 1293*3034Sdougm */ 1294*3034Sdougm 1295*3034Sdougm int 1296*3034Sdougm sa_show(int flags, int argc, char *argv[]) 1297*3034Sdougm { 1298*3034Sdougm sa_group_t group; 1299*3034Sdougm int verbose = 0; 1300*3034Sdougm int properties = 0; 1301*3034Sdougm int c; 1302*3034Sdougm int ret = SA_OK; 1303*3034Sdougm char *protocol = NULL; 1304*3034Sdougm int xml = 0; 1305*3034Sdougm xmlDocPtr doc; 1306*3034Sdougm #ifdef lint 1307*3034Sdougm flags = flags; 1308*3034Sdougm #endif 1309*3034Sdougm 1310*3034Sdougm while ((c = getopt(argc, argv, "?hvP:px")) != EOF) { 1311*3034Sdougm switch (c) { 1312*3034Sdougm case 'v': 1313*3034Sdougm verbose++; 1314*3034Sdougm break; 1315*3034Sdougm case 'p': 1316*3034Sdougm properties++; 1317*3034Sdougm break; 1318*3034Sdougm case 'P': 1319*3034Sdougm protocol = optarg; 1320*3034Sdougm if (!sa_valid_protocol(protocol)) { 1321*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 1322*3034Sdougm protocol); 1323*3034Sdougm return (SA_INVALID_PROTOCOL); 1324*3034Sdougm } 1325*3034Sdougm break; 1326*3034Sdougm case 'x': 1327*3034Sdougm xml++; 1328*3034Sdougm break; 1329*3034Sdougm default: 1330*3034Sdougm case 'h': 1331*3034Sdougm case '?': 1332*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SHOW)); 1333*3034Sdougm return (0); 1334*3034Sdougm } 1335*3034Sdougm } 1336*3034Sdougm 1337*3034Sdougm if (xml) { 1338*3034Sdougm doc = show_group_xml_init(); 1339*3034Sdougm if (doc == NULL) 1340*3034Sdougm ret = SA_NO_MEMORY; 1341*3034Sdougm } 1342*3034Sdougm 1343*3034Sdougm if (optind == argc) { 1344*3034Sdougm /* no group specified so go through them all */ 1345*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 1346*3034Sdougm group = sa_get_next_group(group)) { 1347*3034Sdougm /* 1348*3034Sdougm * have a group so check if one we want and then list 1349*3034Sdougm * contents with appropriate options. 1350*3034Sdougm */ 1351*3034Sdougm if (xml) 1352*3034Sdougm show_group_xml(doc, group); 1353*3034Sdougm else 1354*3034Sdougm show_group(group, verbose, properties, protocol, NULL); 1355*3034Sdougm } 1356*3034Sdougm } else { 1357*3034Sdougm /* have a specified list of groups */ 1358*3034Sdougm for (; optind < argc; optind++) { 1359*3034Sdougm group = sa_get_group(argv[optind]); 1360*3034Sdougm if (group != NULL) { 1361*3034Sdougm if (xml) 1362*3034Sdougm show_group_xml(doc, group); 1363*3034Sdougm else 1364*3034Sdougm show_group(group, verbose, properties, protocol, NULL); 1365*3034Sdougm } else { 1366*3034Sdougm (void) printf(gettext("%s: not found\n"), argv[optind]); 1367*3034Sdougm ret = SA_NO_SUCH_GROUP; 1368*3034Sdougm } 1369*3034Sdougm } 1370*3034Sdougm } 1371*3034Sdougm if (xml && ret == SA_OK) { 1372*3034Sdougm xmlDocFormatDump(stdout, doc, 1); 1373*3034Sdougm xmlFreeDoc(doc); 1374*3034Sdougm } 1375*3034Sdougm return (ret); 1376*3034Sdougm 1377*3034Sdougm } 1378*3034Sdougm 1379*3034Sdougm /* 1380*3034Sdougm * enable_share(group, share, update_legacy) 1381*3034Sdougm * 1382*3034Sdougm * helper function to enable a share if the group is enabled. 1383*3034Sdougm */ 1384*3034Sdougm 1385*3034Sdougm static int 1386*3034Sdougm enable_share(sa_group_t group, sa_share_t share, int update_legacy) 1387*3034Sdougm { 1388*3034Sdougm char *value; 1389*3034Sdougm int enabled; 1390*3034Sdougm sa_optionset_t optionset; 1391*3034Sdougm int ret = SA_OK; 1392*3034Sdougm char *zfs = NULL; 1393*3034Sdougm int iszfs = 0; 1394*3034Sdougm 1395*3034Sdougm /* 1396*3034Sdougm * need to enable this share if the group is enabled but not 1397*3034Sdougm * otherwise. The enable is also done on each protocol 1398*3034Sdougm * represented in the group. 1399*3034Sdougm */ 1400*3034Sdougm value = sa_get_group_attr(group, "state"); 1401*3034Sdougm enabled = value != NULL && strcmp(value, "enabled") == 0; 1402*3034Sdougm if (value != NULL) 1403*3034Sdougm sa_free_attr_string(value); 1404*3034Sdougm /* remove legacy config if necessary */ 1405*3034Sdougm if (update_legacy) 1406*3034Sdougm ret = sa_delete_legacy(share); 1407*3034Sdougm zfs = sa_get_group_attr(group, "zfs"); 1408*3034Sdougm if (zfs != NULL) { 1409*3034Sdougm iszfs++; 1410*3034Sdougm sa_free_attr_string(zfs); 1411*3034Sdougm } 1412*3034Sdougm 1413*3034Sdougm /* 1414*3034Sdougm * Step through each optionset at the group level and 1415*3034Sdougm * enable the share based on the protocol type. This 1416*3034Sdougm * works because protocols must be set on the group 1417*3034Sdougm * for the protocol to be enabled. 1418*3034Sdougm */ 1419*3034Sdougm for (optionset = sa_get_optionset(group, NULL); 1420*3034Sdougm optionset != NULL && ret == SA_OK; 1421*3034Sdougm optionset = sa_get_next_optionset(optionset)) { 1422*3034Sdougm value = sa_get_optionset_attr(optionset, "type"); 1423*3034Sdougm if (value != NULL) { 1424*3034Sdougm if (enabled) 1425*3034Sdougm ret = sa_enable_share(share, value); 1426*3034Sdougm if (update_legacy && !iszfs) 1427*3034Sdougm (void) sa_update_legacy(share, value); 1428*3034Sdougm sa_free_attr_string(value); 1429*3034Sdougm } 1430*3034Sdougm } 1431*3034Sdougm if (ret == SA_OK) 1432*3034Sdougm (void) sa_update_config(); 1433*3034Sdougm return (ret); 1434*3034Sdougm } 1435*3034Sdougm 1436*3034Sdougm /* 1437*3034Sdougm * sa_addshare(flags, argc, argv) 1438*3034Sdougm * 1439*3034Sdougm * implements add-share subcommand. 1440*3034Sdougm */ 1441*3034Sdougm 1442*3034Sdougm int 1443*3034Sdougm sa_addshare(int flags, int argc, char *argv[]) 1444*3034Sdougm { 1445*3034Sdougm int verbose = 0; 1446*3034Sdougm int dryrun = 0; 1447*3034Sdougm int c; 1448*3034Sdougm int ret = SA_OK; 1449*3034Sdougm sa_group_t group; 1450*3034Sdougm sa_share_t share; 1451*3034Sdougm char *sharepath = NULL; 1452*3034Sdougm char *description = NULL; 1453*3034Sdougm char *resource = NULL; 1454*3034Sdougm int persist = SA_SHARE_PERMANENT; /* default to persist */ 1455*3034Sdougm int auth; 1456*3034Sdougm char dir[MAXPATHLEN]; 1457*3034Sdougm 1458*3034Sdougm while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) { 1459*3034Sdougm switch (c) { 1460*3034Sdougm case 'n': 1461*3034Sdougm dryrun++; 1462*3034Sdougm break; 1463*3034Sdougm case 'v': 1464*3034Sdougm verbose++; 1465*3034Sdougm break; 1466*3034Sdougm case 'd': 1467*3034Sdougm description = optarg; 1468*3034Sdougm break; 1469*3034Sdougm case 'r': 1470*3034Sdougm resource = optarg; 1471*3034Sdougm break; 1472*3034Sdougm case 's': 1473*3034Sdougm /* 1474*3034Sdougm * save share path into group. Currently limit 1475*3034Sdougm * to one share per command. 1476*3034Sdougm */ 1477*3034Sdougm if (sharepath != NULL) { 1478*3034Sdougm (void) printf(gettext("Adding multiple shares not" 1479*3034Sdougm "supported\n")); 1480*3034Sdougm return (1); 1481*3034Sdougm } 1482*3034Sdougm sharepath = optarg; 1483*3034Sdougm break; 1484*3034Sdougm case 't': 1485*3034Sdougm persist = SA_SHARE_TRANSIENT; 1486*3034Sdougm break; 1487*3034Sdougm default: 1488*3034Sdougm case 'h': 1489*3034Sdougm case '?': 1490*3034Sdougm (void) printf(gettext("usage: %s\n"), 1491*3034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1492*3034Sdougm return (0); 1493*3034Sdougm } 1494*3034Sdougm } 1495*3034Sdougm 1496*3034Sdougm if (optind >= argc) { 1497*3034Sdougm (void) printf(gettext("usage: %s\n"), 1498*3034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1499*3034Sdougm if (dryrun || sharepath != NULL || description != NULL || 1500*3034Sdougm resource != NULL || verbose || persist) { 1501*3034Sdougm (void) printf(gettext("\tgroup must be specified\n")); 1502*3034Sdougm ret = SA_NO_SUCH_GROUP; 1503*3034Sdougm } else { 1504*3034Sdougm ret = SA_OK; 1505*3034Sdougm } 1506*3034Sdougm } else { 1507*3034Sdougm if (sharepath == NULL) { 1508*3034Sdougm (void) printf(gettext("usage: %s\n"), 1509*3034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1510*3034Sdougm (void) printf(gettext("\t-s sharepath must be specified\n")); 1511*3034Sdougm ret = SA_BAD_PATH; 1512*3034Sdougm } 1513*3034Sdougm if (ret == SA_OK) { 1514*3034Sdougm if (realpath(sharepath, dir) == NULL) { 1515*3034Sdougm ret = SA_BAD_PATH; 1516*3034Sdougm (void) printf(gettext("Path is not valid: %s\n"), 1517*3034Sdougm sharepath); 1518*3034Sdougm } else { 1519*3034Sdougm sharepath = dir; 1520*3034Sdougm } 1521*3034Sdougm } 1522*3034Sdougm if (ret == SA_OK && resource != NULL) { 1523*3034Sdougm /* check for valid syntax */ 1524*3034Sdougm if (strpbrk(resource, " \t/") != NULL) { 1525*3034Sdougm (void) printf(gettext("usage: %s\n"), 1526*3034Sdougm sa_get_usage(USAGE_ADD_SHARE)); 1527*3034Sdougm (void) printf(gettext("\tresource must not contain white" 1528*3034Sdougm "space or '/' characters\n")); 1529*3034Sdougm ret = SA_BAD_PATH; 1530*3034Sdougm } 1531*3034Sdougm } 1532*3034Sdougm if (ret == SA_OK) { 1533*3034Sdougm group = sa_get_group(argv[optind]); 1534*3034Sdougm if (group != NULL) { 1535*3034Sdougm auth = check_authorizations(argv[optind], flags); 1536*3034Sdougm share = sa_find_share(sharepath); 1537*3034Sdougm if (share != NULL) { 1538*3034Sdougm group = sa_get_parent_group(share); 1539*3034Sdougm if (group != NULL) { 1540*3034Sdougm char *groupname; 1541*3034Sdougm groupname = sa_get_group_attr(group, "name"); 1542*3034Sdougm if (groupname != NULL) { 1543*3034Sdougm (void) printf(gettext("Share path already " 1544*3034Sdougm "shared in group " 1545*3034Sdougm "\"%s\": %s\n"), 1546*3034Sdougm groupname, sharepath); 1547*3034Sdougm sa_free_attr_string(groupname); 1548*3034Sdougm } else { 1549*3034Sdougm (void) printf(gettext("Share path already" 1550*3034Sdougm "shared: %s\n"), 1551*3034Sdougm groupname, sharepath); 1552*3034Sdougm } 1553*3034Sdougm } else { 1554*3034Sdougm (void) printf(gettext("Share path %s already " 1555*3034Sdougm "shared\n"), 1556*3034Sdougm sharepath); 1557*3034Sdougm } 1558*3034Sdougm ret = SA_DUPLICATE_NAME; 1559*3034Sdougm } else { 1560*3034Sdougm /* 1561*3034Sdougm * need to check that resource name is unique 1562*3034Sdougm * at some point. 1563*3034Sdougm */ 1564*3034Sdougm if (dryrun) 1565*3034Sdougm ret = sa_check_path(group, sharepath); 1566*3034Sdougm else 1567*3034Sdougm share = sa_add_share(group, sharepath, 1568*3034Sdougm persist, &ret); 1569*3034Sdougm if (!dryrun && share == NULL) { 1570*3034Sdougm (void) printf(gettext("Could not add share: " 1571*3034Sdougm "%s\n"), 1572*3034Sdougm sa_errorstr(ret)); 1573*3034Sdougm } else { 1574*3034Sdougm if (!dryrun && ret == SA_OK) { 1575*3034Sdougm if (resource != NULL) { 1576*3034Sdougm if (strpbrk(resource, " \t/") == NULL) { 1577*3034Sdougm ret = sa_set_share_attr(share, 1578*3034Sdougm "resource", 1579*3034Sdougm resource); 1580*3034Sdougm } 1581*3034Sdougm } 1582*3034Sdougm if (ret == SA_OK && description != NULL) { 1583*3034Sdougm ret = sa_set_share_description(share, 1584*3034Sdougm description); 1585*3034Sdougm } 1586*3034Sdougm if (ret == SA_OK) { 1587*3034Sdougm /* now enable the share(s) */ 1588*3034Sdougm ret = enable_share(group, share, 1); 1589*3034Sdougm ret = sa_update_config(); 1590*3034Sdougm } 1591*3034Sdougm switch (ret) { 1592*3034Sdougm case SA_DUPLICATE_NAME: 1593*3034Sdougm (void) printf(gettext("Resource name in" 1594*3034Sdougm "use: %s\n"), 1595*3034Sdougm resource); 1596*3034Sdougm break; 1597*3034Sdougm default: 1598*3034Sdougm (void) printf(gettext("Could not set " 1599*3034Sdougm "attribute: %s\n"), 1600*3034Sdougm sa_errorstr(ret)); 1601*3034Sdougm break; 1602*3034Sdougm case SA_OK: 1603*3034Sdougm break; 1604*3034Sdougm } 1605*3034Sdougm } else if (dryrun && ret == SA_OK && 1606*3034Sdougm !auth && verbose) { 1607*3034Sdougm (void) printf(gettext("Command would fail: " 1608*3034Sdougm "%s\n"), 1609*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 1610*3034Sdougm ret = SA_NO_PERMISSION; 1611*3034Sdougm } 1612*3034Sdougm } 1613*3034Sdougm } 1614*3034Sdougm } else { 1615*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 1616*3034Sdougm argv[optind]); 1617*3034Sdougm ret = SA_NO_SUCH_GROUP; 1618*3034Sdougm } 1619*3034Sdougm } 1620*3034Sdougm } 1621*3034Sdougm return (ret); 1622*3034Sdougm } 1623*3034Sdougm 1624*3034Sdougm /* 1625*3034Sdougm * sa_moveshare(flags, argc, argv) 1626*3034Sdougm * 1627*3034Sdougm * implements move-share subcommand. 1628*3034Sdougm */ 1629*3034Sdougm 1630*3034Sdougm int 1631*3034Sdougm sa_moveshare(int flags, int argc, char *argv[]) 1632*3034Sdougm { 1633*3034Sdougm int verbose = 0; 1634*3034Sdougm int dryrun = 0; 1635*3034Sdougm int c; 1636*3034Sdougm int ret = SA_OK; 1637*3034Sdougm sa_group_t group; 1638*3034Sdougm sa_share_t share; 1639*3034Sdougm char *sharepath = NULL; 1640*3034Sdougm int authsrc = 0, authdst = 0; 1641*3034Sdougm 1642*3034Sdougm while ((c = getopt(argc, argv, "?hvns:")) != EOF) { 1643*3034Sdougm switch (c) { 1644*3034Sdougm case 'n': 1645*3034Sdougm dryrun++; 1646*3034Sdougm break; 1647*3034Sdougm case 'v': 1648*3034Sdougm verbose++; 1649*3034Sdougm break; 1650*3034Sdougm case 's': 1651*3034Sdougm /* 1652*3034Sdougm * remove share path from group. Currently limit 1653*3034Sdougm * to one share per command. 1654*3034Sdougm */ 1655*3034Sdougm if (sharepath != NULL) { 1656*3034Sdougm (void) printf(gettext("Moving multiple shares not" 1657*3034Sdougm "supported\n")); 1658*3034Sdougm return (SA_BAD_PATH); 1659*3034Sdougm } 1660*3034Sdougm sharepath = optarg; 1661*3034Sdougm break; 1662*3034Sdougm default: 1663*3034Sdougm case 'h': 1664*3034Sdougm case '?': 1665*3034Sdougm (void) printf(gettext("usage: %s\n"), 1666*3034Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 1667*3034Sdougm return (0); 1668*3034Sdougm } 1669*3034Sdougm } 1670*3034Sdougm 1671*3034Sdougm if (optind >= argc || sharepath == NULL) { 1672*3034Sdougm (void) printf(gettext("usage: %s\n"), 1673*3034Sdougm sa_get_usage(USAGE_MOVE_SHARE)); 1674*3034Sdougm if (dryrun || verbose || sharepath != NULL) { 1675*3034Sdougm (void) printf(gettext("\tgroup must be specified\n")); 1676*3034Sdougm ret = SA_NO_SUCH_GROUP; 1677*3034Sdougm } else { 1678*3034Sdougm if (sharepath == NULL) { 1679*3034Sdougm ret = SA_SYNTAX_ERR; 1680*3034Sdougm (void) printf(gettext("\tsharepath must be specified\n")); 1681*3034Sdougm } else 1682*3034Sdougm ret = SA_OK; 1683*3034Sdougm } 1684*3034Sdougm } else { 1685*3034Sdougm if (sharepath == NULL) { 1686*3034Sdougm (void) printf(gettext("sharepath must be specified with " 1687*3034Sdougm "the -s option\n")); 1688*3034Sdougm ret = SA_BAD_PATH; 1689*3034Sdougm } else { 1690*3034Sdougm group = sa_get_group(argv[optind]); 1691*3034Sdougm if (group != NULL) { 1692*3034Sdougm share = sa_find_share(sharepath); 1693*3034Sdougm authdst = check_authorizations(argv[optind], flags); 1694*3034Sdougm if (share == NULL) { 1695*3034Sdougm (void) printf(gettext("Share not found: %s\n"), 1696*3034Sdougm sharepath); 1697*3034Sdougm ret = SA_NO_SUCH_PATH; 1698*3034Sdougm } else { 1699*3034Sdougm sa_group_t parent; 1700*3034Sdougm char *zfsold; 1701*3034Sdougm char *zfsnew; 1702*3034Sdougm 1703*3034Sdougm parent = sa_get_parent_group(share); 1704*3034Sdougm if (parent != NULL) { 1705*3034Sdougm char *pname; 1706*3034Sdougm pname = sa_get_group_attr(parent, "name"); 1707*3034Sdougm if (pname != NULL) { 1708*3034Sdougm authsrc = check_authorizations(pname, flags); 1709*3034Sdougm sa_free_attr_string(pname); 1710*3034Sdougm } 1711*3034Sdougm zfsold = sa_get_group_attr(parent, "zfs"); 1712*3034Sdougm zfsnew = sa_get_group_attr(group, "zfs"); 1713*3034Sdougm if ((zfsold != NULL && zfsnew == NULL) || 1714*3034Sdougm (zfsold == NULL && zfsnew != NULL)) { 1715*3034Sdougm ret = SA_NOT_ALLOWED; 1716*3034Sdougm } 1717*3034Sdougm if (zfsold != NULL) 1718*3034Sdougm sa_free_attr_string(zfsold); 1719*3034Sdougm if (zfsnew != NULL) 1720*3034Sdougm sa_free_attr_string(zfsnew); 1721*3034Sdougm } 1722*3034Sdougm if (!dryrun && ret == SA_OK) { 1723*3034Sdougm ret = sa_move_share(group, share); 1724*3034Sdougm } 1725*3034Sdougm if (ret == SA_OK && parent != group && !dryrun) { 1726*3034Sdougm char *oldstate; 1727*3034Sdougm ret = sa_update_config(); 1728*3034Sdougm /* 1729*3034Sdougm * note that the share may need to be 1730*3034Sdougm * "unshared" if the new group is 1731*3034Sdougm * disabled and the old was enabled or 1732*3034Sdougm * it may need to be share to update 1733*3034Sdougm * if the new group is enabled. 1734*3034Sdougm */ 1735*3034Sdougm oldstate = sa_get_group_attr(parent, "state"); 1736*3034Sdougm /* enable_share determines what to do */ 1737*3034Sdougm if (strcmp(oldstate, "enabled") == 0) { 1738*3034Sdougm (void) sa_disable_share(share, NULL); 1739*3034Sdougm } 1740*3034Sdougm (void) enable_share(group, share, 1); 1741*3034Sdougm if (oldstate != NULL) 1742*3034Sdougm sa_free_attr_string(oldstate); 1743*3034Sdougm } 1744*3034Sdougm if (ret != SA_OK) { 1745*3034Sdougm (void) printf(gettext("Could not move share: %s\n"), 1746*3034Sdougm sa_errorstr(ret)); 1747*3034Sdougm } 1748*3034Sdougm if (dryrun && ret == SA_OK && !(authsrc & authdst) && 1749*3034Sdougm verbose) { 1750*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 1751*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 1752*3034Sdougm } 1753*3034Sdougm } 1754*3034Sdougm } else { 1755*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 1756*3034Sdougm argv[optind]); 1757*3034Sdougm ret = SA_NO_SUCH_GROUP; 1758*3034Sdougm } 1759*3034Sdougm } 1760*3034Sdougm } 1761*3034Sdougm return (ret); 1762*3034Sdougm } 1763*3034Sdougm 1764*3034Sdougm /* 1765*3034Sdougm * sa_removeshare(flags, argc, argv) 1766*3034Sdougm * 1767*3034Sdougm * implements remove-share subcommand. 1768*3034Sdougm */ 1769*3034Sdougm 1770*3034Sdougm int 1771*3034Sdougm sa_removeshare(int flags, int argc, char *argv[]) 1772*3034Sdougm { 1773*3034Sdougm int verbose = 0; 1774*3034Sdougm int dryrun = 0; 1775*3034Sdougm int force = 0; 1776*3034Sdougm int c; 1777*3034Sdougm int ret = SA_OK; 1778*3034Sdougm sa_group_t group; 1779*3034Sdougm sa_share_t share; 1780*3034Sdougm char *sharepath = NULL; 1781*3034Sdougm char dir[MAXPATHLEN]; 1782*3034Sdougm int auth; 1783*3034Sdougm 1784*3034Sdougm while ((c = getopt(argc, argv, "?hfns:v")) != EOF) { 1785*3034Sdougm switch (c) { 1786*3034Sdougm case 'n': 1787*3034Sdougm dryrun++; 1788*3034Sdougm break; 1789*3034Sdougm case 'v': 1790*3034Sdougm verbose++; 1791*3034Sdougm break; 1792*3034Sdougm case 'f': 1793*3034Sdougm force++; 1794*3034Sdougm break; 1795*3034Sdougm case 's': 1796*3034Sdougm /* 1797*3034Sdougm * remove share path from group. Currently limit 1798*3034Sdougm * to one share per command. 1799*3034Sdougm */ 1800*3034Sdougm if (sharepath != NULL) { 1801*3034Sdougm (void) printf(gettext("Removing multiple shares not" 1802*3034Sdougm "supported\n")); 1803*3034Sdougm return (SA_SYNTAX_ERR); 1804*3034Sdougm } 1805*3034Sdougm sharepath = optarg; 1806*3034Sdougm break; 1807*3034Sdougm default: 1808*3034Sdougm case 'h': 1809*3034Sdougm case '?': 1810*3034Sdougm (void) printf(gettext("usage: %s\n"), 1811*3034Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 1812*3034Sdougm return (0); 1813*3034Sdougm } 1814*3034Sdougm } 1815*3034Sdougm 1816*3034Sdougm if (optind >= argc || sharepath == NULL) { 1817*3034Sdougm if (sharepath == NULL) { 1818*3034Sdougm (void) printf(gettext("usage: %s\n"), 1819*3034Sdougm sa_get_usage(USAGE_REMOVE_SHARE)); 1820*3034Sdougm (void) printf(gettext("\t-s sharepath must be specified\n")); 1821*3034Sdougm ret = SA_BAD_PATH; 1822*3034Sdougm } else { 1823*3034Sdougm ret = SA_OK; 1824*3034Sdougm } 1825*3034Sdougm } 1826*3034Sdougm if (ret == SA_OK) { 1827*3034Sdougm if (optind < argc) { 1828*3034Sdougm if ((optind + 1) < argc) { 1829*3034Sdougm (void) printf(gettext("Extraneous group(s) at end of " 1830*3034Sdougm "command\n")); 1831*3034Sdougm ret = SA_SYNTAX_ERR; 1832*3034Sdougm } else { 1833*3034Sdougm group = sa_get_group(argv[optind]); 1834*3034Sdougm if (group == NULL) { 1835*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), 1836*3034Sdougm argv[optind]); 1837*3034Sdougm ret = SA_NO_SUCH_GROUP; 1838*3034Sdougm } 1839*3034Sdougm } 1840*3034Sdougm } else { 1841*3034Sdougm group = NULL; 1842*3034Sdougm } 1843*3034Sdougm if (ret == SA_OK) { 1844*3034Sdougm if (realpath(sharepath, dir) == NULL) { 1845*3034Sdougm ret = SA_BAD_PATH; 1846*3034Sdougm (void) printf(gettext("Path is not valid: %s\n"), 1847*3034Sdougm sharepath); 1848*3034Sdougm } else { 1849*3034Sdougm sharepath = dir; 1850*3034Sdougm } 1851*3034Sdougm } 1852*3034Sdougm if (ret == SA_OK) { 1853*3034Sdougm if (group != NULL) 1854*3034Sdougm share = sa_get_share(group, sharepath); 1855*3034Sdougm else 1856*3034Sdougm share = sa_find_share(sharepath); 1857*3034Sdougm if (share == NULL) { 1858*3034Sdougm if (group != NULL) 1859*3034Sdougm (void) printf(gettext("Share not found in group %s:" 1860*3034Sdougm "%s\n"), 1861*3034Sdougm argv[optind], sharepath); 1862*3034Sdougm else 1863*3034Sdougm (void) printf(gettext("Share not found: %s\n"), 1864*3034Sdougm sharepath); 1865*3034Sdougm ret = SA_NO_SUCH_PATH; 1866*3034Sdougm } else { 1867*3034Sdougm if (group == NULL) 1868*3034Sdougm group = sa_get_parent_group(share); 1869*3034Sdougm if (!dryrun) { 1870*3034Sdougm if (ret == SA_OK) { 1871*3034Sdougm ret = sa_disable_share(share, NULL); 1872*3034Sdougm /* 1873*3034Sdougm * we don't care if it fails since it 1874*3034Sdougm * could be disabled already. 1875*3034Sdougm */ 1876*3034Sdougm if (ret == SA_OK || ret == SA_NO_SUCH_PATH || 1877*3034Sdougm ret == SA_NOT_SUPPORTED) { 1878*3034Sdougm ret = sa_remove_share(share); 1879*3034Sdougm } 1880*3034Sdougm if (ret == SA_OK) 1881*3034Sdougm ret = sa_update_config(); 1882*3034Sdougm } 1883*3034Sdougm if (ret != SA_OK) { 1884*3034Sdougm (void) printf(gettext("Could not remove share:" 1885*3034Sdougm " %s\n"), 1886*3034Sdougm sa_errorstr(ret)); 1887*3034Sdougm } 1888*3034Sdougm } else if (ret == SA_OK) { 1889*3034Sdougm char *pname; 1890*3034Sdougm pname = sa_get_group_attr(group, "name"); 1891*3034Sdougm if (pname != NULL) { 1892*3034Sdougm auth = check_authorizations(pname, flags); 1893*3034Sdougm sa_free_attr_string(pname); 1894*3034Sdougm } 1895*3034Sdougm if (!auth && verbose) { 1896*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 1897*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 1898*3034Sdougm } 1899*3034Sdougm } 1900*3034Sdougm } 1901*3034Sdougm } 1902*3034Sdougm } 1903*3034Sdougm return (ret); 1904*3034Sdougm } 1905*3034Sdougm 1906*3034Sdougm /* 1907*3034Sdougm * sa_set_share(flags, argc, argv) 1908*3034Sdougm * 1909*3034Sdougm * implements set-share subcommand. 1910*3034Sdougm */ 1911*3034Sdougm 1912*3034Sdougm int 1913*3034Sdougm sa_set_share(int flags, int argc, char *argv[]) 1914*3034Sdougm { 1915*3034Sdougm int dryrun = 0; 1916*3034Sdougm int c; 1917*3034Sdougm int ret = SA_OK; 1918*3034Sdougm sa_group_t group, sharegroup; 1919*3034Sdougm sa_share_t share; 1920*3034Sdougm char *sharepath = NULL; 1921*3034Sdougm char *description = NULL; 1922*3034Sdougm char *resource = NULL; 1923*3034Sdougm int auth; 1924*3034Sdougm int verbose = 0; 1925*3034Sdougm 1926*3034Sdougm while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) { 1927*3034Sdougm switch (c) { 1928*3034Sdougm case 'n': 1929*3034Sdougm dryrun++; 1930*3034Sdougm break; 1931*3034Sdougm case 'd': 1932*3034Sdougm description = optarg; 1933*3034Sdougm break; 1934*3034Sdougm case 'r': 1935*3034Sdougm resource = optarg; 1936*3034Sdougm break; 1937*3034Sdougm case 'v': 1938*3034Sdougm verbose++; 1939*3034Sdougm break; 1940*3034Sdougm case 's': 1941*3034Sdougm /* 1942*3034Sdougm * save share path into group. Currently limit 1943*3034Sdougm * to one share per command. 1944*3034Sdougm */ 1945*3034Sdougm if (sharepath != NULL) { 1946*3034Sdougm (void) printf(gettext("Updating multiple shares not" 1947*3034Sdougm "supported\n")); 1948*3034Sdougm return (SA_BAD_PATH); 1949*3034Sdougm } 1950*3034Sdougm sharepath = optarg; 1951*3034Sdougm break; 1952*3034Sdougm default: 1953*3034Sdougm case 'h': 1954*3034Sdougm case '?': 1955*3034Sdougm (void) printf(gettext("usage: %s\n"), 1956*3034Sdougm sa_get_usage(USAGE_SET_SHARE)); 1957*3034Sdougm return (SA_OK); 1958*3034Sdougm } 1959*3034Sdougm } 1960*3034Sdougm if (optind >= argc || sharepath == NULL) { 1961*3034Sdougm if (sharepath == NULL) { 1962*3034Sdougm (void) printf(gettext("usage: %s\n"), 1963*3034Sdougm sa_get_usage(USAGE_SET_SHARE)); 1964*3034Sdougm (void) printf(gettext("\tgroup must be specified\n")); 1965*3034Sdougm ret = SA_BAD_PATH; 1966*3034Sdougm } else { 1967*3034Sdougm ret = SA_OK; 1968*3034Sdougm } 1969*3034Sdougm } 1970*3034Sdougm if ((optind + 1) < argc) { 1971*3034Sdougm (void) printf(gettext("usage: %s\n"), 1972*3034Sdougm sa_get_usage(USAGE_SET_SHARE)); 1973*3034Sdougm (void) printf(gettext("\tExtraneous group(s) at end\n")); 1974*3034Sdougm ret = SA_SYNTAX_ERR; 1975*3034Sdougm } 1976*3034Sdougm if (ret == SA_OK) { 1977*3034Sdougm char *groupname; 1978*3034Sdougm if (optind < argc) { 1979*3034Sdougm groupname = argv[optind]; 1980*3034Sdougm group = sa_get_group(groupname); 1981*3034Sdougm } else { 1982*3034Sdougm group = NULL; 1983*3034Sdougm groupname = NULL; 1984*3034Sdougm } 1985*3034Sdougm share = sa_find_share(sharepath); 1986*3034Sdougm if (share != NULL) { 1987*3034Sdougm sharegroup = sa_get_parent_group(share); 1988*3034Sdougm if (group != NULL && group != sharegroup) { 1989*3034Sdougm (void) printf(gettext("Group \"%s\" does not contain " 1990*3034Sdougm "share %s\n"), 1991*3034Sdougm argv[optind], sharepath); 1992*3034Sdougm ret = SA_BAD_PATH; 1993*3034Sdougm } else { 1994*3034Sdougm int delgroupname = 0; 1995*3034Sdougm if (groupname == NULL) { 1996*3034Sdougm groupname = sa_get_group_attr(sharegroup, "name"); 1997*3034Sdougm delgroupname = 1; 1998*3034Sdougm } 1999*3034Sdougm if (groupname != NULL) { 2000*3034Sdougm auth = check_authorizations(groupname, flags); 2001*3034Sdougm if (delgroupname) { 2002*3034Sdougm sa_free_attr_string(groupname); 2003*3034Sdougm groupname = NULL; 2004*3034Sdougm } 2005*3034Sdougm } else { 2006*3034Sdougm ret = SA_NO_MEMORY; 2007*3034Sdougm } 2008*3034Sdougm if (resource != NULL) { 2009*3034Sdougm if (strpbrk(resource, " \t/") == NULL) { 2010*3034Sdougm if (!dryrun) { 2011*3034Sdougm ret = sa_set_share_attr(share, "resource", 2012*3034Sdougm resource); 2013*3034Sdougm } else { 2014*3034Sdougm sa_share_t resshare; 2015*3034Sdougm resshare = sa_get_resource(sharegroup, 2016*3034Sdougm resource); 2017*3034Sdougm if (resshare != NULL && resshare != share) 2018*3034Sdougm ret = SA_DUPLICATE_NAME; 2019*3034Sdougm } 2020*3034Sdougm } else { 2021*3034Sdougm ret = SA_BAD_PATH; 2022*3034Sdougm (void) printf(gettext("Resource must not contain " 2023*3034Sdougm "white space or '/'\n")); 2024*3034Sdougm } 2025*3034Sdougm } 2026*3034Sdougm if (ret == SA_OK && description != NULL) { 2027*3034Sdougm ret = sa_set_share_description(share, description); 2028*3034Sdougm } 2029*3034Sdougm } 2030*3034Sdougm if (!dryrun && ret == SA_OK) { 2031*3034Sdougm ret = sa_update_config(); 2032*3034Sdougm } 2033*3034Sdougm switch (ret) { 2034*3034Sdougm case SA_DUPLICATE_NAME: 2035*3034Sdougm (void) printf(gettext("Resource name in use: %s\n"), 2036*3034Sdougm resource); 2037*3034Sdougm break; 2038*3034Sdougm default: 2039*3034Sdougm (void) printf(gettext("Could not set attribute: %s\n"), 2040*3034Sdougm sa_errorstr(ret)); 2041*3034Sdougm break; 2042*3034Sdougm case SA_OK: 2043*3034Sdougm if (dryrun && !auth && verbose) { 2044*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 2045*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 2046*3034Sdougm } 2047*3034Sdougm break; 2048*3034Sdougm } 2049*3034Sdougm } else { 2050*3034Sdougm (void) printf(gettext("Share path \"%s\" not found\n"), 2051*3034Sdougm sharepath); 2052*3034Sdougm ret = SA_NO_SUCH_PATH; 2053*3034Sdougm } 2054*3034Sdougm } 2055*3034Sdougm return (ret); 2056*3034Sdougm } 2057*3034Sdougm 2058*3034Sdougm /* 2059*3034Sdougm * add_security(group, sectype, optlist, proto, *err) 2060*3034Sdougm * 2061*3034Sdougm * Helper function to add a security option (named optionset) to the 2062*3034Sdougm * group. 2063*3034Sdougm */ 2064*3034Sdougm 2065*3034Sdougm static int 2066*3034Sdougm add_security(sa_group_t group, char *sectype, 2067*3034Sdougm struct options *optlist, char *proto, int *err) 2068*3034Sdougm { 2069*3034Sdougm sa_security_t security; 2070*3034Sdougm int ret = SA_OK; 2071*3034Sdougm int result = 0; 2072*3034Sdougm 2073*3034Sdougm sectype = sa_proto_space_alias(proto, sectype); 2074*3034Sdougm security = sa_get_security(group, sectype, proto); 2075*3034Sdougm if (security == NULL) { 2076*3034Sdougm security = sa_create_security(group, sectype, proto); 2077*3034Sdougm } 2078*3034Sdougm if (sectype != NULL) 2079*3034Sdougm sa_free_attr_string(sectype); 2080*3034Sdougm if (security != NULL) { 2081*3034Sdougm while (optlist != NULL) { 2082*3034Sdougm sa_property_t prop; 2083*3034Sdougm prop = sa_get_property(security, optlist->optname); 2084*3034Sdougm if (prop == NULL) { 2085*3034Sdougm /* 2086*3034Sdougm * add the property, but only if it is 2087*3034Sdougm * a non-NULL or non-zero length value 2088*3034Sdougm */ 2089*3034Sdougm if (optlist->optvalue != NULL) { 2090*3034Sdougm prop = sa_create_property(optlist->optname, 2091*3034Sdougm optlist->optvalue); 2092*3034Sdougm if (prop != NULL) { 2093*3034Sdougm ret = sa_valid_property(security, proto, prop); 2094*3034Sdougm if (ret != SA_OK) { 2095*3034Sdougm (void) sa_remove_property(prop); 2096*3034Sdougm (void) printf(gettext("Could not add " 2097*3034Sdougm "property %s: %s\n"), 2098*3034Sdougm optlist->optname, 2099*3034Sdougm sa_errorstr(ret)); 2100*3034Sdougm } 2101*3034Sdougm if (ret == SA_OK) { 2102*3034Sdougm ret = sa_add_property(security, prop); 2103*3034Sdougm if (ret != SA_OK) { 2104*3034Sdougm (void) printf(gettext("Could not add " 2105*3034Sdougm "property (%s=%s): %s\n"), 2106*3034Sdougm optlist->optname, 2107*3034Sdougm optlist->optvalue, 2108*3034Sdougm sa_errorstr(ret)); 2109*3034Sdougm } else { 2110*3034Sdougm result = 1; 2111*3034Sdougm } 2112*3034Sdougm } 2113*3034Sdougm } 2114*3034Sdougm } 2115*3034Sdougm } else { 2116*3034Sdougm ret = sa_update_property(prop, optlist->optvalue); 2117*3034Sdougm result = 1; /* should check if really changed */ 2118*3034Sdougm } 2119*3034Sdougm optlist = optlist->next; 2120*3034Sdougm } 2121*3034Sdougm /* 2122*3034Sdougm * when done, properties may have all been removed but 2123*3034Sdougm * we need to keep the security type itself until 2124*3034Sdougm * explicitly removed. 2125*3034Sdougm */ 2126*3034Sdougm if (result) 2127*3034Sdougm ret = sa_commit_properties(security, 0); 2128*3034Sdougm } 2129*3034Sdougm *err = ret; 2130*3034Sdougm return (result); 2131*3034Sdougm } 2132*3034Sdougm 2133*3034Sdougm /* 2134*3034Sdougm * basic_set(groupname, optlist, protocol, sharepath, dryrun) 2135*3034Sdougm * 2136*3034Sdougm * This function implements "set" when a name space (-S) is not 2137*3034Sdougm * specified. It is a basic set. Options and other CLI parsing has 2138*3034Sdougm * already been done. 2139*3034Sdougm */ 2140*3034Sdougm 2141*3034Sdougm static int 2142*3034Sdougm basic_set(char *groupname, struct options *optlist, char *protocol, 2143*3034Sdougm char *sharepath, int dryrun) 2144*3034Sdougm { 2145*3034Sdougm sa_group_t group; 2146*3034Sdougm int ret = SA_OK; 2147*3034Sdougm int change = 0; 2148*3034Sdougm struct list *worklist = NULL; 2149*3034Sdougm 2150*3034Sdougm group = sa_get_group(groupname); 2151*3034Sdougm if (group != NULL) { 2152*3034Sdougm sa_share_t share = NULL; 2153*3034Sdougm if (sharepath != NULL) { 2154*3034Sdougm share = sa_get_share(group, sharepath); 2155*3034Sdougm if (share == NULL) { 2156*3034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 2157*3034Sdougm groupname, sharepath); 2158*3034Sdougm ret = SA_NO_SUCH_PATH; 2159*3034Sdougm } 2160*3034Sdougm } 2161*3034Sdougm if (ret == SA_OK) { 2162*3034Sdougm /* group must exist */ 2163*3034Sdougm ret = valid_options(optlist, protocol, 2164*3034Sdougm share == NULL ? group : share, NULL); 2165*3034Sdougm if (ret == SA_OK && !dryrun) { 2166*3034Sdougm if (share != NULL) 2167*3034Sdougm change |= add_optionset(share, optlist, protocol, 2168*3034Sdougm &ret); 2169*3034Sdougm else 2170*3034Sdougm change |= add_optionset(group, optlist, protocol, 2171*3034Sdougm &ret); 2172*3034Sdougm if (ret == SA_OK && change) { 2173*3034Sdougm worklist = add_list(worklist, group, share); 2174*3034Sdougm } 2175*3034Sdougm } 2176*3034Sdougm } 2177*3034Sdougm free_opt(optlist); 2178*3034Sdougm } else { 2179*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2180*3034Sdougm ret = SA_NO_SUCH_GROUP; 2181*3034Sdougm } 2182*3034Sdougm /* 2183*3034Sdougm * we have a group and potentially legal additions 2184*3034Sdougm */ 2185*3034Sdougm 2186*3034Sdougm /* commit to configuration if not a dryrun */ 2187*3034Sdougm if (!dryrun && ret == SA_OK) { 2188*3034Sdougm if (change && worklist != NULL) { 2189*3034Sdougm /* properties changed, so update all shares */ 2190*3034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 2191*3034Sdougm } 2192*3034Sdougm } 2193*3034Sdougm if (worklist != NULL) 2194*3034Sdougm free_list(worklist); 2195*3034Sdougm return (ret); 2196*3034Sdougm } 2197*3034Sdougm 2198*3034Sdougm /* 2199*3034Sdougm * space_set(groupname, optlist, protocol, sharepath, dryrun) 2200*3034Sdougm * 2201*3034Sdougm * This function implements "set" when a name space (-S) is 2202*3034Sdougm * specified. It is a namespace set. Options and other CLI parsing has 2203*3034Sdougm * already been done. 2204*3034Sdougm */ 2205*3034Sdougm 2206*3034Sdougm static int 2207*3034Sdougm space_set(char *groupname, struct options *optlist, char *protocol, 2208*3034Sdougm char *sharepath, int dryrun, char *sectype) 2209*3034Sdougm { 2210*3034Sdougm sa_group_t group; 2211*3034Sdougm int ret = SA_OK; 2212*3034Sdougm int change = 0; 2213*3034Sdougm struct list *worklist = NULL; 2214*3034Sdougm 2215*3034Sdougm /* 2216*3034Sdougm * make sure protcol and sectype are valid 2217*3034Sdougm */ 2218*3034Sdougm 2219*3034Sdougm if (sa_proto_valid_space(protocol, sectype) == 0) { 2220*3034Sdougm (void) printf(gettext("Option space \"%s\" not valid " 2221*3034Sdougm "for protocol.\n"), 2222*3034Sdougm sectype); 2223*3034Sdougm return (SA_INVALID_SECURITY); 2224*3034Sdougm } 2225*3034Sdougm 2226*3034Sdougm group = sa_get_group(groupname); 2227*3034Sdougm if (group != NULL) { 2228*3034Sdougm sa_share_t share = NULL; 2229*3034Sdougm if (sharepath != NULL) { 2230*3034Sdougm share = sa_get_share(group, sharepath); 2231*3034Sdougm if (share == NULL) { 2232*3034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 2233*3034Sdougm groupname, sharepath); 2234*3034Sdougm ret = SA_NO_SUCH_PATH; 2235*3034Sdougm } 2236*3034Sdougm } 2237*3034Sdougm if (ret == SA_OK) { 2238*3034Sdougm /* group must exist */ 2239*3034Sdougm ret = valid_options(optlist, protocol, 2240*3034Sdougm share == NULL ? group : share, sectype); 2241*3034Sdougm if (ret == SA_OK && !dryrun) { 2242*3034Sdougm if (share != NULL) 2243*3034Sdougm change = add_security(share, sectype, optlist, 2244*3034Sdougm protocol, 2245*3034Sdougm &ret); 2246*3034Sdougm else 2247*3034Sdougm change = add_security(group, sectype, optlist, 2248*3034Sdougm protocol, 2249*3034Sdougm &ret); 2250*3034Sdougm if (ret != SA_OK) 2251*3034Sdougm (void) printf(gettext("Could not set property: %s\n"), 2252*3034Sdougm sa_errorstr(ret)); 2253*3034Sdougm } 2254*3034Sdougm if (ret == SA_OK && change) 2255*3034Sdougm worklist = add_list(worklist, group, share); 2256*3034Sdougm } 2257*3034Sdougm free_opt(optlist); 2258*3034Sdougm } else { 2259*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2260*3034Sdougm ret = SA_NO_SUCH_GROUP; 2261*3034Sdougm } 2262*3034Sdougm /* 2263*3034Sdougm * we have a group and potentially legal additions 2264*3034Sdougm */ 2265*3034Sdougm 2266*3034Sdougm /* commit to configuration if not a dryrun */ 2267*3034Sdougm if (!dryrun && ret == 0) { 2268*3034Sdougm if (change && worklist != NULL) { 2269*3034Sdougm /* properties changed, so update all shares */ 2270*3034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 2271*3034Sdougm } 2272*3034Sdougm ret = sa_update_config(); 2273*3034Sdougm } 2274*3034Sdougm if (worklist != NULL) 2275*3034Sdougm free_list(worklist); 2276*3034Sdougm return (ret); 2277*3034Sdougm } 2278*3034Sdougm 2279*3034Sdougm /* 2280*3034Sdougm * sa_set(flags, argc, argv) 2281*3034Sdougm * 2282*3034Sdougm * Implements the set subcommand. It keys off of -S to determine which 2283*3034Sdougm * set of operations to actually do. 2284*3034Sdougm */ 2285*3034Sdougm 2286*3034Sdougm int 2287*3034Sdougm sa_set(int flags, int argc, char *argv[]) 2288*3034Sdougm { 2289*3034Sdougm char *groupname; 2290*3034Sdougm int verbose = 0; 2291*3034Sdougm int dryrun = 0; 2292*3034Sdougm int c; 2293*3034Sdougm char *protocol = NULL; 2294*3034Sdougm int ret = SA_OK; 2295*3034Sdougm struct options *optlist = NULL; 2296*3034Sdougm char *sharepath = NULL; 2297*3034Sdougm char *optset = NULL; 2298*3034Sdougm int auth; 2299*3034Sdougm 2300*3034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2301*3034Sdougm switch (c) { 2302*3034Sdougm case 'v': 2303*3034Sdougm verbose++; 2304*3034Sdougm break; 2305*3034Sdougm case 'n': 2306*3034Sdougm dryrun++; 2307*3034Sdougm break; 2308*3034Sdougm case 'P': 2309*3034Sdougm protocol = optarg; 2310*3034Sdougm if (!sa_valid_protocol(protocol)) { 2311*3034Sdougm (void) printf(gettext("Invalid protocol specified:" 2312*3034Sdougm "%s\n"), 2313*3034Sdougm protocol); 2314*3034Sdougm return (SA_INVALID_PROTOCOL); 2315*3034Sdougm } 2316*3034Sdougm break; 2317*3034Sdougm case 'p': 2318*3034Sdougm ret = add_opt(&optlist, optarg, 0); 2319*3034Sdougm switch (ret) { 2320*3034Sdougm case OPT_ADD_SYNTAX: 2321*3034Sdougm (void) printf(gettext("Property syntax error: %s\n"), 2322*3034Sdougm optarg); 2323*3034Sdougm return (SA_SYNTAX_ERR); 2324*3034Sdougm case OPT_ADD_MEMORY: 2325*3034Sdougm (void) printf(gettext("No memory to set property: %s\n"), 2326*3034Sdougm optarg); 2327*3034Sdougm return (SA_NO_MEMORY); 2328*3034Sdougm default: 2329*3034Sdougm break; 2330*3034Sdougm } 2331*3034Sdougm break; 2332*3034Sdougm case 's': 2333*3034Sdougm sharepath = optarg; 2334*3034Sdougm break; 2335*3034Sdougm case 'S': 2336*3034Sdougm optset = optarg; 2337*3034Sdougm break; 2338*3034Sdougm default: 2339*3034Sdougm case 'h': 2340*3034Sdougm case '?': 2341*3034Sdougm (void) printf(gettext("usage: %s\n"), 2342*3034Sdougm sa_get_usage(USAGE_SET)); 2343*3034Sdougm return (SA_OK); 2344*3034Sdougm } 2345*3034Sdougm } 2346*3034Sdougm 2347*3034Sdougm if (optlist != NULL) 2348*3034Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 2349*3034Sdougm 2350*3034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 2351*3034Sdougm protocol == NULL || 2352*3034Sdougm ret != OPT_ADD_OK) { 2353*3034Sdougm char *sep = "\t"; 2354*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET)); 2355*3034Sdougm if (optind >= argc) { 2356*3034Sdougm (void) printf(gettext("%sgroup must be specified"), sep); 2357*3034Sdougm sep = ", "; 2358*3034Sdougm } 2359*3034Sdougm if (optlist == NULL) { 2360*3034Sdougm (void) printf(gettext("%sat least one property must be" 2361*3034Sdougm " specified"), sep); 2362*3034Sdougm sep = ", "; 2363*3034Sdougm } 2364*3034Sdougm if (protocol == NULL) { 2365*3034Sdougm (void) printf(gettext("%sprotocol must be specified"), sep); 2366*3034Sdougm sep = ", "; 2367*3034Sdougm } 2368*3034Sdougm (void) printf("\n"); 2369*3034Sdougm ret = SA_SYNTAX_ERR; 2370*3034Sdougm } else { 2371*3034Sdougm /* 2372*3034Sdougm * if a group already exists, we can only add a new 2373*3034Sdougm * protocol to it and not create a new one or add the 2374*3034Sdougm * same protocol again. 2375*3034Sdougm */ 2376*3034Sdougm 2377*3034Sdougm groupname = argv[optind]; 2378*3034Sdougm auth = check_authorizations(groupname, flags); 2379*3034Sdougm if (optset == NULL) 2380*3034Sdougm ret = basic_set(groupname, optlist, protocol, 2381*3034Sdougm sharepath, dryrun); 2382*3034Sdougm else 2383*3034Sdougm ret = space_set(groupname, optlist, protocol, 2384*3034Sdougm sharepath, dryrun, optset); 2385*3034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 2386*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 2387*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 2388*3034Sdougm } 2389*3034Sdougm } 2390*3034Sdougm return (ret); 2391*3034Sdougm } 2392*3034Sdougm 2393*3034Sdougm /* 2394*3034Sdougm * remove_options(group, optlist, proto, *err) 2395*3034Sdougm * 2396*3034Sdougm * helper function to actually remove options from a group after all 2397*3034Sdougm * preprocessing is done. 2398*3034Sdougm */ 2399*3034Sdougm 2400*3034Sdougm static int 2401*3034Sdougm remove_options(sa_group_t group, struct options *optlist, 2402*3034Sdougm char *proto, int *err) 2403*3034Sdougm { 2404*3034Sdougm struct options *cur; 2405*3034Sdougm sa_optionset_t optionset; 2406*3034Sdougm sa_property_t prop; 2407*3034Sdougm int change = 0; 2408*3034Sdougm int ret = SA_OK; 2409*3034Sdougm 2410*3034Sdougm optionset = sa_get_optionset(group, proto); 2411*3034Sdougm if (optionset != NULL) { 2412*3034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 2413*3034Sdougm prop = sa_get_property(optionset, cur->optname); 2414*3034Sdougm if (prop != NULL) { 2415*3034Sdougm ret = sa_remove_property(prop); 2416*3034Sdougm if (ret != SA_OK) 2417*3034Sdougm break; 2418*3034Sdougm change = 1; 2419*3034Sdougm } 2420*3034Sdougm } 2421*3034Sdougm } 2422*3034Sdougm if (ret == SA_OK && change) 2423*3034Sdougm ret = sa_commit_properties(optionset, 0); 2424*3034Sdougm 2425*3034Sdougm if (err != NULL) 2426*3034Sdougm *err = ret; 2427*3034Sdougm return (change); 2428*3034Sdougm } 2429*3034Sdougm 2430*3034Sdougm /* 2431*3034Sdougm * valid_unset(group, optlist, proto) 2432*3034Sdougm * 2433*3034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 2434*3034Sdougm * error if a property doesn't exist. 2435*3034Sdougm */ 2436*3034Sdougm 2437*3034Sdougm static int 2438*3034Sdougm valid_unset(sa_group_t group, struct options *optlist, char *proto) 2439*3034Sdougm { 2440*3034Sdougm struct options *cur; 2441*3034Sdougm sa_optionset_t optionset; 2442*3034Sdougm sa_property_t prop; 2443*3034Sdougm int ret = SA_OK; 2444*3034Sdougm 2445*3034Sdougm optionset = sa_get_optionset(group, proto); 2446*3034Sdougm if (optionset != NULL) { 2447*3034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 2448*3034Sdougm prop = sa_get_property(optionset, cur->optname); 2449*3034Sdougm if (prop == NULL) { 2450*3034Sdougm (void) printf(gettext("Could not unset property %s:" 2451*3034Sdougm " not set\n"), 2452*3034Sdougm cur->optname); 2453*3034Sdougm ret = SA_NO_SUCH_PROP; 2454*3034Sdougm } 2455*3034Sdougm } 2456*3034Sdougm } 2457*3034Sdougm return (ret); 2458*3034Sdougm } 2459*3034Sdougm 2460*3034Sdougm /* 2461*3034Sdougm * valid_unset_security(group, optlist, proto) 2462*3034Sdougm * 2463*3034Sdougm * Sanity check the optlist to make sure they can be removed. Issue an 2464*3034Sdougm * error if a property doesn't exist. 2465*3034Sdougm */ 2466*3034Sdougm 2467*3034Sdougm static int 2468*3034Sdougm valid_unset_security(sa_group_t group, struct options *optlist, char *proto, 2469*3034Sdougm char *sectype) 2470*3034Sdougm { 2471*3034Sdougm struct options *cur; 2472*3034Sdougm sa_security_t security; 2473*3034Sdougm sa_property_t prop; 2474*3034Sdougm int ret = SA_OK; 2475*3034Sdougm char *sec; 2476*3034Sdougm 2477*3034Sdougm sec = sa_proto_space_alias(proto, sectype); 2478*3034Sdougm security = sa_get_security(group, sec, proto); 2479*3034Sdougm if (security != NULL) { 2480*3034Sdougm for (cur = optlist; cur != NULL; cur = cur->next) { 2481*3034Sdougm prop = sa_get_property(security, cur->optname); 2482*3034Sdougm if (prop == NULL) { 2483*3034Sdougm (void) printf(gettext("Could not unset property %s:" 2484*3034Sdougm " not set\n"), 2485*3034Sdougm cur->optname); 2486*3034Sdougm ret = SA_NO_SUCH_PROP; 2487*3034Sdougm } 2488*3034Sdougm } 2489*3034Sdougm } else { 2490*3034Sdougm (void) printf(gettext("Could not unset %s: space not defined\n"), 2491*3034Sdougm sectype); 2492*3034Sdougm ret = SA_NO_SUCH_SECURITY; 2493*3034Sdougm } 2494*3034Sdougm if (sec != NULL) 2495*3034Sdougm sa_free_attr_string(sec); 2496*3034Sdougm return (ret); 2497*3034Sdougm } 2498*3034Sdougm 2499*3034Sdougm /* 2500*3034Sdougm * remove_security(group, optlist, proto) 2501*3034Sdougm * 2502*3034Sdougm * Remove the properties since they were checked as valid. 2503*3034Sdougm */ 2504*3034Sdougm 2505*3034Sdougm static int 2506*3034Sdougm remove_security(sa_group_t group, char *sectype, 2507*3034Sdougm struct options *optlist, char *proto, int *err) 2508*3034Sdougm { 2509*3034Sdougm sa_security_t security; 2510*3034Sdougm int ret = SA_OK; 2511*3034Sdougm int change = 0; 2512*3034Sdougm 2513*3034Sdougm sectype = sa_proto_space_alias(proto, sectype); 2514*3034Sdougm security = sa_get_security(group, sectype, proto); 2515*3034Sdougm if (sectype != NULL) 2516*3034Sdougm sa_free_attr_string(sectype); 2517*3034Sdougm 2518*3034Sdougm if (security != NULL) { 2519*3034Sdougm while (optlist != NULL) { 2520*3034Sdougm sa_property_t prop; 2521*3034Sdougm prop = sa_get_property(security, optlist->optname); 2522*3034Sdougm if (prop != NULL) { 2523*3034Sdougm ret = sa_remove_property(prop); 2524*3034Sdougm if (ret != SA_OK) 2525*3034Sdougm break; 2526*3034Sdougm change = 1; 2527*3034Sdougm } 2528*3034Sdougm optlist = optlist->next; 2529*3034Sdougm } 2530*3034Sdougm /* 2531*3034Sdougm * when done, properties may have all been removed but 2532*3034Sdougm * we need to keep the security type itself until 2533*3034Sdougm * explicitly removed. 2534*3034Sdougm */ 2535*3034Sdougm if (ret == SA_OK && change) 2536*3034Sdougm ret = sa_commit_properties(security, 0); 2537*3034Sdougm } else { 2538*3034Sdougm ret = SA_NO_SUCH_PROP; 2539*3034Sdougm } 2540*3034Sdougm if (err != NULL) 2541*3034Sdougm *err = ret; 2542*3034Sdougm return (change); 2543*3034Sdougm } 2544*3034Sdougm 2545*3034Sdougm /* 2546*3034Sdougm * basic_unset(groupname, optlist, protocol, sharepath, dryrun) 2547*3034Sdougm * 2548*3034Sdougm * unset non-named optionset properties. 2549*3034Sdougm */ 2550*3034Sdougm 2551*3034Sdougm static int 2552*3034Sdougm basic_unset(char *groupname, struct options *optlist, char *protocol, 2553*3034Sdougm char *sharepath, int dryrun) 2554*3034Sdougm { 2555*3034Sdougm sa_group_t group; 2556*3034Sdougm int ret = SA_OK; 2557*3034Sdougm int change = 0; 2558*3034Sdougm struct list *worklist = NULL; 2559*3034Sdougm 2560*3034Sdougm group = sa_get_group(groupname); 2561*3034Sdougm if (group != NULL) { 2562*3034Sdougm sa_share_t share = NULL; 2563*3034Sdougm if (sharepath != NULL) { 2564*3034Sdougm share = sa_get_share(group, sharepath); 2565*3034Sdougm if (share == NULL) { 2566*3034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 2567*3034Sdougm groupname, sharepath); 2568*3034Sdougm ret = SA_NO_SUCH_PATH; 2569*3034Sdougm } 2570*3034Sdougm } 2571*3034Sdougm if (ret == SA_OK) { 2572*3034Sdougm /* group must exist */ 2573*3034Sdougm ret = valid_unset(share != NULL ? share : group, 2574*3034Sdougm optlist, protocol); 2575*3034Sdougm if (ret == SA_OK && !dryrun) { 2576*3034Sdougm if (share != NULL) { 2577*3034Sdougm sa_optionset_t optionset; 2578*3034Sdougm sa_property_t prop; 2579*3034Sdougm change |= remove_options(share, optlist, protocol, 2580*3034Sdougm &ret); 2581*3034Sdougm /* if a share optionset is empty, remove it */ 2582*3034Sdougm optionset = sa_get_optionset((sa_share_t)share, 2583*3034Sdougm protocol); 2584*3034Sdougm if (optionset != NULL) { 2585*3034Sdougm prop = sa_get_property(optionset, NULL); 2586*3034Sdougm if (prop == NULL) 2587*3034Sdougm (void) sa_destroy_optionset(optionset); 2588*3034Sdougm } 2589*3034Sdougm } else { 2590*3034Sdougm change |= remove_options(group, optlist, protocol, 2591*3034Sdougm &ret); 2592*3034Sdougm } 2593*3034Sdougm if (ret == SA_OK && change) 2594*3034Sdougm worklist = add_list(worklist, group, share); 2595*3034Sdougm if (ret != SA_OK) 2596*3034Sdougm (void) printf(gettext("Could not remove properties:" 2597*3034Sdougm "%s\n"), 2598*3034Sdougm sa_errorstr(ret)); 2599*3034Sdougm } 2600*3034Sdougm } else { 2601*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2602*3034Sdougm ret = SA_NO_SUCH_GROUP; 2603*3034Sdougm } 2604*3034Sdougm free_opt(optlist); 2605*3034Sdougm } 2606*3034Sdougm 2607*3034Sdougm /* 2608*3034Sdougm * we have a group and potentially legal additions 2609*3034Sdougm */ 2610*3034Sdougm /* commit to configuration if not a dryrun */ 2611*3034Sdougm if (!dryrun && ret == SA_OK) { 2612*3034Sdougm if (change && worklist != NULL) { 2613*3034Sdougm /* properties changed, so update all shares */ 2614*3034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 2615*3034Sdougm } 2616*3034Sdougm } 2617*3034Sdougm if (worklist != NULL) 2618*3034Sdougm free_list(worklist); 2619*3034Sdougm return (ret); 2620*3034Sdougm } 2621*3034Sdougm 2622*3034Sdougm /* 2623*3034Sdougm * space_unset(groupname, optlist, protocol, sharepath, dryrun) 2624*3034Sdougm * 2625*3034Sdougm * unset named optionset properties. 2626*3034Sdougm */ 2627*3034Sdougm static int 2628*3034Sdougm space_unset(char *groupname, struct options *optlist, char *protocol, 2629*3034Sdougm char *sharepath, int dryrun, char *sectype) 2630*3034Sdougm { 2631*3034Sdougm sa_group_t group; 2632*3034Sdougm int ret = SA_OK; 2633*3034Sdougm int change = 0; 2634*3034Sdougm struct list *worklist = NULL; 2635*3034Sdougm 2636*3034Sdougm group = sa_get_group(groupname); 2637*3034Sdougm if (group != NULL) { 2638*3034Sdougm sa_share_t share = NULL; 2639*3034Sdougm if (sharepath != NULL) { 2640*3034Sdougm share = sa_get_share(group, sharepath); 2641*3034Sdougm if (share == NULL) { 2642*3034Sdougm (void) printf(gettext("Share does not exist in group %s\n"), 2643*3034Sdougm groupname, sharepath); 2644*3034Sdougm ret = SA_NO_SUCH_PATH; 2645*3034Sdougm } 2646*3034Sdougm } 2647*3034Sdougm if (ret == SA_OK) { 2648*3034Sdougm ret = valid_unset_security(share != NULL ? share : group, 2649*3034Sdougm optlist, protocol, sectype); 2650*3034Sdougm if (ret == SA_OK && !dryrun) { 2651*3034Sdougm if (optlist != NULL) { 2652*3034Sdougm if (share != NULL) { 2653*3034Sdougm sa_security_t optionset; 2654*3034Sdougm sa_property_t prop; 2655*3034Sdougm change = remove_security(share, sectype, 2656*3034Sdougm optlist, protocol, 2657*3034Sdougm &ret); 2658*3034Sdougm /* if a share security is empty, remove it */ 2659*3034Sdougm optionset = sa_get_security((sa_group_t)share, 2660*3034Sdougm sectype, 2661*3034Sdougm protocol); 2662*3034Sdougm if (optionset != NULL) { 2663*3034Sdougm prop = sa_get_property(optionset, NULL); 2664*3034Sdougm if (prop == NULL) 2665*3034Sdougm ret = sa_destroy_security(optionset); 2666*3034Sdougm } 2667*3034Sdougm } else { 2668*3034Sdougm change = remove_security(group, sectype, 2669*3034Sdougm optlist, protocol, 2670*3034Sdougm &ret); 2671*3034Sdougm } 2672*3034Sdougm } else { 2673*3034Sdougm sa_security_t security; 2674*3034Sdougm char *sec; 2675*3034Sdougm sec = sa_proto_space_alias(protocol, sectype); 2676*3034Sdougm security = sa_get_security(group, sec, protocol); 2677*3034Sdougm if (sec != NULL) 2678*3034Sdougm sa_free_attr_string(sec); 2679*3034Sdougm if (security != NULL) { 2680*3034Sdougm ret = sa_destroy_security(security); 2681*3034Sdougm if (ret == SA_OK) 2682*3034Sdougm change = 1; 2683*3034Sdougm } else { 2684*3034Sdougm ret = SA_NO_SUCH_PROP; 2685*3034Sdougm } 2686*3034Sdougm } 2687*3034Sdougm if (ret != SA_OK) 2688*3034Sdougm (void) printf(gettext("Could not unset property: %s\n"), 2689*3034Sdougm sa_errorstr(ret)); 2690*3034Sdougm } 2691*3034Sdougm 2692*3034Sdougm if (ret == SA_OK && change) 2693*3034Sdougm worklist = add_list(worklist, group, 0); 2694*3034Sdougm } 2695*3034Sdougm } else { 2696*3034Sdougm (void) printf(gettext("Group \"%s\" not found\n"), groupname); 2697*3034Sdougm ret = SA_NO_SUCH_GROUP; 2698*3034Sdougm } 2699*3034Sdougm free_opt(optlist); 2700*3034Sdougm /* 2701*3034Sdougm * we have a group and potentially legal additions 2702*3034Sdougm */ 2703*3034Sdougm 2704*3034Sdougm /* commit to configuration if not a dryrun */ 2705*3034Sdougm if (!dryrun && ret == 0) { 2706*3034Sdougm if (change && worklist != NULL) { 2707*3034Sdougm /* properties changed, so update all shares */ 2708*3034Sdougm (void) enable_all_groups(worklist, 0, 0, protocol); 2709*3034Sdougm } 2710*3034Sdougm ret = sa_update_config(); 2711*3034Sdougm } 2712*3034Sdougm if (worklist != NULL) 2713*3034Sdougm free_list(worklist); 2714*3034Sdougm return (ret); 2715*3034Sdougm } 2716*3034Sdougm 2717*3034Sdougm /* 2718*3034Sdougm * sa_unset(flags, argc, argv) 2719*3034Sdougm * 2720*3034Sdougm * implements the unset subcommand. Parsing done here and then basic 2721*3034Sdougm * or space versions of the real code are called. 2722*3034Sdougm */ 2723*3034Sdougm 2724*3034Sdougm int 2725*3034Sdougm sa_unset(int flags, int argc, char *argv[]) 2726*3034Sdougm { 2727*3034Sdougm char *groupname; 2728*3034Sdougm int verbose = 0; 2729*3034Sdougm int dryrun = 0; 2730*3034Sdougm int c; 2731*3034Sdougm char *protocol = NULL; 2732*3034Sdougm int ret = SA_OK; 2733*3034Sdougm struct options *optlist = NULL; 2734*3034Sdougm char *sharepath = NULL; 2735*3034Sdougm char *optset = NULL; 2736*3034Sdougm int auth; 2737*3034Sdougm 2738*3034Sdougm while ((c = getopt(argc, argv, "?hvnP:p:s:S:")) != EOF) { 2739*3034Sdougm switch (c) { 2740*3034Sdougm case 'v': 2741*3034Sdougm verbose++; 2742*3034Sdougm break; 2743*3034Sdougm case 'n': 2744*3034Sdougm dryrun++; 2745*3034Sdougm break; 2746*3034Sdougm case 'P': 2747*3034Sdougm protocol = optarg; 2748*3034Sdougm if (!sa_valid_protocol(protocol)) { 2749*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 2750*3034Sdougm protocol); 2751*3034Sdougm return (SA_INVALID_PROTOCOL); 2752*3034Sdougm } 2753*3034Sdougm break; 2754*3034Sdougm case 'p': 2755*3034Sdougm ret = add_opt(&optlist, optarg, 1); 2756*3034Sdougm switch (ret) { 2757*3034Sdougm case OPT_ADD_SYNTAX: 2758*3034Sdougm (void) printf(gettext("Property syntax error for " 2759*3034Sdougm "property %s\n"), 2760*3034Sdougm optarg); 2761*3034Sdougm return (SA_SYNTAX_ERR); 2762*3034Sdougm case OPT_ADD_PROPERTY: 2763*3034Sdougm (void) printf(gettext("Properties need to be set" 2764*3034Sdougm " with set command: %s\n"), 2765*3034Sdougm optarg); 2766*3034Sdougm return (SA_SYNTAX_ERR); 2767*3034Sdougm default: 2768*3034Sdougm break; 2769*3034Sdougm } 2770*3034Sdougm break; 2771*3034Sdougm case 's': 2772*3034Sdougm sharepath = optarg; 2773*3034Sdougm break; 2774*3034Sdougm case 'S': 2775*3034Sdougm optset = optarg; 2776*3034Sdougm break; 2777*3034Sdougm default: 2778*3034Sdougm case 'h': 2779*3034Sdougm case '?': 2780*3034Sdougm (void) printf(gettext("usage: %s\n"), 2781*3034Sdougm sa_get_usage(USAGE_UNSET)); 2782*3034Sdougm return (SA_OK); 2783*3034Sdougm } 2784*3034Sdougm } 2785*3034Sdougm 2786*3034Sdougm if (optlist != NULL) 2787*3034Sdougm ret = chk_opt(optlist, optset != NULL, protocol); 2788*3034Sdougm 2789*3034Sdougm if (optind >= argc || (optlist == NULL && optset == NULL) || 2790*3034Sdougm protocol == NULL) { 2791*3034Sdougm char *sep = "\t"; 2792*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_UNSET)); 2793*3034Sdougm if (optind >= argc) { 2794*3034Sdougm (void) printf(gettext("%sgroup must be specified"), sep); 2795*3034Sdougm sep = ", "; 2796*3034Sdougm } 2797*3034Sdougm if (optlist == NULL) { 2798*3034Sdougm (void) printf(gettext("%sat least one property must be " 2799*3034Sdougm "specified"), 2800*3034Sdougm sep); 2801*3034Sdougm sep = ", "; 2802*3034Sdougm } 2803*3034Sdougm if (protocol == NULL) { 2804*3034Sdougm (void) printf(gettext("%sprotocol must be specified"), sep); 2805*3034Sdougm sep = ", "; 2806*3034Sdougm } 2807*3034Sdougm (void) printf("\n"); 2808*3034Sdougm ret = SA_SYNTAX_ERR; 2809*3034Sdougm } else { 2810*3034Sdougm 2811*3034Sdougm /* 2812*3034Sdougm * if a group already exists, we can only add a new 2813*3034Sdougm * protocol to it and not create a new one or add the 2814*3034Sdougm * same protocol again. 2815*3034Sdougm */ 2816*3034Sdougm 2817*3034Sdougm groupname = argv[optind]; 2818*3034Sdougm auth = check_authorizations(groupname, flags); 2819*3034Sdougm if (optset == NULL) 2820*3034Sdougm ret = basic_unset(groupname, optlist, protocol, 2821*3034Sdougm sharepath, dryrun); 2822*3034Sdougm else 2823*3034Sdougm ret = space_unset(groupname, optlist, protocol, 2824*3034Sdougm sharepath, dryrun, optset); 2825*3034Sdougm 2826*3034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 2827*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 2828*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 2829*3034Sdougm } 2830*3034Sdougm } 2831*3034Sdougm return (ret); 2832*3034Sdougm } 2833*3034Sdougm 2834*3034Sdougm /* 2835*3034Sdougm * sa_enable_group(flags, argc, argv) 2836*3034Sdougm * 2837*3034Sdougm * Implements the enable subcommand 2838*3034Sdougm */ 2839*3034Sdougm 2840*3034Sdougm int 2841*3034Sdougm sa_enable_group(int flags, int argc, char *argv[]) 2842*3034Sdougm { 2843*3034Sdougm int verbose = 0; 2844*3034Sdougm int dryrun = 0; 2845*3034Sdougm int all = 0; 2846*3034Sdougm int c; 2847*3034Sdougm int ret = SA_OK; 2848*3034Sdougm char *protocol = NULL; 2849*3034Sdougm char *state; 2850*3034Sdougm struct list *worklist = NULL; 2851*3034Sdougm int auth = 1; 2852*3034Sdougm 2853*3034Sdougm while ((c = getopt(argc, argv, "?havnP:")) != EOF) { 2854*3034Sdougm switch (c) { 2855*3034Sdougm case 'a': 2856*3034Sdougm all = 1; 2857*3034Sdougm break; 2858*3034Sdougm case 'n': 2859*3034Sdougm dryrun++; 2860*3034Sdougm break; 2861*3034Sdougm case 'P': 2862*3034Sdougm protocol = optarg; 2863*3034Sdougm if (!sa_valid_protocol(protocol)) { 2864*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 2865*3034Sdougm protocol); 2866*3034Sdougm return (SA_INVALID_PROTOCOL); 2867*3034Sdougm } 2868*3034Sdougm break; 2869*3034Sdougm case 'v': 2870*3034Sdougm verbose++; 2871*3034Sdougm break; 2872*3034Sdougm default: 2873*3034Sdougm case 'h': 2874*3034Sdougm case '?': 2875*3034Sdougm (void) printf(gettext("usage: %s\n"), 2876*3034Sdougm sa_get_usage(USAGE_ENABLE)); 2877*3034Sdougm return (0); 2878*3034Sdougm } 2879*3034Sdougm } 2880*3034Sdougm 2881*3034Sdougm if (optind == argc && !all) { 2882*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_ENABLE)); 2883*3034Sdougm (void) printf(gettext("\tmust specify group\n")); 2884*3034Sdougm ret = SA_NO_SUCH_PATH; 2885*3034Sdougm } else { 2886*3034Sdougm sa_group_t group; 2887*3034Sdougm if (!all) { 2888*3034Sdougm while (optind < argc) { 2889*3034Sdougm group = sa_get_group(argv[optind]); 2890*3034Sdougm if (group != NULL) { 2891*3034Sdougm auth &= check_authorizations(argv[optind], flags); 2892*3034Sdougm state = sa_get_group_attr(group, "state"); 2893*3034Sdougm if (state != NULL && 2894*3034Sdougm strcmp(state, "enabled") == 0) { 2895*3034Sdougm /* already enabled */ 2896*3034Sdougm if (verbose) 2897*3034Sdougm (void) printf(gettext("Group \"%s\" is already " 2898*3034Sdougm "enabled\n"), 2899*3034Sdougm argv[optind]); 2900*3034Sdougm ret = SA_BUSY; /* already enabled */ 2901*3034Sdougm } else { 2902*3034Sdougm worklist = add_list(worklist, group, 0); 2903*3034Sdougm if (verbose) 2904*3034Sdougm (void) printf(gettext("Enabling group " 2905*3034Sdougm "\"%s\"\n"), 2906*3034Sdougm argv[optind]); 2907*3034Sdougm } 2908*3034Sdougm if (state != NULL) 2909*3034Sdougm sa_free_attr_string(state); 2910*3034Sdougm } else { 2911*3034Sdougm ret = SA_NO_SUCH_GROUP; 2912*3034Sdougm } 2913*3034Sdougm optind++; 2914*3034Sdougm } 2915*3034Sdougm } else { 2916*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 2917*3034Sdougm group = sa_get_next_group(group)) { 2918*3034Sdougm worklist = add_list(worklist, group, 0); 2919*3034Sdougm } 2920*3034Sdougm } 2921*3034Sdougm if (!dryrun && ret == SA_OK) { 2922*3034Sdougm ret = enable_all_groups(worklist, 1, 0, NULL); 2923*3034Sdougm } 2924*3034Sdougm if (ret != SA_OK && ret != SA_BUSY) 2925*3034Sdougm (void) printf(gettext("Could not enable group: %s\n"), 2926*3034Sdougm sa_errorstr(ret)); 2927*3034Sdougm if (ret == SA_BUSY) 2928*3034Sdougm ret = SA_OK; 2929*3034Sdougm } 2930*3034Sdougm if (worklist != NULL) 2931*3034Sdougm free_list(worklist); 2932*3034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 2933*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 2934*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 2935*3034Sdougm } 2936*3034Sdougm return (ret); 2937*3034Sdougm } 2938*3034Sdougm 2939*3034Sdougm /* 2940*3034Sdougm * disable_group(group, setstate) 2941*3034Sdougm * 2942*3034Sdougm * disable all the shares in the specified group honoring the setstate 2943*3034Sdougm * argument. This is a helper for disable_all_groups in order to 2944*3034Sdougm * simplify regular and subgroup (zfs) disabling. Group has already 2945*3034Sdougm * been checked for non-NULL. 2946*3034Sdougm */ 2947*3034Sdougm 2948*3034Sdougm static int 2949*3034Sdougm disable_group(sa_group_t group) 2950*3034Sdougm { 2951*3034Sdougm sa_share_t share; 2952*3034Sdougm int ret = SA_OK; 2953*3034Sdougm 2954*3034Sdougm for (share = sa_get_share(group, NULL); 2955*3034Sdougm share != NULL && ret == SA_OK; 2956*3034Sdougm share = sa_get_next_share(share)) { 2957*3034Sdougm ret = sa_disable_share(share, NULL); 2958*3034Sdougm if (ret == SA_NO_SUCH_PATH) { 2959*3034Sdougm /* 2960*3034Sdougm * this is OK since the path is gone. we can't 2961*3034Sdougm * re-share it anyway so no error. 2962*3034Sdougm */ 2963*3034Sdougm ret = SA_OK; 2964*3034Sdougm } 2965*3034Sdougm } 2966*3034Sdougm return (ret); 2967*3034Sdougm } 2968*3034Sdougm 2969*3034Sdougm 2970*3034Sdougm /* 2971*3034Sdougm * disable_all_groups(work, setstate) 2972*3034Sdougm * 2973*3034Sdougm * helper function that disables the shares in the list of groups 2974*3034Sdougm * provided. It optionally marks the group as disabled. Used by both 2975*3034Sdougm * enable and start subcommands. 2976*3034Sdougm */ 2977*3034Sdougm 2978*3034Sdougm static int 2979*3034Sdougm disable_all_groups(struct list *work, int setstate) 2980*3034Sdougm { 2981*3034Sdougm int ret = SA_OK; 2982*3034Sdougm sa_group_t subgroup, group; 2983*3034Sdougm 2984*3034Sdougm while (work != NULL && ret == SA_OK) { 2985*3034Sdougm group = (sa_group_t)work->item; 2986*3034Sdougm if (setstate) 2987*3034Sdougm ret = sa_set_group_attr(group, "state", "disabled"); 2988*3034Sdougm if (ret == SA_OK) { 2989*3034Sdougm char *name; 2990*3034Sdougm name = sa_get_group_attr(group, "name"); 2991*3034Sdougm if (name != NULL && strcmp(name, "zfs") == 0) { 2992*3034Sdougm /* need to get the sub-groups for stopping */ 2993*3034Sdougm for (subgroup = sa_get_sub_group(group); subgroup != NULL; 2994*3034Sdougm subgroup = sa_get_next_group(subgroup)) { 2995*3034Sdougm ret = disable_group(subgroup); 2996*3034Sdougm } 2997*3034Sdougm } else { 2998*3034Sdougm ret = disable_group(group); 2999*3034Sdougm } 3000*3034Sdougm /* 3001*3034Sdougm * we don't want to "disable" since it won't come 3002*3034Sdougm * up after a reboot. The SMF framework should do 3003*3034Sdougm * the right thing. On enable we do want to do 3004*3034Sdougm * something. 3005*3034Sdougm */ 3006*3034Sdougm } 3007*3034Sdougm work = work->next; 3008*3034Sdougm } 3009*3034Sdougm if (ret == SA_OK) 3010*3034Sdougm ret = sa_update_config(); 3011*3034Sdougm return (ret); 3012*3034Sdougm } 3013*3034Sdougm 3014*3034Sdougm /* 3015*3034Sdougm * sa_disable_group(flags, argc, argv) 3016*3034Sdougm * 3017*3034Sdougm * Implements the disable subcommand 3018*3034Sdougm */ 3019*3034Sdougm 3020*3034Sdougm int 3021*3034Sdougm sa_disable_group(int flags, int argc, char *argv[]) 3022*3034Sdougm { 3023*3034Sdougm int verbose = 0; 3024*3034Sdougm int dryrun = 0; 3025*3034Sdougm int all = 0; 3026*3034Sdougm int c; 3027*3034Sdougm int ret = SA_OK; 3028*3034Sdougm char *protocol; 3029*3034Sdougm char *state; 3030*3034Sdougm struct list *worklist = NULL; 3031*3034Sdougm int auth = 1; 3032*3034Sdougm 3033*3034Sdougm while ((c = getopt(argc, argv, "?havn")) != EOF) { 3034*3034Sdougm switch (c) { 3035*3034Sdougm case 'a': 3036*3034Sdougm all = 1; 3037*3034Sdougm break; 3038*3034Sdougm case 'n': 3039*3034Sdougm dryrun++; 3040*3034Sdougm break; 3041*3034Sdougm case 'P': 3042*3034Sdougm protocol = optarg; 3043*3034Sdougm if (!sa_valid_protocol(protocol)) { 3044*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 3045*3034Sdougm protocol); 3046*3034Sdougm return (SA_INVALID_PROTOCOL); 3047*3034Sdougm } 3048*3034Sdougm break; 3049*3034Sdougm case 'v': 3050*3034Sdougm verbose++; 3051*3034Sdougm break; 3052*3034Sdougm default: 3053*3034Sdougm case 'h': 3054*3034Sdougm case '?': 3055*3034Sdougm (void) printf(gettext("usage: %s\n"), 3056*3034Sdougm sa_get_usage(USAGE_DISABLE)); 3057*3034Sdougm return (0); 3058*3034Sdougm } 3059*3034Sdougm } 3060*3034Sdougm 3061*3034Sdougm if (optind == argc && !all) { 3062*3034Sdougm (void) printf(gettext("usage: %s\n"), 3063*3034Sdougm sa_get_usage(USAGE_DISABLE)); 3064*3034Sdougm (void) printf(gettext("\tmust specify group\n")); 3065*3034Sdougm ret = SA_NO_SUCH_PATH; 3066*3034Sdougm } else { 3067*3034Sdougm sa_group_t group; 3068*3034Sdougm if (!all) { 3069*3034Sdougm while (optind < argc) { 3070*3034Sdougm group = sa_get_group(argv[optind]); 3071*3034Sdougm if (group != NULL) { 3072*3034Sdougm auth &= check_authorizations(argv[optind], flags); 3073*3034Sdougm state = sa_get_group_attr(group, "state"); 3074*3034Sdougm if (state == NULL || 3075*3034Sdougm strcmp(state, "disabled") == 0) { 3076*3034Sdougm /* already disabled */ 3077*3034Sdougm if (verbose) 3078*3034Sdougm (void) printf(gettext("Group \"%s\" is " 3079*3034Sdougm "already disabled\n"), 3080*3034Sdougm argv[optind]); 3081*3034Sdougm ret = SA_BUSY; /* already disable */ 3082*3034Sdougm } else { 3083*3034Sdougm worklist = add_list(worklist, group, 0); 3084*3034Sdougm if (verbose) 3085*3034Sdougm (void) printf(gettext("Disabling group " 3086*3034Sdougm "\"%s\"\n"), 3087*3034Sdougm argv[optind]); 3088*3034Sdougm } 3089*3034Sdougm if (state != NULL) 3090*3034Sdougm sa_free_attr_string(state); 3091*3034Sdougm } else { 3092*3034Sdougm ret = SA_NO_SUCH_GROUP; 3093*3034Sdougm } 3094*3034Sdougm optind++; 3095*3034Sdougm } 3096*3034Sdougm } else { 3097*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 3098*3034Sdougm group = sa_get_next_group(group)) { 3099*3034Sdougm worklist = add_list(worklist, group, 0); 3100*3034Sdougm } 3101*3034Sdougm } 3102*3034Sdougm if (ret == SA_OK && !dryrun) { 3103*3034Sdougm ret = disable_all_groups(worklist, 1); 3104*3034Sdougm } 3105*3034Sdougm if (ret != SA_OK && ret != SA_BUSY) 3106*3034Sdougm (void) printf(gettext("Could not disable group: %s\n"), 3107*3034Sdougm sa_errorstr(ret)); 3108*3034Sdougm if (ret == SA_BUSY) 3109*3034Sdougm ret = SA_OK; 3110*3034Sdougm } 3111*3034Sdougm if (worklist != NULL) 3112*3034Sdougm free_list(worklist); 3113*3034Sdougm if (dryrun && ret == SA_OK && !auth && verbose) { 3114*3034Sdougm (void) printf(gettext("Command would fail: %s\n"), 3115*3034Sdougm sa_errorstr(SA_NO_PERMISSION)); 3116*3034Sdougm } 3117*3034Sdougm return (ret); 3118*3034Sdougm } 3119*3034Sdougm 3120*3034Sdougm /* 3121*3034Sdougm * check_sharetab() 3122*3034Sdougm * 3123*3034Sdougm * Checks to see if the /etc/dfs/sharetab file is stale (exists from 3124*3034Sdougm * before the current boot). If it is, truncate it since nothing is 3125*3034Sdougm * really shared. 3126*3034Sdougm */ 3127*3034Sdougm 3128*3034Sdougm static void 3129*3034Sdougm check_sharetab() 3130*3034Sdougm { 3131*3034Sdougm int fd; 3132*3034Sdougm struct utmpx *utmpxp; 3133*3034Sdougm struct stat st; 3134*3034Sdougm 3135*3034Sdougm fd = open(SA_LEGACY_SHARETAB, O_RDWR); 3136*3034Sdougm if (fd >= 0) { 3137*3034Sdougm /* 3138*3034Sdougm * Attempt to get a lock on the file. Whgen we get 3139*3034Sdougm * one, then check to see if it is older than the boot 3140*3034Sdougm * time. Truncate if older than boot. 3141*3034Sdougm */ 3142*3034Sdougm (void) lockf(fd, F_LOCK, 0); 3143*3034Sdougm if ((fstat(fd, &st) == 0) && /* does sharetab exist? */ 3144*3034Sdougm (utmpxp = getutxent()) != NULL && /* does utmpx exist? */ 3145*3034Sdougm (utmpxp->ut_xtime > st.st_mtime)) /* sharetab older? */ 3146*3034Sdougm (void) ftruncate(fd, 0); 3147*3034Sdougm 3148*3034Sdougm (void) lockf(fd, F_ULOCK, 0); 3149*3034Sdougm (void) close(fd); 3150*3034Sdougm endutxent(); 3151*3034Sdougm } 3152*3034Sdougm } 3153*3034Sdougm 3154*3034Sdougm /* 3155*3034Sdougm * sa_start_group(flags, argc, argv) 3156*3034Sdougm * 3157*3034Sdougm * Implements the start command. 3158*3034Sdougm * This is similar to enable except it doesn't change the state 3159*3034Sdougm * of the group(s) and only enables shares if the group is already 3160*3034Sdougm * enabled. 3161*3034Sdougm */ 3162*3034Sdougm 3163*3034Sdougm int 3164*3034Sdougm sa_start_group(int flags, int argc, char *argv[]) 3165*3034Sdougm { 3166*3034Sdougm int verbose = 0; 3167*3034Sdougm int all = 0; 3168*3034Sdougm int c; 3169*3034Sdougm int ret = SMF_EXIT_OK; 3170*3034Sdougm char *protocol = NULL; 3171*3034Sdougm char *state; 3172*3034Sdougm struct list *worklist = NULL; 3173*3034Sdougm #ifdef lint 3174*3034Sdougm flags = flags; 3175*3034Sdougm #endif 3176*3034Sdougm 3177*3034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3178*3034Sdougm switch (c) { 3179*3034Sdougm case 'a': 3180*3034Sdougm all = 1; 3181*3034Sdougm break; 3182*3034Sdougm case 'P': 3183*3034Sdougm protocol = optarg; 3184*3034Sdougm if (!sa_valid_protocol(protocol)) { 3185*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 3186*3034Sdougm protocol); 3187*3034Sdougm return (SA_INVALID_PROTOCOL); 3188*3034Sdougm } 3189*3034Sdougm break; 3190*3034Sdougm case 'v': 3191*3034Sdougm verbose++; 3192*3034Sdougm break; 3193*3034Sdougm default: 3194*3034Sdougm case 'h': 3195*3034Sdougm case '?': 3196*3034Sdougm (void) printf(gettext("usage: %s\n"), 3197*3034Sdougm sa_get_usage(USAGE_START)); 3198*3034Sdougm return (SA_OK); 3199*3034Sdougm } 3200*3034Sdougm } 3201*3034Sdougm 3202*3034Sdougm if (optind == argc && !all) { 3203*3034Sdougm (void) printf(gettext("usage: %s\n"), 3204*3034Sdougm sa_get_usage(USAGE_START)); 3205*3034Sdougm ret = SMF_EXIT_ERR_FATAL; 3206*3034Sdougm } else { 3207*3034Sdougm sa_group_t group; 3208*3034Sdougm 3209*3034Sdougm check_sharetab(); 3210*3034Sdougm 3211*3034Sdougm if (!all) { 3212*3034Sdougm while (optind < argc) { 3213*3034Sdougm group = sa_get_group(argv[optind]); 3214*3034Sdougm if (group != NULL) { 3215*3034Sdougm state = sa_get_group_attr(group, "state"); 3216*3034Sdougm if (state == NULL || 3217*3034Sdougm strcmp(state, "enabled") == 0) { 3218*3034Sdougm worklist = add_list(worklist, group, 0); 3219*3034Sdougm if (verbose) 3220*3034Sdougm (void) printf(gettext("Starting group " 3221*3034Sdougm "\"%s\"\n"), 3222*3034Sdougm argv[optind]); 3223*3034Sdougm } else { 3224*3034Sdougm /* 3225*3034Sdougm * determine if there are any 3226*3034Sdougm * protocols. if there aren't any, 3227*3034Sdougm * then there isn't anything to do in 3228*3034Sdougm * any case so no error. 3229*3034Sdougm */ 3230*3034Sdougm if (sa_get_optionset(group, protocol) != NULL) { 3231*3034Sdougm ret = SMF_EXIT_OK; 3232*3034Sdougm } 3233*3034Sdougm } 3234*3034Sdougm if (state != NULL) 3235*3034Sdougm sa_free_attr_string(state); 3236*3034Sdougm } 3237*3034Sdougm optind++; 3238*3034Sdougm } 3239*3034Sdougm } else { 3240*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 3241*3034Sdougm group = sa_get_next_group(group)) { 3242*3034Sdougm state = sa_get_group_attr(group, "state"); 3243*3034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 3244*3034Sdougm worklist = add_list(worklist, group, 0); 3245*3034Sdougm if (state != NULL) 3246*3034Sdougm sa_free_attr_string(state); 3247*3034Sdougm } 3248*3034Sdougm } 3249*3034Sdougm (void) enable_all_groups(worklist, 0, 1, NULL); 3250*3034Sdougm } 3251*3034Sdougm if (worklist != NULL) 3252*3034Sdougm free_list(worklist); 3253*3034Sdougm return (ret); 3254*3034Sdougm } 3255*3034Sdougm 3256*3034Sdougm /* 3257*3034Sdougm * sa_stop_group(flags, argc, argv) 3258*3034Sdougm * 3259*3034Sdougm * Implements the stop command. 3260*3034Sdougm * This is similar to disable except it doesn't change the state 3261*3034Sdougm * of the group(s) and only disables shares if the group is already 3262*3034Sdougm * enabled. 3263*3034Sdougm */ 3264*3034Sdougm 3265*3034Sdougm int 3266*3034Sdougm sa_stop_group(int flags, int argc, char *argv[]) 3267*3034Sdougm { 3268*3034Sdougm int verbose = 0; 3269*3034Sdougm int all = 0; 3270*3034Sdougm int c; 3271*3034Sdougm int ret = SMF_EXIT_OK; 3272*3034Sdougm char *protocol = NULL; 3273*3034Sdougm char *state; 3274*3034Sdougm struct list *worklist = NULL; 3275*3034Sdougm #ifdef lint 3276*3034Sdougm flags = flags; 3277*3034Sdougm #endif 3278*3034Sdougm 3279*3034Sdougm while ((c = getopt(argc, argv, "?havP:")) != EOF) { 3280*3034Sdougm switch (c) { 3281*3034Sdougm case 'a': 3282*3034Sdougm all = 1; 3283*3034Sdougm break; 3284*3034Sdougm case 'P': 3285*3034Sdougm protocol = optarg; 3286*3034Sdougm if (!sa_valid_protocol(protocol)) { 3287*3034Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 3288*3034Sdougm protocol); 3289*3034Sdougm return (SA_INVALID_PROTOCOL); 3290*3034Sdougm } 3291*3034Sdougm break; 3292*3034Sdougm case 'v': 3293*3034Sdougm verbose++; 3294*3034Sdougm break; 3295*3034Sdougm default: 3296*3034Sdougm case 'h': 3297*3034Sdougm case '?': 3298*3034Sdougm (void) printf(gettext("usage: %s\n"), 3299*3034Sdougm sa_get_usage(USAGE_STOP)); 3300*3034Sdougm return (0); 3301*3034Sdougm } 3302*3034Sdougm } 3303*3034Sdougm 3304*3034Sdougm if (optind == argc && !all) { 3305*3034Sdougm (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_STOP)); 3306*3034Sdougm ret = SMF_EXIT_ERR_FATAL; 3307*3034Sdougm } else { 3308*3034Sdougm sa_group_t group; 3309*3034Sdougm if (!all) { 3310*3034Sdougm while (optind < argc) { 3311*3034Sdougm group = sa_get_group(argv[optind]); 3312*3034Sdougm if (group != NULL) { 3313*3034Sdougm state = sa_get_group_attr(group, "state"); 3314*3034Sdougm if (state == NULL || 3315*3034Sdougm strcmp(state, "enabled") == 0) { 3316*3034Sdougm worklist = add_list(worklist, group, 0); 3317*3034Sdougm if (verbose) 3318*3034Sdougm (void) printf(gettext("Stopping group " 3319*3034Sdougm "\"%s\"\n"), 3320*3034Sdougm argv[optind]); 3321*3034Sdougm } else { 3322*3034Sdougm ret = SMF_EXIT_OK; 3323*3034Sdougm } 3324*3034Sdougm if (state != NULL) 3325*3034Sdougm sa_free_attr_string(state); 3326*3034Sdougm } 3327*3034Sdougm optind++; 3328*3034Sdougm } 3329*3034Sdougm } else { 3330*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 3331*3034Sdougm group = sa_get_next_group(group)) { 3332*3034Sdougm state = sa_get_group_attr(group, "state"); 3333*3034Sdougm if (state == NULL || strcmp(state, "enabled") == 0) 3334*3034Sdougm worklist = add_list(worklist, group, 0); 3335*3034Sdougm if (state != NULL) 3336*3034Sdougm sa_free_attr_string(state); 3337*3034Sdougm } 3338*3034Sdougm } 3339*3034Sdougm (void) disable_all_groups(worklist, 0); 3340*3034Sdougm ret = sa_update_config(); 3341*3034Sdougm } 3342*3034Sdougm if (worklist != NULL) 3343*3034Sdougm free_list(worklist); 3344*3034Sdougm return (ret); 3345*3034Sdougm } 3346*3034Sdougm 3347*3034Sdougm /* 3348*3034Sdougm * remove_all_options(share, proto) 3349*3034Sdougm * 3350*3034Sdougm * Removes all options on a share. 3351*3034Sdougm */ 3352*3034Sdougm 3353*3034Sdougm static void 3354*3034Sdougm remove_all_options(sa_share_t share, char *proto) 3355*3034Sdougm { 3356*3034Sdougm sa_optionset_t optionset; 3357*3034Sdougm sa_security_t security; 3358*3034Sdougm sa_security_t prevsec = NULL; 3359*3034Sdougm 3360*3034Sdougm optionset = sa_get_optionset(share, proto); 3361*3034Sdougm if (optionset != NULL) 3362*3034Sdougm (void) sa_destroy_optionset(optionset); 3363*3034Sdougm for (security = sa_get_security(share, NULL, NULL); 3364*3034Sdougm security != NULL; 3365*3034Sdougm security = sa_get_next_security(security)) { 3366*3034Sdougm char *type; 3367*3034Sdougm /* 3368*3034Sdougm * we walk through the list. prevsec keeps the 3369*3034Sdougm * previous security so we can delete it without 3370*3034Sdougm * destroying the list. 3371*3034Sdougm */ 3372*3034Sdougm if (prevsec != NULL) { 3373*3034Sdougm /* remove the previously seen security */ 3374*3034Sdougm (void) sa_destroy_security(prevsec); 3375*3034Sdougm /* set to NULL so we don't try multiple times */ 3376*3034Sdougm prevsec = NULL; 3377*3034Sdougm } 3378*3034Sdougm type = sa_get_security_attr(security, "type"); 3379*3034Sdougm if (type != NULL) { 3380*3034Sdougm /* 3381*3034Sdougm * if the security matches the specified protocol, we 3382*3034Sdougm * want to remove it. prevsec holds it until either 3383*3034Sdougm * the next pass or we fall out of the loop. 3384*3034Sdougm */ 3385*3034Sdougm if (strcmp(type, proto) == 0) 3386*3034Sdougm prevsec = security; 3387*3034Sdougm sa_free_attr_string(type); 3388*3034Sdougm } 3389*3034Sdougm } 3390*3034Sdougm /* in case there is one left */ 3391*3034Sdougm if (prevsec != NULL) 3392*3034Sdougm (void) sa_destroy_security(prevsec); 3393*3034Sdougm } 3394*3034Sdougm 3395*3034Sdougm 3396*3034Sdougm /* 3397*3034Sdougm * for legacy support, we need to handle the old syntax. This is what 3398*3034Sdougm * we get if sharemgr is called with the name "share" rather than 3399*3034Sdougm * sharemgr. 3400*3034Sdougm */ 3401*3034Sdougm 3402*3034Sdougm static int 3403*3034Sdougm format_legacy_path(char *buff, int buffsize, char *proto, char *cmd) 3404*3034Sdougm { 3405*3034Sdougm int err; 3406*3034Sdougm 3407*3034Sdougm err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd); 3408*3034Sdougm if (err > buffsize) 3409*3034Sdougm return (-1); 3410*3034Sdougm return (0); 3411*3034Sdougm } 3412*3034Sdougm 3413*3034Sdougm 3414*3034Sdougm /* 3415*3034Sdougm * check_legacy_cmd(proto, cmd) 3416*3034Sdougm * 3417*3034Sdougm * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is 3418*3034Sdougm * executable. 3419*3034Sdougm */ 3420*3034Sdougm 3421*3034Sdougm static int 3422*3034Sdougm check_legacy_cmd(char *path) 3423*3034Sdougm { 3424*3034Sdougm struct stat st; 3425*3034Sdougm int ret = 0; 3426*3034Sdougm 3427*3034Sdougm if (stat(path, &st) == 0) { 3428*3034Sdougm if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 3429*3034Sdougm ret = 1; 3430*3034Sdougm } 3431*3034Sdougm return (ret); 3432*3034Sdougm } 3433*3034Sdougm 3434*3034Sdougm /* 3435*3034Sdougm * run_legacy_command(proto, cmd, argv) 3436*3034Sdougm * 3437*3034Sdougm * we know the command exists, so attempt to execute it with all the 3438*3034Sdougm * arguments. This implements full legacy share support for those 3439*3034Sdougm * protocols that don't have plugin providers. 3440*3034Sdougm */ 3441*3034Sdougm 3442*3034Sdougm static int 3443*3034Sdougm run_legacy_command(char *path, char *argv[]) 3444*3034Sdougm { 3445*3034Sdougm int ret; 3446*3034Sdougm 3447*3034Sdougm ret = execv(path, argv); 3448*3034Sdougm if (ret < 0) { 3449*3034Sdougm switch (errno) { 3450*3034Sdougm case EACCES: 3451*3034Sdougm ret = SA_NO_PERMISSION; 3452*3034Sdougm break; 3453*3034Sdougm default: 3454*3034Sdougm ret = SA_SYSTEM_ERR; 3455*3034Sdougm break; 3456*3034Sdougm } 3457*3034Sdougm } 3458*3034Sdougm return (ret); 3459*3034Sdougm } 3460*3034Sdougm 3461*3034Sdougm /* 3462*3034Sdougm * out_share(out, group, proto, options) 3463*3034Sdougm * 3464*3034Sdougm * Display the share information in the format that the "share" 3465*3034Sdougm * command has traditionally used. 3466*3034Sdougm */ 3467*3034Sdougm 3468*3034Sdougm static void 3469*3034Sdougm out_share(FILE *out, sa_group_t group, char *proto, char *options) 3470*3034Sdougm { 3471*3034Sdougm sa_share_t share; 3472*3034Sdougm char resfmt[128]; 3473*3034Sdougm 3474*3034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 3475*3034Sdougm share = sa_get_next_share(share)) { 3476*3034Sdougm char *path; 3477*3034Sdougm char *type; 3478*3034Sdougm char *resource; 3479*3034Sdougm char *description; 3480*3034Sdougm char *groupname; 3481*3034Sdougm char *sharedstate; 3482*3034Sdougm int shared = 1; 3483*3034Sdougm char *soptions; 3484*3034Sdougm 3485*3034Sdougm sharedstate = sa_get_share_attr(share, "shared"); 3486*3034Sdougm path = sa_get_share_attr(share, "path"); 3487*3034Sdougm type = sa_get_share_attr(share, "type"); 3488*3034Sdougm resource = sa_get_share_attr(share, "resource"); 3489*3034Sdougm groupname = sa_get_group_attr(group, "name"); 3490*3034Sdougm 3491*3034Sdougm if (groupname != NULL && strcmp(groupname, "default") == 0) { 3492*3034Sdougm sa_free_attr_string(groupname); 3493*3034Sdougm groupname = NULL; 3494*3034Sdougm } 3495*3034Sdougm description = sa_get_share_description(share); 3496*3034Sdougm soptions = options; 3497*3034Sdougm 3498*3034Sdougm if (sharedstate == NULL) 3499*3034Sdougm shared = 0; 3500*3034Sdougm 3501*3034Sdougm soptions = sa_proto_legacy_format(proto, share, 1); 3502*3034Sdougm 3503*3034Sdougm if (shared) { 3504*3034Sdougm /* only persisting share go here */ 3505*3034Sdougm (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s", 3506*3034Sdougm resource != NULL ? resource : "-", 3507*3034Sdougm groupname != NULL ? "@" : "", 3508*3034Sdougm groupname != NULL ? groupname : ""); 3509*3034Sdougm (void) fprintf(out, "%-14.14s %s %s \"%s\" \n", 3510*3034Sdougm resfmt, 3511*3034Sdougm path, 3512*3034Sdougm (soptions != NULL && strlen(soptions) > 0) ? 3513*3034Sdougm soptions : "rw", 3514*3034Sdougm (description != NULL) ? description : ""); 3515*3034Sdougm } 3516*3034Sdougm 3517*3034Sdougm if (path != NULL) 3518*3034Sdougm sa_free_attr_string(path); 3519*3034Sdougm if (type != NULL) 3520*3034Sdougm sa_free_attr_string(type); 3521*3034Sdougm if (resource != NULL) 3522*3034Sdougm sa_free_attr_string(resource); 3523*3034Sdougm if (groupname != NULL) 3524*3034Sdougm sa_free_attr_string(groupname); 3525*3034Sdougm if (description != NULL) 3526*3034Sdougm sa_free_share_description(description); 3527*3034Sdougm if (sharedstate != NULL) 3528*3034Sdougm sa_free_attr_string(sharedstate); 3529*3034Sdougm if (soptions != NULL && soptions != options) 3530*3034Sdougm sa_format_free(soptions); 3531*3034Sdougm } 3532*3034Sdougm } 3533*3034Sdougm 3534*3034Sdougm /* 3535*3034Sdougm * output_legacy_file(out, proto) 3536*3034Sdougm * 3537*3034Sdougm * Walk all of the groups for the specified protocol and call 3538*3034Sdougm * out_share() to format and write in the format displayed by the 3539*3034Sdougm * "share" command with no arguments. 3540*3034Sdougm */ 3541*3034Sdougm 3542*3034Sdougm static void 3543*3034Sdougm output_legacy_file(FILE *out, char *proto) 3544*3034Sdougm { 3545*3034Sdougm sa_group_t group; 3546*3034Sdougm 3547*3034Sdougm for (group = sa_get_group(NULL); group != NULL; 3548*3034Sdougm group = sa_get_next_group(group)) { 3549*3034Sdougm char *options; 3550*3034Sdougm char *zfs; 3551*3034Sdougm 3552*3034Sdougm /* 3553*3034Sdougm * get default options preformated, being careful to 3554*3034Sdougm * handle legacy shares differently from new style 3555*3034Sdougm * shares. Legacy share have options on the share. 3556*3034Sdougm */ 3557*3034Sdougm 3558*3034Sdougm zfs = sa_get_group_attr(group, "zfs"); 3559*3034Sdougm if (zfs != NULL) { 3560*3034Sdougm sa_group_t zgroup; 3561*3034Sdougm sa_free_attr_string(zfs); 3562*3034Sdougm options = sa_proto_legacy_format(proto, group, 1); 3563*3034Sdougm for (zgroup = sa_get_sub_group(group); zgroup != NULL; 3564*3034Sdougm zgroup = sa_get_next_group(zgroup)) { 3565*3034Sdougm 3566*3034Sdougm /* got a group, so display it */ 3567*3034Sdougm out_share(out, zgroup, proto, options); 3568*3034Sdougm } 3569*3034Sdougm } else { 3570*3034Sdougm options = sa_proto_legacy_format(proto, group, 1); 3571*3034Sdougm out_share(out, group, proto, options); 3572*3034Sdougm } 3573*3034Sdougm if (options != NULL) 3574*3034Sdougm free(options); 3575*3034Sdougm } 3576*3034Sdougm } 3577*3034Sdougm 3578*3034Sdougm int 3579*3034Sdougm sa_legacy_share(int flags, int argc, char *argv[]) 3580*3034Sdougm { 3581*3034Sdougm char *protocol = "nfs"; 3582*3034Sdougm char *options = NULL; 3583*3034Sdougm char *description = NULL; 3584*3034Sdougm char *groupname = NULL; 3585*3034Sdougm char *sharepath = NULL; 3586*3034Sdougm char *resource = NULL; 3587*3034Sdougm char *groupstatus = NULL; 3588*3034Sdougm int persist = SA_SHARE_TRANSIENT; 3589*3034Sdougm int argsused = 0; 3590*3034Sdougm int c; 3591*3034Sdougm int ret = SA_OK; 3592*3034Sdougm int zfs = 0; 3593*3034Sdougm int true_legacy = 0; 3594*3034Sdougm int curtype = SA_SHARE_TRANSIENT; 3595*3034Sdougm char cmd[MAXPATHLEN]; 3596*3034Sdougm #ifdef lint 3597*3034Sdougm flags = flags; 3598*3034Sdougm #endif 3599*3034Sdougm 3600*3034Sdougm while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) { 3601*3034Sdougm switch (c) { 3602*3034Sdougm case 'd': 3603*3034Sdougm description = optarg; 3604*3034Sdougm argsused++; 3605*3034Sdougm break; 3606*3034Sdougm case 'F': 3607*3034Sdougm protocol = optarg; 3608*3034Sdougm if (!sa_valid_protocol(protocol)) { 3609*3034Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 3610*3034Sdougm protocol, "share") == 0 && check_legacy_cmd(cmd)) { 3611*3034Sdougm true_legacy++; 3612*3034Sdougm } else { 3613*3034Sdougm (void) fprintf(stderr, 3614*3034Sdougm gettext("Invalid protocol specified:" 3615*3034Sdougm "%s\n"), 3616*3034Sdougm protocol); 3617*3034Sdougm return (SA_INVALID_PROTOCOL); 3618*3034Sdougm } 3619*3034Sdougm } 3620*3034Sdougm break; 3621*3034Sdougm case 'o': 3622*3034Sdougm options = optarg; 3623*3034Sdougm argsused++; 3624*3034Sdougm break; 3625*3034Sdougm case 'p': 3626*3034Sdougm persist = SA_SHARE_PERMANENT; 3627*3034Sdougm argsused++; 3628*3034Sdougm break; 3629*3034Sdougm case 'h': 3630*3034Sdougm case '?': 3631*3034Sdougm default: 3632*3034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 3633*3034Sdougm sa_get_usage(USAGE_SHARE)); 3634*3034Sdougm return (SA_OK); 3635*3034Sdougm } 3636*3034Sdougm } 3637*3034Sdougm 3638*3034Sdougm /* have the info so construct what is needed */ 3639*3034Sdougm if (!argsused && optind == argc) { 3640*3034Sdougm /* display current info in share format */ 3641*3034Sdougm (void) output_legacy_file(stdout, "nfs"); 3642*3034Sdougm } else { 3643*3034Sdougm sa_group_t group = NULL; 3644*3034Sdougm sa_share_t share; 3645*3034Sdougm char dir[MAXPATHLEN]; 3646*3034Sdougm 3647*3034Sdougm /* we are modifying the configuration */ 3648*3034Sdougm if (optind == argc) { 3649*3034Sdougm (void) fprintf(stderr, gettext("usage: %s\n"), 3650*3034Sdougm sa_get_usage(USAGE_SHARE)); 3651*3034Sdougm return (SA_LEGACY_ERR); 3652*3034Sdougm } 3653*3034Sdougm 3654*3034Sdougm if (true_legacy) { 3655*3034Sdougm /* if still using legacy share/unshare, exec it */ 3656*3034Sdougm ret = run_legacy_command(cmd, argv); 3657*3034Sdougm return (ret); 3658*3034Sdougm } 3659*3034Sdougm 3660*3034Sdougm sharepath = argv[optind++]; 3661*3034Sdougm if (optind < argc) { 3662*3034Sdougm resource = argv[optind]; 3663*3034Sdougm groupname = strchr(resource, '@'); 3664*3034Sdougm if (groupname != NULL) 3665*3034Sdougm *groupname++ = '\0'; 3666*3034Sdougm } 3667*3034Sdougm if (realpath(sharepath, dir) == NULL) 3668*3034Sdougm ret = SA_BAD_PATH; 3669*3034Sdougm else 3670*3034Sdougm sharepath = dir; 3671*3034Sdougm if (ret == SA_OK) { 3672*3034Sdougm share = sa_find_share(sharepath); 3673*3034Sdougm } else { 3674*3034Sdougm share = NULL; 3675*3034Sdougm } 3676*3034Sdougm if (groupname != NULL) { 3677*3034Sdougm ret = SA_NOT_ALLOWED; 3678*3034Sdougm } else if (ret == SA_OK) { 3679*3034Sdougm char *legacygroup = "default"; 3680*3034Sdougm /* 3681*3034Sdougm * the legacy group is always present and zfs groups 3682*3034Sdougm * come and go. zfs shares may be in sub-groups and 3683*3034Sdougm * the zfs share will already be in that group so it 3684*3034Sdougm * isn't an error. 3685*3034Sdougm */ 3686*3034Sdougm if (share != NULL) { 3687*3034Sdougm /* 3688*3034Sdougm * if the share exists, then make sure it is one we 3689*3034Sdougm * want to handle. 3690*3034Sdougm */ 3691*3034Sdougm group = sa_get_parent_group(share); 3692*3034Sdougm } else { 3693*3034Sdougm group = sa_get_group(legacygroup); 3694*3034Sdougm } 3695*3034Sdougm if (group != NULL) { 3696*3034Sdougm groupstatus = group_status(group); 3697*3034Sdougm if (share == NULL) { 3698*3034Sdougm share = sa_add_share(group, sharepath, persist, &ret); 3699*3034Sdougm if (share == NULL && ret == SA_DUPLICATE_NAME) { 3700*3034Sdougm /* could be a ZFS path being started */ 3701*3034Sdougm if (sa_zfs_is_shared(sharepath)) { 3702*3034Sdougm ret = SA_OK; 3703*3034Sdougm group = sa_get_group("zfs"); 3704*3034Sdougm if (group == NULL) { 3705*3034Sdougm /* this shouldn't happen */ 3706*3034Sdougm ret = SA_CONFIG_ERR; 3707*3034Sdougm } 3708*3034Sdougm if (group != NULL) { 3709*3034Sdougm share = sa_add_share(group, sharepath, 3710*3034Sdougm persist, &ret); 3711*3034Sdougm } 3712*3034Sdougm } 3713*3034Sdougm } 3714*3034Sdougm } else { 3715*3034Sdougm /* 3716*3034Sdougm * may want to change persist state, but the 3717*3034Sdougm * important thing is to change options unless 3718*3034Sdougm * this is ZFS where we just want to do the 3719*3034Sdougm * enable since everything is current. 3720*3034Sdougm */ 3721*3034Sdougm if (!sa_zfs_is_shared(sharepath)) { 3722*3034Sdougm char *type; 3723*3034Sdougm remove_all_options(share, protocol); 3724*3034Sdougm type = sa_get_share_attr(share, "type"); 3725*3034Sdougm if (type != NULL && 3726*3034Sdougm strcmp(type, "transient") != 0) { 3727*3034Sdougm curtype = SA_SHARE_PERMANENT; 3728*3034Sdougm } 3729*3034Sdougm if (type != NULL) 3730*3034Sdougm sa_free_attr_string(type); 3731*3034Sdougm if (curtype != persist) { 3732*3034Sdougm (void) sa_set_share_attr(share, "type", 3733*3034Sdougm persist == SA_SHARE_PERMANENT ? 3734*3034Sdougm "persist" : "transient"); 3735*3034Sdougm } 3736*3034Sdougm } else { 3737*3034Sdougm zfs++; 3738*3034Sdougm } 3739*3034Sdougm } 3740*3034Sdougm if (!zfs) { 3741*3034Sdougm /* have a group to hold this share path */ 3742*3034Sdougm if (ret == SA_OK && options != NULL && 3743*3034Sdougm strlen(options) > 0) { 3744*3034Sdougm ret = sa_parse_legacy_options(share, 3745*3034Sdougm options, 3746*3034Sdougm protocol); 3747*3034Sdougm } 3748*3034Sdougm if (ret == SA_OK && description != NULL) 3749*3034Sdougm ret = sa_set_share_description(share, description); 3750*3034Sdougm if (ret == SA_OK && resource != NULL) 3751*3034Sdougm ret = sa_set_share_attr(share, "resource", 3752*3034Sdougm resource); 3753*3034Sdougm } 3754*3034Sdougm if (ret == SA_OK) { 3755*3034Sdougm if (strcmp(groupstatus, "enabled") == 0) 3756*3034Sdougm ret = sa_enable_share(share, protocol); 3757*3034Sdougm if (ret == SA_OK && persist == SA_SHARE_PERMANENT) { 3758*3034Sdougm (void) sa_update_legacy(share, protocol); 3759*3034Sdougm } 3760*3034Sdougm if (ret == SA_OK) 3761*3034Sdougm ret = sa_update_config(); 3762*3034Sdougm } 3763*3034Sdougm } else { 3764*3034Sdougm ret = SA_SYSTEM_ERR; 3765*3034Sdougm } 3766*3034Sdougm } 3767*3034Sdougm } 3768*3034Sdougm if (ret != SA_OK) { 3769*3034Sdougm (void) fprintf(stderr, gettext("Could not share: %s: %s\n"), 3770*3034Sdougm sharepath, sa_errorstr(ret)); 3771*3034Sdougm ret = SA_LEGACY_ERR; 3772*3034Sdougm 3773*3034Sdougm } 3774*3034Sdougm return (ret); 3775*3034Sdougm } 3776*3034Sdougm 3777*3034Sdougm /* 3778*3034Sdougm * sa_legacy_unshare(flags, argc, argv) 3779*3034Sdougm * 3780*3034Sdougm * Implements the original unshare command. 3781*3034Sdougm */ 3782*3034Sdougm 3783*3034Sdougm int 3784*3034Sdougm sa_legacy_unshare(int flags, int argc, char *argv[]) 3785*3034Sdougm { 3786*3034Sdougm char *protocol = "nfs"; /* for now */ 3787*3034Sdougm char *options = NULL; 3788*3034Sdougm char *sharepath = NULL; 3789*3034Sdougm int persist = SA_SHARE_TRANSIENT; 3790*3034Sdougm int argsused = 0; 3791*3034Sdougm int c; 3792*3034Sdougm int ret = SA_OK; 3793*3034Sdougm int true_legacy = 0; 3794*3034Sdougm char cmd[MAXPATHLEN]; 3795*3034Sdougm #ifdef lint 3796*3034Sdougm flags = flags; 3797*3034Sdougm options = options; 3798*3034Sdougm #endif 3799*3034Sdougm 3800*3034Sdougm while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) { 3801*3034Sdougm switch (c) { 3802*3034Sdougm case 'h': 3803*3034Sdougm case '?': 3804*3034Sdougm break; 3805*3034Sdougm case 'F': 3806*3034Sdougm protocol = optarg; 3807*3034Sdougm if (!sa_valid_protocol(protocol)) { 3808*3034Sdougm if (format_legacy_path(cmd, MAXPATHLEN, 3809*3034Sdougm protocol, "unshare") == 0 && 3810*3034Sdougm check_legacy_cmd(cmd)) { 3811*3034Sdougm true_legacy++; 3812*3034Sdougm } else { 3813*3034Sdougm (void) printf(gettext("Invalid file system name\n")); 3814*3034Sdougm return (SA_INVALID_PROTOCOL); 3815*3034Sdougm } 3816*3034Sdougm } 3817*3034Sdougm break; 3818*3034Sdougm case 'o': 3819*3034Sdougm options = optarg; 3820*3034Sdougm argsused++; 3821*3034Sdougm break; 3822*3034Sdougm case 'p': 3823*3034Sdougm persist = SA_SHARE_PERMANENT; 3824*3034Sdougm argsused++; 3825*3034Sdougm break; 3826*3034Sdougm default: 3827*3034Sdougm (void) printf(gettext("usage: %s\n"), 3828*3034Sdougm sa_get_usage(USAGE_UNSHARE)); 3829*3034Sdougm return (SA_OK); 3830*3034Sdougm } 3831*3034Sdougm } 3832*3034Sdougm 3833*3034Sdougm /* have the info so construct what is needed */ 3834*3034Sdougm if (optind == argc || (optind + 1) < argc) { 3835*3034Sdougm ret = SA_SYNTAX_ERR; 3836*3034Sdougm } else { 3837*3034Sdougm sa_share_t share; 3838*3034Sdougm char dir[MAXPATHLEN]; 3839*3034Sdougm if (true_legacy) { 3840*3034Sdougm /* if still using legacy share/unshare, exec it */ 3841*3034Sdougm ret = run_legacy_command(cmd, argv); 3842*3034Sdougm return (ret); 3843*3034Sdougm } 3844*3034Sdougm sharepath = argv[optind++]; 3845*3034Sdougm if (realpath(sharepath, dir) == NULL) { 3846*3034Sdougm ret = SA_NO_SUCH_PATH; 3847*3034Sdougm } else { 3848*3034Sdougm sharepath = dir; 3849*3034Sdougm share = sa_find_share(sharepath); 3850*3034Sdougm if (share != NULL) { 3851*3034Sdougm ret = sa_disable_share(share, protocol); 3852*3034Sdougm if (ret == SA_OK) { 3853*3034Sdougm if (persist == SA_SHARE_PERMANENT) 3854*3034Sdougm ret = sa_remove_share(share); 3855*3034Sdougm ret = sa_update_config(); 3856*3034Sdougm } 3857*3034Sdougm } else { 3858*3034Sdougm ret = SA_NOT_SHARED; 3859*3034Sdougm } 3860*3034Sdougm } 3861*3034Sdougm } 3862*3034Sdougm switch (ret) { 3863*3034Sdougm default: 3864*3034Sdougm (void) printf("%s: %s\n", sharepath, sa_errorstr(ret)); 3865*3034Sdougm ret = SA_LEGACY_ERR; 3866*3034Sdougm break; 3867*3034Sdougm case SA_SYNTAX_ERR: 3868*3034Sdougm (void) printf(gettext("usage: %s\n"), 3869*3034Sdougm sa_get_usage(USAGE_UNSHARE)); 3870*3034Sdougm break; 3871*3034Sdougm case SA_OK: 3872*3034Sdougm break; 3873*3034Sdougm } 3874*3034Sdougm return (ret); 3875*3034Sdougm } 3876*3034Sdougm 3877*3034Sdougm /* 3878*3034Sdougm * common commands that implement the sub-commands used by all 3879*3034Sdougm * protcols. The entries are found via the lookup command 3880*3034Sdougm */ 3881*3034Sdougm 3882*3034Sdougm static sa_command_t commands[] = { 3883*3034Sdougm {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET}, 3884*3034Sdougm {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION}, 3885*3034Sdougm {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION}, 3886*3034Sdougm {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION}, 3887*3034Sdougm {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION}, 3888*3034Sdougm {"list", 0, sa_list, USAGE_LIST}, 3889*3034Sdougm {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET}, 3890*3034Sdougm {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET}, 3891*3034Sdougm {"set", 0, sa_set, USAGE_SET, SVC_SET}, 3892*3034Sdougm {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET}, 3893*3034Sdougm {"show", 0, sa_show, USAGE_SHOW}, 3894*3034Sdougm {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION}, 3895*3034Sdougm {"start", CMD_NODISPLAY, sa_start_group, USAGE_START, 3896*3034Sdougm SVC_SET|SVC_ACTION}, 3897*3034Sdougm {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION}, 3898*3034Sdougm {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET}, 3899*3034Sdougm {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION}, 3900*3034Sdougm {NULL, 0, NULL, NULL} 3901*3034Sdougm }; 3902*3034Sdougm 3903*3034Sdougm static char * 3904*3034Sdougm sa_get_usage(sa_usage_t index) 3905*3034Sdougm { 3906*3034Sdougm char *ret = NULL; 3907*3034Sdougm switch (index) { 3908*3034Sdougm case USAGE_ADD_SHARE: 3909*3034Sdougm ret = gettext("add-share [-nth] [-r resource-name] " 3910*3034Sdougm "[-d \"description text\"] -s sharepath group"); 3911*3034Sdougm break; 3912*3034Sdougm case USAGE_CREATE: 3913*3034Sdougm ret = gettext("create [-nvh] [-P proto [-p property=value]] group"); 3914*3034Sdougm break; 3915*3034Sdougm case USAGE_DELETE: 3916*3034Sdougm ret = gettext("delete [-nvh] [-P proto] [-f] group"); 3917*3034Sdougm break; 3918*3034Sdougm case USAGE_DISABLE: 3919*3034Sdougm ret = gettext("disable [-nvh] {-a | group ...}"); 3920*3034Sdougm break; 3921*3034Sdougm case USAGE_ENABLE: 3922*3034Sdougm ret = gettext("enable [-nvh] {-a | group ...}"); 3923*3034Sdougm break; 3924*3034Sdougm case USAGE_LIST: 3925*3034Sdougm ret = gettext("list [-vh] [-P proto]"); 3926*3034Sdougm break; 3927*3034Sdougm case USAGE_MOVE_SHARE: 3928*3034Sdougm ret = gettext("move-share [-nvh] -s sharepath destination-group"); 3929*3034Sdougm break; 3930*3034Sdougm case USAGE_REMOVE_SHARE: 3931*3034Sdougm ret = gettext("remove-share [-fnvh] -s sharepath group"); 3932*3034Sdougm break; 3933*3034Sdougm case USAGE_SET: 3934*3034Sdougm ret = gettext("set [-nvh] -P proto [-S optspace] " 3935*3034Sdougm "[-p property=value]* [-s sharepath] group"); 3936*3034Sdougm break; 3937*3034Sdougm case USAGE_SET_SECURITY: 3938*3034Sdougm ret = gettext("set-security [-nvh] -P proto -S security-type " 3939*3034Sdougm "[-p property=value]* group"); 3940*3034Sdougm break; 3941*3034Sdougm case USAGE_SET_SHARE: 3942*3034Sdougm ret = gettext("set-share [-nh] [-r resource] " 3943*3034Sdougm "[-d \"description text\"] -s sharepath group"); 3944*3034Sdougm break; 3945*3034Sdougm case USAGE_SHOW: 3946*3034Sdougm ret = gettext("show [-pvxh] [-P proto] [group ...]"); 3947*3034Sdougm break; 3948*3034Sdougm case USAGE_SHARE: 3949*3034Sdougm ret = gettext("share [-F fstype] [-p] [-o optionlist]" 3950*3034Sdougm "[-d description] [pathname [resourcename]]"); 3951*3034Sdougm break; 3952*3034Sdougm case USAGE_START: 3953*3034Sdougm ret = gettext("start [-vh] [-P proto] {-a | group ...}"); 3954*3034Sdougm break; 3955*3034Sdougm case USAGE_STOP: 3956*3034Sdougm ret = gettext("stop [-vh] [-P proto] {-a | group ...}"); 3957*3034Sdougm break; 3958*3034Sdougm case USAGE_UNSET: 3959*3034Sdougm ret = gettext("unset [-nvh] -P proto [-S optspace] " 3960*3034Sdougm "[-p property]* group"); 3961*3034Sdougm break; 3962*3034Sdougm case USAGE_UNSET_SECURITY: 3963*3034Sdougm ret = gettext("unset-security [-nvh] -P proto -S security-type " 3964*3034Sdougm "[-p property]* group"); 3965*3034Sdougm break; 3966*3034Sdougm case USAGE_UNSHARE: 3967*3034Sdougm ret = gettext("unshare [-F fstype] [-p] [-o optionlist] sharepath"); 3968*3034Sdougm break; 3969*3034Sdougm } 3970*3034Sdougm return (ret); 3971*3034Sdougm } 3972*3034Sdougm 3973*3034Sdougm /* 3974*3034Sdougm * sa_lookup(cmd, proto) 3975*3034Sdougm * 3976*3034Sdougm * Lookup the sub-command. proto isn't currently used, but it may 3977*3034Sdougm * eventually provide a way to provide protocol specific sub-commands. 3978*3034Sdougm */ 3979*3034Sdougm 3980*3034Sdougm sa_command_t * 3981*3034Sdougm sa_lookup(char *cmd, char *proto) 3982*3034Sdougm { 3983*3034Sdougm int i; 3984*3034Sdougm size_t len; 3985*3034Sdougm #ifdef lint 3986*3034Sdougm proto = proto; 3987*3034Sdougm #endif 3988*3034Sdougm 3989*3034Sdougm len = strlen(cmd); 3990*3034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 3991*3034Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 3992*3034Sdougm return (&commands[i]); 3993*3034Sdougm } 3994*3034Sdougm return (NULL); 3995*3034Sdougm } 3996*3034Sdougm 3997*3034Sdougm void 3998*3034Sdougm sub_command_help(char *proto) 3999*3034Sdougm { 4000*3034Sdougm int i; 4001*3034Sdougm #ifdef lint 4002*3034Sdougm proto = proto; 4003*3034Sdougm #endif 4004*3034Sdougm 4005*3034Sdougm (void) printf(gettext("\tsub-commands:\n")); 4006*3034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 4007*3034Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 4008*3034Sdougm (void) printf("\t%s\n", 4009*3034Sdougm sa_get_usage((sa_usage_t)commands[i].cmdidx)); 4010*3034Sdougm } 4011*3034Sdougm } 4012