Print this page
    
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/dfs.cmds/sharemgr/commands.c
          +++ new/usr/src/cmd/dfs.cmds/sharemgr/commands.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
       25 + */
       26 +
       27 +/*
  25   28   * Copyright 2012 Milan Jurik. All rights reserved.
       29 + * Copyright 2018 Nexenta Systems, Inc.
  26   30   * Copyright 2019, Joyent, Inc.
  27   31   */
  28   32  
  29   33  #include <sys/types.h>
  30   34  #include <sys/stat.h>
  31   35  #include <fcntl.h>
  32   36  #include <stdlib.h>
  33   37  #include <stdio.h>
  34   38  #include <string.h>
  35   39  #include <ctype.h>
  36   40  #include <unistd.h>
  37   41  #include <getopt.h>
  38   42  #include <utmpx.h>
  39   43  #include <pwd.h>
  40   44  #include <auth_attr.h>
  41   45  #include <secdb.h>
  42   46  #include <sys/param.h>
  43   47  #include <sys/stat.h>
  44   48  #include <errno.h>
  45   49  
  46   50  #include <libshare.h>
  47   51  #include "sharemgr.h"
  48   52  #include <libscf.h>
  49   53  #include <libxml/tree.h>
  50   54  #include <libintl.h>
  51   55  #include <assert.h>
  52   56  #include <iconv.h>
  53   57  #include <langinfo.h>
  54   58  #include <dirent.h>
  55   59  
  56   60  static char *sa_get_usage(sa_usage_t);
  57   61  
  58   62  /*
  59   63   * Implementation of the common sub-commands supported by sharemgr.
  60   64   * A number of helper functions are also included.
  61   65   */
  62   66  
  63   67  /*
  64   68   * has_protocol(group, proto)
  65   69   *      If the group has an optionset with the specified protocol,
  66   70   *      return true (1) otherwise false (0).
  67   71   */
  68   72  static int
  69   73  has_protocol(sa_group_t group, char *protocol)
  70   74  {
  71   75          sa_optionset_t optionset;
  72   76          int result = 0;
  73   77  
  74   78          optionset = sa_get_optionset(group, protocol);
  75   79          if (optionset != NULL) {
  76   80                  result++;
  77   81          }
  78   82          return (result);
  79   83  }
  80   84  
  81   85  /*
  82   86   * validresource(name)
  83   87   *
  84   88   * Check that name only has valid characters in it. The current valid
  85   89   * set are the printable characters but not including:
  86   90   *      " / \ [ ] : | < > + ; , ? * = \t
  87   91   * Note that space is included and there is a maximum length.
  88   92   */
  89   93  static int
  90   94  validresource(const char *name)
  91   95  {
  92   96          const char *cp;
  93   97          size_t len;
  94   98  
  95   99          if (name == NULL)
  96  100                  return (B_FALSE);
  97  101  
  98  102          len = strlen(name);
  99  103          if (len == 0 || len > SA_MAX_RESOURCE_NAME)
 100  104                  return (B_FALSE);
 101  105  
 102  106          if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
 103  107                  return (B_FALSE);
 104  108          }
 105  109  
 106  110          for (cp = name; *cp != '\0'; cp++)
 107  111                  if (iscntrl(*cp))
 108  112                          return (B_FALSE);
 109  113  
 110  114          return (B_TRUE);
 111  115  }
 112  116  
 113  117  /*
 114  118   * conv_to_utf8(input)
 115  119   *
 116  120   * Convert the input string to utf8 from the current locale.  If the
 117  121   * conversion fails, use the current locale, it is likely close
 118  122   * enough. For example, the "C" locale is a subset of utf-8. The
 119  123   * return value may be a new string or the original input string.
 120  124   */
 121  125  
 122  126  static char *
 123  127  conv_to_utf8(char *input)
 124  128  {
 125  129          iconv_t cd;
 126  130          char *inval = input;
 127  131          char *output = input;
 128  132          char *outleft;
 129  133          char *curlocale;
 130  134          size_t bytesleft;
 131  135          size_t size;
 132  136          size_t osize;
 133  137          static int warned = 0;
 134  138  
 135  139          curlocale = nl_langinfo(CODESET);
 136  140          if (curlocale == NULL)
 137  141                  curlocale = "C";
 138  142          cd = iconv_open("UTF-8", curlocale);
 139  143          if (cd != NULL && cd != (iconv_t)-1) {
 140  144                  size = strlen(input);
 141  145                  /* Assume worst case of characters expanding to 4 bytes. */
 142  146                  bytesleft = size * 4;
 143  147                  output = calloc(bytesleft, 1);
 144  148                  if (output != NULL) {
 145  149                          outleft = output;
 146  150                          /* inval can be modified on return */
 147  151                          osize = iconv(cd, (const char **)&inval, &size,
 148  152                              &outleft, &bytesleft);
 149  153                          if (osize == (size_t)-1 || size != 0) {
 150  154                                  free(output);
 151  155                                  output = input;
 152  156                          }
 153  157                  } else {
 154  158                          /* Need to return something. */
 155  159                          output = input;
 156  160                  }
 157  161                  (void) iconv_close(cd);
 158  162          } else {
 159  163                  if (!warned)
 160  164                          (void) fprintf(stderr,
 161  165                              gettext("Cannot convert to UTF-8 from %s\n"),
 162  166                              curlocale ? curlocale : gettext("unknown"));
 163  167                  warned = 1;
 164  168          }
 165  169          return (output);
 166  170  }
 167  171  
 168  172  /*
 169  173   * conv_from(input)
 170  174   *
 171  175   * Convert the input string from utf8 to current locale.  If the
 172  176   * conversion isn't supported, just use as is. The return value may be
 173  177   * a new string or the original input string.
 174  178   */
 175  179  
 176  180  static char *
 177  181  conv_from_utf8(char *input)
 178  182  {
 179  183          iconv_t cd;
 180  184          char *output = input;
 181  185          char *inval = input;
 182  186          char *outleft;
 183  187          char *curlocale;
 184  188          size_t bytesleft;
 185  189          size_t size;
 186  190          size_t osize;
 187  191          static int warned = 0;
 188  192  
 189  193          curlocale = nl_langinfo(CODESET);
 190  194          if (curlocale == NULL)
 191  195                  curlocale = "C";
 192  196          cd = iconv_open(curlocale, "UTF-8");
 193  197          if (cd != NULL && cd != (iconv_t)-1) {
 194  198                  size = strlen(input);
 195  199                  /* Assume worst case of characters expanding to 4 bytes. */
 196  200                  bytesleft = size * 4;
 197  201                  output = calloc(bytesleft, 1);
 198  202                  if (output != NULL) {
 199  203                          outleft = output;
 200  204                          osize = iconv(cd, (const char **)&inval, &size,
 201  205                              &outleft, &bytesleft);
 202  206                          if (osize == (size_t)-1 || size != 0)
 203  207                                  output = input;
 204  208                  } else {
 205  209                          /* Need to return something. */
 206  210                          output = input;
 207  211                  }
 208  212                  (void) iconv_close(cd);
 209  213          } else {
 210  214                  if (!warned)
 211  215                          (void) fprintf(stderr,
 212  216                              gettext("Cannot convert to %s from UTF-8\n"),
 213  217                              curlocale ? curlocale : gettext("unknown"));
 214  218                  warned = 1;
 215  219          }
 216  220          return (output);
 217  221  }
 218  222  
 219  223  /*
 220  224   * print_rsrc_desc(resource, sharedesc)
 221  225   *
 222  226   * Print the resource description string after converting from UTF8 to
 223  227   * the current locale. If sharedesc is not NULL and there is no
 224  228   * description on the resource, use sharedesc. sharedesc will already
 225  229   * be converted to UTF8.
 226  230   */
 227  231  
 228  232  static void
 229  233  print_rsrc_desc(sa_resource_t resource, char *sharedesc)
 230  234  {
 231  235          char *description;
 232  236          char *desc;
 233  237  
 234  238          if (resource == NULL)
 235  239                  return;
 236  240  
 237  241          description = sa_get_resource_description(resource);
 238  242          if (description != NULL) {
 239  243                  desc = conv_from_utf8(description);
 240  244                  if (desc != description) {
 241  245                          sa_free_share_description(description);
 242  246                          description = desc;
 243  247                  }
 244  248          } else if (sharedesc != NULL) {
 245  249                  description = strdup(sharedesc);
 246  250          }
 247  251          if (description != NULL) {
 248  252                  (void) printf("\t\"%s\"", description);
 249  253                  sa_free_share_description(description);
 250  254          }
 251  255  }
 252  256  
 253  257  /*
 254  258   * set_resource_desc(share, description)
 255  259   *
 256  260   * Set the share description value after converting the description
 257  261   * string to UTF8 from the current locale.
 258  262   */
 259  263  
 260  264  static int
 261  265  set_resource_desc(sa_share_t share, char *description)
 262  266  {
 263  267          char *desc;
 264  268          int ret;
 265  269  
 266  270          desc = conv_to_utf8(description);
 267  271          ret = sa_set_resource_description(share, desc);
 268  272          if (description != desc)
 269  273                  sa_free_share_description(desc);
 270  274          return (ret);
 271  275  }
 272  276  
 273  277  /*
 274  278   * set_share_desc(share, description)
 275  279   *
 276  280   * Set the resource description value after converting the description
 277  281   * string to UTF8 from the current locale.
 278  282   */
 279  283  
 280  284  static int
 281  285  set_share_desc(sa_share_t share, char *description)
 282  286  {
 283  287          char *desc;
 284  288          int ret;
 285  289  
 286  290          desc = conv_to_utf8(description);
 287  291          ret = sa_set_share_description(share, desc);
 288  292          if (description != desc)
 289  293                  sa_free_share_description(desc);
 290  294          return (ret);
 291  295  }
 292  296  
 293  297  /*
 294  298   * add_list(list, item, data, proto)
 295  299   *      Adds a new list member that points holds item in the list.
 296  300   *      If list is NULL, it starts a new list.  The function returns
 297  301   *      the first member of the list.
 298  302   */
 299  303  struct list *
 300  304  add_list(struct list *listp, void *item, void *data, char *proto)
 301  305  {
 302  306          struct list *new, *tmp;
 303  307  
 304  308          new = malloc(sizeof (struct list));
 305  309          if (new != NULL) {
 306  310                  new->next = NULL;
 307  311                  new->item = item;
 308  312                  new->itemdata = data;
 309  313                  new->proto = proto;
 310  314          } else {
 311  315                  return (listp);
 312  316          }
 313  317  
 314  318          if (listp == NULL)
 315  319                  return (new);
 316  320  
 317  321          for (tmp = listp; tmp->next != NULL; tmp = tmp->next) {
 318  322                  /* get to end of list */
 319  323          }
 320  324          tmp->next = new;
 321  325          return (listp);
 322  326  }
 323  327  
 324  328  /*
 325  329   * free_list(list)
 326  330   *      Given a list, free all the members of the list;
 327  331   */
 328  332  static void
 329  333  free_list(struct list *listp)
 330  334  {
 331  335          struct list *tmp;
 332  336          while (listp != NULL) {
 333  337                  tmp = listp;
 334  338                  listp = listp->next;
 335  339                  free(tmp);
 336  340          }
 337  341  }
 338  342  
 339  343  /*
 340  344   * check_authorization(instname, which)
 341  345   *
 342  346   * Checks to see if the specific type of authorization in which is
 343  347   * enabled for the user in this SMF service instance.
 344  348   */
 345  349  
 346  350  static int
 347  351  check_authorization(char *instname, int which)
 348  352  {
 349  353          scf_handle_t *handle = NULL;
 350  354          scf_simple_prop_t *prop = NULL;
 351  355          char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
 352  356          char *authstr = NULL;
 353  357          ssize_t numauths;
 354  358          int ret = B_TRUE;
 355  359          uid_t uid;
 356  360          struct passwd *pw = NULL;
 357  361  
 358  362          uid = getuid();
 359  363          pw = getpwuid(uid);
 360  364          if (pw == NULL) {
 361  365                  ret = B_FALSE;
 362  366          } else {
 363  367                  /*
 364  368                   * Since names are restricted to SA_MAX_NAME_LEN won't
 365  369                   * overflow.
 366  370                   */
 367  371                  (void) snprintf(svcstring, sizeof (svcstring), "%s:%s",
 368  372                      SA_SVC_FMRI_BASE, instname);
 369  373                  handle = scf_handle_create(SCF_VERSION);
 370  374                  if (handle != NULL) {
 371  375                          if (scf_handle_bind(handle) == 0) {
 372  376                                  switch (which) {
 373  377                                  case SVC_SET:
 374  378                                          prop = scf_simple_prop_get(handle,
 375  379                                              svcstring, "general",
 376  380                                              SVC_AUTH_VALUE);
 377  381                                          break;
 378  382                                  case SVC_ACTION:
 379  383                                          prop = scf_simple_prop_get(handle,
 380  384                                              svcstring, "general",
 381  385                                              SVC_AUTH_ACTION);
 382  386                                          break;
 383  387                                  }
 384  388                          }
 385  389                  }
 386  390          }
 387  391          /* make sure we have an authorization string property */
 388  392          if (prop != NULL) {
 389  393                  int i;
 390  394                  numauths = scf_simple_prop_numvalues(prop);
 391  395                  for (ret = 0, i = 0; i < numauths; i++) {
 392  396                          authstr = scf_simple_prop_next_astring(prop);
 393  397                          if (authstr != NULL) {
 394  398                                  /* check if this user has one of the strings */
 395  399                                  if (chkauthattr(authstr, pw->pw_name)) {
 396  400                                          ret = 1;
 397  401                                          break;
 398  402                                  }
 399  403                          }
 400  404                  }
 401  405                  endauthattr();
 402  406                  scf_simple_prop_free(prop);
 403  407          } else {
 404  408                  /* no authorization string defined */
 405  409                  ret = 0;
 406  410          }
 407  411          if (handle != NULL)
 408  412                  scf_handle_destroy(handle);
 409  413          return (ret);
 410  414  }
 411  415  
 412  416  /*
 413  417   * check_authorizations(instname, flags)
 414  418   *
 415  419   * check all the needed authorizations for the user in this service
 416  420   * instance. Return value of 1(true) or 0(false) indicates whether
 417  421   * there are authorizations for the user or not.
 418  422   */
 419  423  
 420  424  static int
 421  425  check_authorizations(char *instname, int flags)
 422  426  {
 423  427          int ret1 = 0;
 424  428          int ret2 = 0;
 425  429          int ret;
 426  430  
 427  431          if (flags & SVC_SET)
 428  432                  ret1 = check_authorization(instname, SVC_SET);
 429  433          if (flags & SVC_ACTION)
 430  434                  ret2 = check_authorization(instname, SVC_ACTION);
 431  435          switch (flags) {
 432  436          case SVC_ACTION:
 433  437                  ret = ret2;
 434  438                  break;
 435  439          case SVC_SET:
 436  440                  ret = ret1;
 437  441                  break;
 438  442          case SVC_ACTION|SVC_SET:
 439  443                  ret = ret1 & ret2;
 440  444                  break;
 441  445          default:
 442  446                  /* if not flags set, we assume we don't need authorizations */
 443  447                  ret = 1;
 444  448          }
 445  449          return (ret);
 446  450  }
 447  451  
 448  452  /*
 449  453   * notify_or_enable_share(share, protocol)
 450  454   *
 451  455   * Since some protocols don't want an "enable" when properties change,
 452  456   * this function will use the protocol specific notify function
 453  457   * first. If that fails, it will then attempt to use the
 454  458   * sa_enable_share().  "protocol" is the protocol that was specified
 455  459   * on the command line.
 456  460   */
 457  461  static void
 458  462  notify_or_enable_share(sa_share_t share, char *protocol)
 459  463  {
 460  464          sa_group_t group;
 461  465          sa_optionset_t opt;
 462  466          int ret = SA_OK;
 463  467          char *path;
 464  468          char *groupproto;
 465  469          sa_share_t parent = share;
 466  470  
 467  471          /* If really a resource, get parent share */
 468  472          if (!sa_is_share(share)) {
 469  473                  parent = sa_get_resource_parent((sa_resource_t)share);
 470  474          }
 471  475  
 472  476          /*
 473  477           * Now that we've got a share in "parent", make sure it has a path.
 474  478           */
 475  479          path = sa_get_share_attr(parent, "path");
 476  480          if (path == NULL)
 477  481                  return;
 478  482  
 479  483          group = sa_get_parent_group(parent);
 480  484  
 481  485          if (group == NULL) {
 482  486                  sa_free_attr_string(path);
 483  487                  return;
 484  488          }
 485  489          for (opt = sa_get_optionset(group, NULL);
 486  490              opt != NULL;
 487  491              opt = sa_get_next_optionset(opt)) {
 488  492                  groupproto = sa_get_optionset_attr(opt, "type");
 489  493                  if (groupproto == NULL ||
 490  494                      (protocol != NULL && strcmp(groupproto, protocol) != 0)) {
 491  495                          if (groupproto != NULL)
 492  496                                  sa_free_attr_string(groupproto);
 493  497                          continue;
 494  498                  }
 495  499                  if (sa_is_share(share)) {
 496  500                          if ((ret = sa_proto_change_notify(share,
 497  501                              groupproto)) != SA_OK) {
 498  502                                  ret = sa_enable_share(share, groupproto);
 499  503                                  if (ret != SA_OK) {
 500  504                                          (void) printf(
 501  505                                              gettext("Could not reenable"
 502  506                                              " share %s: %s\n"),
 503  507                                              path, sa_errorstr(ret));
 504  508                                  }
 505  509                          }
 506  510                  } else {
 507  511                          /* Must be a resource */
 508  512                          if ((ret = sa_proto_notify_resource(share,
 509  513                              groupproto)) != SA_OK) {
 510  514                                  ret = sa_enable_resource(share, groupproto);
 511  515                                  if (ret != SA_OK) {
 512  516                                          (void) printf(
 513  517                                              gettext("Could not "
 514  518                                              "reenable resource %s: "
 515  519                                              "%s\n"), path,
 516  520                                              sa_errorstr(ret));
 517  521                                  }
 518  522                          }
 519  523                  }
 520  524                  sa_free_attr_string(groupproto);
 521  525          }
 522  526          sa_free_attr_string(path);
 523  527  }
 524  528  
 525  529  /*
 526  530   * enable_group(group, updateproto, notify, proto)
 527  531   *
 528  532   * enable all the shares in the specified group. This is a helper for
 529  533   * enable_all_groups in order to simplify regular and subgroup (zfs)
 530  534   * enabling. Group has already been checked for non-NULL. If notify
 531  535   * is non-zero, attempt to use the notify interface rather than
 532  536   * enable.
 533  537   */
 534  538  static void
 535  539  enable_group(sa_group_t group, char *updateproto, int notify, char *proto)
 536  540  {
 537  541          sa_share_t share;
 538  542  
 539  543          /* If the protocol isn't enabled for this group skip it */
 540  544          if (!has_protocol(group, proto))
 541  545                  return;
 542  546  
 543  547          for (share = sa_get_share(group, NULL);
 544  548              share != NULL;
 545  549              share = sa_get_next_share(share)) {
 546  550                  if (updateproto != NULL)
 547  551                          (void) sa_update_legacy(share, updateproto);
 548  552                  if (notify)
 549  553                          notify_or_enable_share(share, proto);
 550  554                  else
 551  555                          (void) sa_enable_share(share, proto);
 552  556          }
 553  557  }
 554  558  
 555  559  /*
 556  560   * isenabled(group)
 557  561   *
 558  562   * Returns B_TRUE if the group is enabled or B_FALSE if it isn't.
 559  563   * Moved to separate function to reduce clutter in the code.
 560  564   */
 561  565  
 562  566  static int
 563  567  isenabled(sa_group_t group)
 564  568  {
 565  569          char *state;
 566  570          int ret = B_FALSE;
 567  571  
 568  572          if (group != NULL) {
 569  573                  state = sa_get_group_attr(group, "state");
 570  574                  if (state != NULL) {
 571  575  
 572  576                          if (strcmp(state, "enabled") == 0)
 573  577                                  ret = B_TRUE;
 574  578                          sa_free_attr_string(state);
 575  579                  }
 576  580          }
 577  581          return (ret);
 578  582  }
 579  583  
 580  584  /*
 581  585   * enable_all_groups(list, setstate, online, updateproto)
 582  586   *
 583  587   * Given a list of groups, enable each one found.  If updateproto is
 584  588   * not NULL, then update all the shares for the protocol that was
 585  589   * passed in. If enable is non-zero, tell enable_group to try the
 586  590   * notify interface since this is a property change.
 587  591   */
 588  592  static int
 589  593  enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
 590  594      int online, char *updateproto, int enable)
 591  595  {
 592  596          int ret;
 593  597          char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
 594  598          char *state;
 595  599          char *name;
 596  600          char *zfs = NULL;
 597  601          sa_group_t group;
 598  602          sa_group_t subgroup;
 599  603  
 600  604          for (ret = SA_OK; work != NULL; work = work->next) {
 601  605                  group = (sa_group_t)work->item;
 602  606  
 603  607                  /*
 604  608                   * If setstate == TRUE, then make sure to set
 605  609                   * enabled. This needs to be done here in order for
 606  610                   * the isenabled check to succeed on a newly enabled
 607  611                   * group.
 608  612                   */
 609  613                  if (setstate == B_TRUE) {
 610  614                          ret = sa_set_group_attr(group, "state", "enabled");
 611  615                          if (ret != SA_OK)
 612  616                                  break;
 613  617                  }
 614  618  
 615  619                  /*
 616  620                   * Check to see if group is enabled. If it isn't, skip
 617  621                   * the rest.  We don't want shares starting if the
 618  622                   * group is disabled. The properties may have been
 619  623                   * updated, but there won't be a change until the
 620  624                   * group is enabled.
 621  625                   */
 622  626                  if (!isenabled(group))
 623  627                          continue;
 624  628  
 625  629                  /* if itemdata != NULL then a single share */
 626  630                  if (work->itemdata != NULL) {
 627  631                          if (enable) {
 628  632                                  if (work->itemdata != NULL)
 629  633                                          notify_or_enable_share(work->itemdata,
 630  634                                              updateproto);
 631  635                                  else
 632  636                                          ret = SA_CONFIG_ERR;
 633  637                          } else {
 634  638                                  if (sa_is_share(work->itemdata)) {
 635  639                                          ret = sa_enable_share(
 636  640                                              (sa_share_t)work->itemdata,
 637  641                                              updateproto);
 638  642                                  } else {
 639  643                                          ret = sa_enable_resource(
 640  644                                              (sa_resource_t)work->itemdata,
 641  645                                              updateproto);
 642  646                                  }
 643  647                          }
 644  648                  }
 645  649                  if (ret != SA_OK)
 646  650                          break;
 647  651  
 648  652                  /* if itemdata == NULL then the whole group */
 649  653                  if (work->itemdata == NULL) {
 650  654                          zfs = sa_get_group_attr(group, "zfs");
 651  655                          /*
 652  656                           * If the share is managed by ZFS, don't
 653  657                           * update any of the protocols since ZFS is
 654  658                           * handling this.  Updateproto will contain
 655  659                           * the name of the protocol that we want to
 656  660                           * update legacy files for.
 657  661                           */
 658  662                          enable_group(group, zfs == NULL ? updateproto : NULL,
 659  663                              enable, work->proto);
 660  664                          if (zfs != NULL)
 661  665                                  sa_free_attr_string(zfs);
 662  666  
 663  667                          for (subgroup = sa_get_sub_group(group);
 664  668                              subgroup != NULL;
 665  669                              subgroup = sa_get_next_group(subgroup)) {
 666  670                                  /* never update legacy for ZFS subgroups */
 667  671                                  enable_group(subgroup, NULL, enable,
 668  672                                      work->proto);
 669  673                          }
 670  674                  }
 671  675                  if (online) {
 672  676                          zfs = sa_get_group_attr(group, "zfs");
 673  677                          name = sa_get_group_attr(group, "name");
 674  678                          if (name != NULL) {
 675  679                                  if (zfs == NULL) {
 676  680                                          (void) snprintf(instance,
 677  681                                              sizeof (instance), "%s:%s",
 678  682                                              SA_SVC_FMRI_BASE, name);
 679  683                                          state = smf_get_state(instance);
 680  684                                          if (state == NULL ||
 681  685                                              strcmp(state, "online") != 0) {
 682  686                                                  (void) smf_enable_instance(
 683  687                                                      instance, 0);
 684  688                                                  free(state);
 685  689                                          }
 686  690                                  } else {
 687  691                                          sa_free_attr_string(zfs);
 688  692                                          zfs = NULL;
 689  693                                  }
 690  694                                  if (name != NULL)
 691  695                                          sa_free_attr_string(name);
 692  696                          }
 693  697                  }
 694  698          }
 695  699          if (ret == SA_OK) {
 696  700                  ret = sa_update_config(handle);
 697  701          }
 698  702          return (ret);
 699  703  }
 700  704  
 701  705  /*
 702  706   * chk_opt(optlistp, security, proto)
 703  707   *
 704  708   * Do a sanity check on the optlist provided for the protocol.  This
 705  709   * is a syntax check and verification that the property is either a
 706  710   * general or specific to a names optionset.
 707  711   */
 708  712  
 709  713  static int
 710  714  chk_opt(struct options *optlistp, int security, char *proto)
 711  715  {
 712  716          struct options *optlist;
 713  717          char *sep = "";
 714  718          int notfirst = 0;
 715  719          int ret;
 716  720  
 717  721          for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
 718  722                  char *optname;
 719  723  
 720  724                  optname = optlist->optname;
 721  725                  ret = OPT_ADD_OK;
 722  726                  /* extract property/value pair */
 723  727                  if (sa_is_security(optname, proto)) {
 724  728                          if (!security)
 725  729                                  ret = OPT_ADD_SECURITY;
 726  730                  } else {
 727  731                          if (security)
 728  732                                  ret = OPT_ADD_PROPERTY;
 729  733                  }
 730  734                  if (ret != OPT_ADD_OK) {
 731  735                          if (notfirst == 0)
 732  736                                  (void) printf(
 733  737                                      gettext("Property syntax error: "));
 734  738                          switch (ret) {
 735  739                          case OPT_ADD_SYNTAX:
 736  740                                  (void) printf(gettext("%ssyntax error: %s"),
 737  741                                      sep, optname);
 738  742                                  sep = ", ";
 739  743                                  break;
 740  744                          case OPT_ADD_SECURITY:
 741  745                                  (void) printf(gettext("%s%s requires -S"),
 742  746                                      optname, sep);
 743  747                                  sep = ", ";
 744  748                                  break;
 745  749                          case OPT_ADD_PROPERTY:
 746  750                                  (void) printf(
 747  751                                      gettext("%s%s not supported with -S"),
 748  752                                      optname, sep);
 749  753                                  sep = ", ";
 750  754                                  break;
 751  755                          }
 752  756                          notfirst++;
 753  757                  }
 754  758          }
 755  759          if (notfirst) {
 756  760                  (void) printf("\n");
 757  761                  ret = SA_SYNTAX_ERR;
 758  762          }
 759  763          return (ret);
 760  764  }
 761  765  
 762  766  /*
 763  767   * free_opt(optlist)
 764  768   *      Free the specified option list.
 765  769   */
 766  770  static void
 767  771  free_opt(struct options *optlist)
 768  772  {
 769  773          struct options *nextopt;
 770  774          while (optlist != NULL) {
 771  775                  nextopt = optlist->next;
 772  776                  free(optlist);
 773  777                  optlist = nextopt;
 774  778          }
 775  779  }
 776  780  
 777  781  /*
 778  782   * check property list for valid properties
 779  783   * A null value is a remove which is always valid.
 780  784   */
 781  785  static int
 782  786  valid_options(sa_handle_t handle, struct options *optlist, char *proto,
 783  787      void *object, char *sec)
 784  788  {
 785  789          int ret = SA_OK;
 786  790          struct options *cur;
 787  791          sa_property_t prop;
 788  792          sa_optionset_t parent = NULL;
 789  793  
 790  794          if (object != NULL) {
 791  795                  if (sec == NULL)
 792  796                          parent = sa_get_optionset(object, proto);
 793  797                  else
 794  798                          parent = sa_get_security(object, sec, proto);
 795  799          }
 796  800  
 797  801          for (cur = optlist; cur != NULL; cur = cur->next) {
 798  802                  if (cur->optvalue == NULL)
 799  803                          continue;
 800  804                  prop = sa_create_property(cur->optname, cur->optvalue);
 801  805                  if (prop == NULL)
 802  806                          ret = SA_NO_MEMORY;
 803  807                  if (ret != SA_OK ||
 804  808                      (ret = sa_valid_property(handle, parent, proto, prop)) !=
 805  809                      SA_OK) {
 806  810                          (void) printf(
 807  811                              gettext("Could not add property %s: %s\n"),
 808  812                              cur->optname, sa_errorstr(ret));
 809  813                  }
 810  814                  (void) sa_remove_property(prop);
 811  815          }
 812  816          return (ret);
 813  817  }
 814  818  
 815  819  /*
 816  820   * add_optionset(group, optlist, protocol, *err)
 817  821   *      Add the options in optlist to an optionset and then add the optionset
 818  822   *      to the group.
 819  823   *
 820  824   *      The return value indicates if there was a "change" while errors are
 821  825   *      returned via the *err parameters.
 822  826   */
 823  827  static int
 824  828  add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
 825  829  {
 826  830          sa_optionset_t optionset;
 827  831          int ret = SA_OK;
 828  832          int result = B_FALSE;
 829  833          sa_handle_t handle;
 830  834  
 831  835          optionset = sa_get_optionset(group, proto);
 832  836          if (optionset == NULL) {
 833  837                  optionset = sa_create_optionset(group, proto);
 834  838                  if (optionset == NULL)
 835  839                          ret = SA_NO_MEMORY;
 836  840                  result = B_TRUE; /* adding a protocol is a change */
 837  841          }
 838  842          if (optionset == NULL) {
 839  843                  ret = SA_NO_MEMORY;
 840  844                  goto out;
 841  845          }
 842  846          handle = sa_find_group_handle(group);
 843  847          if (handle == NULL) {
 844  848                  ret = SA_CONFIG_ERR;
 845  849                  goto out;
 846  850          }
 847  851          while (optlist != NULL) {
 848  852                  sa_property_t prop;
 849  853                  prop = sa_get_property(optionset, optlist->optname);
 850  854                  if (prop == NULL) {
 851  855                          /*
 852  856                           * add the property, but only if it is
 853  857                           * a non-NULL or non-zero length value
 854  858                           */
 855  859                          if (optlist->optvalue != NULL) {
 856  860                                  prop = sa_create_property(optlist->optname,
 857  861                                      optlist->optvalue);
 858  862                                  if (prop != NULL) {
 859  863                                          ret = sa_valid_property(handle,
 860  864                                              optionset, proto, prop);
 861  865                                          if (ret != SA_OK) {
 862  866                                                  (void) sa_remove_property(prop);
 863  867                                                  (void) printf(gettext("Could "
 864  868                                                      "not add property "
 865  869                                                      "%s: %s\n"),
 866  870                                                      optlist->optname,
 867  871                                                      sa_errorstr(ret));
 868  872                                          }
 869  873                                  }
 870  874                                  if (ret == SA_OK) {
 871  875                                          ret = sa_add_property(optionset, prop);
 872  876                                          if (ret != SA_OK) {
 873  877                                                  (void) printf(gettext(
 874  878                                                      "Could not add property "
 875  879                                                      "%s: %s\n"),
 876  880                                                      optlist->optname,
 877  881                                                      sa_errorstr(ret));
 878  882                                          } else {
 879  883                                                  /* there was a change */
 880  884                                                  result = B_TRUE;
 881  885                                          }
 882  886                                  }
 883  887                          }
 884  888                  } else {
 885  889                          ret = sa_update_property(prop, optlist->optvalue);
 886  890                          /* should check to see if value changed */
 887  891                          if (ret != SA_OK) {
 888  892                                  (void) printf(gettext("Could not update "
 889  893                                      "property %s: %s\n"), optlist->optname,
 890  894                                      sa_errorstr(ret));
 891  895                          } else {
 892  896                                  result = B_TRUE;
 893  897                          }
 894  898                  }
 895  899                  optlist = optlist->next;
 896  900          }
 897  901          ret = sa_commit_properties(optionset, 0);
 898  902  
 899  903  out:
 900  904          if (err != NULL)
 901  905                  *err = ret;
 902  906          return (result);
 903  907  }
 904  908  
 905  909  /*
 906  910   * resource_compliant(group)
 907  911   *
 908  912   * Go through all the shares in the group. Assume compliant, but if
 909  913   * any share doesn't have at least one resource name, it isn't
 910  914   * compliant.
 911  915   */
 912  916  static int
 913  917  resource_compliant(sa_group_t group)
 914  918  {
 915  919          sa_share_t share;
 916  920  
 917  921          for (share = sa_get_share(group, NULL); share != NULL;
 918  922              share = sa_get_next_share(share)) {
 919  923                  if (sa_get_share_resource(share, NULL) == NULL) {
 920  924                          return (B_FALSE);
 921  925                  }
 922  926          }
 923  927          return (B_TRUE);
 924  928  }
 925  929  
 926  930  /*
 927  931   * fix_path(path)
 928  932   *
 929  933   * change all illegal characters to something else.  For now, all get
 930  934   * converted to '_' and the leading '/' is stripped off. This is used
 931  935   * to construct an resource name (SMB share name) that is valid.
 932  936   * Caller must pass a valid path.
 933  937   */
 934  938  static void
 935  939  fix_path(char *path)
 936  940  {
 937  941          char *cp;
 938  942          size_t len;
 939  943  
 940  944          assert(path != NULL);
 941  945  
 942  946          /* make sure we are appropriate length */
 943  947          cp = path + 1; /* skip leading slash */
 944  948          while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
 945  949                  cp = strchr(cp, '/');
 946  950                  if (cp != NULL)
 947  951                          cp++;
 948  952          }
 949  953          /* two cases - cp == NULL and cp is substring of path */
 950  954          if (cp == NULL) {
 951  955                  /* just take last SA_MAX_RESOURCE_NAME chars */
 952  956                  len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
 953  957                  (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
 954  958                  path[SA_MAX_RESOURCE_NAME] = '\0';
 955  959          } else {
 956  960                  len = strlen(cp) + 1;
 957  961                  (void) memmove(path, cp, len);
 958  962          }
 959  963  
 960  964          /*
 961  965           * Don't want any of the characters that are not allowed
 962  966           * in and SMB share name. Replace them with '_'.
 963  967           */
 964  968          while (*path) {
 965  969                  switch (*path) {
 966  970                  case '/':
 967  971                  case '"':
 968  972                  case '\\':
 969  973                  case '[':
 970  974                  case ']':
 971  975                  case ':':
 972  976                  case '|':
 973  977                  case '<':
 974  978                  case '>':
 975  979                  case '+':
 976  980                  case ';':
 977  981                  case ',':
 978  982                  case '?':
 979  983                  case '*':
 980  984                  case '=':
 981  985                  case '\t':
 982  986                          *path = '_';
 983  987                          break;
 984  988                  }
 985  989                  path++;
 986  990          }
 987  991  }
 988  992  
 989  993  /*
 990  994   * name_adjust(path, count)
 991  995   *
 992  996   * Add a ~<count> in place of last few characters. The total number of
 993  997   * characters is dependent on count.
 994  998   */
 995  999  #define MAX_MANGLE_NUMBER       10000
 996 1000  
 997 1001  static int
 998 1002  name_adjust(char *path, int count)
 999 1003  {
1000 1004          size_t len;
1001 1005  
1002 1006          len = strlen(path) - 2;
1003 1007          if (count > 10)
1004 1008                  len--;
1005 1009          if (count > 100)
1006 1010                  len--;
1007 1011          if (count > 1000)
1008 1012                  len--;
1009 1013          if (len > 0)
1010 1014                  (void) sprintf(path + len, "~%d", count);
1011 1015          else
1012 1016                  return (SA_BAD_VALUE);
1013 1017  
1014 1018          return (SA_OK);
1015 1019  }
1016 1020  
1017 1021  /*
1018 1022   * make_resources(group)
1019 1023   *
1020 1024   * Go through all the shares in the group and make them have resource
1021 1025   * names.
1022 1026   */
1023 1027  static void
1024 1028  make_resources(sa_group_t group)
1025 1029  {
1026 1030          sa_share_t share;
1027 1031          int count;
1028 1032          int err = SA_OK;
1029 1033  
1030 1034          for (share = sa_get_share(group, NULL); share != NULL;
1031 1035              share = sa_get_next_share(share)) {
1032 1036                  /* Skip those with resources */
1033 1037                  if (sa_get_share_resource(share, NULL) == NULL) {
1034 1038                          char *path;
1035 1039                          path = sa_get_share_attr(share, "path");
1036 1040                          if (path == NULL)
1037 1041                                  continue;
1038 1042                          fix_path(path);
1039 1043                          count = 0;      /* reset for next resource */
1040 1044                          while (sa_add_resource(share, path,
1041 1045                              SA_SHARE_PERMANENT, &err) == NULL &&
1042 1046                              err == SA_DUPLICATE_NAME) {
1043 1047                                  int ret;
1044 1048                                  ret = name_adjust(path, count);
1045 1049                                  count++;
1046 1050                                  if (ret != SA_OK ||
1047 1051                                      count >= MAX_MANGLE_NUMBER) {
1048 1052                                          (void) printf(gettext(
1049 1053                                              "Cannot create resource name for"
1050 1054                                              " path: %s\n"), path);
1051 1055                                          break;
1052 1056                                  }
1053 1057                          }
1054 1058                          sa_free_attr_string(path);
1055 1059                  }
1056 1060          }
1057 1061  }
1058 1062  
1059 1063  /*
1060 1064   * check_valid_group(group, protocol)
1061 1065   *
1062 1066   * Check to see that the group should have the protocol added (if
1063 1067   * there is one specified).
1064 1068   */
1065 1069  
1066 1070  static int
1067 1071  check_valid_group(sa_group_t group, char *groupname, char *protocol)
1068 1072  {
1069 1073  
1070 1074          if (protocol != NULL) {
1071 1075                  if (has_protocol(group, protocol)) {
1072 1076                          (void) printf(gettext(
1073 1077                              "Group \"%s\" already exists"
1074 1078                              " with protocol %s\n"), groupname,
1075 1079                              protocol);
1076 1080                          return (SA_DUPLICATE_NAME);
1077 1081                  } else if (strcmp(groupname, "default") == 0 &&
1078 1082                      strcmp(protocol, "nfs") != 0) {
1079 1083                          (void) printf(gettext(
1080 1084                              "Group \"%s\" only allows protocol "
1081 1085                              "\"%s\"\n"), groupname, "nfs");
1082 1086                          return (SA_INVALID_PROTOCOL);
1083 1087                  }
1084 1088          } else {
1085 1089                  /* must add new protocol */
1086 1090                  (void) printf(gettext(
1087 1091                      "Group already exists and no protocol "
1088 1092                      "specified.\n"));
1089 1093                  return (SA_DUPLICATE_NAME);
1090 1094          }
1091 1095          return (SA_OK);
1092 1096  }
1093 1097  
1094 1098  /*
1095 1099   * enforce_featureset(group, protocol, dryrun, force)
1096 1100   *
1097 1101   * Check the protocol featureset against the group and enforce any
1098 1102   * rules that might be imposed.
1099 1103   */
1100 1104  
1101 1105  static int
1102 1106  enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun,
1103 1107      boolean_t force)
1104 1108  {
1105 1109          uint64_t features;
1106 1110  
1107 1111          if (protocol == NULL)
1108 1112                  return (SA_OK);
1109 1113  
1110 1114          /*
1111 1115           * First check to see if specified protocol is one we want to
1112 1116           * allow on a group. Only server protocols are allowed here.
1113 1117           */
1114 1118          features = sa_proto_get_featureset(protocol);
1115 1119          if (!(features & SA_FEATURE_SERVER)) {
1116 1120                  (void) printf(
1117 1121                      gettext("Protocol \"%s\" not supported.\n"), protocol);
1118 1122                  return (SA_INVALID_PROTOCOL);
1119 1123          }
1120 1124  
1121 1125          /*
1122 1126           * Check to see if the new protocol is one that requires
1123 1127           * resource names and make sure we are compliant before
1124 1128           * proceeding.
1125 1129           */
1126 1130          if ((features & SA_FEATURE_RESOURCE) &&
1127 1131              !resource_compliant(group)) {
1128 1132                  if (force && !dryrun) {
1129 1133                          make_resources(group);
1130 1134                  } else {
1131 1135                          (void) printf(
1132 1136                              gettext("Protocol requires resource names to be "
1133 1137                              "set: %s\n"), protocol);
1134 1138                          return (SA_RESOURCE_REQUIRED);
1135 1139                  }
1136 1140          }
1137 1141          return (SA_OK);
1138 1142  }
1139 1143  
1140 1144  /*
1141 1145   * set_all_protocols(group)
1142 1146   *
1143 1147   * Get the list of all protocols and add all server protocols to the
1144 1148   * group.
1145 1149   */
1146 1150  
1147 1151  static int
1148 1152  set_all_protocols(sa_group_t group)
1149 1153  {
1150 1154          char **protolist;
1151 1155          int numprotos, i;
1152 1156          uint64_t features;
1153 1157          sa_optionset_t optionset;
1154 1158          int ret = SA_OK;
1155 1159  
1156 1160          /*
1157 1161           * Now make sure we really want to put this protocol on a
1158 1162           * group. Only server protocols can go here.
1159 1163           */
1160 1164          numprotos = sa_get_protocols(&protolist);
1161 1165          for (i = 0; i < numprotos; i++) {
1162 1166                  features = sa_proto_get_featureset(protolist[i]);
1163 1167                  if (features & SA_FEATURE_SERVER) {
1164 1168                          optionset = sa_create_optionset(group, protolist[i]);
1165 1169                          if (optionset == NULL) {
1166 1170                                  ret = SA_NO_MEMORY;
1167 1171                                  break;
1168 1172                          }
1169 1173                  }
1170 1174          }
1171 1175  
1172 1176          if (protolist != NULL)
1173 1177                  free(protolist);
1174 1178  
1175 1179          return (ret);
1176 1180  }
1177 1181  
1178 1182  /*
1179 1183   * sa_create(flags, argc, argv)
1180 1184   *      create a new group
1181 1185   *      this may or may not have a protocol associated with it.
1182 1186   *      No protocol means "all" protocols in this case.
1183 1187   */
1184 1188  static int
1185 1189  sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
1186 1190  {
1187 1191          char *groupname;
1188 1192  
1189 1193          sa_group_t group;
1190 1194          boolean_t force = B_FALSE;
1191 1195          boolean_t verbose = B_FALSE;
1192 1196          boolean_t dryrun = B_FALSE;
1193 1197          int c;
1194 1198          char *protocol = NULL;
1195 1199          int ret = SA_OK;
1196 1200          struct options *optlist = NULL;
1197 1201          int err = SA_OK;
1198 1202          int auth;
1199 1203          boolean_t created = B_FALSE;
1200 1204  
1201 1205          while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) {
1202 1206                  switch (c) {
1203 1207                  case 'f':
1204 1208                          force = B_TRUE;
1205 1209                          break;
1206 1210                  case 'v':
1207 1211                          verbose = B_TRUE;
1208 1212                          break;
1209 1213                  case 'n':
1210 1214                          dryrun = B_TRUE;
1211 1215                          break;
1212 1216                  case 'P':
1213 1217                          if (protocol != NULL) {
1214 1218                                  (void) printf(gettext("Specifying "
1215 1219                                      "multiple protocols "
1216 1220                                      "not supported: %s\n"), protocol);
1217 1221                                  return (SA_SYNTAX_ERR);
1218 1222                          }
1219 1223                          protocol = optarg;
1220 1224                          if (sa_valid_protocol(protocol))
1221 1225                                  break;
1222 1226                          (void) printf(gettext(
1223 1227                              "Invalid protocol specified: %s\n"), protocol);
1224 1228                          return (SA_INVALID_PROTOCOL);
1225 1229                  case 'p':
1226 1230                          ret = add_opt(&optlist, optarg, 0);
1227 1231                          switch (ret) {
1228 1232                          case OPT_ADD_SYNTAX:
1229 1233                                  (void) printf(gettext(
1230 1234                                      "Property syntax error for property: %s\n"),
1231 1235                                      optarg);
1232 1236                                  return (SA_SYNTAX_ERR);
1233 1237                          case OPT_ADD_SECURITY:
1234 1238                                  (void) printf(gettext(
1235 1239                                      "Security properties need "
1236 1240                                      "to be set with set-security: %s\n"),
1237 1241                                      optarg);
1238 1242                                  return (SA_SYNTAX_ERR);
1239 1243                          default:
1240 1244                                  break;
1241 1245                          }
1242 1246                          break;
1243 1247                  case 'h':
1244 1248                          /* optopt on valid arg isn't defined */
1245 1249                          optopt = c;
1246 1250                          /*FALLTHROUGH*/
1247 1251                  case '?':
1248 1252                  default:
1249 1253                          /*
1250 1254                           * Since a bad option gets to here, sort it
1251 1255                           * out and return a syntax error return value
1252 1256                           * if necessary.
1253 1257                           */
1254 1258                          switch (optopt) {
1255 1259                          default:
1256 1260                                  err = SA_SYNTAX_ERR;
1257 1261                                  break;
1258 1262                          case 'h':
1259 1263                          case '?':
1260 1264                                  break;
1261 1265                          }
1262 1266                          (void) printf(gettext("usage: %s\n"),
1263 1267                              sa_get_usage(USAGE_CREATE));
1264 1268                          return (err);
1265 1269                  }
1266 1270          }
1267 1271  
1268 1272          if (optind >= argc) {
1269 1273                  (void) printf(gettext("usage: %s\n"),
1270 1274                      sa_get_usage(USAGE_CREATE));
1271 1275                  (void) printf(gettext("\tgroup must be specified.\n"));
1272 1276                  return (SA_BAD_PATH);
1273 1277          }
1274 1278  
1275 1279          if ((optind + 1) < argc) {
1276 1280                  (void) printf(gettext("usage: %s\n"),
1277 1281                      sa_get_usage(USAGE_CREATE));
1278 1282                  (void) printf(gettext("\textraneous group(s) at end\n"));
1279 1283                  return (SA_SYNTAX_ERR);
1280 1284          }
1281 1285  
1282 1286          if (protocol == NULL && optlist != NULL) {
1283 1287                  /* lookup default protocol */
1284 1288                  (void) printf(gettext("usage: %s\n"),
1285 1289                      sa_get_usage(USAGE_CREATE));
1286 1290                  (void) printf(gettext("\tprotocol must be specified "
1287 1291                      "with properties\n"));
1288 1292                  return (SA_INVALID_PROTOCOL);
1289 1293          }
1290 1294  
1291 1295          if (optlist != NULL)
1292 1296                  ret = chk_opt(optlist, 0, protocol);
1293 1297          if (ret == OPT_ADD_SECURITY) {
1294 1298                  (void) printf(gettext("Security properties not "
1295 1299                      "supported with create\n"));
1296 1300                  return (SA_SYNTAX_ERR);
1297 1301          }
1298 1302  
1299 1303          /*
1300 1304           * If a group already exists, we can only add a new protocol
1301 1305           * to it and not create a new one or add the same protocol
1302 1306           * again.
1303 1307           */
1304 1308  
1305 1309          groupname = argv[optind];
1306 1310  
1307 1311          auth = check_authorizations(groupname, flags);
1308 1312  
1309 1313          group = sa_get_group(handle, groupname);
1310 1314          if (group != NULL) {
1311 1315                  /* group exists so must be a protocol add */
1312 1316                  ret = check_valid_group(group, groupname, protocol);
1313 1317          } else {
1314 1318                  /*
1315 1319                   * is it a valid name? Must comply with SMF instance
1316 1320                   * name restrictions.
1317 1321                   */
1318 1322                  if (!sa_valid_group_name(groupname)) {
1319 1323                          ret = SA_INVALID_NAME;
1320 1324                          (void) printf(gettext("Invalid group name: %s\n"),
1321 1325                              groupname);
1322 1326                  }
1323 1327          }
1324 1328          if (ret == SA_OK) {
1325 1329                  /* check protocol vs optlist */
1326 1330                  if (optlist != NULL) {
1327 1331                          /* check options, if any, for validity */
1328 1332                          ret = valid_options(handle, optlist, protocol,
1329 1333                              group, NULL);
1330 1334                  }
1331 1335          }
1332 1336          if (ret == SA_OK && !dryrun) {
1333 1337                  if (group == NULL) {
1334 1338                          group = sa_create_group(handle, (char *)groupname,
1335 1339                              &err);
1336 1340                          created = B_TRUE;
1337 1341                  }
1338 1342                  if (group != NULL) {
1339 1343                          sa_optionset_t optionset;
1340 1344  
1341 1345                          /*
1342 1346                           * Check group and protocol against featureset
1343 1347                           * requirements.
1344 1348                           */
1345 1349                          ret = enforce_featureset(group, protocol,
1346 1350                              dryrun, force);
1347 1351                          if (ret != SA_OK)
1348 1352                                  goto err;
1349 1353  
1350 1354                          /*
1351 1355                           * So far so good. Now add the required
1352 1356                           * optionset(s) to the group.
1353 1357                           */
1354 1358                          if (optlist != NULL) {
1355 1359                                  (void) add_optionset(group, optlist, protocol,
1356 1360                                      &ret);
1357 1361                          } else if (protocol != NULL) {
1358 1362                                  optionset = sa_create_optionset(group,
1359 1363                                      protocol);
1360 1364                                  if (optionset == NULL)
1361 1365                                          ret = SA_NO_MEMORY;
1362 1366                          } else if (protocol == NULL) {
1363 1367                                  /* default group create so add all protocols */
1364 1368                                  ret = set_all_protocols(group);
1365 1369                          }
1366 1370                          /*
1367 1371                           * We have a group and legal additions
1368 1372                           */
1369 1373                          if (ret == SA_OK) {
1370 1374                                  /*
1371 1375                                   * Commit to configuration for protocols that
1372 1376                                   * need to do block updates. For NFS, this
1373 1377                                   * doesn't do anything but it will be run for
1374 1378                                   * all protocols that implement the
1375 1379                                   * appropriate plugin.
1376 1380                                   */
1377 1381                                  ret = sa_update_config(handle);
1378 1382                          } else {
1379 1383                                  if (group != NULL)
1380 1384                                          (void) sa_remove_group(group);
1381 1385                          }
1382 1386                  } else {
1383 1387                          ret = err;
1384 1388                          (void) printf(gettext("Could not create group: %s\n"),
1385 1389                              sa_errorstr(ret));
1386 1390                  }
1387 1391          }
1388 1392          if (dryrun && ret == SA_OK && !auth && verbose) {
1389 1393                  (void) printf(gettext("Command would fail: %s\n"),
1390 1394                      sa_errorstr(SA_NO_PERMISSION));
1391 1395                  ret = SA_NO_PERMISSION;
1392 1396          }
1393 1397  err:
1394 1398          if (ret != SA_OK && created)
1395 1399                  ret = sa_remove_group(group);
1396 1400  
1397 1401          free_opt(optlist);
1398 1402          return (ret);
1399 1403  }
1400 1404  
1401 1405  /*
1402 1406   * group_status(group)
1403 1407   *
1404 1408   * return the current status (enabled/disabled) of the group.
1405 1409   */
1406 1410  
1407 1411  static char *
1408 1412  group_status(sa_group_t group)
1409 1413  {
1410 1414          char *state;
1411 1415          int enabled = 0;
1412 1416  
1413 1417          state = sa_get_group_attr(group, "state");
1414 1418          if (state != NULL) {
1415 1419                  if (strcmp(state, "enabled") == 0) {
1416 1420                          enabled = 1;
1417 1421                  }
1418 1422                  sa_free_attr_string(state);
1419 1423          }
1420 1424          return (enabled ? "enabled" : "disabled");
1421 1425  }
1422 1426  
1423 1427  /*
1424 1428   * sa_delete(flags, argc, argv)
1425 1429   *
1426 1430   *      Delete a group.
1427 1431   */
1428 1432  
1429 1433  static int
1430 1434  sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
1431 1435  {
1432 1436          char *groupname;
1433 1437          sa_group_t group;
1434 1438          sa_share_t share;
1435 1439          int verbose = 0;
1436 1440          int dryrun = 0;
1437 1441          int force = 0;
1438 1442          int c;
1439 1443          char *protocol = NULL;
1440 1444          char *sectype = NULL;
1441 1445          int ret = SA_OK;
1442 1446          int auth;
1443 1447  
1444 1448          while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
1445 1449                  switch (c) {
1446 1450                  case 'v':
1447 1451                          verbose++;
1448 1452                          break;
1449 1453                  case 'n':
1450 1454                          dryrun++;
1451 1455                          break;
1452 1456                  case 'P':
1453 1457                          if (protocol != NULL) {
1454 1458                                  (void) printf(gettext("Specifying "
1455 1459                                      "multiple protocols "
1456 1460                                      "not supported: %s\n"), protocol);
1457 1461                                  return (SA_SYNTAX_ERR);
1458 1462                          }
1459 1463                          protocol = optarg;
1460 1464                          if (!sa_valid_protocol(protocol)) {
1461 1465                                  (void) printf(gettext("Invalid protocol "
1462 1466                                      "specified: %s\n"), protocol);
1463 1467                                  return (SA_INVALID_PROTOCOL);
1464 1468                          }
1465 1469                          break;
1466 1470                  case 'S':
1467 1471                          if (sectype != NULL) {
1468 1472                                  (void) printf(gettext("Specifying "
1469 1473                                      "multiple property "
1470 1474                                      "spaces not supported: %s\n"), sectype);
1471 1475                                  return (SA_SYNTAX_ERR);
1472 1476                          }
1473 1477                          sectype = optarg;
1474 1478                          break;
1475 1479                  case 'f':
1476 1480                          force++;
1477 1481                          break;
1478 1482                  case 'h':
1479 1483                          /* optopt on valid arg isn't defined */
1480 1484                          optopt = c;
1481 1485                          /*FALLTHROUGH*/
1482 1486                  case '?':
1483 1487                  default:
1484 1488                          /*
1485 1489                           * Since a bad option gets to here, sort it
1486 1490                           * out and return a syntax error return value
1487 1491                           * if necessary.
1488 1492                           */
1489 1493                          switch (optopt) {
1490 1494                          default:
1491 1495                                  ret = SA_SYNTAX_ERR;
1492 1496                                  break;
1493 1497                          case 'h':
1494 1498                          case '?':
1495 1499                                  break;
1496 1500                          }
1497 1501                          (void) printf(gettext("usage: %s\n"),
1498 1502                              sa_get_usage(USAGE_DELETE));
1499 1503                          return (ret);
1500 1504                  }
1501 1505          }
1502 1506  
1503 1507          if (optind >= argc) {
1504 1508                  (void) printf(gettext("usage: %s\n"),
1505 1509                      sa_get_usage(USAGE_DELETE));
1506 1510                  (void) printf(gettext("\tgroup must be specified.\n"));
1507 1511                  return (SA_SYNTAX_ERR);
1508 1512          }
1509 1513  
1510 1514          if ((optind + 1) < argc) {
1511 1515                  (void) printf(gettext("usage: %s\n"),
1512 1516                      sa_get_usage(USAGE_DELETE));
1513 1517                  (void) printf(gettext("\textraneous group(s) at end\n"));
1514 1518                  return (SA_SYNTAX_ERR);
1515 1519          }
1516 1520  
1517 1521          if (sectype != NULL && protocol == NULL) {
1518 1522                  (void) printf(gettext("usage: %s\n"),
1519 1523                      sa_get_usage(USAGE_DELETE));
1520 1524                  (void) printf(gettext("\tsecurity requires protocol to be "
1521 1525                      "specified.\n"));
1522 1526                  return (SA_SYNTAX_ERR);
1523 1527          }
1524 1528  
1525 1529          /*
1526 1530           * Determine if the group already exists since it must in
1527 1531           * order to be removed.
1528 1532           *
1529 1533           * We can delete when:
1530 1534           *
1531 1535           *      - group is empty
1532 1536           *      - force flag is set
1533 1537           *      - if protocol specified, only delete the protocol
1534 1538           */
1535 1539  
1536 1540          groupname = argv[optind];
1537 1541          group = sa_get_group(handle, groupname);
1538 1542          if (group == NULL) {
1539 1543                  ret = SA_NO_SUCH_GROUP;
1540 1544                  goto done;
1541 1545          }
1542 1546          auth = check_authorizations(groupname, flags);
1543 1547          if (protocol == NULL) {
1544 1548                  share = sa_get_share(group, NULL);
1545 1549                  if (share != NULL)
1546 1550                          ret = SA_BUSY;
1547 1551                  if (share == NULL || (share != NULL && force == 1)) {
1548 1552                          ret = SA_OK;
1549 1553                          if (!dryrun) {
1550 1554                                  while (share != NULL) {
1551 1555                                          sa_share_t next_share;
1552 1556                                          next_share = sa_get_next_share(share);
1553 1557                                          /*
1554 1558                                           * need to do the disable of
1555 1559                                           * each share, but don't
1556 1560                                           * actually do anything on a
1557 1561                                           * dryrun.
1558 1562                                           */
1559 1563                                          ret = sa_disable_share(share, NULL);
1560 1564                                          ret = sa_remove_share(share);
1561 1565                                          share = next_share;
1562 1566                                  }
1563 1567                                  ret = sa_remove_group(group);
1564 1568                          }
1565 1569                  }
1566 1570                  /* Commit to configuration if not a dryrun */
1567 1571                  if (!dryrun && ret == SA_OK) {
1568 1572                          ret = sa_update_config(handle);
1569 1573                  }
1570 1574          } else {
1571 1575                  /* a protocol delete */
1572 1576                  sa_optionset_t optionset;
1573 1577                  sa_security_t security;
1574 1578                  if (sectype != NULL) {
1575 1579                          /* only delete specified security */
1576 1580                          security = sa_get_security(group, sectype, protocol);
1577 1581                          if (security != NULL && !dryrun)
1578 1582                                  ret = sa_destroy_security(security);
1579 1583                          else
1580 1584                                  ret = SA_INVALID_PROTOCOL;
1581 1585                  } else {
1582 1586                          optionset = sa_get_optionset(group, protocol);
1583 1587                          if (optionset != NULL && !dryrun) {
1584 1588                                  /*
1585 1589                                   * have an optionset with
1586 1590                                   * protocol to delete
1587 1591                                   */
1588 1592                                  ret = sa_destroy_optionset(optionset);
1589 1593                                  /*
1590 1594                                   * Now find all security sets
1591 1595                                   * for the protocol and remove
1592 1596                                   * them. Don't remove other
1593 1597                                   * protocols.
1594 1598                                   */
1595 1599                                  for (security =
1596 1600                                      sa_get_security(group, NULL, NULL);
1597 1601                                      ret == SA_OK && security != NULL;
1598 1602                                      security = sa_get_next_security(security)) {
1599 1603                                          char *secprot;
1600 1604                                          secprot = sa_get_security_attr(security,
1601 1605                                              "type");
1602 1606                                          if (secprot != NULL &&
1603 1607                                              strcmp(secprot, protocol) == 0)
1604 1608                                                  ret = sa_destroy_security(
1605 1609                                                      security);
1606 1610                                          if (secprot != NULL)
1607 1611                                                  sa_free_attr_string(secprot);
1608 1612                                  }
1609 1613                          } else {
1610 1614                                  if (!dryrun)
1611 1615                                          ret = SA_INVALID_PROTOCOL;
1612 1616                          }
1613 1617                  }
1614 1618                  /*
1615 1619                   * With the protocol items removed, make sure that all
1616 1620                   * the shares are updated in the legacy files, if
1617 1621                   * necessary.
1618 1622                   */
1619 1623                  for (share = sa_get_share(group, NULL);
1620 1624                      share != NULL;
1621 1625                      share = sa_get_next_share(share)) {
1622 1626                          (void) sa_delete_legacy(share, protocol);
1623 1627                  }
1624 1628          }
1625 1629  
1626 1630  done:
1627 1631          if (ret != SA_OK) {
1628 1632                  (void) printf(gettext("Could not delete group: %s\n"),
1629 1633                      sa_errorstr(ret));
1630 1634          } else if (dryrun && !auth && verbose) {
1631 1635                  (void) printf(gettext("Command would fail: %s\n"),
1632 1636                      sa_errorstr(SA_NO_PERMISSION));
1633 1637          }
1634 1638          return (ret);
1635 1639  }
1636 1640  
1637 1641  /*
1638 1642   * strndupr(*buff, str, buffsize)
1639 1643   *
1640 1644   * used with small strings to duplicate and possibly increase the
1641 1645   * buffer size of a string.
1642 1646   */
1643 1647  static char *
1644 1648  strndupr(char *buff, char *str, int *buffsize)
1645 1649  {
1646 1650          int limit;
1647 1651          char *orig_buff = buff;
1648 1652  
1649 1653          if (buff == NULL) {
1650 1654                  buff = (char *)malloc(64);
1651 1655                  if (buff == NULL)
1652 1656                          return (NULL);
1653 1657                  *buffsize = 64;
1654 1658                  buff[0] = '\0';
1655 1659          }
1656 1660          limit = strlen(buff) + strlen(str) + 1;
1657 1661          if (limit > *buffsize) {
1658 1662                  limit = *buffsize = *buffsize + ((limit / 64) + 64);
1659 1663                  buff = realloc(buff, limit);
1660 1664          }
1661 1665          if (buff != NULL) {
1662 1666                  (void) strcat(buff, str);
1663 1667          } else {
1664 1668                  /* if it fails, fail it hard */
1665 1669                  if (orig_buff != NULL)
1666 1670                          free(orig_buff);
1667 1671          }
1668 1672          return (buff);
1669 1673  }
1670 1674  
1671 1675  /*
1672 1676   * group_proto(group)
1673 1677   *
1674 1678   * return a string of all the protocols (space separated) associated
1675 1679   * with this group.
1676 1680   */
1677 1681  
1678 1682  static char *
1679 1683  group_proto(sa_group_t group)
1680 1684  {
1681 1685          sa_optionset_t optionset;
1682 1686          char *proto;
1683 1687          char *buff = NULL;
1684 1688          int buffsize = 0;
1685 1689          int addspace = 0;
1686 1690          /*
1687 1691           * get the protocol list by finding the optionsets on this
1688 1692           * group and extracting the type value. The initial call to
1689 1693           * strndupr() initailizes buff.
1690 1694           */
1691 1695          buff = strndupr(buff, "", &buffsize);
1692 1696          if (buff != NULL) {
1693 1697                  for (optionset = sa_get_optionset(group, NULL);
1694 1698                      optionset != NULL && buff != NULL;
1695 1699                      optionset = sa_get_next_optionset(optionset)) {
1696 1700                          /*
1697 1701                           * extract out the protocol type from this optionset
1698 1702                           * and append it to the buffer "buff". strndupr() will
1699 1703                           * reallocate space as necessay.
1700 1704                           */
1701 1705                          proto = sa_get_optionset_attr(optionset, "type");
1702 1706                          if (proto != NULL) {
1703 1707                                  if (addspace++)
1704 1708                                          buff = strndupr(buff, " ", &buffsize);
1705 1709                                  buff = strndupr(buff, proto, &buffsize);
1706 1710                                  sa_free_attr_string(proto);
1707 1711                          }
1708 1712                  }
1709 1713          }
1710 1714          return (buff);
1711 1715  }
1712 1716  
1713 1717  /*
1714 1718   * sa_list(flags, argc, argv)
1715 1719   *
1716 1720   * implements the "list" subcommand to list groups and optionally
1717 1721   * their state and protocols.
1718 1722   */
1719 1723  
1720 1724  static int
1721 1725  sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
1722 1726  {
1723 1727          sa_group_t group;
1724 1728          int verbose = 0;
1725 1729          int c;
1726 1730          char *protocol = NULL;
1727 1731          int ret = SA_OK;
1728 1732  #ifdef lint
1729 1733          flags = flags;
1730 1734  #endif
1731 1735  
1732 1736          while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
1733 1737                  switch (c) {
1734 1738                  case 'v':
1735 1739                          verbose++;
1736 1740                          break;
1737 1741                  case 'P':
1738 1742                          if (protocol != NULL) {
1739 1743                                  (void) printf(gettext(
1740 1744                                      "Specifying multiple protocols "
1741 1745                                      "not supported: %s\n"),
1742 1746                                      protocol);
1743 1747                                  return (SA_SYNTAX_ERR);
1744 1748                          }
1745 1749                          protocol = optarg;
1746 1750                          if (!sa_valid_protocol(protocol)) {
1747 1751                                  (void) printf(gettext(
1748 1752                                      "Invalid protocol specified: %s\n"),
1749 1753                                      protocol);
1750 1754                                  return (SA_INVALID_PROTOCOL);
1751 1755                          }
1752 1756                          break;
1753 1757                  case 'h':
1754 1758                          /* optopt on valid arg isn't defined */
1755 1759                          optopt = c;
1756 1760                          /*FALLTHROUGH*/
1757 1761                  case '?':
1758 1762                  default:
1759 1763                          /*
1760 1764                           * Since a bad option gets to here, sort it
1761 1765                           * out and return a syntax error return value
1762 1766                           * if necessary.
1763 1767                           */
1764 1768                          switch (optopt) {
1765 1769                          default:
1766 1770                                  ret = SA_SYNTAX_ERR;
1767 1771                                  break;
1768 1772                          case 'h':
1769 1773                          case '?':
1770 1774                                  break;
1771 1775                          }
1772 1776                          (void) printf(gettext("usage: %s\n"),
1773 1777                              sa_get_usage(USAGE_LIST));
1774 1778                          return (ret);
1775 1779                  }
1776 1780          }
1777 1781  
1778 1782          if (optind != argc) {
1779 1783                  (void) printf(gettext("usage: %s\n"),
1780 1784                      sa_get_usage(USAGE_LIST));
1781 1785                  return (SA_SYNTAX_ERR);
1782 1786          }
1783 1787  
1784 1788          for (group = sa_get_group(handle, NULL);
1785 1789              group != NULL;
1786 1790              group = sa_get_next_group(group)) {
1787 1791                  char *name;
1788 1792                  char *proto;
1789 1793                  if (protocol == NULL || has_protocol(group, protocol)) {
1790 1794                          name = sa_get_group_attr(group, "name");
1791 1795                          if (name != NULL && (verbose > 1 || name[0] != '#')) {
1792 1796                                  (void) printf("%s", (char *)name);
1793 1797                                  if (verbose) {
1794 1798                                          /*
1795 1799                                           * Need the list of protocols
1796 1800                                           * and current status once
1797 1801                                           * available. We do want to
1798 1802                                           * translate the
1799 1803                                           * enabled/disabled text here.
1800 1804                                           */
1801 1805                                          (void) printf("\t%s", isenabled(group) ?
1802 1806                                              gettext("enabled") :
1803 1807                                              gettext("disabled"));
1804 1808                                          proto = group_proto(group);
1805 1809                                          if (proto != NULL) {
1806 1810                                                  (void) printf("\t%s",
1807 1811                                                      (char *)proto);
1808 1812                                                  free(proto);
1809 1813                                          }
1810 1814                                  }
1811 1815                                  (void) printf("\n");
1812 1816                          }
1813 1817                          if (name != NULL)
1814 1818                                  sa_free_attr_string(name);
1815 1819                  }
1816 1820          }
1817 1821          return (0);
1818 1822  }
1819 1823  
1820 1824  /*
1821 1825   * out_properties(optionset, proto, sec)
1822 1826   *
1823 1827   * Format the properties and encode the protocol and optional named
1824 1828   * optionset into the string.
1825 1829   *
1826 1830   * format is protocol[:name]=(property-list)
1827 1831   */
1828 1832  
1829 1833  static void
1830 1834  out_properties(sa_optionset_t optionset, char *proto, char *sec)
1831 1835  {
1832 1836          char *type;
1833 1837          char *value;
1834 1838          int spacer;
1835 1839          sa_property_t prop;
1836 1840  
1837 1841          if (sec == NULL)
1838 1842                  (void) printf(" %s=(", proto ? proto : gettext("all"));
1839 1843          else
1840 1844                  (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
1841 1845  
1842 1846          for (spacer = 0, prop = sa_get_property(optionset, NULL);
1843 1847              prop != NULL;
1844 1848              prop = sa_get_next_property(prop)) {
1845 1849  
1846 1850                  /*
1847 1851                   * extract the property name/value and output with
1848 1852                   * appropriate spacing. I.e. no prefixed space the
1849 1853                   * first time through but a space on subsequent
1850 1854                   * properties.
1851 1855                   */
1852 1856                  type = sa_get_property_attr(prop, "type");
1853 1857                  value = sa_get_property_attr(prop, "value");
1854 1858                  if (type != NULL) {
1855 1859                          (void) printf("%s%s=", spacer ? " " : "",       type);
1856 1860                          spacer = 1;
1857 1861                          if (value != NULL)
1858 1862                                  (void) printf("\"%s\"", value);
1859 1863                          else
1860 1864                                  (void) printf("\"\"");
1861 1865                  }
1862 1866                  if (type != NULL)
1863 1867                          sa_free_attr_string(type);
1864 1868                  if (value != NULL)
1865 1869                          sa_free_attr_string(value);
1866 1870          }
1867 1871          (void) printf(")");
1868 1872  }
1869 1873  
1870 1874  /*
1871 1875   * show_properties(group, protocol, prefix)
1872 1876   *
1873 1877   * print the properties for a group. If protocol is NULL, do all
1874 1878   * protocols otherwise only the specified protocol. All security
1875 1879   * (named groups specific to the protocol) are included.
1876 1880   *
1877 1881   * The "prefix" is always applied. The caller knows whether it wants
1878 1882   * some type of prefix string (white space) or not.  Once the prefix
1879 1883   * has been output, it is reduced to the zero length string for the
1880 1884   * remainder of the property output.
1881 1885   */
1882 1886  
1883 1887  static void
1884 1888  show_properties(sa_group_t group, char *protocol, char *prefix)
1885 1889  {
1886 1890          sa_optionset_t optionset;
1887 1891          sa_security_t security;
1888 1892          char *value;
1889 1893          char *secvalue;
1890 1894  
1891 1895          if (protocol != NULL) {
1892 1896                  optionset = sa_get_optionset(group, protocol);
1893 1897                  if (optionset != NULL) {
1894 1898                          (void) printf("%s", prefix);
1895 1899                          prefix = "";
1896 1900                          out_properties(optionset, protocol, NULL);
1897 1901                  }
1898 1902                  security = sa_get_security(group, protocol, NULL);
1899 1903                  if (security != NULL) {
1900 1904                          (void) printf("%s", prefix);
1901 1905                          prefix = "";
1902 1906                          out_properties(security, protocol, NULL);
1903 1907                  }
1904 1908          } else {
1905 1909                  for (optionset = sa_get_optionset(group, protocol);
1906 1910                      optionset != NULL;
1907 1911                      optionset = sa_get_next_optionset(optionset)) {
1908 1912  
1909 1913                          value = sa_get_optionset_attr(optionset, "type");
1910 1914                          (void) printf("%s", prefix);
1911 1915                          prefix = "";
1912 1916                          out_properties(optionset, value, 0);
1913 1917                          if (value != NULL)
1914 1918                                  sa_free_attr_string(value);
1915 1919                  }
1916 1920                  for (security = sa_get_security(group, NULL, protocol);
1917 1921                      security != NULL;
1918 1922                      security = sa_get_next_security(security)) {
1919 1923  
1920 1924                          value = sa_get_security_attr(security, "type");
1921 1925                          secvalue = sa_get_security_attr(security, "sectype");
1922 1926                          (void) printf("%s", prefix);
1923 1927                          prefix = "";
1924 1928                          out_properties(security, value, secvalue);
1925 1929                          if (value != NULL)
1926 1930                                  sa_free_attr_string(value);
1927 1931                          if (secvalue != NULL)
1928 1932                                  sa_free_attr_string(secvalue);
1929 1933                  }
1930 1934          }
1931 1935  }
1932 1936  
1933 1937  /*
1934 1938   * get_resource(share)
1935 1939   *
1936 1940   * Get the first resource name, if any, and fix string to be in
1937 1941   * current locale and have quotes if it has embedded spaces.  Return
1938 1942   * an attr string that must be freed.
1939 1943   */
1940 1944  
1941 1945  static char *
1942 1946  get_resource(sa_share_t share)
1943 1947  {
1944 1948          sa_resource_t resource;
1945 1949          char *resstring = NULL;
1946 1950          char *retstring;
1947 1951  
1948 1952          if ((resource = sa_get_share_resource(share, NULL)) != NULL) {
1949 1953                  resstring = sa_get_resource_attr(resource, "name");
1950 1954                  if (resstring != NULL) {
1951 1955                          char *cp;
1952 1956                          int len;
1953 1957  
1954 1958                          retstring = conv_from_utf8(resstring);
1955 1959                          if (retstring != resstring) {
1956 1960                                  sa_free_attr_string(resstring);
1957 1961                                  resstring = retstring;
1958 1962                          }
1959 1963                          if (strpbrk(resstring, " ") != NULL) {
1960 1964                                  /* account for quotes */
1961 1965                                  len = strlen(resstring) + 3;
1962 1966                                  cp = calloc(len, sizeof (char));
1963 1967                                  if (cp != NULL) {
1964 1968                                          (void) snprintf(cp, len,
1965 1969                                              "\"%s\"", resstring);
1966 1970                                          sa_free_attr_string(resstring);
1967 1971                                          resstring = cp;
1968 1972                                  } else {
1969 1973                                          sa_free_attr_string(resstring);
1970 1974                                          resstring = NULL;
1971 1975                                  }
1972 1976                          }
1973 1977                  }
1974 1978          }
1975 1979          return (resstring);
1976 1980  }
1977 1981  
1978 1982  /*
1979 1983   * has_resource_with_opt(share)
1980 1984   *
1981 1985   * Check to see if the share has any resource names with optionsets
1982 1986   * set. Also indicate if multiple resource names since the syntax
1983 1987   * would be about the same.
1984 1988   */
1985 1989  static int
1986 1990  has_resource_with_opt(sa_share_t share)
1987 1991  {
1988 1992          sa_resource_t resource;
1989 1993          int ret = B_FALSE;
1990 1994  
1991 1995          for (resource = sa_get_share_resource(share, NULL);
1992 1996              resource != NULL;
1993 1997              resource = sa_get_next_resource(resource)) {
1994 1998  
1995 1999                  if (sa_get_optionset(resource, NULL) != NULL) {
1996 2000                          ret = B_TRUE;
1997 2001                          break;
1998 2002                  }
1999 2003          }
2000 2004          return (ret);
2001 2005  }
2002 2006  
2003 2007  /*
2004 2008   * has_multiple_resource(share)
2005 2009   *
2006 2010   * Check to see if the share has multiple resource names since
2007 2011   * the syntax would be about the same.
2008 2012   */
2009 2013  static boolean_t
2010 2014  has_multiple_resource(sa_share_t share)
2011 2015  {
2012 2016          sa_resource_t resource;
2013 2017          int num;
2014 2018  
2015 2019          for (num = 0, resource = sa_get_share_resource(share, NULL);
2016 2020              resource != NULL;
2017 2021              resource = sa_get_next_resource(resource)) {
2018 2022                  num++;
2019 2023                  if (num > 1)
2020 2024                          return (B_TRUE);
2021 2025          }
2022 2026          return (B_FALSE);
2023 2027  }
2024 2028  
2025 2029  /*
2026 2030   * show_share(share, verbose, properties, proto, iszfs, sharepath)
2027 2031   *
2028 2032   * print out the share information. With the addition of resource as a
2029 2033   * full object that can have multiple instances below the share, we
2030 2034   * need to display that as well.
2031 2035   */
2032 2036  
2033 2037  static void
2034 2038  show_share(sa_share_t share, int verbose, int properties, char *proto,
2035 2039      int iszfs, char *sharepath)
2036 2040  {
2037 2041          char *drive;
2038 2042          char *exclude;
2039 2043          sa_resource_t resource = NULL;
2040 2044          char *description;
2041 2045          char *rsrcname;
2042 2046          int rsrcwithopt;
2043 2047          boolean_t multiple;
2044 2048          char *type;
2045 2049  
2046 2050          rsrcwithopt = has_resource_with_opt(share);
2047 2051  
2048 2052          if (verbose || (properties && rsrcwithopt)) {
2049 2053                  /* First, indicate if transient */
2050 2054                  type = sa_get_share_attr(share, "type");
2051 2055                  if (type != NULL && !iszfs && verbose &&
2052 2056                      strcmp(type, "transient") == 0)
2053 2057                          (void) printf("\t* ");
2054 2058                  else
2055 2059                          (void) printf("\t  ");
2056 2060  
2057 2061                  if (type != NULL)
2058 2062                          sa_free_attr_string(type);
2059 2063  
2060 2064                  /*
2061 2065                   * If we came in with verbose, we want to handle the case of
2062 2066                   * multiple resources as though they had properties set.
2063 2067                   */
2064 2068                  multiple = has_multiple_resource(share);
2065 2069  
2066 2070                  /*
2067 2071                   * if there is a description on the share and there
2068 2072                   * are resources, treat as multiple resources in order
2069 2073                   * to get all descriptions displayed.
2070 2074                   */
2071 2075                  description = sa_get_share_description(share);
2072 2076                  resource = sa_get_share_resource(share, NULL);
2073 2077  
2074 2078                  if (description != NULL && resource != NULL)
2075 2079                          multiple = B_TRUE;
2076 2080  
2077 2081                  /* Next, if not multiple follow old model */
2078 2082                  if (!multiple && !rsrcwithopt) {
2079 2083                          rsrcname = get_resource(share);
2080 2084                          if (rsrcname != NULL && strlen(rsrcname) > 0) {
2081 2085                                  (void) printf("%s=%s", rsrcname, sharepath);
2082 2086                          } else {
2083 2087                                  (void) printf("%s", sharepath);
2084 2088                          }
2085 2089                          if (rsrcname != NULL)
2086 2090                                  sa_free_attr_string(rsrcname);
2087 2091                          /* Print the description string if there is one. */
2088 2092                          print_rsrc_desc(resource, description);
2089 2093                  } else {
2090 2094                          /* Treat as simple and then resources come later */
2091 2095                          (void) printf("%s", sharepath);
2092 2096                  }
2093 2097                  drive = sa_get_share_attr(share, "drive-letter");
2094 2098                  if (drive != NULL) {
2095 2099                          if (strlen(drive) > 0)
2096 2100                                  (void) printf(gettext("\tdrive-letter=\"%s:\""),
2097 2101                                      drive);
2098 2102                          sa_free_attr_string(drive);
2099 2103                  }
2100 2104                  if (properties)
2101 2105                          show_properties(share, proto, "\t");
2102 2106                  exclude = sa_get_share_attr(share, "exclude");
2103 2107                  if (exclude != NULL) {
2104 2108                          (void) printf(gettext("\tnot-shared-with=[%s]"),
2105 2109                              exclude);
2106 2110                          sa_free_attr_string(exclude);
2107 2111                  }
2108 2112  
2109 2113                  if (description != NULL) {
2110 2114                          print_rsrc_desc((sa_resource_t)share, description);
2111 2115                  }
2112 2116                  /*
2113 2117                   * If there are resource names with options, show them
2114 2118                   * here, with one line per resource. Resource specific
2115 2119                   * options are at the end of the line followed by
2116 2120                   * description, if any.
2117 2121                   */
2118 2122                  if (rsrcwithopt || multiple) {
2119 2123                          for (resource = sa_get_share_resource(share, NULL);
2120 2124                              resource != NULL;
2121 2125                              resource = sa_get_next_resource(resource)) {
2122 2126                                  int has_space;
2123 2127                                  char *rsrc;
2124 2128  
2125 2129                                  (void) printf("\n\t\t  ");
2126 2130                                  rsrcname = sa_get_resource_attr(resource,
2127 2131                                      "name");
2128 2132                                  if (rsrcname == NULL)
2129 2133                                          continue;
2130 2134  
2131 2135                                  rsrc = conv_from_utf8(rsrcname);
2132 2136                                  has_space = strpbrk(rsrc, " ") != NULL;
2133 2137  
2134 2138                                  if (has_space)
2135 2139                                          (void) printf("\"%s\"=%s", rsrc,
2136 2140                                              sharepath);
2137 2141                                  else
2138 2142                                          (void) printf("%s=%s", rsrc,
2139 2143                                              sharepath);
2140 2144                                  if (rsrc != rsrcname)
2141 2145                                          sa_free_attr_string(rsrc);
2142 2146                                  sa_free_attr_string(rsrcname);
2143 2147                                  if (properties || rsrcwithopt)
2144 2148                                          show_properties(resource, proto, "\t");
2145 2149  
2146 2150                                  /* Get description string if any */
2147 2151                                  print_rsrc_desc(resource, description);
2148 2152                          }
2149 2153                  }
2150 2154                  if (description != NULL)
2151 2155                          sa_free_share_description(description);
2152 2156          } else {
2153 2157                  (void) printf("\t  %s", sharepath);
2154 2158                  if (properties)
2155 2159                          show_properties(share, proto, "\t");
2156 2160          }
2157 2161          (void) printf("\n");
2158 2162  }
2159 2163  
  
    | 
      ↓ open down ↓ | 
    2124 lines elided | 
    
      ↑ open up ↑ | 
  
2160 2164  /*
2161 2165   * show_group(group, verbose, properties, proto, subgroup)
2162 2166   *
2163 2167   * helper function to show the contents of a group.
2164 2168   */
2165 2169  
2166 2170  static void
2167 2171  show_group(sa_group_t group, int verbose, int properties, char *proto,
2168 2172      char *subgroup)
2169 2173  {
2170      -        sa_share_t share;
2171 2174          char *groupname;
2172 2175          char *zfs = NULL;
2173 2176          int iszfs = 0;
2174 2177          char *sharepath;
2175 2178  
2176 2179          groupname = sa_get_group_attr(group, "name");
2177 2180          if (groupname != NULL) {
     2181 +                sa_share_t share;
     2182 +
2178 2183                  if (proto != NULL && !has_protocol(group, proto)) {
2179 2184                          sa_free_attr_string(groupname);
2180 2185                          return;
2181 2186                  }
2182 2187                  /*
2183 2188                   * check to see if the group is managed by ZFS. If
2184 2189                   * there is an attribute, then it is. A non-NULL zfs
2185 2190                   * variable will trigger the different way to display
2186 2191                   * and will remove the transient property indicator
2187 2192                   * from the output.
2188 2193                   */
2189 2194                  zfs = sa_get_group_attr(group, "zfs");
2190 2195                  if (zfs != NULL) {
2191 2196                          iszfs = 1;
2192 2197                          sa_free_attr_string(zfs);
2193 2198                  }
2194      -                share = sa_get_share(group, NULL);
     2199 +
2195 2200                  if (subgroup == NULL)
2196 2201                          (void) printf("%s", groupname);
2197 2202                  else
2198 2203                          (void) printf("    %s/%s", subgroup, groupname);
2199 2204                  if (properties)
2200 2205                          show_properties(group, proto, "");
2201 2206                  (void) printf("\n");
2202 2207                  if (strcmp(groupname, "zfs") == 0) {
2203 2208                          sa_group_t zgroup;
2204 2209  
2205 2210                          for (zgroup = sa_get_sub_group(group);
2206 2211                              zgroup != NULL;
2207 2212                              zgroup = sa_get_next_group(zgroup)) {
2208 2213                                  show_group(zgroup, verbose, properties, proto,
2209 2214                                      "zfs");
2210 2215                          }
2211 2216                          sa_free_attr_string(groupname);
2212 2217                          return;
2213 2218                  }
2214 2219                  /*
2215 2220                   * Have a group, so list the contents. Resource and
2216 2221                   * description are only listed if verbose is set.
2217 2222                   */
2218 2223                  for (share = sa_get_share(group, NULL);
2219 2224                      share != NULL;
2220 2225                      share = sa_get_next_share(share)) {
2221 2226                          sharepath = sa_get_share_attr(share, "path");
2222 2227                          if (sharepath != NULL) {
2223 2228                                  show_share(share, verbose, properties, proto,
2224 2229                                      iszfs, sharepath);
2225 2230                                  sa_free_attr_string(sharepath);
2226 2231                          }
2227 2232                  }
2228 2233          }
2229 2234          if (groupname != NULL) {
2230 2235                  sa_free_attr_string(groupname);
2231 2236          }
2232 2237  }
2233 2238  
2234 2239  /*
2235 2240   * show_group_xml_init()
2236 2241   *
2237 2242   * Create an XML document that will be used to display config info via
2238 2243   * XML format.
2239 2244   */
2240 2245  
2241 2246  xmlDocPtr
2242 2247  show_group_xml_init()
2243 2248  {
2244 2249          xmlDocPtr doc;
2245 2250          xmlNodePtr root;
2246 2251  
2247 2252          doc = xmlNewDoc((xmlChar *)"1.0");
2248 2253          if (doc != NULL) {
2249 2254                  root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
2250 2255                  if (root != NULL)
2251 2256                          (void) xmlDocSetRootElement(doc, root);
2252 2257          }
2253 2258          return (doc);
2254 2259  }
2255 2260  
2256 2261  /*
2257 2262   * show_group_xml(doc, group)
2258 2263   *
2259 2264   * Copy the group info into the XML doc.
2260 2265   */
2261 2266  
2262 2267  static void
2263 2268  show_group_xml(xmlDocPtr doc, sa_group_t group)
2264 2269  {
2265 2270          xmlNodePtr node;
2266 2271          xmlNodePtr root;
2267 2272  
2268 2273          root = xmlDocGetRootElement(doc);
2269 2274          node = xmlCopyNode((xmlNodePtr)group, 1);
2270 2275          if (node != NULL && root != NULL) {
2271 2276                  (void) xmlAddChild(root, node);
2272 2277                  /*
2273 2278                   * In the future, we may have interally used tags that
2274 2279                   * should not appear in the XML output. Remove
2275 2280                   * anything we don't want to show here.
2276 2281                   */
2277 2282          }
2278 2283  }
2279 2284  
2280 2285  /*
2281 2286   * sa_show(flags, argc, argv)
2282 2287   *
2283 2288   * Implements the show subcommand.
2284 2289   */
2285 2290  
2286 2291  int
2287 2292  sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
2288 2293  {
2289 2294          sa_group_t group;
2290 2295          int verbose = 0;
2291 2296          int properties = 0;
2292 2297          int c;
2293 2298          int ret = SA_OK;
2294 2299          char *protocol = NULL;
2295 2300          int xml = 0;
2296 2301          xmlDocPtr doc;
2297 2302  #ifdef lint
2298 2303          flags = flags;
2299 2304  #endif
2300 2305  
2301 2306          while ((c = getopt(argc, argv, "?hvP:px")) !=   EOF) {
2302 2307                  switch (c) {
2303 2308                  case 'v':
2304 2309                          verbose++;
2305 2310                          break;
2306 2311                  case 'p':
2307 2312                          properties++;
2308 2313                          break;
2309 2314                  case 'P':
2310 2315                          if (protocol != NULL) {
2311 2316                                  (void) printf(gettext(
2312 2317                                      "Specifying multiple protocols "
2313 2318                                      "not supported: %s\n"),
2314 2319                                      protocol);
2315 2320                                  return (SA_SYNTAX_ERR);
2316 2321                          }
2317 2322                          protocol = optarg;
2318 2323                          if (!sa_valid_protocol(protocol)) {
2319 2324                                  (void) printf(gettext(
2320 2325                                      "Invalid protocol specified: %s\n"),
2321 2326                                      protocol);
2322 2327                                  return (SA_INVALID_PROTOCOL);
2323 2328                          }
2324 2329                          break;
2325 2330                  case 'x':
2326 2331                          xml++;
2327 2332                          break;
2328 2333                  case 'h':
2329 2334                          /* optopt on valid arg isn't defined */
2330 2335                          optopt = c;
2331 2336                          /*FALLTHROUGH*/
2332 2337                  case '?':
2333 2338                  default:
2334 2339                          /*
2335 2340                           * Since a bad option gets to here, sort it
2336 2341                           * out and return a syntax error return value
2337 2342                           * if necessary.
2338 2343                           */
2339 2344                          switch (optopt) {
2340 2345                          default:
2341 2346                                  ret = SA_SYNTAX_ERR;
2342 2347                                  break;
2343 2348                          case 'h':
2344 2349                          case '?':
2345 2350                                  break;
2346 2351                          }
2347 2352                          (void) printf(gettext("usage: %s\n"),
2348 2353                              sa_get_usage(USAGE_SHOW));
2349 2354                          return (ret);
2350 2355                  }
2351 2356          }
2352 2357  
2353 2358          if (xml) {
2354 2359                  doc = show_group_xml_init();
2355 2360                  if (doc == NULL)
2356 2361                          ret = SA_NO_MEMORY;
2357 2362          }
2358 2363  
2359 2364          if (optind == argc) {
2360 2365                  /* No group specified so go through them all */
2361 2366                  for (group = sa_get_group(handle, NULL);
2362 2367                      group != NULL;
2363 2368                      group = sa_get_next_group(group)) {
2364 2369                          /*
2365 2370                           * Have a group so check if one we want and then list
2366 2371                           * contents with appropriate options.
2367 2372                           */
2368 2373                          if (xml)
2369 2374                                  show_group_xml(doc, group);
2370 2375                          else
2371 2376                                  show_group(group, verbose, properties, protocol,
2372 2377                                      NULL);
2373 2378                  }
2374 2379          } else {
2375 2380                  /* Have a specified list of groups */
2376 2381                  for (; optind < argc; optind++) {
2377 2382                          group = sa_get_group(handle, argv[optind]);
2378 2383                          if (group != NULL) {
2379 2384                                  if (xml)
2380 2385                                          show_group_xml(doc, group);
2381 2386                                  else
2382 2387                                          show_group(group, verbose, properties,
2383 2388                                              protocol, NULL);
2384 2389                          } else {
2385 2390                                  (void) printf(gettext("%s: not found\n"),
2386 2391                                      argv[optind]);
2387 2392                                  ret = SA_NO_SUCH_GROUP;
2388 2393                          }
2389 2394                  }
2390 2395          }
2391 2396          if (xml && ret == SA_OK) {
2392 2397                  (void) xmlDocFormatDump(stdout, doc, 1);
2393 2398                  xmlFreeDoc(doc);
2394 2399          }
2395 2400          return (ret);
2396 2401  
2397 2402  }
2398 2403  
2399 2404  /*
2400 2405   * enable_share(group, share, update_legacy)
2401 2406   *
2402 2407   * helper function to enable a share if the group is enabled.
2403 2408   */
2404 2409  
2405 2410  static int
2406 2411  enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
2407 2412      int update_legacy)
2408 2413  {
2409 2414          char *value;
2410 2415          int enabled;
2411 2416          sa_optionset_t optionset;
2412 2417          int err;
2413 2418          int ret = SA_OK;
2414 2419          char *zfs = NULL;
2415 2420          int iszfs = 0;
2416 2421          int isshare;
2417 2422  
2418 2423          /*
2419 2424           * need to enable this share if the group is enabled but not
2420 2425           * otherwise. The enable is also done on each protocol
2421 2426           * represented in the group.
2422 2427           */
2423 2428          value = sa_get_group_attr(group, "state");
2424 2429          enabled = value != NULL && strcmp(value, "enabled") == 0;
2425 2430          if (value != NULL)
2426 2431                  sa_free_attr_string(value);
2427 2432          /* remove legacy config if necessary */
2428 2433          if (update_legacy)
2429 2434                  ret = sa_delete_legacy(share, NULL);
2430 2435          zfs = sa_get_group_attr(group, "zfs");
2431 2436          if (zfs != NULL) {
2432 2437                  iszfs++;
2433 2438                  sa_free_attr_string(zfs);
2434 2439          }
2435 2440  
2436 2441          /*
2437 2442           * Step through each optionset at the group level and
2438 2443           * enable the share based on the protocol type. This
2439 2444           * works because protocols must be set on the group
2440 2445           * for the protocol to be enabled.
2441 2446           */
2442 2447          isshare = sa_is_share(share);
2443 2448          for (optionset = sa_get_optionset(group, NULL);
2444 2449              optionset != NULL && ret == SA_OK;
2445 2450              optionset = sa_get_next_optionset(optionset)) {
2446 2451                  value = sa_get_optionset_attr(optionset, "type");
2447 2452                  if (value != NULL) {
2448 2453                          if (enabled) {
2449 2454                                  if (isshare) {
2450 2455                                          err = sa_enable_share(share, value);
2451 2456                                  } else {
2452 2457                                          err = sa_enable_resource(share, value);
2453 2458                                          if (err == SA_NOT_SUPPORTED) {
2454 2459                                                  sa_share_t parent;
2455 2460                                                  parent = sa_get_resource_parent(
2456 2461                                                      share);
2457 2462                                                  if (parent != NULL)
2458 2463                                                          err = sa_enable_share(
2459 2464                                                              parent, value);
2460 2465                                          }
2461 2466                                  }
2462 2467                                  if (err != SA_OK) {
2463 2468                                          ret = err;
2464 2469                                          (void) printf(gettext(
2465 2470                                              "Failed to enable share for "
2466 2471                                              "\"%s\": %s\n"),
2467 2472                                              value, sa_errorstr(ret));
2468 2473                                  }
2469 2474                          }
2470 2475                          /*
2471 2476                           * If we want to update the legacy, use a copy of
2472 2477                           * share so we can avoid breaking the loop we are in
2473 2478                           * since we might also need to go up the tree to the
2474 2479                           * parent.
2475 2480                           */
2476 2481                          if (update_legacy && !iszfs) {
2477 2482                                  sa_share_t update = share;
2478 2483                                  if (!sa_is_share(share)) {
2479 2484                                          update = sa_get_resource_parent(share);
2480 2485                                  }
2481 2486                                  (void) sa_update_legacy(update, value);
2482 2487                          }
2483 2488                          sa_free_attr_string(value);
2484 2489                  }
2485 2490          }
2486 2491          if (ret == SA_OK)
2487 2492                  (void) sa_update_config(handle);
2488 2493          return (ret);
2489 2494  }
2490 2495  
2491 2496  /*
2492 2497   * sa_require_resource(group)
2493 2498   *
2494 2499   * if any of the defined protocols on the group require resource
2495 2500   * names, then all shares must have them.
2496 2501   */
2497 2502  
2498 2503  static int
2499 2504  sa_require_resource(sa_group_t group)
2500 2505  {
2501 2506          sa_optionset_t optionset;
2502 2507  
2503 2508          for (optionset = sa_get_optionset(group, NULL);
2504 2509              optionset != NULL;
2505 2510              optionset = sa_get_next_optionset(optionset)) {
2506 2511                  char *proto;
2507 2512  
2508 2513                  proto = sa_get_optionset_attr(optionset, "type");
2509 2514                  if (proto != NULL) {
2510 2515                          uint64_t features;
2511 2516  
2512 2517                          features = sa_proto_get_featureset(proto);
2513 2518                          if (features & SA_FEATURE_RESOURCE) {
2514 2519                                  sa_free_attr_string(proto);
2515 2520                                  return (B_TRUE);
2516 2521                          }
2517 2522                          sa_free_attr_string(proto);
2518 2523                  }
2519 2524          }
2520 2525          return (B_FALSE);
2521 2526  }
2522 2527  
2523 2528  /*
2524 2529   * sa_addshare(flags, argc, argv)
2525 2530   *
2526 2531   * implements add-share subcommand.
2527 2532   */
2528 2533  
2529 2534  static int
2530 2535  sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
2531 2536  {
2532 2537          int verbose = 0;
2533 2538          int dryrun = 0;
2534 2539          int c;
2535 2540          int ret = SA_OK;
2536 2541          sa_group_t group;
2537 2542          sa_share_t share;
2538 2543          sa_resource_t resource = NULL;
2539 2544          char *sharepath = NULL;
2540 2545          char *description = NULL;
2541 2546          char *rsrcname = NULL;
2542 2547          char *rsrc = NULL;
2543 2548          int persist = SA_SHARE_PERMANENT; /* default to persist */
2544 2549          int auth;
2545 2550          char dir[MAXPATHLEN];
2546 2551  
2547 2552          while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
2548 2553                  switch (c) {
2549 2554                  case 'n':
2550 2555                          dryrun++;
2551 2556                          break;
2552 2557                  case 'v':
2553 2558                          verbose++;
2554 2559                          break;
2555 2560                  case 'd':
2556 2561                          description = optarg;
2557 2562                          break;
2558 2563                  case 'r':
2559 2564                          if (rsrcname != NULL) {
2560 2565                                  (void) printf(gettext("Adding multiple "
2561 2566                                      "resource names not"
2562 2567                                      " supported\n"));
2563 2568                                  return (SA_SYNTAX_ERR);
2564 2569                          }
2565 2570                          rsrcname = optarg;
2566 2571                          break;
2567 2572                  case 's':
2568 2573                          /*
2569 2574                           * Save share path into group. Currently limit
2570 2575                           * to one share per command.
2571 2576                           */
2572 2577                          if (sharepath != NULL) {
2573 2578                                  (void) printf(gettext(
2574 2579                                      "Adding multiple shares not supported\n"));
2575 2580                                  return (SA_SYNTAX_ERR);
2576 2581                          }
2577 2582                          sharepath = optarg;
2578 2583                          break;
2579 2584                  case 't':
2580 2585                          persist = SA_SHARE_TRANSIENT;
2581 2586                          break;
2582 2587                  case 'h':
2583 2588                          /* optopt on valid arg isn't defined */
2584 2589                          optopt = c;
2585 2590                          /*FALLTHROUGH*/
2586 2591                  case '?':
2587 2592                  default:
2588 2593                          /*
2589 2594                           * Since a bad option gets to here, sort it
2590 2595                           * out and return a syntax error return value
2591 2596                           * if necessary.
2592 2597                           */
2593 2598                          switch (optopt) {
2594 2599                          default:
2595 2600                                  ret = SA_SYNTAX_ERR;
2596 2601                                  break;
2597 2602                          case 'h':
2598 2603                          case '?':
2599 2604                                  break;
2600 2605                          }
2601 2606                          (void) printf(gettext("usage: %s\n"),
2602 2607                              sa_get_usage(USAGE_ADD_SHARE));
2603 2608                          return (ret);
2604 2609                  }
2605 2610          }
2606 2611  
2607 2612          if (optind >= argc) {
2608 2613                  (void) printf(gettext("usage: %s\n"),
2609 2614                      sa_get_usage(USAGE_ADD_SHARE));
2610 2615                  if (dryrun || sharepath != NULL || description != NULL ||
2611 2616                      rsrcname != NULL || verbose || persist) {
2612 2617                          (void) printf(gettext("\tgroup must be specified\n"));
2613 2618                          ret = SA_NO_SUCH_GROUP;
2614 2619                  } else {
2615 2620                          ret = SA_OK;
2616 2621                  }
2617 2622          } else {
2618 2623                  if (sharepath == NULL) {
2619 2624                          (void) printf(gettext("usage: %s\n"),
2620 2625                              sa_get_usage(USAGE_ADD_SHARE));
2621 2626                          (void) printf(gettext(
2622 2627                              "\t-s sharepath must be specified\n"));
2623 2628                          ret = SA_BAD_PATH;
2624 2629                  }
2625 2630                  if (ret == SA_OK) {
2626 2631                          if (realpath(sharepath, dir) == NULL) {
2627 2632                                  ret = SA_BAD_PATH;
2628 2633                                  (void) printf(gettext("Path "
2629 2634                                      "is not valid: %s\n"),
2630 2635                                      sharepath);
2631 2636                          } else {
2632 2637                                  sharepath = dir;
2633 2638                          }
2634 2639                  }
2635 2640                  if (ret == SA_OK && rsrcname != NULL) {
2636 2641                          /* check for valid syntax */
2637 2642                          if (validresource(rsrcname)) {
2638 2643                                  rsrc = conv_to_utf8(rsrcname);
2639 2644                                  resource = sa_find_resource(handle, rsrc);
2640 2645                                  if (resource != NULL) {
2641 2646                                          /*
2642 2647                                           * Resource names must be
2643 2648                                           * unique in the system
2644 2649                                           */
2645 2650                                          ret = SA_DUPLICATE_NAME;
2646 2651                                          (void) printf(gettext("usage: %s\n"),
2647 2652                                              sa_get_usage(USAGE_ADD_SHARE));
2648 2653                                          (void) printf(gettext(
2649 2654                                              "\tresource names must be unique "
2650 2655                                              "in the system\n"));
2651 2656                                  }
2652 2657                          } else {
2653 2658                                  (void) printf(gettext("usage: %s\n"),
2654 2659                                      sa_get_usage(USAGE_ADD_SHARE));
2655 2660                                  (void) printf(gettext(
2656 2661                                      "\tresource names use restricted "
2657 2662                                      "character set\n"));
2658 2663                                  ret = SA_INVALID_NAME;
2659 2664                          }
2660 2665                  }
2661 2666  
2662 2667                  if (ret != SA_OK) {
2663 2668                          if (rsrc != NULL && rsrcname != rsrc)
2664 2669                                  sa_free_attr_string(rsrc);
2665 2670                          return (ret);
2666 2671                  }
2667 2672  
2668 2673                  share = sa_find_share(handle, sharepath);
2669 2674                  if (share != NULL) {
2670 2675                          if (rsrcname == NULL) {
2671 2676                                  /*
2672 2677                                   * Can only have a duplicate share if a new
2673 2678                                   * resource name is being added.
2674 2679                                   */
2675 2680                                  ret = SA_DUPLICATE_NAME;
2676 2681                                  (void) printf(gettext("Share path already "
2677 2682                                      "shared: %s\n"), sharepath);
2678 2683                          }
2679 2684                  }
2680 2685                  if (ret != SA_OK)
2681 2686                          return (ret);
2682 2687  
2683 2688                  group = sa_get_group(handle, argv[optind]);
2684 2689                  if (group != NULL) {
2685 2690                          if (sa_require_resource(group) == B_TRUE &&
2686 2691                              rsrcname == NULL) {
2687 2692                                  (void) printf(gettext(
2688 2693                                      "Resource name is required "
2689 2694                                      "by at least one enabled protocol "
2690 2695                                      "in group\n"));
2691 2696                                  return (SA_RESOURCE_REQUIRED);
2692 2697                          }
2693 2698                          if (share == NULL && ret == SA_OK) {
2694 2699                                  if (dryrun)
2695 2700                                          ret = sa_check_path(group, sharepath,
2696 2701                                              SA_CHECK_NORMAL);
2697 2702                                  else
2698 2703                                          share = sa_add_share(group, sharepath,
2699 2704                                              persist, &ret);
2700 2705                          }
2701 2706                          /*
2702 2707                           * Make sure this isn't an attempt to put a resourced
2703 2708                           * share into a different group than it already is in.
2704 2709                           */
2705 2710                          if (share != NULL) {
2706 2711                                  sa_group_t parent;
2707 2712                                  parent = sa_get_parent_group(share);
2708 2713                                  if (parent != group) {
2709 2714                                          ret = SA_DUPLICATE_NAME;
2710 2715                                          (void) printf(gettext(
2711 2716                                              "Share path already "
2712 2717                                              "shared: %s\n"), sharepath);
2713 2718                                  }
2714 2719                          }
2715 2720                          if (!dryrun && share == NULL) {
2716 2721                                  (void) printf(gettext(
2717 2722                                      "Could not add share: %s\n"),
2718 2723                                      sa_errorstr(ret));
2719 2724                          } else {
2720 2725                                  auth = check_authorizations(argv[optind],
2721 2726                                      flags);
2722 2727                                  if (!dryrun && ret == SA_OK) {
2723 2728                                          if (rsrcname != NULL) {
2724 2729                                                  resource = sa_add_resource(
2725 2730                                                      share,
2726 2731                                                      rsrc,
2727 2732                                                      SA_SHARE_PERMANENT,
2728 2733                                                      &ret);
2729 2734                                          }
2730 2735                                          if (ret == SA_OK &&
2731 2736                                              description != NULL) {
2732 2737                                                  if (resource != NULL)
2733 2738                                                          ret =
2734 2739                                                              set_resource_desc(
2735 2740                                                              resource,
2736 2741                                                              description);
2737 2742                                                  else
2738 2743                                                          ret =
2739 2744                                                              set_share_desc(
2740 2745                                                              share,
2741 2746                                                              description);
2742 2747                                          }
2743 2748                                          if (ret == SA_OK) {
2744 2749                                                  /* now enable the share(s) */
2745 2750                                                  if (resource != NULL) {
2746 2751                                                          ret = enable_share(
2747 2752                                                              handle,
2748 2753                                                              group,
2749 2754                                                              resource,
2750 2755                                                              1);
2751 2756                                                  } else {
2752 2757                                                          ret = enable_share(
2753 2758                                                              handle,
2754 2759                                                              group,
2755 2760                                                              share,
2756 2761                                                              1);
2757 2762                                                  }
2758 2763                                                  ret = sa_update_config(handle);
2759 2764                                          }
2760 2765                                          switch (ret) {
2761 2766                                          case SA_DUPLICATE_NAME:
2762 2767                                                  (void) printf(gettext(
2763 2768                                                      "Resource name in"
2764 2769                                                      "use: %s\n"),
2765 2770                                                      rsrcname);
2766 2771                                                  break;
2767 2772                                          default:
2768 2773                                                  (void) printf(gettext(
2769 2774                                                      "Could not set "
2770 2775                                                      "attribute: %s\n"),
2771 2776                                                      sa_errorstr(ret));
2772 2777                                                  break;
2773 2778                                          case SA_OK:
2774 2779                                                  break;
2775 2780                                          }
2776 2781                                  } else if (dryrun && ret == SA_OK &&
2777 2782                                      !auth && verbose) {
2778 2783                                          (void) printf(gettext(
2779 2784                                              "Command would fail: %s\n"),
2780 2785                                              sa_errorstr(SA_NO_PERMISSION));
2781 2786                                          ret = SA_NO_PERMISSION;
2782 2787                                  }
2783 2788                          }
2784 2789                  } else {
2785 2790                          switch (ret) {
2786 2791                          default:
2787 2792                                  (void) printf(gettext(
2788 2793                                      "Group \"%s\" not found\n"), argv[optind]);
2789 2794                                  ret = SA_NO_SUCH_GROUP;
2790 2795                                  break;
2791 2796                          case SA_BAD_PATH:
2792 2797                          case SA_DUPLICATE_NAME:
2793 2798                                  break;
2794 2799                          }
2795 2800                  }
2796 2801          }
2797 2802          return (ret);
2798 2803  }
2799 2804  
2800 2805  /*
2801 2806   * sa_moveshare(flags, argc, argv)
2802 2807   *
2803 2808   * implements move-share subcommand.
2804 2809   */
2805 2810  
2806 2811  int
2807 2812  sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
2808 2813  {
2809 2814          int verbose = 0;
2810 2815          int dryrun = 0;
2811 2816          int c;
2812 2817          int ret = SA_OK;
2813 2818          sa_group_t group;
2814 2819          sa_share_t share;
2815 2820          char *rsrcname = NULL;
2816 2821          char *sharepath = NULL;
2817 2822          int authsrc = 0, authdst = 0;
2818 2823          char dir[MAXPATHLEN];
2819 2824  
2820 2825          while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) {
2821 2826                  switch (c) {
2822 2827                  case 'n':
2823 2828                          dryrun++;
2824 2829                          break;
2825 2830                  case 'v':
2826 2831                          verbose++;
2827 2832                          break;
2828 2833                  case 'r':
2829 2834                          if (rsrcname != NULL) {
2830 2835                                  (void) printf(gettext(
2831 2836                                      "Moving multiple resource names not"
2832 2837                                      " supported\n"));
2833 2838                                  return (SA_SYNTAX_ERR);
2834 2839                          }
2835 2840                          rsrcname = optarg;
2836 2841                          break;
2837 2842                  case 's':
2838 2843                          /*
2839 2844                           * Remove share path from group. Currently limit
2840 2845                           * to one share per command.
2841 2846                           */
2842 2847                          if (sharepath != NULL) {
2843 2848                                  (void) printf(gettext("Moving multiple shares"
2844 2849                                      " not supported\n"));
2845 2850                                  return (SA_SYNTAX_ERR);
2846 2851                          }
2847 2852                          sharepath = optarg;
2848 2853                          break;
2849 2854                  case 'h':
2850 2855                          /* optopt on valid arg isn't defined */
2851 2856                          optopt = c;
2852 2857                          /*FALLTHROUGH*/
2853 2858                  case '?':
2854 2859                  default:
2855 2860                          /*
2856 2861                           * Since a bad option gets to here, sort it
2857 2862                           * out and return a syntax error return value
2858 2863                           * if necessary.
2859 2864                           */
2860 2865                          switch (optopt) {
2861 2866                          default:
2862 2867                                  ret = SA_SYNTAX_ERR;
2863 2868                                  break;
2864 2869                          case 'h':
2865 2870                          case '?':
2866 2871                                  break;
2867 2872                          }
2868 2873                          (void) printf(gettext("usage: %s\n"),
2869 2874                              sa_get_usage(USAGE_MOVE_SHARE));
2870 2875                          return (ret);
2871 2876                  }
2872 2877          }
2873 2878  
2874 2879          if (optind >= argc || sharepath == NULL) {
2875 2880                  (void) printf(gettext("usage: %s\n"),
2876 2881                      sa_get_usage(USAGE_MOVE_SHARE));
2877 2882                  if (dryrun || verbose || sharepath != NULL) {
2878 2883                          (void) printf(gettext("\tgroup must be specified\n"));
2879 2884                          ret = SA_NO_SUCH_GROUP;
2880 2885                  } else {
2881 2886                          if (sharepath == NULL) {
2882 2887                                  ret = SA_SYNTAX_ERR;
2883 2888                                  (void) printf(gettext(
2884 2889                                      "\tsharepath must be specified\n"));
2885 2890                          } else {
2886 2891                                  ret = SA_OK;
2887 2892                          }
2888 2893                  }
2889 2894          } else {
2890 2895                  sa_group_t parent;
2891 2896                  char *zfsold;
2892 2897                  char *zfsnew;
2893 2898  
2894 2899                  if (sharepath == NULL) {
2895 2900                          (void) printf(gettext(
2896 2901                              "sharepath must be specified with the -s "
2897 2902                              "option\n"));
2898 2903                          return (SA_BAD_PATH);
2899 2904                  }
2900 2905                  group = sa_get_group(handle, argv[optind]);
2901 2906                  if (group == NULL) {
2902 2907                          (void) printf(gettext("Group \"%s\" not found\n"),
2903 2908                              argv[optind]);
2904 2909                          return (SA_NO_SUCH_GROUP);
2905 2910                  }
2906 2911                  share = sa_find_share(handle, sharepath);
2907 2912                  /*
2908 2913                   * If a share wasn't found, it may have been a symlink
2909 2914                   * or has a trailing '/'. Try again after resolving
2910 2915                   * with realpath().
2911 2916                   */
2912 2917                  if (share == NULL) {
2913 2918                          if (realpath(sharepath, dir) == NULL) {
2914 2919                                  (void) printf(gettext("Path "
2915 2920                                      "is not valid: %s\n"),
2916 2921                                      sharepath);
2917 2922                                  return (SA_BAD_PATH);
2918 2923                          }
2919 2924                          sharepath = dir;
2920 2925                          share = sa_find_share(handle, sharepath);
2921 2926                  }
2922 2927                  if (share == NULL) {
2923 2928                          (void) printf(gettext("Share not found: %s\n"),
2924 2929                              sharepath);
2925 2930                          return (SA_NO_SUCH_PATH);
2926 2931                  }
2927 2932                  authdst = check_authorizations(argv[optind], flags);
2928 2933  
2929 2934                  parent = sa_get_parent_group(share);
2930 2935                  if (parent != NULL) {
2931 2936                          char *pname;
2932 2937                          pname = sa_get_group_attr(parent, "name");
2933 2938                          if (pname != NULL) {
2934 2939                                  authsrc = check_authorizations(pname, flags);
2935 2940                                  sa_free_attr_string(pname);
2936 2941                          }
2937 2942                          zfsold = sa_get_group_attr(parent, "zfs");
2938 2943                          zfsnew = sa_get_group_attr(group, "zfs");
2939 2944                          if ((zfsold != NULL && zfsnew == NULL) ||
2940 2945                              (zfsold == NULL && zfsnew != NULL)) {
2941 2946                                  ret = SA_NOT_ALLOWED;
2942 2947                          }
2943 2948                          if (zfsold != NULL)
2944 2949                                  sa_free_attr_string(zfsold);
2945 2950                          if (zfsnew != NULL)
2946 2951                                  sa_free_attr_string(zfsnew);
2947 2952                  }
2948 2953  
2949 2954                  if (ret == SA_OK && parent != group && !dryrun) {
2950 2955                          char *oldstate;
2951 2956                          /*
2952 2957                           * Note that the share may need to be
2953 2958                           * "unshared" if the new group is disabled and
2954 2959                           * the old was enabled or it may need to be
2955 2960                           * share to update if the new group is
2956 2961                           * enabled. We disable before the move and
2957 2962                           * will have to enable after the move in order
2958 2963                           * to cleanup entries for protocols that
2959 2964                           * aren't in the new group.
2960 2965                           */
2961 2966                          oldstate = sa_get_group_attr(parent, "state");
2962 2967                          if (oldstate != NULL) {
2963 2968                                  /* enable_share determines what to do */
2964 2969                                  if (strcmp(oldstate, "enabled") == 0)
2965 2970                                          (void) sa_disable_share(share, NULL);
2966 2971                                  sa_free_attr_string(oldstate);
2967 2972                          }
2968 2973                  }
2969 2974  
2970 2975                  if (!dryrun && ret == SA_OK)
2971 2976                          ret = sa_move_share(group, share);
2972 2977  
2973 2978                  /*
2974 2979                   * Reenable and update any config information.
2975 2980                   */
2976 2981                  if (ret == SA_OK && parent != group && !dryrun) {
2977 2982                          ret = sa_update_config(handle);
2978 2983  
2979 2984                          (void) enable_share(handle, group, share, 1);
2980 2985                  }
2981 2986  
2982 2987                  if (ret != SA_OK)
2983 2988                          (void) printf(gettext("Could not move share: %s\n"),
2984 2989                              sa_errorstr(ret));
2985 2990  
2986 2991                  if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
2987 2992                      verbose) {
2988 2993                          (void) printf(gettext("Command would fail: %s\n"),
2989 2994                              sa_errorstr(SA_NO_PERMISSION));
2990 2995                  }
2991 2996          }
2992 2997          return (ret);
2993 2998  }
2994 2999  
2995 3000  /*
2996 3001   * sa_removeshare(flags, argc, argv)
2997 3002   *
2998 3003   * implements remove-share subcommand.
2999 3004   */
3000 3005  
3001 3006  int
3002 3007  sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
3003 3008  {
3004 3009          int verbose = 0;
3005 3010          int dryrun = 0;
3006 3011          int force = 0;
3007 3012          int c;
3008 3013          int ret = SA_OK;
3009 3014          sa_group_t group;
3010 3015          sa_resource_t resource = NULL;
3011 3016          sa_share_t share = NULL;
3012 3017          char *rsrcname = NULL;
3013 3018          char *sharepath = NULL;
3014 3019          char dir[MAXPATHLEN];
3015 3020          int auth;
3016 3021  
3017 3022          while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) {
3018 3023                  switch (c) {
3019 3024                  case 'n':
3020 3025                          dryrun++;
3021 3026                          break;
3022 3027                  case 'v':
3023 3028                          verbose++;
3024 3029                          break;
3025 3030                  case 'f':
3026 3031                          force++;
3027 3032                          break;
3028 3033                  case 's':
3029 3034                          /*
3030 3035                           * Remove share path from group. Currently limit
3031 3036                           * to one share per command.
3032 3037                           */
3033 3038                          if (sharepath != NULL) {
3034 3039                                  (void) printf(gettext(
3035 3040                                      "Removing multiple shares not "
3036 3041                                      "supported\n"));
3037 3042                                  return (SA_SYNTAX_ERR);
3038 3043                          }
3039 3044                          sharepath = optarg;
3040 3045                          break;
3041 3046                  case 'r':
3042 3047                          /*
3043 3048                           * Remove share from group if last resource or remove
3044 3049                           * resource from share if multiple resources.
3045 3050                           */
3046 3051                          if (rsrcname != NULL) {
3047 3052                                  (void) printf(gettext(
3048 3053                                      "Removing multiple resource names not "
3049 3054                                      "supported\n"));
3050 3055                                  return (SA_SYNTAX_ERR);
3051 3056                          }
3052 3057                          rsrcname = optarg;
3053 3058                          break;
3054 3059                  case 'h':
3055 3060                          /* optopt on valid arg isn't defined */
3056 3061                          optopt = c;
3057 3062                          /*FALLTHROUGH*/
3058 3063                  case '?':
3059 3064                  default:
3060 3065                          /*
3061 3066                           * Since a bad option gets to here, sort it
3062 3067                           * out and return a syntax error return value
3063 3068                           * if necessary.
3064 3069                           */
3065 3070                          switch (optopt) {
3066 3071                          default:
3067 3072                                  ret = SA_SYNTAX_ERR;
3068 3073                                  break;
3069 3074                          case 'h':
3070 3075                          case '?':
3071 3076                                  break;
3072 3077                          }
3073 3078                          (void) printf(gettext("usage: %s\n"),
3074 3079                              sa_get_usage(USAGE_REMOVE_SHARE));
3075 3080                          return (ret);
3076 3081                  }
3077 3082          }
3078 3083  
3079 3084          if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) {
3080 3085                  if (sharepath == NULL && rsrcname == NULL) {
3081 3086                          (void) printf(gettext("usage: %s\n"),
3082 3087                              sa_get_usage(USAGE_REMOVE_SHARE));
3083 3088                          (void) printf(gettext("\t-s sharepath or -r resource"
3084 3089                              " must be specified\n"));
3085 3090                          ret = SA_BAD_PATH;
3086 3091                  } else {
3087 3092                          ret = SA_OK;
3088 3093                  }
3089 3094          }
3090 3095          if (ret != SA_OK) {
3091 3096                  return (ret);
3092 3097          }
3093 3098  
3094 3099          if (optind < argc) {
3095 3100                  if ((optind + 1) < argc) {
3096 3101                          (void) printf(gettext("Extraneous group(s) at end of "
3097 3102                              "command\n"));
3098 3103                          ret = SA_SYNTAX_ERR;
3099 3104                  } else {
3100 3105                          group = sa_get_group(handle, argv[optind]);
3101 3106                          if (group == NULL) {
3102 3107                                  (void) printf(gettext(
3103 3108                                      "Group \"%s\" not found\n"), argv[optind]);
3104 3109                                  ret = SA_NO_SUCH_GROUP;
3105 3110                          }
3106 3111                  }
3107 3112          } else {
3108 3113                  group = NULL;
3109 3114          }
3110 3115  
3111 3116          if (rsrcname != NULL) {
3112 3117                  resource = sa_find_resource(handle, rsrcname);
3113 3118                  if (resource == NULL) {
3114 3119                          ret = SA_NO_SUCH_RESOURCE;
3115 3120                          (void) printf(gettext(
3116 3121                              "Resource name not found for share: %s\n"),
3117 3122                              rsrcname);
3118 3123                  }
3119 3124          }
3120 3125  
3121 3126          /*
3122 3127           * Lookup the path in the internal configuration. Care
3123 3128           * must be taken to handle the case where the
3124 3129           * underlying path has been removed since we need to
3125 3130           * be able to deal with that as well.
3126 3131           */
3127 3132          if (ret == SA_OK) {
3128 3133                  if (sharepath != NULL) {
3129 3134                          if (group != NULL)
3130 3135                                  share = sa_get_share(group, sharepath);
3131 3136                          else
3132 3137                                  share = sa_find_share(handle, sharepath);
3133 3138                  }
3134 3139  
3135 3140                  if (resource != NULL) {
3136 3141                          sa_share_t rsrcshare;
3137 3142                          rsrcshare = sa_get_resource_parent(resource);
3138 3143                          if (share == NULL)
3139 3144                                  share = rsrcshare;
3140 3145                          else if (share != rsrcshare) {
3141 3146                                  ret = SA_NO_SUCH_RESOURCE;
3142 3147                                  (void) printf(gettext(
3143 3148                                      "Bad resource name for share: %s\n"),
3144 3149                                      rsrcname);
3145 3150                                  share = NULL;
3146 3151                          }
3147 3152                  }
3148 3153  
3149 3154                  /*
3150 3155                   * If we didn't find the share with the provided path,
3151 3156                   * it may be a symlink so attempt to resolve it using
3152 3157                   * realpath and try again. Realpath will resolve any
3153 3158                   * symlinks and place them in "dir". Note that
3154 3159                   * sharepath is only used for the lookup the first
3155 3160                   * time and later for error messages. dir will be used
3156 3161                   * on the second attempt. Once a share is found, all
3157 3162                   * operations are based off of the share variable.
3158 3163                   */
3159 3164                  if (share == NULL) {
3160 3165                          if (realpath(sharepath, dir) == NULL) {
3161 3166                                  ret = SA_BAD_PATH;
3162 3167                                  (void) printf(gettext(
3163 3168                                      "Path is not valid: %s\n"), sharepath);
3164 3169                          } else {
3165 3170                                  if (group != NULL)
3166 3171                                          share = sa_get_share(group, dir);
3167 3172                                  else
3168 3173                                          share = sa_find_share(handle, dir);
3169 3174                          }
3170 3175                  }
3171 3176          }
3172 3177  
3173 3178          /*
3174 3179           * If there hasn't been an error, there was likely a
3175 3180           * path found. If not, give the appropriate error
3176 3181           * message and set the return error. If it was found,
3177 3182           * then disable the share and then remove it from the
3178 3183           * configuration.
3179 3184           */
3180 3185          if (ret != SA_OK) {
3181 3186                  return (ret);
3182 3187          }
3183 3188          if (share == NULL) {
3184 3189                  if (group != NULL)
3185 3190                          (void) printf(gettext("Share not found in group %s:"
3186 3191                              " %s\n"), argv[optind], sharepath);
3187 3192                  else
3188 3193                          (void) printf(gettext("Share not found: %s\n"),
3189 3194                              sharepath);
3190 3195                  ret = SA_NO_SUCH_PATH;
3191 3196          } else {
3192 3197                  if (group == NULL)
3193 3198                          group = sa_get_parent_group(share);
3194 3199                  if (!dryrun) {
3195 3200                          if (ret == SA_OK) {
3196 3201                                  if (resource != NULL)
3197 3202                                          ret = sa_disable_resource(resource,
3198 3203                                              NULL);
3199 3204                                  else
3200 3205                                          ret = sa_disable_share(share, NULL);
3201 3206                                  /*
3202 3207                                   * We don't care if it fails since it
3203 3208                                   * could be disabled already. Some
3204 3209                                   * unexpected errors could occur that
3205 3210                                   * prevent removal, so also check for
3206 3211                                   * force being set.
3207 3212                                   */
3208 3213                                  if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3209 3214                                      ret == SA_NOT_SUPPORTED ||
3210 3215                                      ret == SA_SYSTEM_ERR || force) &&
3211 3216                                      resource == NULL)
3212 3217                                          ret = sa_remove_share(share);
3213 3218  
3214 3219                                  if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3215 3220                                      ret == SA_NOT_SUPPORTED ||
3216 3221                                      ret == SA_SYSTEM_ERR || force) &&
3217 3222                                      resource != NULL) {
3218 3223                                          ret = sa_remove_resource(resource);
3219 3224                                          if (ret == SA_OK) {
3220 3225                                                  /*
3221 3226                                                   * If this was the
3222 3227                                                   * last one, remove
3223 3228                                                   * the share as well.
3224 3229                                                   */
3225 3230                                                  resource =
3226 3231                                                      sa_get_share_resource(
3227 3232                                                      share, NULL);
3228 3233                                                  if (resource == NULL)
3229 3234                                                          ret = sa_remove_share(
3230 3235                                                              share);
3231 3236                                          }
3232 3237                                  }
3233 3238                                  if (ret == SA_OK)
3234 3239                                          ret = sa_update_config(handle);
3235 3240                          }
3236 3241                          if (ret != SA_OK)
3237 3242                                  (void) printf(gettext("Could not remove share:"
3238 3243                                      " %s\n"), sa_errorstr(ret));
3239 3244                  } else if (ret == SA_OK) {
3240 3245                          char *pname;
3241 3246                          pname = sa_get_group_attr(group, "name");
3242 3247                          if (pname != NULL) {
3243 3248                                  auth = check_authorizations(pname, flags);
3244 3249                                  sa_free_attr_string(pname);
3245 3250                          }
3246 3251                          if (!auth && verbose) {
3247 3252                                  (void) printf(gettext(
3248 3253                                      "Command would fail: %s\n"),
3249 3254                                      sa_errorstr(SA_NO_PERMISSION));
3250 3255                          }
3251 3256                  }
3252 3257          }
3253 3258          return (ret);
3254 3259  }
3255 3260  
3256 3261  /*
3257 3262   * sa_set_share(flags, argc, argv)
3258 3263   *
3259 3264   * implements set-share subcommand.
3260 3265   */
3261 3266  
3262 3267  int
3263 3268  sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
3264 3269  {
3265 3270          int dryrun = 0;
3266 3271          int c;
3267 3272          int ret = SA_OK;
3268 3273          sa_group_t group, sharegroup;
3269 3274          sa_share_t share = NULL;
3270 3275          sa_resource_t resource = NULL;
3271 3276          char *sharepath = NULL;
3272 3277          char *description = NULL;
3273 3278          char *rsrcname = NULL;
3274 3279          char *rsrc = NULL;
3275 3280          char *newname = NULL;
3276 3281          char *newrsrc;
3277 3282          char *groupname = NULL;
3278 3283          int auth;
3279 3284          int verbose = 0;
3280 3285  
3281 3286          while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
3282 3287                  switch (c) {
3283 3288                  case 'n':
3284 3289                          dryrun++;
3285 3290                          break;
3286 3291                  case 'd':
3287 3292                          description = optarg;
3288 3293                          break;
3289 3294                  case 'v':
3290 3295                          verbose++;
3291 3296                          break;
3292 3297                  case 'r':
3293 3298                          /*
3294 3299                           * Update share by resource name
3295 3300                           */
3296 3301                          if (rsrcname != NULL) {
3297 3302                                  (void) printf(gettext(
3298 3303                                      "Updating multiple resource names not "
3299 3304                                      "supported\n"));
3300 3305                                  return (SA_SYNTAX_ERR);
3301 3306                          }
3302 3307                          rsrcname = optarg;
3303 3308                          break;
3304 3309                  case 's':
3305 3310                          /*
3306 3311                           * Save share path into group. Currently limit
3307 3312                           * to one share per command.
3308 3313                           */
3309 3314                          if (sharepath != NULL) {
3310 3315                                  (void) printf(gettext(
3311 3316                                      "Updating multiple shares not "
3312 3317                                      "supported\n"));
3313 3318                                  return (SA_SYNTAX_ERR);
3314 3319                          }
3315 3320                          sharepath = optarg;
3316 3321                          break;
3317 3322                  case 'h':
3318 3323                          /* optopt on valid arg isn't defined */
3319 3324                          optopt = c;
3320 3325                          /*FALLTHROUGH*/
3321 3326                  case '?':
3322 3327                  default:
3323 3328                          /*
3324 3329                           * Since a bad option gets to here, sort it
3325 3330                           * out and return a syntax error return value
3326 3331                           * if necessary.
3327 3332                           */
3328 3333                          switch (optopt) {
3329 3334                          default:
3330 3335                                  ret = SA_SYNTAX_ERR;
3331 3336                                  break;
3332 3337                          case 'h':
3333 3338                          case '?':
3334 3339                                  break;
3335 3340                          }
3336 3341                          (void) printf(gettext("usage: %s\n"),
3337 3342                              sa_get_usage(USAGE_SET_SHARE));
3338 3343                          return (ret);
3339 3344                  }
3340 3345          }
3341 3346  
3342 3347          if (optind >= argc && sharepath == NULL && rsrcname == NULL) {
3343 3348                  if (sharepath == NULL) {
3344 3349                          (void) printf(gettext("usage: %s\n"),
3345 3350                              sa_get_usage(USAGE_SET_SHARE));
3346 3351                          (void) printf(gettext("\tgroup must be specified\n"));
3347 3352                          ret = SA_BAD_PATH;
3348 3353                  } else {
3349 3354                          ret = SA_OK;
3350 3355                  }
3351 3356          }
3352 3357          if ((optind + 1) < argc) {
3353 3358                  (void) printf(gettext("usage: %s\n"),
3354 3359                      sa_get_usage(USAGE_SET_SHARE));
3355 3360                  (void) printf(gettext("\tExtraneous group(s) at end\n"));
3356 3361                  ret = SA_SYNTAX_ERR;
3357 3362          }
3358 3363  
3359 3364          /*
3360 3365           * Must have at least one of sharepath and rsrcrname.
3361 3366           * It is a syntax error to be missing both.
3362 3367           */
3363 3368          if (sharepath == NULL && rsrcname == NULL) {
3364 3369                  (void) printf(gettext("usage: %s\n"),
3365 3370                      sa_get_usage(USAGE_SET_SHARE));
3366 3371                  ret = SA_SYNTAX_ERR;
3367 3372          }
3368 3373  
3369 3374          if (ret != SA_OK)
3370 3375                  return (ret);
3371 3376  
3372 3377          if (optind < argc) {
3373 3378                  groupname = argv[optind];
3374 3379                  group = sa_get_group(handle, groupname);
3375 3380          } else {
3376 3381                  group = NULL;
3377 3382                  groupname = NULL;
3378 3383          }
3379 3384          if (rsrcname != NULL) {
3380 3385                  /*
3381 3386                   * If rsrcname exists, split rename syntax and then
3382 3387                   * convert to utf 8 if no errors.
3383 3388                   */
3384 3389                  newname = strchr(rsrcname, '=');
3385 3390                  if (newname != NULL) {
3386 3391                          *newname++ = '\0';
3387 3392                  }
3388 3393                  if (!validresource(rsrcname)) {
3389 3394                          ret = SA_INVALID_NAME;
3390 3395                          (void) printf(gettext("Invalid resource name: "
3391 3396                              "\"%s\"\n"), rsrcname);
3392 3397                  } else {
3393 3398                          rsrc = conv_to_utf8(rsrcname);
3394 3399                  }
3395 3400                  if (newname != NULL) {
3396 3401                          if (!validresource(newname)) {
3397 3402                                  ret = SA_INVALID_NAME;
3398 3403                                  (void) printf(gettext("Invalid resource name: "
3399 3404                                      "%s\n"), newname);
3400 3405                                  newname = NULL;
3401 3406                          } else {
3402 3407                                  newrsrc = conv_to_utf8(newname);
3403 3408                          }
3404 3409                  }
3405 3410          }
3406 3411  
3407 3412          if (ret != SA_OK) {
3408 3413                  if (rsrcname != NULL && rsrcname != rsrc)
3409 3414                          sa_free_attr_string(rsrc);
3410 3415                  if (newname != NULL && newname != newrsrc)
3411 3416                          sa_free_attr_string(newrsrc);
3412 3417                  return (ret);
3413 3418          }
3414 3419  
3415 3420          if (sharepath != NULL) {
3416 3421                  share = sa_find_share(handle, sharepath);
3417 3422          } else if (rsrcname != NULL) {
3418 3423                  resource = sa_find_resource(handle, rsrc);
3419 3424                  if (resource != NULL)
3420 3425                          share = sa_get_resource_parent(resource);
3421 3426                  else
3422 3427                          ret = SA_NO_SUCH_RESOURCE;
3423 3428          }
3424 3429          if (share != NULL) {
3425 3430                  sharegroup = sa_get_parent_group(share);
3426 3431                  if (group != NULL && group != sharegroup) {
3427 3432                          (void) printf(gettext("Group \"%s\" does not contain "
3428 3433                              "share %s\n"),
3429 3434                              argv[optind], sharepath);
3430 3435                          ret = SA_BAD_PATH;
3431 3436                  } else {
3432 3437                          int delgroupname = 0;
3433 3438                          if (groupname == NULL) {
3434 3439                                  groupname = sa_get_group_attr(sharegroup,
3435 3440                                      "name");
3436 3441                                  delgroupname = 1;
3437 3442                          }
3438 3443                          if (groupname != NULL) {
3439 3444                                  auth = check_authorizations(groupname, flags);
3440 3445                                  if (delgroupname) {
3441 3446                                          sa_free_attr_string(groupname);
3442 3447                                          groupname = NULL;
3443 3448                                  }
3444 3449                          } else {
3445 3450                                  ret = SA_NO_MEMORY;
3446 3451                          }
3447 3452                          if (rsrcname != NULL) {
3448 3453                                  resource = sa_find_resource(handle, rsrc);
3449 3454                                  if (!dryrun) {
3450 3455                                          if (newname != NULL &&
3451 3456                                              resource != NULL)
3452 3457                                                  ret = sa_rename_resource(
3453 3458                                                      resource, newrsrc);
3454 3459                                          else if (newname != NULL)
3455 3460                                                  ret = SA_NO_SUCH_RESOURCE;
3456 3461                                          if (newname != NULL &&
3457 3462                                              newname != newrsrc)
3458 3463                                                  sa_free_attr_string(newrsrc);
3459 3464                                  }
3460 3465                                  if (rsrc != rsrcname)
3461 3466                                          sa_free_attr_string(rsrc);
3462 3467                          }
3463 3468  
3464 3469                          /*
3465 3470                           * If the user has set a description, it will be
3466 3471                           * on the resource if -r was used otherwise it
3467 3472                           * must be on the share.
3468 3473                           */
3469 3474                          if (!dryrun && ret == SA_OK && description != NULL) {
3470 3475                                  char *desc;
3471 3476                                  desc = conv_to_utf8(description);
3472 3477                                  if (resource != NULL)
3473 3478                                          ret = sa_set_resource_description(
3474 3479                                              resource, desc);
3475 3480                                  else
3476 3481                                          ret = sa_set_share_description(share,
3477 3482                                              desc);
3478 3483                                  if (desc != description)
3479 3484                                          sa_free_share_description(desc);
3480 3485                          }
3481 3486                  }
3482 3487                  if (!dryrun && ret == SA_OK) {
3483 3488                          if (resource != NULL)
3484 3489                                  (void) sa_enable_resource(resource, NULL);
3485 3490                          ret = sa_update_config(handle);
3486 3491                  }
3487 3492                  switch (ret) {
3488 3493                  case SA_DUPLICATE_NAME:
3489 3494                          (void) printf(gettext("Resource name in use: %s\n"),
3490 3495                              rsrcname);
3491 3496                          break;
3492 3497                  default:
3493 3498                          (void) printf(gettext("Could not set: %s\n"),
3494 3499                              sa_errorstr(ret));
3495 3500                          break;
3496 3501                  case SA_OK:
3497 3502                          if (dryrun && !auth && verbose) {
3498 3503                                  (void) printf(gettext(
3499 3504                                      "Command would fail: %s\n"),
3500 3505                                      sa_errorstr(SA_NO_PERMISSION));
3501 3506                          }
3502 3507                          break;
3503 3508                  }
3504 3509          } else {
3505 3510                  switch (ret) {
3506 3511                  case SA_NO_SUCH_RESOURCE:
3507 3512                          (void) printf(gettext("Resource \"%s\" not found\n"),
3508 3513                              rsrcname);
3509 3514                          break;
3510 3515                  default:
3511 3516                          if (sharepath != NULL) {
3512 3517                                  (void) printf(
3513 3518                                      gettext("Share path \"%s\" not found\n"),
3514 3519                                      sharepath);
3515 3520                                  ret = SA_NO_SUCH_PATH;
3516 3521                          } else {
3517 3522                                  (void) printf(gettext("Set failed: %s\n"),
3518 3523                                      sa_errorstr(ret));
3519 3524                          }
3520 3525                  }
3521 3526          }
3522 3527  
3523 3528          return (ret);
3524 3529  }
3525 3530  
3526 3531  /*
3527 3532   * add_security(group, sectype, optlist, proto, *err)
3528 3533   *
3529 3534   * Helper function to add a security option (named optionset) to the
3530 3535   * group.
3531 3536   */
3532 3537  
3533 3538  static int
3534 3539  add_security(sa_group_t group, char *sectype,
3535 3540      struct options *optlist, char *proto, int *err)
3536 3541  {
3537 3542          sa_security_t security;
3538 3543          int ret = SA_OK;
3539 3544          int result = 0;
3540 3545          sa_handle_t handle;
3541 3546  
3542 3547          sectype = sa_proto_space_alias(proto, sectype);
3543 3548          security = sa_get_security(group, sectype, proto);
3544 3549          if (security == NULL)
3545 3550                  security = sa_create_security(group, sectype, proto);
3546 3551  
3547 3552          if (sectype != NULL)
3548 3553                  sa_free_attr_string(sectype);
3549 3554  
3550 3555          if (security == NULL)
3551 3556                  goto done;
3552 3557  
3553 3558          handle = sa_find_group_handle(group);
3554 3559          if (handle == NULL) {
3555 3560                  ret = SA_CONFIG_ERR;
3556 3561                  goto done;
3557 3562          }
3558 3563          while (optlist != NULL) {
3559 3564                  sa_property_t prop;
3560 3565                  prop = sa_get_property(security, optlist->optname);
3561 3566                  if (prop == NULL) {
3562 3567                          /*
3563 3568                           * Add the property, but only if it is
3564 3569                           * a non-NULL or non-zero length value
3565 3570                           */
3566 3571                          if (optlist->optvalue != NULL) {
3567 3572                                  prop = sa_create_property(optlist->optname,
3568 3573                                      optlist->optvalue);
3569 3574                                  if (prop != NULL) {
3570 3575                                          ret = sa_valid_property(handle,
3571 3576                                              security, proto, prop);
3572 3577                                          if (ret != SA_OK) {
3573 3578                                                  (void) sa_remove_property(prop);
3574 3579                                                  (void) printf(gettext(
3575 3580                                                      "Could not add "
3576 3581                                                      "property %s: %s\n"),
3577 3582                                                      optlist->optname,
3578 3583                                                      sa_errorstr(ret));
3579 3584                                          }
3580 3585                                          if (ret == SA_OK) {
3581 3586                                                  ret = sa_add_property(security,
3582 3587                                                      prop);
3583 3588                                                  if (ret != SA_OK) {
3584 3589                                                          (void) printf(gettext(
3585 3590                                                              "Could not add "
3586 3591                                                              "property (%s=%s):"
3587 3592                                                              " %s\n"),
3588 3593                                                              optlist->optname,
3589 3594                                                              optlist->optvalue,
3590 3595                                                              sa_errorstr(ret));
3591 3596                                                  } else {
3592 3597                                                          result = 1;
3593 3598                                                  }
3594 3599                                          }
3595 3600                                  }
3596 3601                          }
3597 3602                  } else {
3598 3603                          ret = sa_update_property(prop, optlist->optvalue);
3599 3604                          result = 1; /* should check if really changed */
3600 3605                  }
3601 3606                  optlist = optlist->next;
3602 3607          }
3603 3608          /*
3604 3609           * When done, properties may have all been removed but
3605 3610           * we need to keep the security type itself until
3606 3611           * explicitly removed.
3607 3612           */
3608 3613          if (result)
3609 3614                  ret = sa_commit_properties(security, 0);
3610 3615  done:
3611 3616          *err = ret;
3612 3617          return (result);
3613 3618  }
3614 3619  
3615 3620  /*
3616 3621   * zfscheck(group, share)
3617 3622   *
3618 3623   * For the special case where a share was provided, make sure it is a
3619 3624   * compatible path for a ZFS property change.  The only path
3620 3625   * acceptable is the path that defines the zfs sub-group (dataset with
3621 3626   * the sharenfs property set) and not one of the paths that inherited
3622 3627   * the NFS properties. Returns SA_OK if it is usable and
3623 3628   * SA_NOT_ALLOWED if it isn't.
3624 3629   *
3625 3630   * If group is not a ZFS group/subgroup, we assume OK since the check
3626 3631   * on return will catch errors for those cases.  What we are looking
3627 3632   * for here is that the group is ZFS and the share is not the defining
3628 3633   * share.  All else is SA_OK.
3629 3634   */
3630 3635  
3631 3636  static int
3632 3637  zfscheck(sa_group_t group, sa_share_t share)
3633 3638  {
3634 3639          int ret = SA_OK;
3635 3640          char *attr;
3636 3641  
3637 3642          if (sa_group_is_zfs(group)) {
3638 3643                  /*
3639 3644                   * The group is a ZFS group.  Does the share represent
3640 3645                   * the dataset that defined the group? It is only OK
3641 3646                   * if the attribute "subgroup" exists on the share and
3642 3647                   * has a value of "true".
3643 3648                   */
3644 3649  
3645 3650                  ret = SA_NOT_ALLOWED;
3646 3651                  attr = sa_get_share_attr(share, "subgroup");
3647 3652                  if (attr != NULL) {
3648 3653                          if (strcmp(attr, "true") == 0)
3649 3654                                  ret = SA_OK;
3650 3655                          sa_free_attr_string(attr);
3651 3656                  }
3652 3657          }
3653 3658          return (ret);
3654 3659  }
3655 3660  
3656 3661  /*
3657 3662   * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
3658 3663   *
3659 3664   * This function implements "set" when a name space (-S) is not
3660 3665   * specified. It is a basic set. Options and other CLI parsing has
3661 3666   * already been done.
3662 3667   *
3663 3668   * "rsrcname" is a "resource name". If it is non-NULL, it must match
3664 3669   * the sharepath if present or group if present, otherwise it is used
3665 3670   * to set options.
3666 3671   *
3667 3672   * Resource names may take options if the protocol supports it. If the
3668 3673   * protocol doesn't support resource level options, rsrcname is just
3669 3674   * an alias for the share.
3670 3675   */
3671 3676  
3672 3677  static int
3673 3678  basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
3674 3679      char *protocol, char *sharepath, char *rsrcname, int dryrun)
3675 3680  {
3676 3681          sa_group_t group;
3677 3682          int ret = SA_OK;
3678 3683          int change = 0;
3679 3684          struct list *worklist = NULL;
3680 3685  
3681 3686          group = sa_get_group(handle, groupname);
3682 3687          if (group != NULL) {
3683 3688                  sa_share_t share = NULL;
3684 3689                  sa_resource_t resource = NULL;
3685 3690  
3686 3691                  /*
3687 3692                   * If there is a sharepath, make sure it belongs to
3688 3693                   * the group.
3689 3694                   */
3690 3695                  if (sharepath != NULL) {
3691 3696                          share = sa_get_share(group, sharepath);
3692 3697                          if (share == NULL) {
3693 3698                                  (void) printf(gettext(
3694 3699                                      "Share does not exist in group %s\n"),
3695 3700                                      groupname, sharepath);
3696 3701                                  ret = SA_NO_SUCH_PATH;
3697 3702                          } else {
3698 3703                                  /* if ZFS and OK, then only group */
3699 3704                                  ret = zfscheck(group, share);
3700 3705                                  if (ret == SA_OK &&
3701 3706                                      sa_group_is_zfs(group))
3702 3707                                          share = NULL;
3703 3708                                  if (ret == SA_NOT_ALLOWED)
3704 3709                                          (void) printf(gettext(
3705 3710                                              "Properties on ZFS group shares "
3706 3711                                              "not supported: %s\n"), sharepath);
3707 3712                          }
3708 3713                  }
3709 3714  
3710 3715                  /*
3711 3716                   * If a resource name exists, make sure it belongs to
3712 3717                   * the share if present else it belongs to the
3713 3718                   * group. Also check the protocol to see if it
3714 3719                   * supports resource level properties or not. If not,
3715 3720                   * use share only.
3716 3721                   */
3717 3722                  if (rsrcname != NULL) {
3718 3723                          if (share != NULL) {
3719 3724                                  resource = sa_get_share_resource(share,
3720 3725                                      rsrcname);
3721 3726                                  if (resource == NULL)
3722 3727                                          ret = SA_NO_SUCH_RESOURCE;
3723 3728                          } else {
3724 3729                                  resource = sa_get_resource(group, rsrcname);
3725 3730                                  if (resource != NULL)
3726 3731                                          share = sa_get_resource_parent(
3727 3732                                              resource);
3728 3733                                  else
3729 3734                                          ret = SA_NO_SUCH_RESOURCE;
3730 3735                          }
3731 3736                          if (ret == SA_OK && resource != NULL) {
3732 3737                                  uint64_t features;
3733 3738                                  /*
3734 3739                                   * Check to see if the resource can take
3735 3740                                   * properties. If so, stick the resource into
3736 3741                                   * "share" so it will all just work.
3737 3742                                   */
3738 3743                                  features = sa_proto_get_featureset(protocol);
3739 3744                                  if (features & SA_FEATURE_RESOURCE)
3740 3745                                          share = (sa_share_t)resource;
3741 3746                          }
3742 3747                  }
3743 3748  
3744 3749                  if (ret == SA_OK) {
3745 3750                          /* group must exist */
3746 3751                          ret = valid_options(handle, optlist, protocol,
3747 3752                              share == NULL ? group : share, NULL);
3748 3753                          if (ret == SA_OK && !dryrun) {
3749 3754                                  if (share != NULL)
3750 3755                                          change |= add_optionset(share, optlist,
3751 3756                                              protocol, &ret);
3752 3757                                  else
3753 3758                                          change |= add_optionset(group, optlist,
3754 3759                                              protocol, &ret);
3755 3760                                  if (ret == SA_OK && change)
3756 3761                                          worklist = add_list(worklist, group,
3757 3762                                              share, protocol);
3758 3763                          }
3759 3764                  }
3760 3765                  free_opt(optlist);
3761 3766          } else {
3762 3767                  (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3763 3768                  ret = SA_NO_SUCH_GROUP;
3764 3769          }
3765 3770          /*
3766 3771           * we have a group and potentially legal additions
3767 3772           */
3768 3773  
3769 3774          /*
3770 3775           * Commit to configuration if not a dryrunp and properties
3771 3776           * have changed.
3772 3777           */
3773 3778          if (!dryrun && ret == SA_OK && change && worklist != NULL)
3774 3779                  /* properties changed, so update all shares */
3775 3780                  (void) enable_all_groups(handle, worklist, 0, 0, protocol,
3776 3781                      B_TRUE);
3777 3782  
3778 3783          if (worklist != NULL)
3779 3784                  free_list(worklist);
3780 3785          return (ret);
3781 3786  }
3782 3787  
3783 3788  /*
3784 3789   * space_set(groupname, optlist, protocol, sharepath, dryrun)
3785 3790   *
3786 3791   * This function implements "set" when a name space (-S) is
3787 3792   * specified. It is a namespace set. Options and other CLI parsing has
3788 3793   * already been done.
3789 3794   */
3790 3795  
3791 3796  static int
3792 3797  space_set(sa_handle_t handle, char *groupname, struct options *optlist,
3793 3798      char *protocol, char *sharepath, int dryrun, char *sectype)
3794 3799  {
3795 3800          sa_group_t group;
3796 3801          int ret = SA_OK;
3797 3802          int change = 0;
3798 3803          struct list *worklist = NULL;
3799 3804  
3800 3805          /*
3801 3806           * make sure protcol and sectype are valid
3802 3807           */
3803 3808  
3804 3809          if (sa_proto_valid_space(protocol, sectype) == 0) {
3805 3810                  (void) printf(gettext("Option space \"%s\" not valid "
3806 3811                      "for protocol.\n"), sectype);
3807 3812                  return (SA_INVALID_SECURITY);
3808 3813          }
3809 3814  
3810 3815          group = sa_get_group(handle, groupname);
3811 3816          if (group != NULL) {
3812 3817                  sa_share_t share = NULL;
3813 3818                  if (sharepath != NULL) {
3814 3819                          share = sa_get_share(group, sharepath);
3815 3820                          if (share == NULL) {
3816 3821                                  (void) printf(gettext(
3817 3822                                      "Share does not exist in group %s\n"),
3818 3823                                      groupname, sharepath);
3819 3824                                  ret = SA_NO_SUCH_PATH;
3820 3825                          } else {
3821 3826                                  /* if ZFS and OK, then only group */
3822 3827                                  ret = zfscheck(group, share);
3823 3828                                  if (ret == SA_OK &&
3824 3829                                      sa_group_is_zfs(group))
3825 3830                                          share = NULL;
3826 3831                                  if (ret == SA_NOT_ALLOWED)
3827 3832                                          (void) printf(gettext(
3828 3833                                              "Properties on ZFS group shares "
3829 3834                                              "not supported: %s\n"), sharepath);
3830 3835                          }
3831 3836                  }
3832 3837                  if (ret == SA_OK) {
3833 3838                          /* group must exist */
3834 3839                          ret = valid_options(handle, optlist, protocol,
3835 3840                              share == NULL ? group : share, sectype);
3836 3841                          if (ret == SA_OK && !dryrun) {
3837 3842                                  if (share != NULL)
3838 3843                                          change = add_security(share, sectype,
3839 3844                                              optlist, protocol, &ret);
3840 3845                                  else
3841 3846                                          change = add_security(group, sectype,
3842 3847                                              optlist, protocol, &ret);
3843 3848                                  if (ret != SA_OK)
3844 3849                                          (void) printf(gettext(
3845 3850                                              "Could not set property: %s\n"),
3846 3851                                              sa_errorstr(ret));
3847 3852                          }
3848 3853                          if (ret == SA_OK && change)
3849 3854                                  worklist = add_list(worklist, group, share,
3850 3855                                      protocol);
3851 3856                  }
3852 3857                  free_opt(optlist);
3853 3858          } else {
3854 3859                  (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3855 3860                  ret = SA_NO_SUCH_GROUP;
3856 3861          }
3857 3862  
3858 3863          /*
3859 3864           * We have a group and potentially legal additions.
3860 3865           */
3861 3866  
3862 3867          /* Commit to configuration if not a dryrun */
3863 3868          if (!dryrun && ret == 0) {
3864 3869                  if (change && worklist != NULL) {
3865 3870                          /* properties changed, so update all shares */
3866 3871                          (void) enable_all_groups(handle, worklist, 0, 0,
3867 3872                              protocol, B_TRUE);
3868 3873                  }
3869 3874                  ret = sa_update_config(handle);
3870 3875          }
3871 3876          if (worklist != NULL)
3872 3877                  free_list(worklist);
3873 3878          return (ret);
3874 3879  }
3875 3880  
3876 3881  /*
3877 3882   * sa_set(flags, argc, argv)
3878 3883   *
3879 3884   * Implements the set subcommand. It keys off of -S to determine which
3880 3885   * set of operations to actually do.
3881 3886   */
3882 3887  
3883 3888  int
3884 3889  sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
3885 3890  {
3886 3891          char *groupname;
3887 3892          int verbose = 0;
3888 3893          int dryrun = 0;
3889 3894          int c;
3890 3895          char *protocol = NULL;
3891 3896          int ret = SA_OK;
3892 3897          struct options *optlist = NULL;
3893 3898          char *rsrcname = NULL;
3894 3899          char *sharepath = NULL;
3895 3900          char *optset = NULL;
3896 3901          int auth;
3897 3902  
3898 3903          while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
3899 3904                  switch (c) {
3900 3905                  case 'v':
3901 3906                          verbose++;
3902 3907                          break;
3903 3908                  case 'n':
3904 3909                          dryrun++;
3905 3910                          break;
3906 3911                  case 'P':
3907 3912                          if (protocol != NULL) {
3908 3913                                  (void) printf(gettext(
3909 3914                                      "Specifying multiple protocols "
3910 3915                                      "not supported: %s\n"), protocol);
3911 3916                                  return (SA_SYNTAX_ERR);
3912 3917                          }
3913 3918                          protocol = optarg;
3914 3919                          if (!sa_valid_protocol(protocol)) {
3915 3920                                  (void) printf(gettext(
3916 3921                                      "Invalid protocol specified: %s\n"),
3917 3922                                      protocol);
3918 3923                                  return (SA_INVALID_PROTOCOL);
3919 3924                          }
3920 3925                          break;
3921 3926                  case 'p':
3922 3927                          ret = add_opt(&optlist, optarg, 0);
3923 3928                          switch (ret) {
3924 3929                          case OPT_ADD_SYNTAX:
3925 3930                                  (void) printf(gettext("Property syntax error:"
3926 3931                                      " %s\n"), optarg);
3927 3932                                  return (SA_SYNTAX_ERR);
3928 3933                          case OPT_ADD_MEMORY:
3929 3934                                  (void) printf(gettext("No memory to set "
3930 3935                                      "property: %s\n"), optarg);
3931 3936                                  return (SA_NO_MEMORY);
3932 3937                          default:
3933 3938                                  break;
3934 3939                          }
3935 3940                          break;
3936 3941                  case 'r':
3937 3942                          if (rsrcname != NULL) {
3938 3943                                  (void) printf(gettext(
3939 3944                                      "Setting multiple resource names not"
3940 3945                                      " supported\n"));
3941 3946                                  return (SA_SYNTAX_ERR);
3942 3947                          }
3943 3948                          rsrcname = optarg;
3944 3949                          break;
3945 3950                  case 's':
3946 3951                          if (sharepath != NULL) {
3947 3952                                  (void) printf(gettext(
3948 3953                                      "Setting multiple shares not supported\n"));
3949 3954                                  return (SA_SYNTAX_ERR);
3950 3955                          }
3951 3956                          sharepath = optarg;
3952 3957                          break;
3953 3958                  case 'S':
3954 3959                          if (optset != NULL) {
3955 3960                                  (void) printf(gettext(
3956 3961                                      "Specifying multiple property "
3957 3962                                      "spaces not supported: %s\n"), optset);
3958 3963                                  return (SA_SYNTAX_ERR);
3959 3964                          }
3960 3965                          optset = optarg;
3961 3966                          break;
3962 3967                  case 'h':
3963 3968                          /* optopt on valid arg isn't defined */
3964 3969                          optopt = c;
3965 3970                          /*FALLTHROUGH*/
3966 3971                  case '?':
3967 3972                  default:
3968 3973                          /*
3969 3974                           * Since a bad option gets to here, sort it
3970 3975                           * out and return a syntax error return value
3971 3976                           * if necessary.
3972 3977                           */
3973 3978                          switch (optopt) {
3974 3979                          default:
3975 3980                                  ret = SA_SYNTAX_ERR;
3976 3981                                  break;
3977 3982                          case 'h':
3978 3983                          case '?':
3979 3984                                  break;
3980 3985                          }
3981 3986                          (void) printf(gettext("usage: %s\n"),
3982 3987                              sa_get_usage(USAGE_SET));
3983 3988                          return (ret);
3984 3989                  }
3985 3990          }
3986 3991  
3987 3992          if (optlist != NULL)
3988 3993                  ret = chk_opt(optlist, optset != NULL, protocol);
3989 3994  
3990 3995          if (optind >= argc || (optlist == NULL && optset == NULL) ||
3991 3996              protocol == NULL || ret != OPT_ADD_OK) {
3992 3997                  char *sep = "\t";
3993 3998  
3994 3999                  (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
3995 4000                  if (optind >= argc) {
3996 4001                          (void) printf(gettext("%sgroup must be specified"),
3997 4002                              sep);
3998 4003                          sep = ", ";
3999 4004                  }
4000 4005                  if (optlist == NULL) {
4001 4006                          (void) printf(gettext("%sat least one property must be"
4002 4007                              " specified"), sep);
4003 4008                          sep = ", ";
4004 4009                  }
4005 4010                  if (protocol == NULL) {
4006 4011                          (void) printf(gettext("%sprotocol must be specified"),
4007 4012                              sep);
4008 4013                          sep = ", ";
4009 4014                  }
4010 4015                  (void) printf("\n");
4011 4016                  ret = SA_SYNTAX_ERR;
4012 4017          } else {
4013 4018                  /*
4014 4019                   * Group already exists so we can proceed after a few
4015 4020                   * additional checks related to ZFS handling.
4016 4021                   */
4017 4022  
4018 4023                  groupname = argv[optind];
4019 4024                  if (strcmp(groupname, "zfs") == 0) {
4020 4025                          (void) printf(gettext("Changing properties for group "
4021 4026                              "\"zfs\" not allowed\n"));
4022 4027                          return (SA_NOT_ALLOWED);
4023 4028                  }
4024 4029  
4025 4030                  auth = check_authorizations(groupname, flags);
4026 4031                  if (optset == NULL)
4027 4032                          ret = basic_set(handle, groupname, optlist, protocol,
4028 4033                              sharepath, rsrcname, dryrun);
4029 4034                  else
4030 4035                          ret = space_set(handle, groupname, optlist, protocol,
4031 4036                              sharepath, dryrun, optset);
4032 4037                  if (dryrun && ret == SA_OK && !auth && verbose) {
4033 4038                          (void) printf(gettext("Command would fail: %s\n"),
4034 4039                              sa_errorstr(SA_NO_PERMISSION));
4035 4040                  }
4036 4041          }
4037 4042          return (ret);
4038 4043  }
4039 4044  
4040 4045  /*
4041 4046   * remove_options(group, optlist, proto, *err)
4042 4047   *
4043 4048   * Helper function to actually remove options from a group after all
4044 4049   * preprocessing is done.
4045 4050   */
4046 4051  
4047 4052  static int
4048 4053  remove_options(sa_group_t group, struct options *optlist,
4049 4054      char *proto, int *err)
4050 4055  {
4051 4056          struct options *cur;
4052 4057          sa_optionset_t optionset;
4053 4058          sa_property_t prop;
4054 4059          int change = 0;
4055 4060          int ret = SA_OK;
4056 4061  
4057 4062          optionset = sa_get_optionset(group, proto);
4058 4063          if (optionset != NULL) {
4059 4064                  for (cur = optlist; cur != NULL; cur = cur->next) {
4060 4065                          prop = sa_get_property(optionset, cur->optname);
4061 4066                          if (prop != NULL) {
4062 4067                                  ret = sa_remove_property(prop);
4063 4068                                  if (ret != SA_OK)
4064 4069                                          break;
4065 4070                                  change = 1;
4066 4071                          }
4067 4072                  }
4068 4073          }
4069 4074          if (ret == SA_OK && change)
4070 4075                  ret = sa_commit_properties(optionset, 0);
4071 4076  
4072 4077          if (err != NULL)
4073 4078                  *err = ret;
4074 4079          return (change);
4075 4080  }
4076 4081  
4077 4082  /*
4078 4083   * valid_unset(group, optlist, proto)
4079 4084   *
4080 4085   * Sanity check the optlist to make sure they can be removed. Issue an
4081 4086   * error if a property doesn't exist.
4082 4087   */
4083 4088  
4084 4089  static int
4085 4090  valid_unset(sa_group_t group, struct options *optlist, char *proto)
4086 4091  {
4087 4092          struct options *cur;
4088 4093          sa_optionset_t optionset;
4089 4094          sa_property_t prop;
4090 4095          int ret = SA_OK;
4091 4096  
4092 4097          optionset = sa_get_optionset(group, proto);
4093 4098          if (optionset != NULL) {
4094 4099                  for (cur = optlist; cur != NULL; cur = cur->next) {
4095 4100                          prop = sa_get_property(optionset, cur->optname);
4096 4101                          if (prop == NULL) {
4097 4102                                  (void) printf(gettext(
4098 4103                                      "Could not unset property %s: not set\n"),
4099 4104                                      cur->optname);
4100 4105                                  ret = SA_NO_SUCH_PROP;
4101 4106                          }
4102 4107                  }
4103 4108          }
4104 4109          return (ret);
4105 4110  }
4106 4111  
4107 4112  /*
4108 4113   * valid_unset_security(group, optlist, proto)
4109 4114   *
4110 4115   * Sanity check the optlist to make sure they can be removed. Issue an
4111 4116   * error if a property doesn't exist.
4112 4117   */
4113 4118  
4114 4119  static int
4115 4120  valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
4116 4121      char *sectype)
4117 4122  {
4118 4123          struct options *cur;
4119 4124          sa_security_t security;
4120 4125          sa_property_t prop;
4121 4126          int ret = SA_OK;
4122 4127          char *sec;
4123 4128  
4124 4129          sec = sa_proto_space_alias(proto, sectype);
4125 4130          security = sa_get_security(group, sec, proto);
4126 4131          if (security != NULL) {
4127 4132                  for (cur = optlist; cur != NULL; cur = cur->next) {
4128 4133                          prop = sa_get_property(security, cur->optname);
4129 4134                          if (prop == NULL) {
4130 4135                                  (void) printf(gettext(
4131 4136                                      "Could not unset property %s: not set\n"),
4132 4137                                      cur->optname);
4133 4138                                  ret = SA_NO_SUCH_PROP;
4134 4139                          }
4135 4140                  }
4136 4141          } else {
4137 4142                  (void) printf(gettext(
4138 4143                      "Could not unset %s: space not defined\n"), sectype);
4139 4144                  ret = SA_NO_SUCH_SECURITY;
4140 4145          }
4141 4146          if (sec != NULL)
4142 4147                  sa_free_attr_string(sec);
4143 4148          return (ret);
4144 4149  }
4145 4150  
4146 4151  /*
4147 4152   * remove_security(group, optlist, proto)
4148 4153   *
4149 4154   * Remove the properties since they were checked as valid.
4150 4155   */
4151 4156  
4152 4157  static int
4153 4158  remove_security(sa_group_t group, char *sectype,
4154 4159      struct options *optlist, char *proto, int *err)
4155 4160  {
4156 4161          sa_security_t security;
4157 4162          int ret = SA_OK;
4158 4163          int change = 0;
4159 4164  
4160 4165          sectype = sa_proto_space_alias(proto, sectype);
4161 4166          security = sa_get_security(group, sectype, proto);
4162 4167          if (sectype != NULL)
4163 4168                  sa_free_attr_string(sectype);
4164 4169  
4165 4170          if (security != NULL) {
4166 4171                  while (optlist != NULL) {
4167 4172                          sa_property_t prop;
4168 4173                          prop = sa_get_property(security, optlist->optname);
4169 4174                          if (prop != NULL) {
4170 4175                                  ret = sa_remove_property(prop);
4171 4176                                  if (ret != SA_OK)
4172 4177                                          break;
4173 4178                                  change = 1;
4174 4179                          }
4175 4180                          optlist = optlist->next;
4176 4181                  }
4177 4182                  /*
4178 4183                   * when done, properties may have all been removed but
4179 4184                   * we need to keep the security type itself until
4180 4185                   * explicitly removed.
4181 4186                   */
4182 4187                  if (ret == SA_OK && change)
4183 4188                          ret = sa_commit_properties(security, 0);
4184 4189          } else {
4185 4190                  ret = SA_NO_SUCH_PROP;
4186 4191          }
4187 4192          if (err != NULL)
4188 4193                  *err = ret;
4189 4194          return (change);
4190 4195  }
4191 4196  
4192 4197  /*
4193 4198   * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
4194 4199   *
4195 4200   * Unset non-named optionset properties.
4196 4201   */
4197 4202  
4198 4203  static int
4199 4204  basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4200 4205      char *protocol, char *sharepath, char *rsrcname, int dryrun)
4201 4206  {
4202 4207          sa_group_t group;
4203 4208          int ret = SA_OK;
4204 4209          int change = 0;
4205 4210          struct list *worklist = NULL;
4206 4211          sa_share_t share = NULL;
4207 4212          sa_resource_t resource = NULL;
4208 4213  
4209 4214          group = sa_get_group(handle, groupname);
4210 4215          if (group == NULL)
4211 4216                  return (ret);
4212 4217  
4213 4218          /*
4214 4219           * If there is a sharepath, make sure it belongs to
4215 4220           * the group.
4216 4221           */
4217 4222          if (sharepath != NULL) {
4218 4223                  share = sa_get_share(group, sharepath);
4219 4224                  if (share == NULL) {
4220 4225                          (void) printf(gettext(
4221 4226                              "Share does not exist in group %s\n"),
4222 4227                              groupname, sharepath);
4223 4228                          ret = SA_NO_SUCH_PATH;
4224 4229                  }
4225 4230          }
4226 4231          /*
4227 4232           * If a resource name exists, make sure it belongs to
4228 4233           * the share if present else it belongs to the
4229 4234           * group. Also check the protocol to see if it
4230 4235           * supports resource level properties or not. If not,
4231 4236           * use share only.
4232 4237           */
4233 4238          if (rsrcname != NULL) {
4234 4239                  if (share != NULL) {
4235 4240                          resource = sa_get_share_resource(share, rsrcname);
4236 4241                          if (resource == NULL)
4237 4242                                  ret = SA_NO_SUCH_RESOURCE;
4238 4243                  } else {
4239 4244                          resource = sa_get_resource(group, rsrcname);
4240 4245                          if (resource != NULL) {
4241 4246                                  share = sa_get_resource_parent(resource);
4242 4247                          } else {
4243 4248                                  ret = SA_NO_SUCH_RESOURCE;
4244 4249                          }
4245 4250                  }
4246 4251                  if (ret == SA_OK && resource != NULL) {
4247 4252                          uint64_t features;
4248 4253                          /*
4249 4254                           * Check to see if the resource can take
4250 4255                           * properties. If so, stick the resource into
4251 4256                           * "share" so it will all just work.
4252 4257                           */
4253 4258                          features = sa_proto_get_featureset(protocol);
4254 4259                          if (features & SA_FEATURE_RESOURCE)
4255 4260                                  share = (sa_share_t)resource;
4256 4261                  }
4257 4262          }
4258 4263  
4259 4264          if (ret == SA_OK) {
4260 4265                  /* group must exist */
4261 4266                  ret = valid_unset(share != NULL ? share : group,
4262 4267                      optlist, protocol);
4263 4268                  if (ret == SA_OK && !dryrun) {
4264 4269                          if (share != NULL) {
4265 4270                                  sa_optionset_t optionset;
4266 4271                                  sa_property_t prop;
4267 4272                                  change |= remove_options(share, optlist,
4268 4273                                      protocol, &ret);
4269 4274                                  /*
4270 4275                                   * If a share optionset is
4271 4276                                   * empty, remove it.
4272 4277                                   */
4273 4278                                  optionset = sa_get_optionset((sa_share_t)share,
4274 4279                                      protocol);
4275 4280                                  if (optionset != NULL) {
4276 4281                                          prop = sa_get_property(optionset, NULL);
4277 4282                                          if (prop == NULL)
4278 4283                                                  (void) sa_destroy_optionset(
4279 4284                                                      optionset);
4280 4285                                  }
4281 4286                          } else {
4282 4287                                  change |= remove_options(group,
4283 4288                                      optlist, protocol, &ret);
4284 4289                          }
4285 4290                          if (ret == SA_OK && change)
4286 4291                                  worklist = add_list(worklist, group, share,
4287 4292                                      protocol);
4288 4293                          if (ret != SA_OK)
4289 4294                                  (void) printf(gettext(
4290 4295                                      "Could not remove properties: "
4291 4296                                      "%s\n"), sa_errorstr(ret));
4292 4297                  }
4293 4298          } else {
4294 4299                  (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4295 4300                  ret = SA_NO_SUCH_GROUP;
4296 4301          }
4297 4302          free_opt(optlist);
4298 4303  
4299 4304          /*
4300 4305           * We have a group and potentially legal additions
4301 4306           *
4302 4307           * Commit to configuration if not a dryrun
4303 4308           */
4304 4309          if (!dryrun && ret == SA_OK) {
4305 4310                  if (change && worklist != NULL) {
4306 4311                          /* properties changed, so update all shares */
4307 4312                          (void) enable_all_groups(handle, worklist, 0, 0,
4308 4313                              protocol, B_TRUE);
4309 4314                  }
4310 4315          }
4311 4316          if (worklist != NULL)
4312 4317                  free_list(worklist);
4313 4318          return (ret);
4314 4319  }
4315 4320  
4316 4321  /*
4317 4322   * space_unset(groupname, optlist, protocol, sharepath, dryrun)
4318 4323   *
4319 4324   * Unset named optionset properties.
4320 4325   */
4321 4326  static int
4322 4327  space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4323 4328      char *protocol, char *sharepath, int dryrun, char *sectype)
4324 4329  {
4325 4330          sa_group_t group;
4326 4331          int ret = SA_OK;
4327 4332          int change = 0;
4328 4333          struct list *worklist = NULL;
4329 4334          sa_share_t share = NULL;
4330 4335  
4331 4336          group = sa_get_group(handle, groupname);
4332 4337          if (group == NULL) {
4333 4338                  (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4334 4339                  return (SA_NO_SUCH_GROUP);
4335 4340          }
4336 4341          if (sharepath != NULL) {
4337 4342                  share = sa_get_share(group, sharepath);
4338 4343                  if (share == NULL) {
4339 4344                          (void) printf(gettext(
4340 4345                              "Share does not exist in group %s\n"),
4341 4346                              groupname, sharepath);
4342 4347                          return (SA_NO_SUCH_PATH);
4343 4348                  }
4344 4349          }
4345 4350          ret = valid_unset_security(share != NULL ? share : group,
4346 4351              optlist, protocol, sectype);
4347 4352  
4348 4353          if (ret == SA_OK && !dryrun) {
4349 4354                  if (optlist != NULL) {
4350 4355                          if (share != NULL) {
4351 4356                                  sa_security_t optionset;
4352 4357                                  sa_property_t prop;
4353 4358                                  change = remove_security(share,
4354 4359                                      sectype, optlist, protocol, &ret);
4355 4360  
4356 4361                                  /* If a share security is empty, remove it */
4357 4362                                  optionset = sa_get_security((sa_group_t)share,
4358 4363                                      sectype, protocol);
4359 4364                                  if (optionset != NULL) {
4360 4365                                          prop = sa_get_property(optionset,
4361 4366                                              NULL);
4362 4367                                          if (prop == NULL)
4363 4368                                                  ret = sa_destroy_security(
4364 4369                                                      optionset);
4365 4370                                  }
4366 4371                          } else {
4367 4372                                  change = remove_security(group, sectype,
4368 4373                                      optlist, protocol, &ret);
4369 4374                          }
4370 4375                  } else {
4371 4376                          sa_security_t security;
4372 4377                          char *sec;
4373 4378                          sec = sa_proto_space_alias(protocol, sectype);
4374 4379                          security = sa_get_security(group, sec, protocol);
4375 4380                          if (sec != NULL)
4376 4381                                  sa_free_attr_string(sec);
4377 4382                          if (security != NULL) {
4378 4383                                  ret = sa_destroy_security(security);
4379 4384                                  if (ret == SA_OK)
4380 4385                                          change = 1;
4381 4386                          } else {
4382 4387                                  ret = SA_NO_SUCH_PROP;
4383 4388                          }
4384 4389                  }
4385 4390                  if (ret != SA_OK)
4386 4391                          (void) printf(gettext("Could not unset property: %s\n"),
4387 4392                              sa_errorstr(ret));
4388 4393          }
4389 4394  
4390 4395          if (ret == SA_OK && change)
4391 4396                  worklist = add_list(worklist, group, 0, protocol);
4392 4397  
4393 4398          free_opt(optlist);
4394 4399          /*
4395 4400           * We have a group and potentially legal additions
4396 4401           */
4397 4402  
4398 4403          /* Commit to configuration if not a dryrun */
4399 4404          if (!dryrun && ret == 0) {
4400 4405                  /* properties changed, so update all shares */
4401 4406                  if (change && worklist != NULL)
4402 4407                          (void) enable_all_groups(handle, worklist, 0, 0,
4403 4408                              protocol, B_TRUE);
4404 4409                  ret = sa_update_config(handle);
4405 4410          }
4406 4411          if (worklist != NULL)
4407 4412                  free_list(worklist);
4408 4413          return (ret);
4409 4414  }
4410 4415  
4411 4416  /*
4412 4417   * sa_unset(flags, argc, argv)
4413 4418   *
4414 4419   * Implements the unset subcommand. Parsing done here and then basic
4415 4420   * or space versions of the real code are called.
4416 4421   */
4417 4422  
4418 4423  int
4419 4424  sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
4420 4425  {
4421 4426          char *groupname;
4422 4427          int verbose = 0;
4423 4428          int dryrun = 0;
4424 4429          int c;
4425 4430          char *protocol = NULL;
4426 4431          int ret = SA_OK;
4427 4432          struct options *optlist = NULL;
4428 4433          char *rsrcname = NULL;
4429 4434          char *sharepath = NULL;
4430 4435          char *optset = NULL;
4431 4436          int auth;
4432 4437  
4433 4438          while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
4434 4439                  switch (c) {
4435 4440                  case 'v':
4436 4441                          verbose++;
4437 4442                          break;
4438 4443                  case 'n':
4439 4444                          dryrun++;
4440 4445                          break;
4441 4446                  case 'P':
4442 4447                          if (protocol != NULL) {
4443 4448                                  (void) printf(gettext(
4444 4449                                      "Specifying multiple protocols "
4445 4450                                      "not supported: %s\n"), protocol);
4446 4451                                  return (SA_SYNTAX_ERR);
4447 4452                          }
4448 4453                          protocol = optarg;
4449 4454                          if (!sa_valid_protocol(protocol)) {
4450 4455                                  (void) printf(gettext(
4451 4456                                      "Invalid protocol specified: %s\n"),
4452 4457                                      protocol);
4453 4458                                  return (SA_INVALID_PROTOCOL);
4454 4459                          }
4455 4460                          break;
4456 4461                  case 'p':
4457 4462                          ret = add_opt(&optlist, optarg, 1);
4458 4463                          switch (ret) {
4459 4464                          case OPT_ADD_SYNTAX:
4460 4465                                  (void) printf(gettext("Property syntax error "
4461 4466                                      "for property %s\n"), optarg);
4462 4467                                  return (SA_SYNTAX_ERR);
4463 4468  
4464 4469                          case OPT_ADD_PROPERTY:
4465 4470                                  (void) printf(gettext("Properties need to be "
4466 4471                                      "set with set command: %s\n"), optarg);
4467 4472                                  return (SA_SYNTAX_ERR);
4468 4473  
4469 4474                          default:
4470 4475                                  break;
4471 4476                          }
4472 4477                          break;
4473 4478                  case 'r':
4474 4479                          /*
4475 4480                           * Unset properties on resource if applicable or on
4476 4481                           * share if resource for this protocol doesn't use
4477 4482                           * resources.
4478 4483                           */
4479 4484                          if (rsrcname != NULL) {
4480 4485                                  (void) printf(gettext(
4481 4486                                      "Unsetting multiple resource "
4482 4487                                      "names not supported\n"));
4483 4488                                  return (SA_SYNTAX_ERR);
4484 4489                          }
4485 4490                          rsrcname = optarg;
4486 4491                          break;
4487 4492                  case 's':
4488 4493                          if (sharepath != NULL) {
4489 4494                                  (void) printf(gettext(
4490 4495                                      "Adding multiple shares not supported\n"));
4491 4496                                  return (SA_SYNTAX_ERR);
4492 4497                          }
4493 4498                          sharepath = optarg;
4494 4499                          break;
4495 4500                  case 'S':
4496 4501                          if (optset != NULL) {
4497 4502                                  (void) printf(gettext(
4498 4503                                      "Specifying multiple property "
4499 4504                                      "spaces not supported: %s\n"), optset);
4500 4505                                  return (SA_SYNTAX_ERR);
4501 4506                          }
4502 4507                          optset = optarg;
4503 4508                          break;
4504 4509                  case 'h':
4505 4510                          /* optopt on valid arg isn't defined */
4506 4511                          optopt = c;
4507 4512                          /*FALLTHROUGH*/
4508 4513                  case '?':
4509 4514                  default:
4510 4515                          /*
4511 4516                           * Since a bad option gets to here, sort it
4512 4517                           * out and return a syntax error return value
4513 4518                           * if necessary.
4514 4519                           */
4515 4520                          switch (optopt) {
4516 4521                          default:
4517 4522                                  ret = SA_SYNTAX_ERR;
4518 4523                                  break;
4519 4524                          case 'h':
4520 4525                          case '?':
4521 4526                                  break;
4522 4527                          }
4523 4528                          (void) printf(gettext("usage: %s\n"),
4524 4529                              sa_get_usage(USAGE_UNSET));
4525 4530                          return (ret);
4526 4531                  }
4527 4532          }
4528 4533  
4529 4534          if (optlist != NULL)
4530 4535                  ret = chk_opt(optlist, optset != NULL, protocol);
4531 4536  
4532 4537          if (optind >= argc || (optlist == NULL && optset == NULL) ||
4533 4538              protocol == NULL) {
4534 4539                  char *sep = "\t";
4535 4540                  (void) printf(gettext("usage: %s\n"),
4536 4541                      sa_get_usage(USAGE_UNSET));
4537 4542                  if (optind >= argc) {
4538 4543                          (void) printf(gettext("%sgroup must be specified"),
4539 4544                              sep);
4540 4545                          sep = ", ";
4541 4546                  }
4542 4547                  if (optlist == NULL) {
4543 4548                          (void) printf(gettext("%sat least one property must "
4544 4549                              "be specified"), sep);
4545 4550                          sep = ", ";
4546 4551                  }
4547 4552                  if (protocol == NULL) {
4548 4553                          (void) printf(gettext("%sprotocol must be specified"),
4549 4554                              sep);
4550 4555                          sep = ", ";
4551 4556                  }
4552 4557                  (void) printf("\n");
4553 4558                  ret = SA_SYNTAX_ERR;
4554 4559          } else {
4555 4560  
4556 4561                  /*
4557 4562                   * If a group already exists, we can only add a new
4558 4563                   * protocol to it and not create a new one or add the
4559 4564                   * same protocol again.
4560 4565                   */
4561 4566  
4562 4567                  groupname = argv[optind];
4563 4568                  auth = check_authorizations(groupname, flags);
4564 4569                  if (optset == NULL)
4565 4570                          ret = basic_unset(handle, groupname, optlist, protocol,
4566 4571                              sharepath, rsrcname, dryrun);
4567 4572                  else
4568 4573                          ret = space_unset(handle, groupname, optlist, protocol,
4569 4574                              sharepath, dryrun, optset);
4570 4575  
4571 4576                  if (dryrun && ret == SA_OK && !auth && verbose)
4572 4577                          (void) printf(gettext("Command would fail: %s\n"),
4573 4578                              sa_errorstr(SA_NO_PERMISSION));
4574 4579          }
4575 4580          return (ret);
4576 4581  }
4577 4582  
4578 4583  /*
4579 4584   * sa_enable_group(flags, argc, argv)
4580 4585   *
4581 4586   * Implements the enable subcommand
4582 4587   */
4583 4588  
4584 4589  int
4585 4590  sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4586 4591  {
4587 4592          int verbose = 0;
4588 4593          int dryrun = 0;
4589 4594          int all = 0;
4590 4595          int c;
4591 4596          int ret = SA_OK;
4592 4597          char *protocol = NULL;
4593 4598          char *state;
4594 4599          struct list *worklist = NULL;
4595 4600          int auth = 1;
4596 4601          sa_group_t group;
4597 4602  
4598 4603          while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
4599 4604                  switch (c) {
4600 4605                  case 'a':
4601 4606                          all = 1;
4602 4607                          break;
4603 4608                  case 'n':
4604 4609                          dryrun++;
4605 4610                          break;
4606 4611                  case 'P':
4607 4612                          if (protocol != NULL) {
4608 4613                                  (void) printf(gettext(
4609 4614                                      "Specifying multiple protocols "
4610 4615                                      "not supported: %s\n"), protocol);
4611 4616                                  return (SA_SYNTAX_ERR);
4612 4617                          }
4613 4618                          protocol = optarg;
4614 4619                          if (!sa_valid_protocol(protocol)) {
4615 4620                                  (void) printf(gettext(
4616 4621                                      "Invalid protocol specified: %s\n"),
4617 4622                                      protocol);
4618 4623                                  return (SA_INVALID_PROTOCOL);
4619 4624                          }
4620 4625                          break;
4621 4626                  case 'v':
4622 4627                          verbose++;
4623 4628                          break;
4624 4629                  case 'h':
4625 4630                          /* optopt on valid arg isn't defined */
4626 4631                          optopt = c;
4627 4632                          /*FALLTHROUGH*/
4628 4633                  case '?':
4629 4634                  default:
4630 4635                          /*
4631 4636                           * Since a bad option gets to here, sort it
4632 4637                           * out and return a syntax error return value
4633 4638                           * if necessary.
4634 4639                           */
4635 4640                          switch (optopt) {
4636 4641                          default:
4637 4642                                  ret = SA_SYNTAX_ERR;
4638 4643                                  break;
4639 4644                          case 'h':
4640 4645                          case '?':
4641 4646                                  (void) printf(gettext("usage: %s\n"),
4642 4647                                      sa_get_usage(USAGE_ENABLE));
4643 4648                                  return (ret);
4644 4649                          }
4645 4650                  }
4646 4651          }
4647 4652  
4648 4653          if (optind == argc && !all) {
4649 4654                  (void) printf(gettext("usage: %s\n"),
4650 4655                      sa_get_usage(USAGE_ENABLE));
4651 4656                  (void) printf(gettext("\tmust specify group\n"));
4652 4657                  return (SA_NO_SUCH_PATH);
4653 4658          }
4654 4659          if (!all) {
4655 4660                  while (optind < argc) {
4656 4661                          group = sa_get_group(handle, argv[optind]);
4657 4662                          if (group != NULL) {
4658 4663                                  auth &= check_authorizations(argv[optind],
4659 4664                                      flags);
4660 4665                                  state = sa_get_group_attr(group, "state");
4661 4666                                  if (state != NULL &&
4662 4667                                      strcmp(state, "enabled") == 0) {
4663 4668                                          /* already enabled */
4664 4669                                          if (verbose)
4665 4670                                                  (void) printf(gettext(
4666 4671                                                      "Group \"%s\" is already "
4667 4672                                                      "enabled\n"),
4668 4673                                                      argv[optind]);
4669 4674                                          ret = SA_BUSY; /* already enabled */
4670 4675                                  } else {
4671 4676                                          worklist = add_list(worklist, group,
4672 4677                                              0, protocol);
4673 4678                                          if (verbose)
4674 4679                                                  (void) printf(gettext(
4675 4680                                                      "Enabling group \"%s\"\n"),
4676 4681                                                      argv[optind]);
4677 4682                                  }
4678 4683                                  if (state != NULL)
4679 4684                                          sa_free_attr_string(state);
4680 4685                          } else {
4681 4686                                  ret = SA_NO_SUCH_GROUP;
4682 4687                          }
4683 4688                          optind++;
4684 4689                  }
4685 4690          } else {
4686 4691                  for (group = sa_get_group(handle, NULL);
4687 4692                      group != NULL;
4688 4693                      group = sa_get_next_group(group)) {
4689 4694                          worklist = add_list(worklist, group, 0, protocol);
4690 4695                  }
4691 4696          }
4692 4697          if (!dryrun && ret == SA_OK)
4693 4698                  ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE);
4694 4699  
4695 4700          if (ret != SA_OK && ret != SA_BUSY)
4696 4701                  (void) printf(gettext("Could not enable group: %s\n"),
4697 4702                      sa_errorstr(ret));
4698 4703          if (ret == SA_BUSY)
4699 4704                  ret = SA_OK;
4700 4705  
4701 4706          if (worklist != NULL)
4702 4707                  free_list(worklist);
4703 4708          if (dryrun && ret == SA_OK && !auth && verbose) {
4704 4709                  (void) printf(gettext("Command would fail: %s\n"),
4705 4710                      sa_errorstr(SA_NO_PERMISSION));
4706 4711          }
4707 4712          return (ret);
4708 4713  }
4709 4714  
4710 4715  /*
4711 4716   * disable_group(group, proto)
4712 4717   *
4713 4718   * Disable all the shares in the specified group.. This is a helper
4714 4719   * for disable_all_groups in order to simplify regular and subgroup
4715 4720   * (zfs) disabling. Group has already been checked for non-NULL.
4716 4721   */
4717 4722  
4718 4723  static int
4719 4724  disable_group(sa_group_t group, char *proto)
4720 4725  {
4721 4726          sa_share_t share;
4722 4727          int ret = SA_OK;
4723 4728  
4724 4729          /*
4725 4730           * If the protocol isn't enabled, skip it and treat as
4726 4731           * successful.
4727 4732           */
4728 4733          if (!has_protocol(group, proto))
4729 4734                  return (ret);
4730 4735  
4731 4736          for (share = sa_get_share(group, NULL);
4732 4737              share != NULL && ret == SA_OK;
4733 4738              share = sa_get_next_share(share)) {
4734 4739                  ret = sa_disable_share(share, proto);
4735 4740                  if (ret == SA_NO_SUCH_PATH) {
4736 4741                          /*
4737 4742                           * this is OK since the path is gone. we can't
4738 4743                           * re-share it anyway so no error.
4739 4744                           */
4740 4745                          ret = SA_OK;
4741 4746                  }
4742 4747          }
4743 4748          return (ret);
4744 4749  }
4745 4750  
4746 4751  /*
4747 4752   * disable_all_groups(work, setstate)
4748 4753   *
4749 4754   * helper function that disables the shares in the list of groups
4750 4755   * provided. It optionally marks the group as disabled. Used by both
4751 4756   * enable and start subcommands.
4752 4757   */
4753 4758  
4754 4759  static int
4755 4760  disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
4756 4761  {
4757 4762          int ret = SA_OK;
4758 4763          sa_group_t subgroup, group;
4759 4764  
4760 4765          while (work != NULL && ret == SA_OK) {
4761 4766                  group = (sa_group_t)work->item;
4762 4767                  if (setstate)
4763 4768                          ret = sa_set_group_attr(group, "state", "disabled");
4764 4769                  if (ret == SA_OK) {
4765 4770                          char *name;
4766 4771                          name = sa_get_group_attr(group, "name");
4767 4772                          if (name != NULL && strcmp(name, "zfs") == 0) {
4768 4773                                  /* need to get the sub-groups for stopping */
4769 4774                                  for (subgroup = sa_get_sub_group(group);
4770 4775                                      subgroup != NULL;
4771 4776                                      subgroup = sa_get_next_group(subgroup)) {
4772 4777                                          ret = disable_group(subgroup,
4773 4778                                              work->proto);
4774 4779                                  }
4775 4780                          } else {
4776 4781                                  ret = disable_group(group, work->proto);
4777 4782                          }
4778 4783                          if (name != NULL)
4779 4784                                  sa_free_attr_string(name);
4780 4785                          /*
4781 4786                           * We don't want to "disable" since it won't come
4782 4787                           * up after a reboot.  The SMF framework should do
4783 4788                           * the right thing. On enable we do want to do
4784 4789                           * something.
4785 4790                           */
4786 4791                  }
4787 4792                  work = work->next;
4788 4793          }
4789 4794          if (ret == SA_OK)
4790 4795                  ret = sa_update_config(handle);
4791 4796          return (ret);
4792 4797  }
4793 4798  
4794 4799  /*
4795 4800   * sa_disable_group(flags, argc, argv)
4796 4801   *
4797 4802   * Implements the disable subcommand
4798 4803   */
4799 4804  
4800 4805  int
4801 4806  sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4802 4807  {
4803 4808          int verbose = 0;
4804 4809          int dryrun = 0;
4805 4810          int all = 0;
4806 4811          int c;
4807 4812          int ret = SA_OK;
4808 4813          char *protocol = NULL;
4809 4814          char *state;
4810 4815          struct list *worklist = NULL;
4811 4816          sa_group_t group;
4812 4817          int auth = 1;
4813 4818  
4814 4819          while ((c = getopt(argc, argv, "?havn")) != EOF) {
4815 4820                  switch (c) {
4816 4821                  case 'a':
4817 4822                          all = 1;
4818 4823                          break;
4819 4824                  case 'n':
4820 4825                          dryrun++;
4821 4826                          break;
4822 4827                  case 'P':
4823 4828                          if (protocol != NULL) {
4824 4829                                  (void) printf(gettext(
4825 4830                                      "Specifying multiple protocols "
4826 4831                                      "not supported: %s\n"), protocol);
4827 4832                                  return (SA_SYNTAX_ERR);
4828 4833                          }
4829 4834                          protocol = optarg;
4830 4835                          if (!sa_valid_protocol(protocol)) {
4831 4836                                  (void) printf(gettext(
4832 4837                                      "Invalid protocol specified: %s\n"),
4833 4838                                      protocol);
4834 4839                                  return (SA_INVALID_PROTOCOL);
4835 4840                          }
4836 4841                          break;
4837 4842                  case 'v':
4838 4843                          verbose++;
4839 4844                          break;
4840 4845                  case 'h':
4841 4846                          /* optopt on valid arg isn't defined */
4842 4847                          optopt = c;
4843 4848                          /*FALLTHROUGH*/
4844 4849                  case '?':
4845 4850                  default:
4846 4851                          /*
4847 4852                           * Since a bad option gets to here, sort it
4848 4853                           * out and return a syntax error return value
4849 4854                           * if necessary.
4850 4855                           */
4851 4856                          switch (optopt) {
4852 4857                          default:
4853 4858                                  ret = SA_SYNTAX_ERR;
4854 4859                                  break;
4855 4860                          case 'h':
4856 4861                          case '?':
4857 4862                                  break;
4858 4863                          }
4859 4864                          (void) printf(gettext("usage: %s\n"),
4860 4865                              sa_get_usage(USAGE_DISABLE));
4861 4866                          return (ret);
4862 4867                  }
4863 4868          }
4864 4869  
4865 4870          if (optind == argc && !all) {
4866 4871                  (void) printf(gettext("usage: %s\n"),
4867 4872                      sa_get_usage(USAGE_DISABLE));
4868 4873                  (void) printf(gettext("\tmust specify group\n"));
4869 4874                  return (SA_NO_SUCH_PATH);
4870 4875          }
4871 4876          if (!all) {
4872 4877                  while (optind < argc) {
4873 4878                          group = sa_get_group(handle, argv[optind]);
4874 4879                          if (group != NULL) {
4875 4880                                  auth &= check_authorizations(argv[optind],
4876 4881                                      flags);
4877 4882                                  state = sa_get_group_attr(group, "state");
4878 4883                                  if (state == NULL ||
4879 4884                                      strcmp(state, "disabled") == 0) {
4880 4885                                          /* already disabled */
4881 4886                                          if (verbose)
4882 4887                                                  (void) printf(gettext(
4883 4888                                                      "Group \"%s\" is "
4884 4889                                                      "already disabled\n"),
4885 4890                                                      argv[optind]);
4886 4891                                          ret = SA_BUSY; /* already disabled */
4887 4892                                  } else {
4888 4893                                          worklist = add_list(worklist, group, 0,
4889 4894                                              protocol);
4890 4895                                          if (verbose)
4891 4896                                                  (void) printf(gettext(
4892 4897                                                      "Disabling group "
4893 4898                                                      "\"%s\"\n"), argv[optind]);
4894 4899                                  }
4895 4900                                  if (state != NULL)
4896 4901                                          sa_free_attr_string(state);
4897 4902                          } else {
4898 4903                                  ret = SA_NO_SUCH_GROUP;
4899 4904                          }
4900 4905                          optind++;
4901 4906                  }
4902 4907          } else {
4903 4908                  for (group = sa_get_group(handle, NULL);
4904 4909                      group != NULL;
4905 4910                      group = sa_get_next_group(group))
4906 4911                          worklist = add_list(worklist, group, 0, protocol);
4907 4912          }
4908 4913  
4909 4914          if (ret == SA_OK && !dryrun)
4910 4915                  ret = disable_all_groups(handle, worklist, 1);
4911 4916          if (ret != SA_OK && ret != SA_BUSY)
4912 4917                  (void) printf(gettext("Could not disable group: %s\n"),
4913 4918                      sa_errorstr(ret));
4914 4919          if (ret == SA_BUSY)
4915 4920                  ret = SA_OK;
4916 4921          if (worklist != NULL)
4917 4922                  free_list(worklist);
4918 4923          if (dryrun && ret == SA_OK && !auth && verbose)
4919 4924                  (void) printf(gettext("Command would fail: %s\n"),
4920 4925                      sa_errorstr(SA_NO_PERMISSION));
4921 4926          return (ret);
4922 4927  }
4923 4928  
4924 4929  /*
4925 4930   * sa_start_group(flags, argc, argv)
4926 4931   *
4927 4932   * Implements the start command.
4928 4933   * This is similar to enable except it doesn't change the state
4929 4934   * of the group(s) and only enables shares if the group is already
4930 4935   * enabled.
4931 4936   */
4932 4937  
4933 4938  int
4934 4939  sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
4935 4940  {
4936 4941          int verbose = 0;
4937 4942          int all = 0;
4938 4943          int c;
4939 4944          int ret = SMF_EXIT_OK;
4940 4945          char *protocol = NULL;
4941 4946          char *state;
4942 4947          struct list *worklist = NULL;
4943 4948          sa_group_t group;
4944 4949  #ifdef lint
4945 4950          flags = flags;
4946 4951  #endif
4947 4952  
4948 4953          while ((c = getopt(argc, argv, "?havP:")) != EOF) {
4949 4954                  switch (c) {
4950 4955                  case 'a':
4951 4956                          all = 1;
4952 4957                          break;
4953 4958                  case 'P':
4954 4959                          if (protocol != NULL) {
4955 4960                                  (void) printf(gettext(
4956 4961                                      "Specifying multiple protocols "
4957 4962                                      "not supported: %s\n"), protocol);
4958 4963                                  return (SA_SYNTAX_ERR);
4959 4964                          }
4960 4965                          protocol = optarg;
4961 4966                          if (!sa_valid_protocol(protocol)) {
4962 4967                                  (void) printf(gettext(
4963 4968                                      "Invalid protocol specified: %s\n"),
4964 4969                                      protocol);
4965 4970                                  return (SA_INVALID_PROTOCOL);
4966 4971                          }
4967 4972                          break;
4968 4973                  case 'v':
4969 4974                          verbose++;
4970 4975                          break;
4971 4976                  case 'h':
4972 4977                          /* optopt on valid arg isn't defined */
4973 4978                          optopt = c;
4974 4979                          /*FALLTHROUGH*/
4975 4980                  case '?':
4976 4981                  default:
4977 4982                          /*
4978 4983                           * Since a bad option gets to here, sort it
4979 4984                           * out and return a syntax error return value
4980 4985                           * if necessary.
4981 4986                           */
4982 4987                          ret = SA_OK;
4983 4988                          switch (optopt) {
4984 4989                          default:
4985 4990                                  ret = SA_SYNTAX_ERR;
4986 4991                                  break;
4987 4992                          case 'h':
4988 4993                          case '?':
4989 4994                                  break;
4990 4995                          }
4991 4996                          (void) printf(gettext("usage: %s\n"),
4992 4997                              sa_get_usage(USAGE_START));
4993 4998                          return (ret);
4994 4999                  }
4995 5000          }
4996 5001  
4997 5002          if (optind == argc && !all) {
4998 5003                  (void) printf(gettext("usage: %s\n"),
4999 5004                      sa_get_usage(USAGE_START));
5000 5005                  return (SMF_EXIT_ERR_FATAL);
5001 5006          }
5002 5007  
5003 5008          if (!all) {
5004 5009                  while (optind < argc) {
5005 5010                          group = sa_get_group(handle, argv[optind]);
5006 5011                          if (group != NULL) {
5007 5012                                  state = sa_get_group_attr(group, "state");
5008 5013                                  if (state == NULL ||
5009 5014                                      strcmp(state, "enabled") == 0) {
5010 5015                                          worklist = add_list(worklist, group, 0,
5011 5016                                              protocol);
5012 5017                                          if (verbose)
5013 5018                                                  (void) printf(gettext(
5014 5019                                                      "Starting group \"%s\"\n"),
5015 5020                                                      argv[optind]);
5016 5021                                  } else {
5017 5022                                          /*
5018 5023                                           * Determine if there are any
5019 5024                                           * protocols.  If there aren't any,
5020 5025                                           * then there isn't anything to do in
5021 5026                                           * any case so no error.
5022 5027                                           */
5023 5028                                          if (sa_get_optionset(group,
5024 5029                                              protocol) != NULL) {
5025 5030                                                  ret = SMF_EXIT_OK;
5026 5031                                          }
5027 5032                                  }
5028 5033                                  if (state != NULL)
5029 5034                                          sa_free_attr_string(state);
5030 5035                          }
5031 5036                          optind++;
5032 5037                  }
5033 5038          } else {
5034 5039                  for (group = sa_get_group(handle, NULL);
5035 5040                      group != NULL;
5036 5041                      group = sa_get_next_group(group)) {
5037 5042                          state = sa_get_group_attr(group, "state");
5038 5043                          if (state == NULL || strcmp(state, "enabled") == 0)
5039 5044                                  worklist = add_list(worklist, group, 0,
5040 5045                                      protocol);
5041 5046                          if (state != NULL)
5042 5047                                  sa_free_attr_string(state);
5043 5048                  }
5044 5049          }
5045 5050  
5046 5051          (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE);
5047 5052  
5048 5053          if (worklist != NULL)
5049 5054                  free_list(worklist);
5050 5055          return (ret);
5051 5056  }
5052 5057  
5053 5058  /*
5054 5059   * sa_stop_group(flags, argc, argv)
5055 5060   *
5056 5061   * Implements the stop command.
5057 5062   * This is similar to disable except it doesn't change the state
5058 5063   * of the group(s) and only disables shares if the group is already
5059 5064   * enabled.
5060 5065   */
5061 5066  int
5062 5067  sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
5063 5068  {
5064 5069          int verbose = 0;
5065 5070          int all = 0;
5066 5071          int c;
5067 5072          int ret = SMF_EXIT_OK;
5068 5073          char *protocol = NULL;
5069 5074          char *state;
5070 5075          struct list *worklist = NULL;
5071 5076          sa_group_t group;
5072 5077  #ifdef lint
5073 5078          flags = flags;
5074 5079  #endif
5075 5080  
5076 5081          while ((c = getopt(argc, argv, "?havP:")) != EOF) {
5077 5082                  switch (c) {
5078 5083                  case 'a':
5079 5084                          all = 1;
5080 5085                          break;
5081 5086                  case 'P':
5082 5087                          if (protocol != NULL) {
5083 5088                                  (void) printf(gettext(
5084 5089                                      "Specifying multiple protocols "
5085 5090                                      "not supported: %s\n"), protocol);
5086 5091                                  return (SA_SYNTAX_ERR);
5087 5092                          }
5088 5093                          protocol = optarg;
5089 5094                          if (!sa_valid_protocol(protocol)) {
5090 5095                                  (void) printf(gettext(
5091 5096                                      "Invalid protocol specified: %s\n"),
5092 5097                                      protocol);
5093 5098                                  return (SA_INVALID_PROTOCOL);
5094 5099                          }
5095 5100                          break;
5096 5101                  case 'v':
5097 5102                          verbose++;
5098 5103                          break;
5099 5104                  case 'h':
5100 5105                          /* optopt on valid arg isn't defined */
5101 5106                          optopt = c;
5102 5107                          /*FALLTHROUGH*/
5103 5108                  case '?':
5104 5109                  default:
5105 5110                          /*
5106 5111                           * Since a bad option gets to here, sort it
5107 5112                           * out and return a syntax error return value
5108 5113                           * if necessary.
5109 5114                           */
5110 5115                          ret = SA_OK;
5111 5116                          switch (optopt) {
5112 5117                          default:
5113 5118                                  ret = SA_SYNTAX_ERR;
5114 5119                                  break;
5115 5120                          case 'h':
5116 5121                          case '?':
5117 5122                                  break;
5118 5123                          }
5119 5124                          (void) printf(gettext("usage: %s\n"),
5120 5125                              sa_get_usage(USAGE_STOP));
5121 5126                          return (ret);
5122 5127                  }
5123 5128          }
5124 5129  
5125 5130          if (optind == argc && !all) {
5126 5131                  (void) printf(gettext("usage: %s\n"),
5127 5132                      sa_get_usage(USAGE_STOP));
5128 5133                  return (SMF_EXIT_ERR_FATAL);
5129 5134          } else if (!all) {
5130 5135                  while (optind < argc) {
5131 5136                          group = sa_get_group(handle, argv[optind]);
5132 5137                          if (group != NULL) {
5133 5138                                  state = sa_get_group_attr(group, "state");
5134 5139                                  if (state == NULL ||
5135 5140                                      strcmp(state, "enabled") == 0) {
5136 5141                                          worklist = add_list(worklist, group, 0,
5137 5142                                              protocol);
5138 5143                                          if (verbose)
5139 5144                                                  (void) printf(gettext(
5140 5145                                                      "Stopping group \"%s\"\n"),
5141 5146                                                      argv[optind]);
5142 5147                                  } else {
5143 5148                                          ret = SMF_EXIT_OK;
5144 5149                                  }
5145 5150                                  if (state != NULL)
5146 5151                                          sa_free_attr_string(state);
5147 5152                          }
5148 5153                          optind++;
5149 5154                  }
5150 5155          } else {
5151 5156                  for (group = sa_get_group(handle, NULL);
5152 5157                      group != NULL;
5153 5158                      group = sa_get_next_group(group)) {
5154 5159                          state = sa_get_group_attr(group, "state");
5155 5160                          if (state == NULL || strcmp(state, "enabled") == 0)
5156 5161                                  worklist = add_list(worklist, group, 0,
5157 5162                                      protocol);
5158 5163                          if (state != NULL)
5159 5164                                  sa_free_attr_string(state);
5160 5165                  }
5161 5166          }
5162 5167          (void) disable_all_groups(handle, worklist, 0);
5163 5168          ret = sa_update_config(handle);
5164 5169  
5165 5170          if (worklist != NULL)
5166 5171                  free_list(worklist);
5167 5172          return (ret);
5168 5173  }
5169 5174  
5170 5175  /*
5171 5176   * remove_all_options(share, proto)
5172 5177   *
5173 5178   * Removes all options on a share.
5174 5179   */
5175 5180  
5176 5181  static void
5177 5182  remove_all_options(sa_share_t share, char *proto)
5178 5183  {
5179 5184          sa_optionset_t optionset;
5180 5185          sa_security_t security;
5181 5186          sa_security_t prevsec = NULL;
5182 5187  
5183 5188          optionset = sa_get_optionset(share, proto);
5184 5189          if (optionset != NULL)
5185 5190                  (void) sa_destroy_optionset(optionset);
5186 5191          for (security = sa_get_security(share, NULL, NULL);
5187 5192              security != NULL;
5188 5193              security = sa_get_next_security(security)) {
5189 5194                  char *type;
5190 5195                  /*
5191 5196                   * We walk through the list.  prevsec keeps the
5192 5197                   * previous security so we can delete it without
5193 5198                   * destroying the list.
5194 5199                   */
5195 5200                  if (prevsec != NULL) {
5196 5201                          /* remove the previously seen security */
5197 5202                          (void) sa_destroy_security(prevsec);
5198 5203                          /* set to NULL so we don't try multiple times */
5199 5204                          prevsec = NULL;
5200 5205                  }
5201 5206                  type = sa_get_security_attr(security, "type");
5202 5207                  if (type != NULL) {
5203 5208                          /*
5204 5209                           * if the security matches the specified protocol, we
5205 5210                           * want to remove it. prevsec holds it until either
5206 5211                           * the next pass or we fall out of the loop.
5207 5212                           */
5208 5213                          if (strcmp(type, proto) == 0)
5209 5214                                  prevsec = security;
5210 5215                          sa_free_attr_string(type);
5211 5216                  }
5212 5217          }
5213 5218          /* in case there is one left */
5214 5219          if (prevsec != NULL)
5215 5220                  (void) sa_destroy_security(prevsec);
5216 5221  }
5217 5222  
5218 5223  
5219 5224  /*
5220 5225   * for legacy support, we need to handle the old syntax. This is what
5221 5226   * we get if sharemgr is called with the name "share" rather than
5222 5227   * sharemgr.
5223 5228   */
5224 5229  
5225 5230  static int
5226 5231  format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
5227 5232  {
5228 5233          int err;
5229 5234  
5230 5235          err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
5231 5236          if (err > buffsize)
5232 5237                  return (-1);
5233 5238          return (0);
5234 5239  }
5235 5240  
5236 5241  
5237 5242  /*
5238 5243   * check_legacy_cmd(proto, cmd)
5239 5244   *
5240 5245   * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
5241 5246   * executable.
5242 5247   */
5243 5248  
5244 5249  static int
5245 5250  check_legacy_cmd(char *path)
5246 5251  {
5247 5252          struct stat st;
5248 5253          int ret = 0;
5249 5254  
5250 5255          if (stat(path, &st) == 0) {
5251 5256                  if (S_ISREG(st.st_mode) &&
5252 5257                      st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
5253 5258                          ret = 1;
5254 5259          }
5255 5260          return (ret);
5256 5261  }
5257 5262  
5258 5263  /*
5259 5264   * run_legacy_command(proto, cmd, argv)
5260 5265   *
5261 5266   * We know the command exists, so attempt to execute it with all the
5262 5267   * arguments. This implements full legacy share support for those
5263 5268   * protocols that don't have plugin providers.
5264 5269   */
5265 5270  
5266 5271  static int
5267 5272  run_legacy_command(char *path, char *argv[])
5268 5273  {
5269 5274          int ret;
5270 5275  
5271 5276          ret = execv(path, argv);
5272 5277          if (ret < 0) {
5273 5278                  switch (errno) {
5274 5279                  case EACCES:
5275 5280                          ret = SA_NO_PERMISSION;
5276 5281                          break;
5277 5282                  default:
5278 5283                          ret = SA_SYSTEM_ERR;
5279 5284                          break;
5280 5285                  }
5281 5286          }
5282 5287          return (ret);
5283 5288  }
5284 5289  
5285 5290  /*
5286 5291   * out_share(out, group, proto)
5287 5292   *
5288 5293   * Display the share information in the format that the "share"
5289 5294   * command has traditionally used.
5290 5295   */
5291 5296  
5292 5297  static void
5293 5298  out_share(FILE *out, sa_group_t group, char *proto)
5294 5299  {
5295 5300          sa_share_t share;
5296 5301          char resfmt[128];
5297 5302          char *defprop;
5298 5303  
5299 5304          /*
5300 5305           * The original share command defaulted to displaying NFS
5301 5306           * shares or allowed a protocol to be specified. We want to
5302 5307           * skip those shares that are not the specified protocol.
5303 5308           */
5304 5309          if (proto != NULL && sa_get_optionset(group, proto) == NULL)
5305 5310                  return;
5306 5311  
5307 5312          if (proto == NULL)
5308 5313                  proto = "nfs";
5309 5314  
5310 5315          /*
5311 5316           * get the default property string.  NFS uses "rw" but
5312 5317           * everything else will use "".
5313 5318           */
5314 5319          if (proto != NULL && strcmp(proto, "nfs") != 0)
5315 5320                  defprop = "\"\"";
5316 5321          else
5317 5322                  defprop = "rw";
5318 5323  
5319 5324          for (share = sa_get_share(group, NULL);
5320 5325              share != NULL;
5321 5326              share = sa_get_next_share(share)) {
5322 5327                  char *path;
5323 5328                  char *type;
5324 5329                  char *resource;
5325 5330                  char *description;
5326 5331                  char *groupname;
5327 5332                  char *sharedstate;
5328 5333                  int shared = 1;
5329 5334                  char *soptions;
5330 5335                  char shareopts[MAXNAMLEN];
5331 5336  
5332 5337                  sharedstate = sa_get_share_attr(share, "shared");
5333 5338                  path = sa_get_share_attr(share, "path");
5334 5339                  type = sa_get_share_attr(share, "type");
5335 5340                  resource = get_resource(share);
5336 5341                  groupname = sa_get_group_attr(group, "name");
5337 5342  
5338 5343                  if (groupname != NULL && strcmp(groupname, "default") == 0) {
5339 5344                          sa_free_attr_string(groupname);
5340 5345                          groupname = NULL;
5341 5346                  }
5342 5347                  description = sa_get_share_description(share);
5343 5348  
5344 5349                  /*
5345 5350                   * Want the sharetab version if it exists, defaulting
5346 5351                   * to NFS if no protocol specified.
5347 5352                   */
5348 5353                  (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto);
5349 5354                  soptions = sa_get_share_attr(share, shareopts);
5350 5355  
5351 5356                  if (sharedstate == NULL)
5352 5357                          shared = 0;
5353 5358  
5354 5359                  if (soptions == NULL)
5355 5360                          soptions = sa_proto_legacy_format(proto, share, 1);
5356 5361  
5357 5362                  if (shared) {
5358 5363                          /* only active shares go here */
5359 5364                          (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
5360 5365                              resource != NULL ? resource : "-",
5361 5366                              groupname != NULL ? "@" : "",
5362 5367                              groupname != NULL ? groupname : "");
5363 5368                          (void) fprintf(out, "%-14.14s  %s   %s   \"%s\"  \n",
5364 5369                              resfmt, (path != NULL) ? path : "",
5365 5370                              (soptions != NULL && strlen(soptions) > 0) ?
5366 5371                              soptions : defprop,
5367 5372                              (description != NULL) ? description : "");
5368 5373                  }
5369 5374  
5370 5375                  if (path != NULL)
5371 5376                          sa_free_attr_string(path);
5372 5377                  if (type != NULL)
5373 5378                          sa_free_attr_string(type);
5374 5379                  if (resource != NULL)
5375 5380                          sa_free_attr_string(resource);
5376 5381                  if (groupname != NULL)
5377 5382                          sa_free_attr_string(groupname);
5378 5383                  if (description != NULL)
5379 5384                          sa_free_share_description(description);
5380 5385                  if (sharedstate != NULL)
5381 5386                          sa_free_attr_string(sharedstate);
5382 5387                  if (soptions != NULL)
5383 5388                          sa_format_free(soptions);
5384 5389          }
5385 5390  }
5386 5391  
5387 5392  /*
5388 5393   * output_legacy_file(out, proto)
5389 5394   *
5390 5395   * Walk all of the groups for the specified protocol and call
5391 5396   * out_share() to format and write in the format displayed by the
5392 5397   * "share" command with no arguments.
5393 5398   */
5394 5399  
5395 5400  static void
5396 5401  output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
5397 5402  {
5398 5403          sa_group_t group;
5399 5404  
5400 5405          for (group = sa_get_group(handle, NULL);
5401 5406              group != NULL;
5402 5407              group = sa_get_next_group(group)) {
5403 5408                  char *zfs;
5404 5409  
5405 5410                  /*
5406 5411                   * Go through all the groups and ZFS
5407 5412                   * sub-groups. out_share() will format the shares in
5408 5413                   * the group appropriately.
5409 5414                   */
5410 5415  
5411 5416                  zfs = sa_get_group_attr(group, "zfs");
5412 5417                  if (zfs != NULL) {
5413 5418                          sa_group_t zgroup;
5414 5419                          sa_free_attr_string(zfs);
5415 5420                          for (zgroup = sa_get_sub_group(group);
5416 5421                              zgroup != NULL;
5417 5422                              zgroup = sa_get_next_group(zgroup)) {
5418 5423  
5419 5424                                  /* got a group, so display it */
5420 5425                                  out_share(out, zgroup, proto);
5421 5426                          }
5422 5427                  } else {
5423 5428                          out_share(out, group, proto);
5424 5429                  }
5425 5430          }
5426 5431  }
5427 5432  
5428 5433  int
5429 5434  sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
5430 5435  {
5431 5436          char *protocol = "nfs";
5432 5437          char *options = NULL;
5433 5438          char *description = NULL;
5434 5439          char *groupname = NULL;
5435 5440          char *sharepath = NULL;
5436 5441          char *resource = NULL;
5437 5442          char *groupstatus = NULL;
5438 5443          int persist = SA_SHARE_TRANSIENT;
5439 5444          int argsused = 0;
5440 5445          int c;
5441 5446          int ret = SA_OK;
5442 5447          int zfs = 0;
5443 5448          int true_legacy = 0;
5444 5449          int curtype = SA_SHARE_TRANSIENT;
5445 5450          char cmd[MAXPATHLEN];
5446 5451          sa_group_t group = NULL;
5447 5452          sa_resource_t rsrc = NULL;
5448 5453          sa_share_t share;
5449 5454          char dir[MAXPATHLEN];
5450 5455          uint64_t features;
5451 5456  #ifdef lint
5452 5457          flags = flags;
5453 5458  #endif
5454 5459  
5455 5460          while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
5456 5461                  switch (c) {
5457 5462                  case 'd':
5458 5463                          description = optarg;
5459 5464                          argsused++;
5460 5465                          break;
5461 5466                  case 'F':
5462 5467                          protocol = optarg;
5463 5468                          if (!sa_valid_protocol(protocol)) {
5464 5469                                  if (format_legacy_path(cmd, MAXPATHLEN,
5465 5470                                      protocol, "share") == 0 &&
5466 5471                                      check_legacy_cmd(cmd)) {
5467 5472                                          true_legacy++;
5468 5473                                  } else {
5469 5474                                          (void) fprintf(stderr, gettext(
5470 5475                                              "Invalid protocol specified: "
5471 5476                                              "%s\n"), protocol);
5472 5477                                          return (SA_INVALID_PROTOCOL);
5473 5478                                  }
5474 5479                          }
5475 5480                          break;
5476 5481                  case 'o':
5477 5482                          options = optarg;
5478 5483                          argsused++;
5479 5484                          break;
5480 5485                  case 'p':
5481 5486                          persist = SA_SHARE_PERMANENT;
5482 5487                          argsused++;
5483 5488                          break;
5484 5489                  case 'h':
5485 5490                          /* optopt on valid arg isn't defined */
5486 5491                          optopt = c;
5487 5492                          /*FALLTHROUGH*/
5488 5493                  case '?':
5489 5494                  default:
5490 5495                          /*
5491 5496                           * Since a bad option gets to here, sort it
5492 5497                           * out and return a syntax error return value
5493 5498                           * if necessary.
5494 5499                           */
5495 5500                          switch (optopt) {
5496 5501                          default:
5497 5502                                  ret = SA_LEGACY_ERR;
5498 5503                                  break;
5499 5504                          case 'h':
5500 5505                          case '?':
5501 5506                                  break;
5502 5507                          }
5503 5508                          (void) fprintf(stderr, gettext("usage: %s\n"),
5504 5509                              sa_get_usage(USAGE_SHARE));
5505 5510                          return (ret);
5506 5511                  }
5507 5512          }
5508 5513  
5509 5514          /* Have the info so construct what is needed */
5510 5515          if (!argsused && optind == argc) {
5511 5516                  /* display current info in share format */
5512 5517                  (void) output_legacy_file(stdout, protocol, handle);
5513 5518                  return (ret);
5514 5519          }
5515 5520  
5516 5521          /* We are modifying the configuration */
5517 5522          if (optind == argc) {
5518 5523                  (void) fprintf(stderr, gettext("usage: %s\n"),
5519 5524                      sa_get_usage(USAGE_SHARE));
5520 5525                  return (SA_LEGACY_ERR);
5521 5526          }
5522 5527          if (true_legacy) {
5523 5528                  /* If still using legacy share/unshare, exec it */
5524 5529                  ret = run_legacy_command(cmd, argv);
5525 5530                  return (ret);
5526 5531          }
5527 5532  
5528 5533          sharepath = argv[optind++];
5529 5534          if (optind < argc) {
5530 5535                  resource = argv[optind];
5531 5536                  groupname = strchr(resource, '@');
5532 5537                  if (groupname != NULL)
5533 5538                          *groupname++ = '\0';
5534 5539          }
5535 5540          if (realpath(sharepath, dir) == NULL)
5536 5541                  ret = SA_BAD_PATH;
5537 5542          else
5538 5543                  sharepath = dir;
5539 5544          if (ret == SA_OK)
5540 5545                  share = sa_find_share(handle, sharepath);
5541 5546          else
5542 5547                  share = NULL;
5543 5548  
5544 5549          features = sa_proto_get_featureset(protocol);
5545 5550  
5546 5551          if (groupname != NULL) {
5547 5552                  ret = SA_NOT_ALLOWED;
5548 5553          } else if (ret == SA_OK) {
5549 5554                  char *legacygroup;
5550 5555                  /*
5551 5556                   * The legacy group is always present and zfs groups
5552 5557                   * come and go.  zfs shares may be in sub-groups and
5553 5558                   * the zfs share will already be in that group so it
5554 5559                   * isn't an error. If the protocol is "smb", the group
5555 5560                   * "smb" is used when "default" would otherwise be
5556 5561                   * used.  "default" is NFS only and "smb" is SMB only.
5557 5562                   */
5558 5563                  if (strcmp(protocol, "smb") == 0)
5559 5564                          legacygroup = "smb";
5560 5565                  else
5561 5566                          legacygroup = "default";
5562 5567  
5563 5568                  /*
5564 5569                   * If the share exists (not NULL), then make sure it
5565 5570                   * is one we want to handle by getting the parent
5566 5571                   * group.
5567 5572                   */
5568 5573                  if (share != NULL) {
5569 5574                          group = sa_get_parent_group(share);
5570 5575                  } else {
5571 5576                          group = sa_get_group(handle, legacygroup);
5572 5577                          if (group == NULL && strcmp(legacygroup, "smb") == 0) {
5573 5578                                  /*
5574 5579                                   * This group may not exist, so create
5575 5580                                   * as necessary. It only contains the
5576 5581                                   * "smb" protocol.
5577 5582                                   */
5578 5583                                  group = sa_create_group(handle, legacygroup,
5579 5584                                      &ret);
5580 5585                                  if (group != NULL)
5581 5586                                          (void) sa_create_optionset(group,
5582 5587                                              protocol);
5583 5588                          }
5584 5589                  }
5585 5590  
5586 5591                  if (group == NULL) {
5587 5592                          ret = SA_SYSTEM_ERR;
5588 5593                          goto err;
5589 5594                  }
5590 5595  
5591 5596                  groupstatus = group_status(group);
5592 5597                  if (share == NULL) {
5593 5598                          share = sa_add_share(group, sharepath,
5594 5599                              persist, &ret);
5595 5600                          if (share == NULL &&
5596 5601                              ret == SA_DUPLICATE_NAME) {
5597 5602                                  /*
5598 5603                                   * Could be a ZFS path being started
5599 5604                                   */
5600 5605                                  if (sa_zfs_is_shared(handle,
5601 5606                                      sharepath)) {
5602 5607                                          ret = SA_OK;
5603 5608                                          group = sa_get_group(handle,
5604 5609                                              "zfs");
5605 5610                                          if (group == NULL) {
5606 5611                                                  /*
5607 5612                                                   * This shouldn't
5608 5613                                                   * happen.
5609 5614                                                   */
5610 5615                                                  ret = SA_CONFIG_ERR;
5611 5616                                          } else {
5612 5617                                                  share = sa_add_share(
5613 5618                                                      group, sharepath,
5614 5619                                                      persist, &ret);
5615 5620                                          }
5616 5621                                  }
5617 5622                          }
5618 5623                  } else {
5619 5624                          char *type;
5620 5625                          /*
5621 5626                           * May want to change persist state, but the
5622 5627                           * important thing is to change options. We
5623 5628                           * need to change them regardless of the
5624 5629                           * source.
5625 5630                           */
5626 5631  
5627 5632                          if (sa_zfs_is_shared(handle, sharepath)) {
5628 5633                                  zfs = 1;
5629 5634                          }
5630 5635                          remove_all_options(share, protocol);
5631 5636                          type = sa_get_share_attr(share, "type");
5632 5637                          if (type != NULL &&
5633 5638                              strcmp(type, "transient") != 0) {
5634 5639                                  curtype = SA_SHARE_PERMANENT;
5635 5640                          }
5636 5641                          if (type != NULL)
5637 5642                                  sa_free_attr_string(type);
5638 5643                          if (curtype != persist) {
5639 5644                                  (void) sa_set_share_attr(share, "type",
5640 5645                                      persist == SA_SHARE_PERMANENT ?
5641 5646                                      "persist" : "transient");
5642 5647                          }
5643 5648                  }
5644 5649  
5645 5650                  /*
5646 5651                   * If there is a resource name, we may
5647 5652                   * actually care about it if this is share for
5648 5653                   * a protocol that uses resource level sharing
5649 5654                   * (SMB). We need to find the resource and, if
5650 5655                   * it exists, make sure it belongs to the
5651 5656                   * current share. If it doesn't exist, attempt
5652 5657                   * to create it.
5653 5658                   */
5654 5659  
5655 5660                  if (ret == SA_OK && resource != NULL) {
5656 5661                          rsrc = sa_find_resource(handle, resource);
5657 5662                          if (rsrc != NULL) {
5658 5663                                  if (share != sa_get_resource_parent(rsrc))
5659 5664                                          ret = SA_DUPLICATE_NAME;
5660 5665                          } else {
5661 5666                                  rsrc = sa_add_resource(share, resource,
5662 5667                                      persist, &ret);
5663 5668                          }
5664 5669                          if (features & SA_FEATURE_RESOURCE)
5665 5670                                  share = rsrc;
5666 5671                  }
5667 5672  
5668 5673                  /* Have a group to hold this share path */
5669 5674                  if (ret == SA_OK && options != NULL &&
5670 5675                      strlen(options) > 0) {
5671 5676                          ret = sa_parse_legacy_options(share,
5672 5677                              options,
5673 5678                              protocol);
5674 5679                  }
5675 5680                  if (!zfs) {
5676 5681                          /*
5677 5682                           * ZFS shares never have a description
5678 5683                           * and we can't store the values so
5679 5684                           * don't try.
5680 5685                           */
5681 5686                          if (ret == SA_OK && description != NULL)
5682 5687                                  ret = sa_set_share_description(share,
5683 5688                                      description);
5684 5689                  }
5685 5690                  if (ret == SA_OK &&
5686 5691                      strcmp(groupstatus, "enabled") == 0) {
5687 5692                          if (rsrc != share)
5688 5693                                  ret = sa_enable_share(share, protocol);
5689 5694                          else
5690 5695                                  ret = sa_enable_resource(rsrc,
5691 5696                                      protocol);
5692 5697                          if (ret == SA_OK &&
5693 5698                              persist == SA_SHARE_PERMANENT) {
5694 5699                                  (void) sa_update_legacy(share,
5695 5700                                      protocol);
5696 5701                          }
5697 5702                          if (ret == SA_OK)
5698 5703                                  ret = sa_update_config(handle);
5699 5704                  }
5700 5705          }
5701 5706  err:
5702 5707          if (ret != SA_OK) {
5703 5708                  (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
5704 5709                      sharepath, sa_errorstr(ret));
5705 5710                  ret = SA_LEGACY_ERR;
5706 5711          }
5707 5712          return (ret);
5708 5713  }
5709 5714  
5710 5715  /*
5711 5716   * sa_legacy_unshare(flags, argc, argv)
5712 5717   *
5713 5718   * Implements the original unshare command.
5714 5719   */
5715 5720  int
5716 5721  sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
5717 5722  {
5718 5723          char *protocol = "nfs"; /* for now */
5719 5724          char *options = NULL;
5720 5725          char *sharepath = NULL;
5721 5726          int persist = SA_SHARE_TRANSIENT;
5722 5727          int argsused = 0;
5723 5728          int c;
5724 5729          int ret = SA_OK;
5725 5730          int true_legacy = 0;
5726 5731          uint64_t features = 0;
5727 5732          sa_resource_t resource = NULL;
5728 5733          char cmd[MAXPATHLEN];
5729 5734  #ifdef lint
5730 5735          flags = flags;
5731 5736          options = options;
5732 5737  #endif
5733 5738  
5734 5739          while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
5735 5740                  switch (c) {
5736 5741                  case 'F':
5737 5742                          protocol = optarg;
5738 5743                          if (!sa_valid_protocol(protocol)) {
5739 5744                                  if (format_legacy_path(cmd, MAXPATHLEN,
5740 5745                                      protocol, "unshare") == 0 &&
5741 5746                                      check_legacy_cmd(cmd)) {
5742 5747                                          true_legacy++;
5743 5748                                  } else {
5744 5749                                          (void) printf(gettext(
5745 5750                                              "Invalid file system name\n"));
5746 5751                                          return (SA_INVALID_PROTOCOL);
5747 5752                                  }
5748 5753                          }
5749 5754                          break;
5750 5755                  case 'o':
5751 5756                          options = optarg;
5752 5757                          argsused++;
5753 5758                          break;
5754 5759                  case 'p':
5755 5760                          persist = SA_SHARE_PERMANENT;
5756 5761                          argsused++;
5757 5762                          break;
5758 5763                  case 'h':
5759 5764                          /* optopt on valid arg isn't defined */
5760 5765                          optopt = c;
5761 5766                          /*FALLTHROUGH*/
5762 5767                  case '?':
5763 5768                  default:
5764 5769                          /*
5765 5770                           * Since a bad option gets to here, sort it
5766 5771                           * out and return a syntax error return value
5767 5772                           * if necessary.
5768 5773                           */
5769 5774                          switch (optopt) {
5770 5775                          default:
5771 5776                                  ret = SA_LEGACY_ERR;
5772 5777                                  break;
5773 5778                          case 'h':
5774 5779                          case '?':
5775 5780                                  break;
5776 5781                          }
5777 5782                          (void) printf(gettext("usage: %s\n"),
5778 5783                              sa_get_usage(USAGE_UNSHARE));
5779 5784                          return (ret);
5780 5785                  }
5781 5786          }
5782 5787  
5783 5788          /* Have the info so construct what is needed */
5784 5789          if (optind == argc || (optind + 1) < argc || options != NULL) {
5785 5790                  ret = SA_SYNTAX_ERR;
5786 5791          } else {
5787 5792                  sa_share_t share;
5788 5793                  char dir[MAXPATHLEN];
5789 5794                  if (true_legacy) {
5790 5795                          /* if still using legacy share/unshare, exec it */
5791 5796                          ret = run_legacy_command(cmd, argv);
5792 5797                          return (ret);
5793 5798                  }
5794 5799                  /*
5795 5800                   * Find the path in the internal configuration. If it
5796 5801                   * isn't found, attempt to resolve the path via
5797 5802                   * realpath() and try again.
5798 5803                   */
5799 5804                  sharepath = argv[optind++];
5800 5805                  share = sa_find_share(handle, sharepath);
5801 5806                  if (share == NULL) {
5802 5807                          if (realpath(sharepath, dir) == NULL) {
5803 5808                                  ret = SA_NO_SUCH_PATH;
5804 5809                          } else {
5805 5810                                  share = sa_find_share(handle, dir);
5806 5811                          }
5807 5812                  }
5808 5813                  if (share == NULL) {
5809 5814                          /* Could be a resource name so check that next */
5810 5815                          features = sa_proto_get_featureset(protocol);
5811 5816                          resource = sa_find_resource(handle, sharepath);
5812 5817                          if (resource != NULL) {
5813 5818                                  share = sa_get_resource_parent(resource);
5814 5819                                  if (features & SA_FEATURE_RESOURCE)
5815 5820                                          (void) sa_disable_resource(resource,
5816 5821                                              protocol);
5817 5822                                  if (persist == SA_SHARE_PERMANENT) {
5818 5823                                          ret = sa_remove_resource(resource);
5819 5824                                          if (ret == SA_OK)
5820 5825                                                  ret = sa_update_config(handle);
5821 5826                                  }
5822 5827                                  /*
5823 5828                                   * If we still have a resource on the
5824 5829                                   * share, we don't disable the share
5825 5830                                   * itself. IF there aren't anymore, we
5826 5831                                   * need to remove the share. The
5827 5832                                   * removal will be done in the next
5828 5833                                   * section if appropriate.
5829 5834                                   */
5830 5835                                  resource = sa_get_share_resource(share, NULL);
5831 5836                                  if (resource != NULL)
5832 5837                                          share = NULL;
5833 5838                          } else if (ret == SA_OK) {
5834 5839                                  /* Didn't find path and no  resource */
5835 5840                                  ret = SA_BAD_PATH;
5836 5841                          }
5837 5842                  }
5838 5843                  if (share != NULL && resource == NULL) {
5839 5844                          ret = sa_disable_share(share, protocol);
5840 5845                          /*
5841 5846                           * Errors are ok and removal should still occur. The
5842 5847                           * legacy unshare is more forgiving of errors than the
5843 5848                           * remove-share subcommand which may need the force
5844 5849                           * flag set for some error conditions. That is, the
5845 5850                           * "unshare" command will always unshare if it can
5846 5851                           * while "remove-share" might require the force option.
5847 5852                           */
5848 5853                          if (persist == SA_SHARE_PERMANENT) {
5849 5854                                  ret = sa_remove_share(share);
5850 5855                                  if (ret == SA_OK)
5851 5856                                          ret = sa_update_config(handle);
5852 5857                          }
5853 5858                  } else if (ret == SA_OK && share == NULL && resource == NULL) {
5854 5859                          /*
5855 5860                           * If both share and resource are NULL, then
5856 5861                           * share not found. If one or the other was
5857 5862                           * found or there was an earlier error, we
5858 5863                           * assume it was handled earlier.
5859 5864                           */
5860 5865                          ret = SA_NOT_SHARED;
5861 5866                  }
5862 5867          }
5863 5868          switch (ret) {
5864 5869          default:
5865 5870                  (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
5866 5871                  ret = SA_LEGACY_ERR;
5867 5872                  break;
5868 5873          case SA_SYNTAX_ERR:
5869 5874                  (void) printf(gettext("usage: %s\n"),
5870 5875                      sa_get_usage(USAGE_UNSHARE));
5871 5876                  break;
5872 5877          case SA_OK:
5873 5878                  break;
5874 5879          }
5875 5880          return (ret);
5876 5881  }
5877 5882  
5878 5883  /*
5879 5884   * Common commands that implement the sub-commands used by all
5880 5885   * protocols. The entries are found via the lookup command
5881 5886   */
5882 5887  
5883 5888  static sa_command_t commands[] = {
5884 5889          {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
5885 5890          {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
5886 5891          {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
5887 5892          {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
5888 5893          {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
5889 5894          {"list", 0, sa_list, USAGE_LIST},
5890 5895          {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
5891 5896          {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
5892 5897          {"set", 0, sa_set, USAGE_SET, SVC_SET},
5893 5898          {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
5894 5899          {"show", 0, sa_show, USAGE_SHOW},
5895 5900          {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
5896 5901          {"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
5897 5902              SVC_SET|SVC_ACTION},
5898 5903          {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
5899 5904          {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
5900 5905          {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
5901 5906          {NULL, 0, NULL, 0}
5902 5907  };
5903 5908  
5904 5909  static char *
5905 5910  sa_get_usage(sa_usage_t index)
5906 5911  {
5907 5912          char *ret = NULL;
5908 5913          switch (index) {
5909 5914          case USAGE_ADD_SHARE:
5910 5915                  ret = gettext("add-share [-nth] [-r resource-name] "
5911 5916                      "[-d \"description text\"] -s sharepath group");
5912 5917                  break;
5913 5918          case USAGE_CREATE:
5914 5919                  ret = gettext(
5915 5920                      "create [-nvh] [-P proto [-p property=value]] group");
5916 5921                  break;
5917 5922          case USAGE_DELETE:
5918 5923                  ret = gettext("delete [-nvh] [-P proto] [-f] group");
5919 5924                  break;
5920 5925          case USAGE_DISABLE:
5921 5926                  ret = gettext("disable [-nvh] {-a | group ...}");
5922 5927                  break;
5923 5928          case USAGE_ENABLE:
5924 5929                  ret = gettext("enable [-nvh] {-a | group ...}");
5925 5930                  break;
5926 5931          case USAGE_LIST:
5927 5932                  ret = gettext("list [-vh] [-P proto]");
5928 5933                  break;
5929 5934          case USAGE_MOVE_SHARE:
5930 5935                  ret = gettext(
5931 5936                      "move-share [-nvh] -s sharepath destination-group");
5932 5937                  break;
5933 5938          case USAGE_REMOVE_SHARE:
5934 5939                  ret = gettext(
5935 5940                      "remove-share [-fnvh] {-s sharepath | -r resource} "
5936 5941                      "group");
5937 5942                  break;
5938 5943          case USAGE_SET:
5939 5944                  ret = gettext("set [-nvh] -P proto [-S optspace] "
5940 5945                      "[-p property=value]* [-s sharepath] [-r resource]] "
5941 5946                      "group");
5942 5947                  break;
5943 5948          case USAGE_SET_SECURITY:
5944 5949                  ret = gettext("set-security [-nvh] -P proto -S security-type "
5945 5950                      "[-p property=value]* group");
5946 5951                  break;
5947 5952          case USAGE_SET_SHARE:
5948 5953                  ret = gettext("set-share [-nh] [-r resource] "
5949 5954                      "[-d \"description text\"] -s sharepath group");
5950 5955                  break;
5951 5956          case USAGE_SHOW:
5952 5957                  ret = gettext("show [-pvxh] [-P proto] [group ...]");
5953 5958                  break;
5954 5959          case USAGE_SHARE:
5955 5960                  ret = gettext("share [-F fstype] [-p] [-o optionlist]"
5956 5961                      "[-d description] [pathname [resourcename]]");
5957 5962                  break;
5958 5963          case USAGE_START:
5959 5964                  ret = gettext("start [-vh] [-P proto] {-a | group ...}");
5960 5965                  break;
5961 5966          case USAGE_STOP:
5962 5967                  ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
5963 5968                  break;
5964 5969          case USAGE_UNSET:
5965 5970                  ret = gettext("unset [-nvh] -P proto [-S optspace] "
5966 5971                      "[-p property]* group");
5967 5972                  break;
5968 5973          case USAGE_UNSET_SECURITY:
5969 5974                  ret = gettext("unset-security [-nvh] -P proto "
5970 5975                      "-S security-type [-p property]* group");
5971 5976                  break;
5972 5977          case USAGE_UNSHARE:
5973 5978                  ret = gettext(
5974 5979                      "unshare [-F fstype] [-p] [-o optionlist] sharepath");
5975 5980                  break;
5976 5981          }
5977 5982          return (ret);
5978 5983  }
5979 5984  
5980 5985  /*
5981 5986   * sa_lookup(cmd, proto)
5982 5987   *
5983 5988   * Lookup the sub-command. proto isn't currently used, but it may
5984 5989   * eventually provide a way to provide protocol specific sub-commands.
5985 5990   */
5986 5991  sa_command_t *
5987 5992  sa_lookup(char *cmd, char *proto)
5988 5993  {
5989 5994          int i;
5990 5995          size_t len;
5991 5996  #ifdef lint
5992 5997          proto = proto;
5993 5998  #endif
5994 5999  
5995 6000          len = strlen(cmd);
5996 6001          for (i = 0; commands[i].cmdname != NULL; i++) {
5997 6002                  if (strncmp(cmd, commands[i].cmdname, len) == 0)
5998 6003                          return (&commands[i]);
5999 6004          }
6000 6005          return (NULL);
6001 6006  }
6002 6007  
6003 6008  void
6004 6009  sub_command_help(char *proto)
6005 6010  {
6006 6011          int i;
6007 6012  #ifdef lint
6008 6013          proto = proto;
6009 6014  #endif
6010 6015  
6011 6016          (void) printf(gettext("\tsub-commands:\n"));
6012 6017          for (i = 0; commands[i].cmdname != NULL; i++) {
6013 6018                  if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
6014 6019                          (void) printf("\t%s\n",
6015 6020                              sa_get_usage((sa_usage_t)commands[i].cmdidx));
6016 6021          }
6017 6022  }
  
    | 
      ↓ open down ↓ | 
    3813 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX