Print this page
    
11945 pool import performance regression due to repeated libshare initialization
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libshare/common/libshare.c
          +++ new/usr/src/lib/libshare/common/libshare.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
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25   25   * Copyright (c) 2016 by Delphix. All rights reserved.
  26   26   */
  27   27  
  28   28  /*
  29   29   * Share control API
  30   30   */
  31   31  #include <stdio.h>
  32   32  #include <string.h>
  33   33  #include <ctype.h>
  34   34  #include <sys/types.h>
  35   35  #include <sys/stat.h>
  36   36  #include <fcntl.h>
  37   37  #include <unistd.h>
  38   38  #include <libxml/parser.h>
  39   39  #include <libxml/tree.h>
  40   40  #include "libshare.h"
  41   41  #include "libshare_impl.h"
  42   42  #include <libscf.h>
  43   43  #include "scfutil.h"
  44   44  #include <ctype.h>
  45   45  #include <libintl.h>
  46   46  #include <thread.h>
  47   47  #include <synch.h>
  48   48  #include <errno.h>
  49   49  
  50   50  #define DFS_LOCK_FILE   "/etc/dfs/fstypes"
  51   51  #define SA_STRSIZE      256     /* max string size for names */
  52   52  
  53   53  /*
  54   54   * internal object type values returned by sa_get_object_type()
  55   55   */
  56   56  #define SA_TYPE_UNKNOWN         0
  57   57  #define SA_TYPE_GROUP           1
  58   58  #define SA_TYPE_SHARE           2
  59   59  #define SA_TYPE_RESOURCE        3
  60   60  #define SA_TYPE_OPTIONSET       4
  61   61  #define SA_TYPE_ALTSPACE        5
  62   62  
  63   63  /*
  64   64   * internal data structures
  65   65   */
  66   66  
  67   67  extern struct sa_proto_plugin *sap_proto_list;
  68   68  
  69   69  /* current SMF/SVC repository handle */
  70   70  extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
  71   71  extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
  72   72  extern int get_one_transient(sa_handle_impl_t, xmlNodePtr *, char **, size_t);
  73   73  extern char *sa_fstype(char *);
  74   74  extern int sa_is_share(void *);
  75   75  extern int sa_is_resource(void *);
  76   76  extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
  77   77  extern int sa_group_is_zfs(sa_group_t);
  78   78  extern int sa_path_is_zfs(char *);
  79   79  extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
  80   80  extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
  81   81  extern void update_legacy_config(sa_handle_t);
  82   82  extern int issubdir(char *, char *);
  83   83  extern int sa_zfs_init(sa_handle_impl_t);
  84   84  extern void sa_zfs_fini(sa_handle_impl_t);
  85   85  extern void sablocksigs(sigset_t *);
  86   86  extern void saunblocksigs(sigset_t *);
  87   87  static sa_group_t sa_get_optionset_parent(sa_optionset_t);
  88   88  static char *get_node_attr(void *, char *);
  89   89  extern void sa_update_sharetab_ts(sa_handle_t);
  90   90  
  91   91  /*
  92   92   * Data structures for finding/managing the document root to access
  93   93   * handle mapping. The list isn't expected to grow very large so a
  94   94   * simple list is acceptable. The purpose is to provide a way to start
  95   95   * with a group or share and find the library handle needed for
  96   96   * various operations.
  97   97   */
  98   98  mutex_t sa_global_lock;
  99   99  struct doc2handle {
 100  100          struct doc2handle       *next;
 101  101          xmlNodePtr              root;
 102  102          sa_handle_impl_t        handle;
 103  103  };
 104  104  
 105  105  mutex_t sa_dfstab_lock;
 106  106  
 107  107  /* definitions used in a couple of property functions */
 108  108  #define SA_PROP_OP_REMOVE       1
 109  109  #define SA_PROP_OP_ADD          2
 110  110  #define SA_PROP_OP_UPDATE       3
 111  111  
 112  112  static struct doc2handle *sa_global_handles = NULL;
 113  113  
 114  114  /* helper functions */
 115  115  
 116  116  /*
 117  117   * sa_errorstr(err)
 118  118   *
 119  119   * convert an error value to an error string
 120  120   */
 121  121  
 122  122  char *
 123  123  sa_errorstr(int err)
 124  124  {
 125  125          static char errstr[32];
 126  126          char *ret = NULL;
 127  127  
 128  128          switch (err) {
 129  129          case SA_OK:
 130  130                  ret = dgettext(TEXT_DOMAIN, "ok");
 131  131                  break;
 132  132          case SA_NO_SUCH_PATH:
 133  133                  ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
 134  134                  break;
 135  135          case SA_NO_MEMORY:
 136  136                  ret = dgettext(TEXT_DOMAIN, "no memory");
 137  137                  break;
 138  138          case SA_DUPLICATE_NAME:
 139  139                  ret = dgettext(TEXT_DOMAIN, "name in use");
 140  140                  break;
 141  141          case SA_BAD_PATH:
 142  142                  ret = dgettext(TEXT_DOMAIN, "bad path");
 143  143                  break;
 144  144          case SA_NO_SUCH_GROUP:
 145  145                  ret = dgettext(TEXT_DOMAIN, "no such group");
 146  146                  break;
 147  147          case SA_CONFIG_ERR:
 148  148                  ret = dgettext(TEXT_DOMAIN, "configuration error");
 149  149                  break;
 150  150          case SA_SYSTEM_ERR:
 151  151                  ret = dgettext(TEXT_DOMAIN, "system error");
 152  152                  break;
 153  153          case SA_SYNTAX_ERR:
 154  154                  ret = dgettext(TEXT_DOMAIN, "syntax error");
 155  155                  break;
 156  156          case SA_NO_PERMISSION:
 157  157                  ret = dgettext(TEXT_DOMAIN, "no permission");
 158  158                  break;
 159  159          case SA_BUSY:
 160  160                  ret = dgettext(TEXT_DOMAIN, "busy");
 161  161                  break;
 162  162          case SA_NO_SUCH_PROP:
 163  163                  ret = dgettext(TEXT_DOMAIN, "no such property");
 164  164                  break;
 165  165          case SA_INVALID_NAME:
 166  166                  ret = dgettext(TEXT_DOMAIN, "invalid name");
 167  167                  break;
 168  168          case SA_INVALID_PROTOCOL:
 169  169                  ret = dgettext(TEXT_DOMAIN, "invalid protocol");
 170  170                  break;
 171  171          case SA_NOT_ALLOWED:
 172  172                  ret = dgettext(TEXT_DOMAIN, "operation not allowed");
 173  173                  break;
 174  174          case SA_BAD_VALUE:
 175  175                  ret = dgettext(TEXT_DOMAIN, "bad property value");
 176  176                  break;
 177  177          case SA_INVALID_SECURITY:
 178  178                  ret = dgettext(TEXT_DOMAIN, "invalid security type");
 179  179                  break;
 180  180          case SA_NO_SUCH_SECURITY:
 181  181                  ret = dgettext(TEXT_DOMAIN, "security type not found");
 182  182                  break;
 183  183          case SA_VALUE_CONFLICT:
 184  184                  ret = dgettext(TEXT_DOMAIN, "property value conflict");
 185  185                  break;
 186  186          case SA_NOT_IMPLEMENTED:
 187  187                  ret = dgettext(TEXT_DOMAIN, "not implemented");
 188  188                  break;
 189  189          case SA_INVALID_PATH:
 190  190                  ret = dgettext(TEXT_DOMAIN, "invalid path");
 191  191                  break;
 192  192          case SA_NOT_SUPPORTED:
 193  193                  ret = dgettext(TEXT_DOMAIN, "operation not supported");
 194  194                  break;
 195  195          case SA_PROP_SHARE_ONLY:
 196  196                  ret = dgettext(TEXT_DOMAIN, "property not valid for group");
 197  197                  break;
 198  198          case SA_NOT_SHARED:
 199  199                  ret = dgettext(TEXT_DOMAIN, "not shared");
 200  200                  break;
 201  201          case SA_NO_SUCH_RESOURCE:
 202  202                  ret = dgettext(TEXT_DOMAIN, "no such resource");
 203  203                  break;
 204  204          case SA_RESOURCE_REQUIRED:
 205  205                  ret = dgettext(TEXT_DOMAIN, "resource name required");
 206  206                  break;
 207  207          case SA_MULTIPLE_ERROR:
 208  208                  ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
 209  209                  break;
 210  210          case SA_PATH_IS_SUBDIR:
 211  211                  ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
 212  212                  break;
 213  213          case SA_PATH_IS_PARENTDIR:
 214  214                  ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
 215  215                  break;
 216  216          case SA_NO_SECTION:
 217  217                  ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
 218  218                  break;
 219  219          case SA_NO_PROPERTIES:
 220  220                  ret = dgettext(TEXT_DOMAIN, "properties not found");
 221  221                  break;
 222  222          case SA_NO_SUCH_SECTION:
 223  223                  ret = dgettext(TEXT_DOMAIN, "section not found");
 224  224                  break;
 225  225          case SA_PASSWORD_ENC:
 226  226                  ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
 227  227                  break;
 228  228          case SA_SHARE_EXISTS:
 229  229                  ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
 230  230                  break;
 231  231          default:
 232  232                  (void) snprintf(errstr, sizeof (errstr),
 233  233                      dgettext(TEXT_DOMAIN, "unknown %d"), err);
 234  234                  ret = errstr;
 235  235          }
 236  236          return (ret);
 237  237  }
 238  238  
 239  239  /*
 240  240   * Document root to active handle mapping functions.  These are only
 241  241   * used internally. A mutex is used to prevent access while the list
 242  242   * is changing. In general, the list will be relatively short - one
 243  243   * item per thread that has called sa_init().
 244  244   */
 245  245  
 246  246  sa_handle_impl_t
 247  247  get_handle_for_root(xmlNodePtr root)
 248  248  {
 249  249          struct doc2handle *item;
 250  250  
 251  251          (void) mutex_lock(&sa_global_lock);
 252  252          for (item = sa_global_handles; item != NULL; item = item->next) {
 253  253                  if (item->root == root)
 254  254                          break;
 255  255          }
 256  256          (void) mutex_unlock(&sa_global_lock);
 257  257          if (item != NULL)
 258  258                  return (item->handle);
 259  259          return (NULL);
 260  260  }
 261  261  
 262  262  static int
 263  263  add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle)
 264  264  {
 265  265          struct doc2handle *item;
 266  266          int ret = SA_NO_MEMORY;
 267  267  
 268  268          item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1);
 269  269          if (item != NULL) {
 270  270                  item->root = root;
 271  271                  item->handle = handle;
 272  272                  (void) mutex_lock(&sa_global_lock);
 273  273                  item->next = sa_global_handles;
 274  274                  sa_global_handles = item;
 275  275                  (void) mutex_unlock(&sa_global_lock);
 276  276                  ret = SA_OK;
 277  277          }
 278  278          return (ret);
 279  279  }
 280  280  
 281  281  /*
 282  282   * remove_handle_for_root(root)
 283  283   *
 284  284   * Walks the list of handles and removes the one for this "root" from
 285  285   * the list. It is up to the caller to free the data.
 286  286   */
 287  287  
 288  288  static void
 289  289  remove_handle_for_root(xmlNodePtr root)
 290  290  {
 291  291          struct doc2handle *item, *prev;
 292  292  
 293  293          (void) mutex_lock(&sa_global_lock);
 294  294          for (prev = NULL, item = sa_global_handles; item != NULL;
 295  295              item = item->next) {
 296  296                  if (item->root == root) {
 297  297                          /* first in the list */
 298  298                          if (prev == NULL)
 299  299                                  sa_global_handles = sa_global_handles->next;
 300  300                          else
 301  301                                  prev->next = item->next;
 302  302                          /* Item is out of the list so free the list structure */
 303  303                          free(item);
 304  304                          break;
 305  305                  }
 306  306                  prev = item;
 307  307          }
 308  308          (void) mutex_unlock(&sa_global_lock);
 309  309  }
 310  310  
 311  311  /*
 312  312   * sa_find_group_handle(sa_group_t group)
 313  313   *
 314  314   * Find the sa_handle_t for the configuration associated with this
 315  315   * group.
 316  316   */
 317  317  sa_handle_t
 318  318  sa_find_group_handle(sa_group_t group)
 319  319  {
 320  320          xmlNodePtr node = (xmlNodePtr)group;
 321  321          sa_handle_t handle;
 322  322  
 323  323          while (node != NULL) {
 324  324                  if (strcmp((char *)(node->name), "sharecfg") == 0) {
 325  325                          /* have the root so get the handle */
 326  326                          handle = (sa_handle_t)get_handle_for_root(node);
 327  327                          return (handle);
 328  328                  }
 329  329                  node = node->parent;
 330  330          }
 331  331          return (NULL);
 332  332  }
 333  333  
 334  334  /*
 335  335   * set_legacy_timestamp(root, path, timevalue)
 336  336   *
 337  337   * add the current timestamp value to the configuration for use in
 338  338   * determining when to update the legacy files.  For SMF, this
 339  339   * property is kept in default/operation/legacy_timestamp
 340  340   */
 341  341  
 342  342  static void
 343  343  set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval)
 344  344  {
 345  345          xmlNodePtr node;
 346  346          xmlChar *lpath = NULL;
 347  347          sa_handle_impl_t handle;
 348  348  
 349  349          /* Have to have a handle or else we weren't initialized. */
 350  350          handle = get_handle_for_root(root);
 351  351          if (handle == NULL)
 352  352                  return;
 353  353  
 354  354          for (node = root->xmlChildrenNode; node != NULL;
 355  355              node = node->next) {
 356  356                  if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) {
 357  357                          /* a possible legacy node for this path */
 358  358                          lpath = xmlGetProp(node, (xmlChar *)"path");
 359  359                          if (lpath != NULL &&
 360  360                              xmlStrcmp(lpath, (xmlChar *)path) == 0) {
 361  361                                  xmlFree(lpath);
 362  362                                  break;
 363  363                          }
 364  364                          if (lpath != NULL)
 365  365                                  xmlFree(lpath);
 366  366                  }
 367  367          }
 368  368          if (node == NULL) {
 369  369                  /* need to create the first legacy timestamp node */
 370  370                  node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL);
 371  371          }
 372  372          if (node != NULL) {
 373  373                  char tstring[32];
 374  374                  int ret;
 375  375  
 376  376                  (void) snprintf(tstring, sizeof (tstring), "%lld", tval);
 377  377                  (void) xmlSetProp(node, (xmlChar *)"timestamp",
 378  378                      (xmlChar *)tstring);
 379  379                  (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path);
 380  380                  /* now commit to SMF */
 381  381                  ret = sa_get_instance(handle->scfhandle, "default");
 382  382                  if (ret == SA_OK) {
 383  383                          ret = sa_start_transaction(handle->scfhandle,
 384  384                              "operation");
 385  385                          if (ret == SA_OK) {
 386  386                                  ret = sa_set_property(handle->scfhandle,
 387  387                                      "legacy-timestamp", tstring);
 388  388                                  if (ret == SA_OK) {
 389  389                                          (void) sa_end_transaction(
 390  390                                              handle->scfhandle, handle);
 391  391                                  } else {
 392  392                                          sa_abort_transaction(handle->scfhandle);
 393  393                                  }
 394  394                          }
 395  395                  }
 396  396          }
 397  397  }
 398  398  
 399  399  /*
 400  400   * is_shared(share)
 401  401   *
 402  402   * determine if the specified share is currently shared or not.
 403  403   */
 404  404  static int
 405  405  is_shared(sa_share_t share)
 406  406  {
 407  407          char *shared;
 408  408          int result = 0; /* assume not */
 409  409  
 410  410          shared = sa_get_share_attr(share, "shared");
 411  411          if (shared != NULL) {
 412  412                  if (strcmp(shared, "true") == 0)
 413  413                          result = 1;
 414  414                  sa_free_attr_string(shared);
 415  415          }
 416  416          return (result);
 417  417  }
 418  418  
 419  419  /*
 420  420   * excluded_protocol(share, proto)
 421  421   *
 422  422   * Returns B_TRUE if the specified protocol appears in the "exclude"
 423  423   * property. This is used to prevent sharing special case shares
 424  424   * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is
 425  425   * returned if the protocol isn't in the list.
 426  426   */
 427  427  static boolean_t
 428  428  excluded_protocol(sa_share_t share, char *proto)
 429  429  {
 430  430          char *protolist;
 431  431          char *str;
 432  432          char *token;
 433  433  
 434  434          protolist = sa_get_share_attr(share, "exclude");
 435  435          if (protolist != NULL) {
 436  436                  str = protolist;
 437  437                  while ((token = strtok(str, ",")) != NULL) {
 438  438                          if (strcmp(token, proto) == 0) {
 439  439                                  sa_free_attr_string(protolist);
 440  440                                  return (B_TRUE);
 441  441                          }
 442  442                          str = NULL;
 443  443                  }
 444  444                  sa_free_attr_string(protolist);
 445  445          }
 446  446          return (B_FALSE);
 447  447  }
 448  448  
 449  449  /*
 450  450   * checksubdirgroup(group, newpath, strictness)
 451  451   *
 452  452   * check all the specified newpath against all the paths in the
 453  453   * group. This is a helper function for checksubdir to make it easier
 454  454   * to also check ZFS subgroups.
 455  455   * The strictness values mean:
 456  456   * SA_CHECK_NORMAL == only check newpath against shares that are active
 457  457   * SA_CHECK_STRICT == check newpath against both active shares and those
 458  458   *                    stored in the repository
 459  459   */
 460  460  static int
 461  461  checksubdirgroup(sa_group_t group, char *newpath, int strictness)
 462  462  {
 463  463          sa_share_t share;
 464  464          char *path;
 465  465          int issub = SA_OK;
 466  466          int subdir;
 467  467          int parent;
 468  468  
 469  469          if (newpath == NULL)
 470  470                  return (SA_INVALID_PATH);
 471  471  
 472  472          for (share = sa_get_share(group, NULL); share != NULL;
 473  473              share = sa_get_next_share(share)) {
 474  474                  /*
 475  475                   * The original behavior of share never checked
 476  476                   * against the permanent configuration
 477  477                   * (/etc/dfs/dfstab).  PIT has a number of cases where
 478  478                   * it depends on this older behavior even though it
 479  479                   * could be considered incorrect.  We may tighten this
 480  480                   * up in the future.
 481  481                   */
 482  482                  if (strictness == SA_CHECK_NORMAL && !is_shared(share))
 483  483                          continue;
 484  484  
 485  485                  path = sa_get_share_attr(share, "path");
 486  486                  /*
 487  487                   * If path is NULL, then a share is in the process of
 488  488                   * construction or someone has modified the property
 489  489                   * group inappropriately. It should be
 490  490                   * ignored. issubdir() comes from the original share
 491  491                   * implementation and does the difficult part of
 492  492                   * checking subdirectories.
 493  493                   */
 494  494                  if (path == NULL)
 495  495                          continue;
 496  496  
 497  497                  if (strcmp(path, newpath) == 0) {
 498  498                          issub = SA_INVALID_PATH;
 499  499                  } else {
 500  500                          subdir = issubdir(newpath, path);
 501  501                          parent = issubdir(path, newpath);
 502  502                          if (subdir || parent) {
 503  503                                  sa_free_attr_string(path);
 504  504                                  path = NULL;
 505  505                                  return (subdir ?
 506  506                                      SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR);
 507  507                          }
 508  508                  }
 509  509                  sa_free_attr_string(path);
 510  510                  path = NULL;
 511  511          }
 512  512          return (issub);
 513  513  }
 514  514  
 515  515  /*
 516  516   * checksubdir(newpath, strictness)
 517  517   *
 518  518   * checksubdir determines if the specified path (newpath) is a
 519  519   * subdirectory of another share. It calls checksubdirgroup() to do
 520  520   * the complicated work. The strictness parameter determines how
 521  521   * strict a check to make against the path. The strictness values
 522  522   * mean: SA_CHECK_NORMAL == only check newpath against shares that are
 523  523   * active SA_CHECK_STRICT == check newpath against both active shares
 524  524   * and those * stored in the repository
 525  525   */
 526  526  static int
 527  527  checksubdir(sa_handle_t handle, char *newpath, int strictness)
 528  528  {
 529  529          sa_group_t group;
 530  530          int issub = SA_OK;
 531  531          char *path = NULL;
 532  532  
 533  533          for (group = sa_get_group(handle, NULL);
 534  534              group != NULL && issub == SA_OK;
 535  535              group = sa_get_next_group(group)) {
 536  536                  if (sa_group_is_zfs(group)) {
 537  537                          sa_group_t subgroup;
 538  538                          for (subgroup = sa_get_sub_group(group);
 539  539                              subgroup != NULL && issub == SA_OK;
 540  540                              subgroup = sa_get_next_group(subgroup))
 541  541                                  issub = checksubdirgroup(subgroup, newpath,
 542  542                                      strictness);
 543  543                  } else {
 544  544                          issub = checksubdirgroup(group, newpath, strictness);
 545  545                  }
 546  546          }
 547  547          if (path != NULL)
 548  548                  sa_free_attr_string(path);
 549  549          return (issub);
 550  550  }
 551  551  
 552  552  /*
 553  553   * validpath(path, strictness)
 554  554   * determine if the provided path is valid for a share. It shouldn't
 555  555   * be a sub-dir of an already shared path or the parent directory of a
 556  556   * share path.
 557  557   */
 558  558  static int
 559  559  validpath(sa_handle_t handle, char *path, int strictness)
 560  560  {
 561  561          int error = SA_OK;
 562  562          struct stat st;
 563  563          sa_share_t share;
 564  564          char *fstype;
 565  565  
 566  566          if (*path != '/')
 567  567                  return (SA_BAD_PATH);
 568  568  
 569  569          if (stat(path, &st) < 0) {
 570  570                  error = SA_NO_SUCH_PATH;
 571  571          } else {
 572  572                  share = sa_find_share(handle, path);
 573  573                  if (share != NULL)
 574  574                          error = SA_DUPLICATE_NAME;
 575  575  
 576  576                  if (error == SA_OK) {
 577  577                          /*
 578  578                           * check for special case with file system
 579  579                           * that might have restrictions.  For now, ZFS
 580  580                           * is the only case since it has its own idea
 581  581                           * of how to configure shares. We do this
 582  582                           * before subdir checking since things like
 583  583                           * ZFS will do that for us. This should also
 584  584                           * be done via plugin interface.
 585  585                           */
 586  586                          fstype = sa_fstype(path);
 587  587                          if (fstype != NULL && strcmp(fstype, "zfs") == 0) {
 588  588                                  if (sa_zfs_is_shared(handle, path))
 589  589                                          error = SA_INVALID_NAME;
 590  590                          }
 591  591                          if (fstype != NULL)
 592  592                                  sa_free_fstype(fstype);
 593  593                  }
 594  594                  if (error == SA_OK)
 595  595                          error = checksubdir(handle, path, strictness);
 596  596          }
 597  597          return (error);
 598  598  }
 599  599  
 600  600  /*
 601  601   * check to see if group/share is persistent.
 602  602   *
 603  603   * "group" can be either an sa_group_t or an sa_share_t. (void *)
 604  604   * works since both these types are also void *.
 605  605   * If the share is a ZFS share, mark it as persistent.
 606  606   */
 607  607  int
 608  608  sa_is_persistent(void *group)
 609  609  {
 610  610          char *type;
 611  611          int persist = 1;
 612  612          sa_group_t grp;
 613  613  
 614  614          type = sa_get_group_attr((sa_group_t)group, "type");
 615  615          if (type != NULL) {
 616  616                  if (strcmp(type, "transient") == 0)
 617  617                          persist = 0;
 618  618                  sa_free_attr_string(type);
 619  619          }
 620  620  
 621  621          grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group;
 622  622          if (sa_group_is_zfs(grp))
 623  623                  persist = 1;
 624  624  
 625  625          return (persist);
 626  626  }
 627  627  
 628  628  /*
 629  629   * sa_valid_group_name(name)
 630  630   *
 631  631   * check that the "name" contains only valid characters and otherwise
 632  632   * fits the required naming conventions. Valid names must start with
 633  633   * an alphabetic and the remainder may consist of only alphanumeric
 634  634   * plus the '-' and '_' characters. This name limitation comes from
 635  635   * inherent limitations in SMF.
 636  636   */
 637  637  
 638  638  int
 639  639  sa_valid_group_name(char *name)
 640  640  {
 641  641          int ret = 1;
 642  642          ssize_t len;
 643  643  
 644  644          if (name != NULL && isalpha(*name)) {
 645  645                  char c;
 646  646                  len = strlen(name);
 647  647                  if (len < (scf_max_name_len - sizeof ("group:"))) {
 648  648                          for (c = *name++; c != '\0' && ret != 0; c = *name++) {
 649  649                                  if (!isalnum(c) && c != '-' && c != '_')
 650  650                                          ret = 0;
 651  651                          }
 652  652                  } else {
 653  653                          ret = 0;
 654  654                  }
 655  655          } else {
 656  656                  ret = 0;
 657  657          }
 658  658          return (ret);
 659  659  }
 660  660  
 661  661  
 662  662  /*
 663  663   * is_zfs_group(group)
 664  664   *      Determine if the specified group is a ZFS sharenfs group
 665  665   */
 666  666  static int
 667  667  is_zfs_group(sa_group_t group)
 668  668  {
 669  669          int ret = 0;
 670  670          xmlNodePtr parent;
 671  671          xmlChar *zfs;
 672  672  
 673  673          if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0)
 674  674                  parent = (xmlNodePtr)sa_get_parent_group(group);
 675  675          else
 676  676                  parent = (xmlNodePtr)group;
 677  677          zfs = xmlGetProp(parent, (xmlChar *)"zfs");
 678  678          if (zfs != NULL) {
 679  679                  xmlFree(zfs);
 680  680                  ret = 1;
 681  681          }
 682  682          return (ret);
 683  683  }
 684  684  
 685  685  /*
 686  686   * sa_get_object_type(object)
 687  687   *
 688  688   * This function returns a numeric value representing the object
 689  689   * type. This allows using simpler checks when doing type specific
 690  690   * operations.
 691  691   */
 692  692  
 693  693  static int
 694  694  sa_get_object_type(void *object)
 695  695  {
 696  696          xmlNodePtr node = (xmlNodePtr)object;
 697  697          int type;
 698  698  
 699  699          if (xmlStrcmp(node->name, (xmlChar *)"group") == 0)
 700  700                  type = SA_TYPE_GROUP;
 701  701          else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0)
 702  702                  type = SA_TYPE_SHARE;
 703  703          else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
 704  704                  type = SA_TYPE_RESOURCE;
 705  705          else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0)
 706  706                  type = SA_TYPE_OPTIONSET;
 707  707          else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0)
 708  708                  type = SA_TYPE_ALTSPACE;
 709  709          else
 710  710                  assert(0);
 711  711          return (type);
 712  712  }
 713  713  
 714  714  /*
 715  715   * sa_optionset_name(optionset, oname, len, id)
 716  716   *      return the SMF name for the optionset. If id is not NULL, it
 717  717   *      will have the GUID value for a share and should be used
 718  718   *      instead of the keyword "optionset" which is used for
 719  719   *      groups. If the optionset doesn't have a protocol type
 720  720   *      associated with it, "default" is used. This shouldn't happen
 721  721   *      at this point but may be desirable in the future if there are
 722  722   *      protocol independent properties added. The name is returned in
 723  723   *      oname.
 724  724   */
 725  725  
 726  726  static int
 727  727  sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id)
 728  728  {
 729  729          char *proto;
 730  730          void *parent;
 731  731          int ptype;
 732  732  
 733  733          if (id == NULL)
 734  734                  id = "optionset";
 735  735  
 736  736          parent = sa_get_optionset_parent(optionset);
 737  737          if (parent != NULL) {
 738  738                  ptype = sa_get_object_type(parent);
 739  739                  proto = sa_get_optionset_attr(optionset, "type");
 740  740                  if (ptype != SA_TYPE_RESOURCE) {
 741  741                          len = snprintf(oname, len, "%s_%s", id,
 742  742                              proto ? proto : "default");
 743  743                  } else {
 744  744                          char *index;
 745  745                          index = get_node_attr((void *)parent, "id");
 746  746                          if (index != NULL) {
 747  747                                  len = snprintf(oname, len, "%s_%s_%s", id,
 748  748                                      proto ? proto : "default", index);
 749  749                                  sa_free_attr_string(index);
 750  750                          } else {
 751  751                                  len = 0;
 752  752                          }
 753  753                  }
 754  754  
 755  755                  if (proto != NULL)
 756  756                          sa_free_attr_string(proto);
 757  757          } else {
 758  758                  len = 0;
 759  759          }
 760  760          return (len);
 761  761  }
 762  762  
 763  763  /*
 764  764   * sa_security_name(optionset, oname, len, id)
 765  765   *
 766  766   * return the SMF name for the security. If id is not NULL, it will
 767  767   * have the GUID value for a share and should be used instead of the
 768  768   * keyword "optionset" which is used for groups. If the optionset
 769  769   * doesn't have a protocol type associated with it, "default" is
 770  770   * used. This shouldn't happen at this point but may be desirable in
 771  771   * the future if there are protocol independent properties added. The
 772  772   * name is returned in oname. The security type is also encoded into
 773  773   * the name. In the future, this wil *be handled a bit differently.
 774  774   */
 775  775  
 776  776  static int
 777  777  sa_security_name(sa_security_t security, char *oname, size_t len, char *id)
 778  778  {
 779  779          char *proto;
 780  780          char *sectype;
 781  781  
 782  782          if (id == NULL)
 783  783                  id = "optionset";
 784  784  
 785  785          proto = sa_get_security_attr(security, "type");
 786  786          sectype = sa_get_security_attr(security, "sectype");
 787  787          len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default",
 788  788              sectype ? sectype : "default");
 789  789          if (proto != NULL)
 790  790                  sa_free_attr_string(proto);
 791  791          if (sectype != NULL)
 792  792                  sa_free_attr_string(sectype);
 793  793          return (len);
 794  794  }
 795  795  
 796  796  /*
 797  797   * verifydefgroupopts(handle)
 798  798   *
 799  799   * Make sure a "default" group exists and has default protocols enabled.
 800  800   */
 801  801  static void
 802  802  verifydefgroupopts(sa_handle_t handle)
 803  803  {
 804  804          sa_group_t defgrp;
 805  805          sa_optionset_t opt;
 806  806  
 807  807          defgrp = sa_get_group(handle, "default");
 808  808          if (defgrp != NULL) {
 809  809                  opt = sa_get_optionset(defgrp, NULL);
 810  810                  /*
 811  811                   * NFS is the default for default group
 812  812                   */
 813  813                  if (opt == NULL)
 814  814                          opt = sa_create_optionset(defgrp, "nfs");
 815  815          }
 816  816  }
 817  817  
 818  818  /*
 819  819   * sa_init_impl(init_service, arg)
 820  820   *      Initialize the API
 821  821   *      find all the shared objects
 822  822   *      init the tables with all objects
 823  823   *      read in the current configuration
 824  824   *
 825  825   *      arg is a parameter passed in whose meaning is based on the init_service.
 826  826   *      See libshare.h under API initialization.
 827  827   */
 828  828  #define GETPROP(prop)   scf_simple_prop_next_astring(prop)
 829  829  #define CHECKTSTAMP(st, tval)   stat(SA_LEGACY_DFSTAB, &st) >= 0 && \
 830  830          tval != TSTAMP(st.st_ctim)
 831  831  static sa_handle_t
 832  832  sa_init_impl(int init_service, void *arg)
 833  833  {
 834  834          struct stat st;
 835  835          /* legacy is used for debugging only as far as I can tell */
 836  836          int legacy = 0;
 837  837          uint64_t tval = 0;
 838  838          int lockfd;
 839  839          sigset_t old;
 840  840          int updatelegacy = B_FALSE;
 841  841          scf_simple_prop_t *prop;
 842  842          sa_handle_impl_t handle;
 843  843          int err;
 844  844  
 845  845          handle = calloc(sizeof (struct sa_handle_impl), 1);
 846  846  
 847  847          if (handle != NULL) {
 848  848                  handle->sa_service = init_service;
 849  849                  /*
 850  850                   * Get protocol specific structures, but only if this
 851  851                   * is the only handle.
 852  852                   */
 853  853                  (void) mutex_lock(&sa_global_lock);
 854  854                  if (sa_global_handles == NULL)
 855  855                          (void) proto_plugin_init();
 856  856                  (void) mutex_unlock(&sa_global_lock);
 857  857                  if (init_service & (SA_INIT_SHARE_API |
 858  858                      SA_INIT_SHARE_API_SELECTIVE | SA_INIT_ONE_SHARE_FROM_NAME |
 859  859                      SA_INIT_ONE_SHARE_FROM_HANDLE)) {
 860  860                          /*
 861  861                           * initialize access into libzfs. We use this
 862  862                           * when collecting info about ZFS datasets and
 863  863                           * shares.
 864  864                           */
 865  865                          if (sa_zfs_init(handle) == B_FALSE) {
 866  866                                  free(handle);
 867  867                                  (void) mutex_lock(&sa_global_lock);
 868  868                                  (void) proto_plugin_fini();
 869  869                                  (void) mutex_unlock(&sa_global_lock);
 870  870                                  return (NULL);
 871  871                          }
 872  872                          /*
 873  873                           * since we want to use SMF, initialize an svc handle
 874  874                           * and find out what is there.
 875  875                           */
 876  876                          handle->scfhandle = sa_scf_init(handle);
 877  877                          if (handle->scfhandle != NULL) {
 878  878                                  /*
 879  879                                   * Need to lock the extraction of the
 880  880                                   * configuration if the dfstab file has
 881  881                                   * changed. Lock everything now and release if
 882  882                                   * not needed.  Use a file that isn't being
 883  883                                   * manipulated by other parts of the system in
 884  884                                   * order to not interfere with locking. Using
 885  885                                   * dfstab doesn't work.
 886  886                                   */
 887  887                                  sablocksigs(&old);
 888  888                                  lockfd = open(DFS_LOCK_FILE, O_RDWR);
 889  889                                  if (lockfd >= 0) {
 890  890                                          errno = 0;
 891  891                                          (void) lockf(lockfd, F_LOCK, 0);
 892  892                                          (void) mutex_lock(&sa_dfstab_lock);
 893  893                                          /*
 894  894                                           * Check whether we are going to need
 895  895                                           * to merge any dfstab changes. This
 896  896                                           * is done by comparing the value of
 897  897                                           * legacy-timestamp with the current
 898  898                                           * st_ctim of the file. If they are
 899  899                                           * different, an update is needed and
 900  900                                           * the file must remain locked until
 901  901                                           * the merge is done in order to
 902  902                                           * prevent multiple startups from
 903  903                                           * changing the SMF repository at the
 904  904                                           * same time.  The first to get the
 905  905                                           * lock will make any changes before
 906  906                                           * the others can read the repository.
 907  907                                           */
 908  908                                          prop = scf_simple_prop_get
 909  909                                              (handle->scfhandle->handle,
 910  910                                              (const char *)SA_SVC_FMRI_BASE
 911  911                                              ":default", "operation",
 912  912                                              "legacy-timestamp");
 913  913                                          if (prop != NULL) {
 914  914                                                  char *i64;
 915  915                                                  i64 = GETPROP(prop);
 916  916                                                  if (i64 != NULL)
 917  917                                                          tval = strtoull(i64,
 918  918                                                              NULL, 0);
 919  919                                                  if (CHECKTSTAMP(st, tval))
 920  920                                                          updatelegacy = B_TRUE;
 921  921                                                  scf_simple_prop_free(prop);
 922  922                                          } else {
 923  923                                                  /*
 924  924                                                   * We haven't set the
 925  925                                                   * timestamp before so do it.
 926  926                                                   */
 927  927                                                  updatelegacy = B_TRUE;
 928  928                                          }
 929  929                                          if (updatelegacy == B_FALSE) {
 930  930                                                  (void) mutex_unlock(
 931  931                                                      &sa_dfstab_lock);
 932  932                                                  (void) lockf(lockfd, F_ULOCK,
 933  933                                                      0);
 934  934                                                  (void) close(lockfd);
 935  935                                          }
 936  936  
 937  937                                  }
 938  938                                  /*
 939  939                                   * It is essential that the document tree and
 940  940                                   * the internal list of roots to handles be
 941  941                                   * setup before anything that might try to
 942  942                                   * create a new object is called. The document
 943  943                                   * tree is the combination of handle->doc and
 944  944                                   * handle->tree. This allows searches,
 945  945                                   * etc. when all you have is an object in the
 946  946                                   * tree.
 947  947                                   */
 948  948                                  handle->doc = xmlNewDoc((xmlChar *)"1.0");
 949  949                                  handle->tree = xmlNewNode(NULL,
 950  950                                      (xmlChar *)"sharecfg");
 951  951                                  if (handle->doc != NULL &&
 952  952                                      handle->tree != NULL) {
 953  953                                          (void) xmlDocSetRootElement(handle->doc,
 954  954                                              handle->tree);
 955  955                                          err = add_handle_for_root(handle->tree,
 956  956                                              handle);
 957  957                                          if (err == SA_OK)
 958  958                                                  err = sa_get_config(
 959  959                                                      handle->scfhandle,
 960  960                                                      handle->tree, handle);
 961  961                                  } else {
 962  962                                          if (handle->doc != NULL)
 963  963                                                  xmlFreeDoc(handle->doc);
 964  964                                          if (handle->tree != NULL)
 965  965                                                  xmlFreeNode(handle->tree);
 966  966                                          err = SA_NO_MEMORY;
 967  967                                  }
 968  968  
 969  969                                  saunblocksigs(&old);
 970  970  
 971  971                                  if (err != SA_OK) {
 972  972                                          /*
 973  973                                           * If we couldn't add the tree handle
 974  974                                           * to the list, then things are going
 975  975                                           * to fail badly. Might as well undo
 976  976                                           * everything now and fail the
 977  977                                           * sa_init().
 978  978                                           */
 979  979                                          sa_fini(handle);
 980  980                                          if (updatelegacy == B_TRUE) {
 981  981                                                  (void) mutex_unlock(
 982  982                                                      &sa_dfstab_lock);
 983  983                                                  (void) lockf(lockfd,
 984  984                                                      F_ULOCK, 0);
 985  985                                                  (void) close(lockfd);
 986  986                                          }
 987  987                                          return (NULL);
 988  988                                  }
 989  989  
 990  990                                  if (tval == 0) {
 991  991                                          /*
 992  992                                           * first time so make sure
 993  993                                           * default is setup
 994  994                                           */
 995  995                                          verifydefgroupopts(handle);
 996  996                                  }
 997  997  
 998  998                                  if (updatelegacy == B_TRUE) {
 999  999                                          sablocksigs(&old);
1000 1000                                          getlegacyconfig((sa_handle_t)handle,
1001 1001                                              SA_LEGACY_DFSTAB, &handle->tree);
1002 1002                                          if (stat(SA_LEGACY_DFSTAB, &st) >= 0)
1003 1003                                                  set_legacy_timestamp(
1004 1004                                                      handle->tree,
1005 1005                                                      SA_LEGACY_DFSTAB,
1006 1006                                                      TSTAMP(st.st_ctim));
1007 1007                                          saunblocksigs(&old);
1008 1008                                          /*
1009 1009                                           * Safe to unlock now to allow
1010 1010                                           * others to run
1011 1011                                           */
1012 1012                                          (void) mutex_unlock(&sa_dfstab_lock);
1013 1013                                          (void) lockf(lockfd, F_ULOCK, 0);
1014 1014                                          (void) close(lockfd);
1015 1015                                  }
1016 1016                                  /* Get sharetab timestamp */
1017 1017                                  sa_update_sharetab_ts((sa_handle_t)handle);
1018 1018  
1019 1019                                  /* Get lastupdate (transaction) timestamp */
1020 1020                                  prop = scf_simple_prop_get(
1021 1021                                      handle->scfhandle->handle,
1022 1022                                      (const char *)SA_SVC_FMRI_BASE ":default",
1023 1023                                      "state", "lastupdate");
1024 1024                                  if (prop != NULL) {
1025 1025                                          char *str;
1026 1026                                          str =
1027 1027                                              scf_simple_prop_next_astring(prop);
1028 1028                                          if (str != NULL)
1029 1029                                                  handle->tstrans =
1030 1030                                                      strtoull(str, NULL, 0);
1031 1031                                          else
1032 1032                                                  handle->tstrans = 0;
1033 1033                                          scf_simple_prop_free(prop);
1034 1034                                  }
1035 1035                                  /*
1036 1036                                   * In this conditional the library reads from
1037 1037                                   * zfs and /etc/dfs/sharetab to find datasets
1038 1038                                   * that must be shared. The result is a tree of
1039 1039                                   * groups that are stored in the handle for
1040 1040                                   * libshare to utilize later when asked to share
1041 1041                                   * or unshare datasets.
1042 1042                                   */
1043 1043                                  if (init_service &
1044 1044                                      SA_INIT_SHARE_API_SELECTIVE) {
1045 1045                                          char **paths;
1046 1046                                          size_t paths_len, i;
1047 1047  
1048 1048                                          legacy |= sa_get_one_zfs_share(handle,
1049 1049                                              "zfs",
1050 1050                                              (sa_init_selective_arg_t *)arg,
1051 1051                                              &paths, &paths_len);
1052 1052                                          legacy |= get_one_transient(handle,
1053 1053                                              &handle->tree, paths, paths_len);
1054 1054                                          for (i = 0; i < paths_len; ++i) {
1055 1055                                                  free(paths[i]);
1056 1056                                          }
1057 1057                                          free(paths);
1058 1058                                  } else if (init_service &
1059 1059                                      SA_INIT_ONE_SHARE_FROM_NAME) {
1060 1060                                          char path[ZFS_MAXPROPLEN];
1061 1061                                          char *ptr = path;
1062 1062                                          char **ptr_to_path = &ptr;
1063 1063  
1064 1064                                          legacy |=
1065 1065                                              sa_get_zfs_share_for_name(handle,
1066 1066                                              "zfs", (char *)arg, path);
1067 1067                                          legacy |= get_one_transient(handle,
1068 1068                                              &handle->tree, ptr_to_path, 1);
1069 1069                                  } else if (init_service &
1070 1070                                      SA_INIT_ONE_SHARE_FROM_HANDLE) {
1071 1071                                          char path[ZFS_MAXPROPLEN];
1072 1072                                          char *ptr = path;
1073 1073                                          char **ptr_to_path = &ptr;
1074 1074  
1075 1075                                          legacy |=
1076 1076                                              sa_get_zfs_share_for_name(handle,
1077 1077                                              "zfs",
1078 1078                                              zfs_get_name(
1079 1079                                              (zfs_handle_t *)arg),
1080 1080                                              path);
1081 1081                                          legacy |= get_one_transient(handle,
1082 1082                                              &handle->tree, ptr_to_path, 1);
1083 1083                                  } else {
1084 1084                                          legacy |= sa_get_zfs_shares(handle,
1085 1085                                              "zfs");
1086 1086                                          legacy |= gettransients(handle,
1087 1087                                              &handle->tree);
1088 1088                                  }
1089 1089                          }
1090 1090                  }
1091 1091          }
1092 1092          return ((sa_handle_t)handle);
1093 1093  }
1094 1094  
1095 1095  /*
1096 1096   * sa_init exists as a legacy interface, new consumers should use sa_init_arg.
1097 1097   */
1098 1098  sa_handle_t
1099 1099  sa_init(int init_service)
1100 1100  {
1101 1101          return (sa_init_impl(init_service, NULL));
1102 1102  }
1103 1103  
1104 1104  /*
1105 1105   * See libshare.h "API Initialization" section for valid values of init_service
1106 1106   * as well as the appropriate argument type for a given init_service.
1107 1107   */
1108 1108  sa_handle_t
1109 1109  sa_init_arg(int init_service, void *arg)
1110 1110  {
1111 1111          return (sa_init_impl(init_service, arg));
1112 1112  }
1113 1113  
1114 1114  /*
1115 1115   * sa_fini(handle)
1116 1116   *      Uninitialize the API structures including the configuration
1117 1117   *      data structures and ZFS related data.
1118 1118   */
1119 1119  
1120 1120  void
1121 1121  sa_fini(sa_handle_t handle)
1122 1122  {
1123 1123          sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
1124 1124  
1125 1125          if (impl_handle != NULL) {
1126 1126                  /*
1127 1127                   * Free the config trees and any other data structures
1128 1128                   * used in the handle.
1129 1129                   */
1130 1130                  if (impl_handle->doc != NULL)
1131 1131                          xmlFreeDoc(impl_handle->doc);
1132 1132  
1133 1133                  /* Remove and free the entry in the global list. */
1134 1134                  remove_handle_for_root(impl_handle->tree);
1135 1135  
1136 1136                  /*
1137 1137                   * If this was the last handle to release, unload the
1138 1138                   * plugins that were loaded. Use a mutex in case
1139 1139                   * another thread is reinitializing.
1140 1140                   */
1141 1141                  (void) mutex_lock(&sa_global_lock);
1142 1142                  if (sa_global_handles == NULL)
1143 1143                          (void) proto_plugin_fini();
1144 1144                  (void) mutex_unlock(&sa_global_lock);
  
    | 
      ↓ open down ↓ | 
    1110 lines elided | 
    
      ↑ open up ↑ | 
  
1145 1145  
1146 1146                  sa_scf_fini(impl_handle->scfhandle);
1147 1147                  sa_zfs_fini(impl_handle);
1148 1148  
1149 1149                  /* Make sure we free the handle */
1150 1150                  free(impl_handle);
1151 1151  
1152 1152          }
1153 1153  }
1154 1154  
     1155 +/*
     1156 + * sa_service(sa_handle_t handle)
     1157 + *
     1158 + * Returns the service for which the handle is currently initialized.
     1159 + */
     1160 +int
     1161 +sa_service(sa_handle_t handle)
     1162 +{
     1163 +        if (handle == NULL)
     1164 +                return (0);
     1165 +
     1166 +        return (((sa_handle_impl_t)handle)->sa_service);
     1167 +}
     1168 +
1155 1169  /*
1156 1170   * sa_get_protocols(char **protocol)
1157 1171   *      Get array of protocols that are supported
1158 1172   *      Returns pointer to an allocated and NULL terminated
1159 1173   *      array of strings.  Caller must free.
1160 1174   *      This really should be determined dynamically.
1161 1175   *      If there aren't any defined, return -1.
1162 1176   *      Use free() to return memory.
1163 1177   */
1164 1178  
1165 1179  int
1166 1180  sa_get_protocols(char ***protocols)
1167 1181  {
1168 1182          int numproto = -1;
1169 1183  
1170 1184          if (protocols != NULL) {
1171 1185                  struct sa_proto_plugin *plug;
1172 1186                  for (numproto = 0, plug = sap_proto_list; plug != NULL;
1173 1187                      plug = plug->plugin_next) {
1174 1188                          numproto++;
1175 1189                  }
1176 1190  
1177 1191                  *protocols = calloc(numproto + 1,  sizeof (char *));
1178 1192                  if (*protocols != NULL) {
1179 1193                          int ret = 0;
1180 1194                          for (plug = sap_proto_list; plug != NULL;
1181 1195                              plug = plug->plugin_next) {
1182 1196                                  /* faking for now */
1183 1197                                  (*protocols)[ret++] =
1184 1198                                      plug->plugin_ops->sa_protocol;
1185 1199                          }
1186 1200                  } else {
1187 1201                          numproto = -1;
1188 1202                  }
1189 1203          }
1190 1204          return (numproto);
1191 1205  }
1192 1206  
1193 1207  /*
1194 1208   * find_group_by_name(node, group)
1195 1209   *
1196 1210   * search the XML document subtree specified by node to find the group
1197 1211   * specified by group. Searching subtree allows subgroups to be
1198 1212   * searched for.
1199 1213   */
1200 1214  
1201 1215  static xmlNodePtr
1202 1216  find_group_by_name(xmlNodePtr node, xmlChar *group)
1203 1217  {
1204 1218          xmlChar *name = NULL;
1205 1219  
1206 1220          for (node = node->xmlChildrenNode; node != NULL;
1207 1221              node = node->next) {
1208 1222                  if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) {
1209 1223                          /* if no groupname, return the first found */
1210 1224                          if (group == NULL)
1211 1225                                  break;
1212 1226                          name = xmlGetProp(node, (xmlChar *)"name");
1213 1227                          if (name != NULL && xmlStrcmp(name, group) == 0)
1214 1228                                  break;
1215 1229                          if (name != NULL) {
1216 1230                                  xmlFree(name);
1217 1231                                  name = NULL;
1218 1232                          }
1219 1233                  }
1220 1234          }
1221 1235          if (name != NULL)
1222 1236                  xmlFree(name);
1223 1237          return (node);
1224 1238  }
1225 1239  
1226 1240  /*
1227 1241   * sa_get_group(groupname)
1228 1242   *      Return the "group" specified.  If groupname is NULL,
1229 1243   *      return the first group of the list of groups.
1230 1244   */
1231 1245  sa_group_t
1232 1246  sa_get_group(sa_handle_t handle, char *groupname)
1233 1247  {
1234 1248          xmlNodePtr node = NULL;
1235 1249          char *subgroup = NULL;
1236 1250          char *group = NULL;
1237 1251          sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
1238 1252  
1239 1253          if (impl_handle != NULL && impl_handle->tree != NULL) {
1240 1254                  if (groupname != NULL) {
1241 1255                          group = strdup(groupname);
1242 1256                          if (group != NULL) {
1243 1257                                  subgroup = strchr(group, '/');
1244 1258                                  if (subgroup != NULL)
1245 1259                                          *subgroup++ = '\0';
1246 1260                          }
1247 1261                  }
1248 1262                  /*
1249 1263                   * We want to find the, possibly, named group. If
1250 1264                   * group is not NULL, then lookup the name. If it is
1251 1265                   * NULL, we only do the find if groupname is also
1252 1266                   * NULL. This allows lookup of the "first" group in
1253 1267                   * the internal list.
1254 1268                   */
1255 1269                  if (group != NULL || groupname == NULL)
1256 1270                          node = find_group_by_name(impl_handle->tree,
1257 1271                              (xmlChar *)group);
1258 1272  
1259 1273                  /* if a subgroup, find it before returning */
1260 1274                  if (subgroup != NULL && node != NULL)
1261 1275                          node = find_group_by_name(node, (xmlChar *)subgroup);
1262 1276          }
1263 1277          if (node != NULL && (char *)group != NULL)
1264 1278                  (void) sa_get_instance(impl_handle->scfhandle, (char *)group);
1265 1279          if (group != NULL)
1266 1280                  free(group);
1267 1281          return ((sa_group_t)(node));
1268 1282  }
1269 1283  
1270 1284  /*
1271 1285   * sa_get_next_group(group)
1272 1286   *      Return the "next" group after the specified group from
1273 1287   *      the internal group list.  NULL if there are no more.
1274 1288   */
1275 1289  sa_group_t
1276 1290  sa_get_next_group(sa_group_t group)
1277 1291  {
1278 1292          xmlNodePtr ngroup = NULL;
1279 1293          if (group != NULL) {
1280 1294                  for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL;
1281 1295                      ngroup = ngroup->next) {
1282 1296                          if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0)
1283 1297                                  break;
1284 1298                  }
1285 1299          }
1286 1300          return ((sa_group_t)ngroup);
1287 1301  }
1288 1302  
1289 1303  /*
1290 1304   * sa_get_share(group, sharepath)
1291 1305   *      Return the share object for the share specified. The share
1292 1306   *      must be in the specified group.  Return NULL if not found.
1293 1307   */
1294 1308  sa_share_t
1295 1309  sa_get_share(sa_group_t group, char *sharepath)
1296 1310  {
1297 1311          xmlNodePtr node = NULL;
1298 1312          xmlChar *path;
1299 1313  
1300 1314          /*
1301 1315           * For future scalability, this should end up building a cache
1302 1316           * since it will get called regularly by the mountd and info
1303 1317           * services.
1304 1318           */
1305 1319          if (group != NULL) {
1306 1320                  for (node = ((xmlNodePtr)group)->children; node != NULL;
1307 1321                      node = node->next) {
1308 1322                          if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) {
1309 1323                                  if (sharepath == NULL) {
1310 1324                                          break;
1311 1325                                  } else {
1312 1326                                          /* is it the correct share? */
1313 1327                                          path = xmlGetProp(node,
1314 1328                                              (xmlChar *)"path");
1315 1329                                          if (path != NULL &&
1316 1330                                              xmlStrcmp(path,
1317 1331                                              (xmlChar *)sharepath) == 0) {
1318 1332                                                  xmlFree(path);
1319 1333                                                  break;
1320 1334                                          }
1321 1335                                          xmlFree(path);
1322 1336                                  }
1323 1337                          }
1324 1338                  }
1325 1339          }
1326 1340          return ((sa_share_t)node);
1327 1341  }
1328 1342  
1329 1343  /*
1330 1344   * sa_get_next_share(share)
1331 1345   *      Return the next share following the specified share
1332 1346   *      from the internal list of shares. Returns NULL if there
1333 1347   *      are no more shares.  The list is relative to the same
1334 1348   *      group.
1335 1349   */
1336 1350  sa_share_t
1337 1351  sa_get_next_share(sa_share_t share)
1338 1352  {
1339 1353          xmlNodePtr node = NULL;
1340 1354  
1341 1355          if (share != NULL) {
1342 1356                  for (node = ((xmlNodePtr)share)->next; node != NULL;
1343 1357                      node = node->next) {
1344 1358                          if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) {
1345 1359                                  break;
1346 1360                          }
1347 1361                  }
1348 1362          }
1349 1363          return ((sa_share_t)node);
1350 1364  }
1351 1365  
1352 1366  /*
1353 1367   * _sa_get_child_node(node, type)
1354 1368   *
1355 1369   * find the child node of the specified node that has "type". This is
1356 1370   * used to implement several internal functions.
1357 1371   */
1358 1372  
1359 1373  static xmlNodePtr
1360 1374  _sa_get_child_node(xmlNodePtr node, xmlChar *type)
1361 1375  {
1362 1376          xmlNodePtr child;
1363 1377          for (child = node->xmlChildrenNode; child != NULL;
1364 1378              child = child->next)
1365 1379                  if (xmlStrcmp(child->name, type) == 0)
1366 1380                          return (child);
1367 1381          return ((xmlNodePtr)NULL);
1368 1382  }
1369 1383  
1370 1384  /*
1371 1385   *  find_share(group, path)
1372 1386   *
1373 1387   * Search all the shares in the specified group for one that has the
1374 1388   * specified path.
1375 1389   */
1376 1390  
1377 1391  static sa_share_t
1378 1392  find_share(sa_group_t group, char *sharepath)
1379 1393  {
1380 1394          sa_share_t share;
1381 1395          char *path;
1382 1396  
1383 1397          for (share = sa_get_share(group, NULL); share != NULL;
1384 1398              share = sa_get_next_share(share)) {
1385 1399                  path = sa_get_share_attr(share, "path");
1386 1400                  if (path != NULL && strcmp(path, sharepath) == 0) {
1387 1401                          sa_free_attr_string(path);
1388 1402                          break;
1389 1403                  }
1390 1404                  if (path != NULL)
1391 1405                          sa_free_attr_string(path);
1392 1406          }
1393 1407          return (share);
1394 1408  }
1395 1409  
1396 1410  /*
1397 1411   * sa_get_sub_group(group)
1398 1412   *
1399 1413   * Get the first sub-group of group. The sa_get_next_group() function
1400 1414   * can be used to get the rest. This is currently only used for ZFS
1401 1415   * sub-groups but could be used to implement a more general mechanism.
1402 1416   */
1403 1417  
1404 1418  sa_group_t
1405 1419  sa_get_sub_group(sa_group_t group)
1406 1420  {
1407 1421          return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group,
1408 1422              (xmlChar *)"group"));
1409 1423  }
1410 1424  
1411 1425  /*
1412 1426   * sa_find_share(sharepath)
1413 1427   *      Finds a share regardless of group.  In the future, this
1414 1428   *      function should utilize a cache and hash table of some kind.
1415 1429   *      The current assumption is that a path will only be shared
1416 1430   *      once.  In the future, this may change as implementation of
1417 1431   *      resource names comes into being.
1418 1432   */
1419 1433  sa_share_t
1420 1434  sa_find_share(sa_handle_t handle, char *sharepath)
1421 1435  {
1422 1436          sa_group_t group;
1423 1437          sa_group_t zgroup;
1424 1438          sa_share_t share = NULL;
1425 1439          int done = 0;
1426 1440  
1427 1441          for (group = sa_get_group(handle, NULL); group != NULL && !done;
1428 1442              group = sa_get_next_group(group)) {
1429 1443                  if (is_zfs_group(group)) {
1430 1444                          for (zgroup =
1431 1445                              (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
1432 1446                              (xmlChar *)"group");
1433 1447                              zgroup != NULL;
1434 1448                              zgroup = sa_get_next_group(zgroup)) {
1435 1449                                  share = find_share(zgroup, sharepath);
1436 1450                                  if (share != NULL)
1437 1451                                          break;
1438 1452                          }
1439 1453                  } else {
1440 1454                          share = find_share(group, sharepath);
1441 1455                  }
1442 1456                  if (share != NULL)
1443 1457                          break;
1444 1458          }
1445 1459          return (share);
1446 1460  }
1447 1461  
1448 1462  /*
1449 1463   *  sa_check_path(group, path, strictness)
1450 1464   *
1451 1465   * Check that path is a valid path relative to the group.  Currently,
1452 1466   * we are ignoring the group and checking only the NFS rules. Later,
1453 1467   * we may want to use the group to then check against the protocols
1454 1468   * enabled on the group. The strictness values mean:
1455 1469   * SA_CHECK_NORMAL == only check newpath against shares that are active
1456 1470   * SA_CHECK_STRICT == check newpath against both active shares and those
1457 1471   *                    stored in the repository
1458 1472   */
1459 1473  
1460 1474  int
1461 1475  sa_check_path(sa_group_t group, char *path, int strictness)
1462 1476  {
1463 1477          sa_handle_t handle;
1464 1478  
1465 1479          handle = sa_find_group_handle(group);
1466 1480          if (handle == NULL)
1467 1481                  return (SA_BAD_PATH);
1468 1482  
1469 1483          return (validpath(handle, path, strictness));
1470 1484  }
1471 1485  
1472 1486  /*
1473 1487   * mark_excluded_protos(group, share, flags)
1474 1488   *
1475 1489   * Walk through all the protocols enabled for the group and check to
1476 1490   * see if the share has any of them should be in the exclude list
1477 1491   * based on the featureset of the protocol. If there are any, add the
1478 1492   * "exclude" property to the share.
1479 1493   */
1480 1494  static void
1481 1495  mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags)
1482 1496  {
1483 1497          sa_optionset_t optionset;
1484 1498          char exclude_list[SA_STRSIZE];
1485 1499          char *sep = "";
1486 1500  
1487 1501          exclude_list[0] = '\0';
1488 1502          for (optionset = sa_get_optionset(group, NULL);
1489 1503              optionset != NULL;
1490 1504              optionset = sa_get_next_optionset(optionset)) {
1491 1505                  char *value;
1492 1506                  uint64_t features;
1493 1507                  value = sa_get_optionset_attr(optionset, "type");
1494 1508                  if (value == NULL)
1495 1509                          continue;
1496 1510                  features = sa_proto_get_featureset(value);
1497 1511                  if (!(features & flags)) {
1498 1512                          (void) strlcat(exclude_list, sep,
1499 1513                              sizeof (exclude_list));
1500 1514                          (void) strlcat(exclude_list, value,
1501 1515                              sizeof (exclude_list));
1502 1516                          sep = ",";
1503 1517                  }
1504 1518                  sa_free_attr_string(value);
1505 1519          }
1506 1520          if (exclude_list[0] != '\0')
1507 1521                  (void) xmlSetProp(share, (xmlChar *)"exclude",
1508 1522                      (xmlChar *)exclude_list);
1509 1523  }
1510 1524  
1511 1525  /*
1512 1526   * get_all_features(group)
1513 1527   *
1514 1528   * Walk through all the protocols on the group and collect all
1515 1529   * possible enabled features. This is the OR of all the featuresets.
1516 1530   */
1517 1531  static uint64_t
1518 1532  get_all_features(sa_group_t group)
1519 1533  {
1520 1534          sa_optionset_t optionset;
1521 1535          uint64_t features = 0;
1522 1536  
1523 1537          for (optionset = sa_get_optionset(group, NULL);
1524 1538              optionset != NULL;
1525 1539              optionset = sa_get_next_optionset(optionset)) {
1526 1540                  char *value;
1527 1541                  value = sa_get_optionset_attr(optionset, "type");
1528 1542                  if (value == NULL)
1529 1543                          continue;
1530 1544                  features |= sa_proto_get_featureset(value);
1531 1545                  sa_free_attr_string(value);
1532 1546          }
1533 1547          return (features);
1534 1548  }
1535 1549  
1536 1550  
1537 1551  /*
1538 1552   * _sa_add_share(group, sharepath, persist, *error, flags)
1539 1553   *
1540 1554   * Common code for all types of add_share. sa_add_share() is the
1541 1555   * public API, we also need to be able to do this when parsing legacy
1542 1556   * files and construction of the internal configuration while
1543 1557   * extracting config info from SMF. "flags" indicates if some
1544 1558   * protocols need relaxed rules while other don't. These values are
1545 1559   * the featureset values defined in libshare.h.
1546 1560   */
1547 1561  
1548 1562  sa_share_t
1549 1563  _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error,
1550 1564      uint64_t flags)
1551 1565  {
1552 1566          xmlNodePtr node = NULL;
1553 1567          int err;
1554 1568  
1555 1569          err  = SA_OK; /* assume success */
1556 1570  
1557 1571          node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL);
1558 1572          if (node == NULL) {
1559 1573                  if (error != NULL)
1560 1574                          *error = SA_NO_MEMORY;
1561 1575                  return (node);
1562 1576          }
1563 1577  
1564 1578          (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
1565 1579          (void) xmlSetProp(node, (xmlChar *)"type",
1566 1580              persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
1567 1581          if (flags != 0)
1568 1582                  mark_excluded_protos(group, node, flags);
1569 1583          if (persist != SA_SHARE_TRANSIENT) {
1570 1584                  /*
1571 1585                   * persistent shares come in two flavors: SMF and
1572 1586                   * ZFS. Sort this one out based on target group and
1573 1587                   * path type. Both NFS and SMB are supported. First,
1574 1588                   * check to see if the protocol is enabled on the
1575 1589                   * subgroup and then setup the share appropriately.
1576 1590                   */
1577 1591                  if (sa_group_is_zfs(group) &&
1578 1592                      sa_path_is_zfs(sharepath)) {
1579 1593                          if (sa_get_optionset(group, "nfs") != NULL)
1580 1594                                  err = sa_zfs_set_sharenfs(group, sharepath, 1);
1581 1595                          else if (sa_get_optionset(group, "smb") != NULL)
1582 1596                                  err = sa_zfs_set_sharesmb(group, sharepath, 1);
1583 1597                  } else {
1584 1598                          sa_handle_impl_t impl_handle;
1585 1599                          impl_handle =
1586 1600                              (sa_handle_impl_t)sa_find_group_handle(group);
1587 1601                          if (impl_handle != NULL) {
1588 1602                                  err = sa_commit_share(impl_handle->scfhandle,
1589 1603                                      group, (sa_share_t)node);
1590 1604                          } else {
1591 1605                                  err = SA_SYSTEM_ERR;
1592 1606                          }
1593 1607                  }
1594 1608          }
1595 1609          if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
1596 1610                  /* called by the dfstab parser so could be a show */
1597 1611                  err = SA_OK;
1598 1612  
1599 1613          if (err != SA_OK) {
1600 1614                  /*
1601 1615                   * we couldn't commit to the repository so undo
1602 1616                   * our internal state to reflect reality.
1603 1617                   */
1604 1618                  xmlUnlinkNode(node);
1605 1619                  xmlFreeNode(node);
1606 1620                  node = NULL;
1607 1621          }
1608 1622  
1609 1623          if (error != NULL)
1610 1624                  *error = err;
1611 1625  
1612 1626          return (node);
1613 1627  }
1614 1628  
1615 1629  /*
1616 1630   * sa_add_share(group, sharepath, persist, *error)
1617 1631   *
1618 1632   *      Add a new share object to the specified group.  The share will
1619 1633   *      have the specified sharepath and will only be constructed if
1620 1634   *      it is a valid path to be shared.  NULL is returned on error
1621 1635   *      and a detailed error value will be returned via the error
1622 1636   *      pointer.
1623 1637   */
1624 1638  sa_share_t
1625 1639  sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
1626 1640  {
1627 1641          xmlNodePtr node = NULL;
1628 1642          int strictness = SA_CHECK_NORMAL;
1629 1643          sa_handle_t handle;
1630 1644          uint64_t special = 0;
1631 1645          uint64_t features;
1632 1646  
1633 1647          /*
1634 1648           * If the share is to be permanent, use strict checking so a
1635 1649           * bad config doesn't get created. Transient shares only need
1636 1650           * to check against the currently active
1637 1651           * shares. SA_SHARE_PARSER is a modifier used internally to
1638 1652           * indicate that we are being called by the dfstab parser and
1639 1653           * that we need strict checking in all cases. Normally persist
1640 1654           * is in integer value but SA_SHARE_PARSER may be or'd into
1641 1655           * it as an override.
1642 1656           */
1643 1657          if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT)
1644 1658                  strictness = SA_CHECK_STRICT;
1645 1659  
1646 1660          handle = sa_find_group_handle(group);
1647 1661  
1648 1662          /*
1649 1663           * need to determine if the share is valid. The rules are:
1650 1664           *      - The path must not already exist
1651 1665           *      - The path must not be a subdir or parent dir of an
1652 1666           *        existing path unless at least one protocol allows it.
1653 1667           * The sub/parent check is done in sa_check_path().
1654 1668           */
1655 1669  
1656 1670          if (sa_find_share(handle, sharepath) == NULL) {
1657 1671                  *error = sa_check_path(group, sharepath, strictness);
1658 1672                  features = get_all_features(group);
1659 1673                  switch (*error) {
1660 1674                  case SA_PATH_IS_SUBDIR:
1661 1675                          if (features & SA_FEATURE_ALLOWSUBDIRS)
1662 1676                                  special |= SA_FEATURE_ALLOWSUBDIRS;
1663 1677                          break;
1664 1678                  case SA_PATH_IS_PARENTDIR:
1665 1679                          if (features & SA_FEATURE_ALLOWPARDIRS)
1666 1680                                  special |= SA_FEATURE_ALLOWPARDIRS;
1667 1681                          break;
1668 1682                  }
1669 1683                  if (*error == SA_OK || special != SA_FEATURE_NONE)
1670 1684                          node = _sa_add_share(group, sharepath, persist,
1671 1685                              error, special);
1672 1686          } else {
1673 1687                  *error = SA_DUPLICATE_NAME;
1674 1688          }
1675 1689  
1676 1690          return ((sa_share_t)node);
1677 1691  }
1678 1692  
1679 1693  /*
1680 1694   * sa_enable_share(share, protocol)
1681 1695   *      Enable the specified share to the specified protocol.
1682 1696   *      If protocol is NULL, then all protocols.
1683 1697   */
1684 1698  int
1685 1699  sa_enable_share(sa_share_t share, char *protocol)
1686 1700  {
1687 1701          char *sharepath;
1688 1702          struct stat st;
1689 1703          int err = SA_OK;
1690 1704          int ret;
1691 1705  
1692 1706          sharepath = sa_get_share_attr(share, "path");
1693 1707          if (sharepath == NULL)
1694 1708                  return (SA_NO_MEMORY);
1695 1709          if (stat(sharepath, &st) < 0) {
1696 1710                  err = SA_NO_SUCH_PATH;
1697 1711          } else {
1698 1712                  /* tell the server about the share */
1699 1713                  if (protocol != NULL) {
1700 1714                          if (excluded_protocol(share, protocol))
1701 1715                                  goto done;
1702 1716  
1703 1717                          /* lookup protocol specific handler */
1704 1718                          err = sa_proto_share(protocol, share);
1705 1719                          if (err == SA_OK)
1706 1720                                  (void) sa_set_share_attr(share,
1707 1721                                      "shared", "true");
1708 1722                  } else {
1709 1723                          /* Tell all protocols about the share */
1710 1724                          sa_group_t group;
1711 1725                          sa_optionset_t optionset;
1712 1726  
1713 1727                          group = sa_get_parent_group(share);
1714 1728  
1715 1729                          for (optionset = sa_get_optionset(group, NULL);
1716 1730                              optionset != NULL;
1717 1731                              optionset = sa_get_next_optionset(optionset)) {
1718 1732                                  char *proto;
1719 1733                                  proto = sa_get_optionset_attr(optionset,
1720 1734                                      "type");
1721 1735                                  if (proto != NULL) {
1722 1736                                          if (!excluded_protocol(share, proto)) {
1723 1737                                                  ret = sa_proto_share(proto,
1724 1738                                                      share);
1725 1739                                                  if (ret != SA_OK)
1726 1740                                                          err = ret;
1727 1741                                          }
1728 1742                                          sa_free_attr_string(proto);
1729 1743                                  }
1730 1744                          }
1731 1745                          (void) sa_set_share_attr(share, "shared", "true");
1732 1746                  }
1733 1747          }
1734 1748  done:
1735 1749          if (sharepath != NULL)
1736 1750                  sa_free_attr_string(sharepath);
1737 1751          return (err);
1738 1752  }
1739 1753  
1740 1754  /*
1741 1755   * sa_disable_share(share, protocol)
1742 1756   *      Disable the specified share to the specified protocol.  If
1743 1757   *      protocol is NULL, then all protocols that are enabled for the
1744 1758   *      share should be disabled.
1745 1759   */
1746 1760  int
1747 1761  sa_disable_share(sa_share_t share, char *protocol)
1748 1762  {
1749 1763          char *path;
1750 1764          int err = SA_OK;
1751 1765          int ret = SA_OK;
1752 1766  
1753 1767          path = sa_get_share_attr(share, "path");
1754 1768  
1755 1769          if (protocol != NULL) {
1756 1770                  ret = sa_proto_unshare(share, protocol, path);
1757 1771          } else {
1758 1772                  /* need to do all protocols */
1759 1773                  sa_group_t group;
1760 1774                  sa_optionset_t optionset;
1761 1775  
1762 1776                  group = sa_get_parent_group(share);
1763 1777  
1764 1778                  /* Tell all protocols about the share */
1765 1779                  for (optionset = sa_get_optionset(group, NULL);
1766 1780                      optionset != NULL;
1767 1781                      optionset = sa_get_next_optionset(optionset)) {
1768 1782                          char *proto;
1769 1783  
1770 1784                          proto = sa_get_optionset_attr(optionset, "type");
1771 1785                          if (proto != NULL) {
1772 1786                                  err = sa_proto_unshare(share, proto, path);
1773 1787                                  if (err != SA_OK)
1774 1788                                          ret = err;
1775 1789                                  sa_free_attr_string(proto);
1776 1790                          }
1777 1791                  }
1778 1792          }
1779 1793          if (ret == SA_OK)
1780 1794                  (void) sa_set_share_attr(share, "shared", NULL);
1781 1795          if (path != NULL)
1782 1796                  sa_free_attr_string(path);
1783 1797          return (ret);
1784 1798  }
1785 1799  
1786 1800  /*
1787 1801   * sa_remove_share(share)
1788 1802   *
1789 1803   * remove the specified share from its containing group.
1790 1804   * Remove from the SMF or ZFS configuration space.
1791 1805   */
1792 1806  
1793 1807  int
1794 1808  sa_remove_share(sa_share_t share)
1795 1809  {
1796 1810          sa_group_t group;
1797 1811          int ret = SA_OK;
1798 1812          char *type;
1799 1813          int transient = 0;
1800 1814          char *groupname;
1801 1815          char *zfs;
1802 1816  
1803 1817          type = sa_get_share_attr(share, "type");
1804 1818          group = sa_get_parent_group(share);
1805 1819          zfs = sa_get_group_attr(group, "zfs");
1806 1820          groupname = sa_get_group_attr(group, "name");
1807 1821          if (type != NULL && strcmp(type, "persist") != 0)
1808 1822                  transient = 1;
1809 1823          if (type != NULL)
1810 1824                  sa_free_attr_string(type);
1811 1825  
1812 1826          /* remove the node from its group then free the memory */
1813 1827  
1814 1828          /*
1815 1829           * need to test if "busy"
1816 1830           */
1817 1831          /* only do SMF action if permanent */
1818 1832          if (!transient || zfs != NULL) {
1819 1833                  /* remove from legacy dfstab as well as possible SMF */
1820 1834                  ret = sa_delete_legacy(share, NULL);
1821 1835                  if (ret == SA_OK) {
1822 1836                          if (!sa_group_is_zfs(group)) {
1823 1837                                  sa_handle_impl_t impl_handle;
1824 1838                                  impl_handle = (sa_handle_impl_t)
1825 1839                                      sa_find_group_handle(group);
1826 1840                                  if (impl_handle != NULL) {
1827 1841                                          ret = sa_delete_share(
1828 1842                                              impl_handle->scfhandle, group,
1829 1843                                              share);
1830 1844                                  } else {
1831 1845                                          ret = SA_SYSTEM_ERR;
1832 1846                                  }
1833 1847                          } else {
1834 1848                                  char *sharepath = sa_get_share_attr(share,
1835 1849                                      "path");
1836 1850                                  if (sharepath != NULL) {
1837 1851                                          ret = sa_zfs_set_sharenfs(group,
1838 1852                                              sharepath, 0);
1839 1853                                          sa_free_attr_string(sharepath);
1840 1854                                  }
1841 1855                          }
1842 1856                  }
1843 1857          }
1844 1858          if (groupname != NULL)
1845 1859                  sa_free_attr_string(groupname);
1846 1860          if (zfs != NULL)
1847 1861                  sa_free_attr_string(zfs);
1848 1862  
1849 1863          xmlUnlinkNode((xmlNodePtr)share);
1850 1864          xmlFreeNode((xmlNodePtr)share);
1851 1865          return (ret);
1852 1866  }
1853 1867  
1854 1868  /*
1855 1869   * sa_move_share(group, share)
1856 1870   *
1857 1871   * move the specified share to the specified group.  Update SMF
1858 1872   * appropriately.
1859 1873   */
1860 1874  
1861 1875  int
1862 1876  sa_move_share(sa_group_t group, sa_share_t share)
1863 1877  {
1864 1878          sa_group_t oldgroup;
1865 1879          int ret = SA_OK;
1866 1880  
1867 1881          /* remove the node from its group then free the memory */
1868 1882  
1869 1883          oldgroup = sa_get_parent_group(share);
1870 1884          if (oldgroup != group) {
1871 1885                  sa_handle_impl_t impl_handle;
1872 1886                  xmlUnlinkNode((xmlNodePtr)share);
1873 1887                  /*
1874 1888                   * now that the share isn't in its old group, add to
1875 1889                   * the new one
1876 1890                   */
1877 1891                  (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
1878 1892                  /* need to deal with SMF */
1879 1893                  impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1880 1894                  if (impl_handle != NULL) {
1881 1895                          /*
1882 1896                           * need to remove from old group first and then add to
1883 1897                           * new group. Ideally, we would do the other order but
1884 1898                           * need to avoid having the share in two groups at the
1885 1899                           * same time.
1886 1900                           */
1887 1901                          ret = sa_delete_share(impl_handle->scfhandle, oldgroup,
1888 1902                              share);
1889 1903                          if (ret == SA_OK)
1890 1904                                  ret = sa_commit_share(impl_handle->scfhandle,
1891 1905                                      group, share);
1892 1906                  } else {
1893 1907                          ret = SA_SYSTEM_ERR;
1894 1908                  }
1895 1909          }
1896 1910          return (ret);
1897 1911  }
1898 1912  
1899 1913  /*
1900 1914   * sa_get_parent_group(share)
1901 1915   *
1902 1916   * Return the containing group for the share. If a group was actually
1903 1917   * passed in, we don't want a parent so return NULL.
1904 1918   */
1905 1919  
1906 1920  sa_group_t
1907 1921  sa_get_parent_group(sa_share_t share)
1908 1922  {
1909 1923          xmlNodePtr node = NULL;
1910 1924          if (share != NULL) {
1911 1925                  node = ((xmlNodePtr)share)->parent;
1912 1926                  /*
1913 1927                   * make sure parent is a group and not sharecfg since
1914 1928                   * we may be cheating and passing in a group.
1915 1929                   * Eventually, groups of groups might come into being.
1916 1930                   */
1917 1931                  if (node == NULL ||
1918 1932                      xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0)
1919 1933                          node = NULL;
1920 1934          }
1921 1935          return ((sa_group_t)node);
1922 1936  }
1923 1937  
1924 1938  /*
1925 1939   * _sa_create_group(impl_handle, groupname)
1926 1940   *
1927 1941   * Create a group in the document. The caller will need to deal with
1928 1942   * configuration store and activation.
1929 1943   */
1930 1944  
1931 1945  sa_group_t
1932 1946  _sa_create_group(sa_handle_impl_t impl_handle, char *groupname)
1933 1947  {
1934 1948          xmlNodePtr node = NULL;
1935 1949  
1936 1950          if (sa_valid_group_name(groupname)) {
1937 1951                  node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group",
1938 1952                      NULL);
1939 1953                  if (node != NULL) {
1940 1954                          (void) xmlSetProp(node, (xmlChar *)"name",
1941 1955                              (xmlChar *)groupname);
1942 1956                          (void) xmlSetProp(node, (xmlChar *)"state",
1943 1957                              (xmlChar *)"enabled");
1944 1958                  }
1945 1959          }
1946 1960          return ((sa_group_t)node);
1947 1961  }
1948 1962  
1949 1963  /*
1950 1964   * _sa_create_zfs_group(group, groupname)
1951 1965   *
1952 1966   * Create a ZFS subgroup under the specified group. This may
1953 1967   * eventually form the basis of general sub-groups, but is currently
1954 1968   * restricted to ZFS.
1955 1969   */
1956 1970  sa_group_t
1957 1971  _sa_create_zfs_group(sa_group_t group, char *groupname)
1958 1972  {
1959 1973          xmlNodePtr node = NULL;
1960 1974  
1961 1975          node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL);
1962 1976          if (node != NULL) {
1963 1977                  (void) xmlSetProp(node, (xmlChar *)"name",
1964 1978                      (xmlChar *)groupname);
1965 1979                  (void) xmlSetProp(node, (xmlChar *)"state",
1966 1980                      (xmlChar *)"enabled");
1967 1981          }
1968 1982  
1969 1983          return ((sa_group_t)node);
1970 1984  }
1971 1985  
1972 1986  /*
1973 1987   * sa_create_group(groupname, *error)
1974 1988   *
1975 1989   * Create a new group with groupname.  Need to validate that it is a
1976 1990   * legal name for SMF and the construct the SMF service instance of
1977 1991   * svc:/network/shares/group to implement the group. All necessary
1978 1992   * operational properties must be added to the group at this point
1979 1993   * (via the SMF transaction model).
1980 1994   */
1981 1995  sa_group_t
1982 1996  sa_create_group(sa_handle_t handle, char *groupname, int *error)
1983 1997  {
1984 1998          xmlNodePtr node = NULL;
1985 1999          sa_group_t group;
1986 2000          int ret;
1987 2001          char rbacstr[SA_STRSIZE];
1988 2002          sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
1989 2003  
1990 2004          ret = SA_OK;
1991 2005  
1992 2006          if (impl_handle == NULL || impl_handle->scfhandle == NULL) {
1993 2007                  ret = SA_SYSTEM_ERR;
1994 2008                  goto err;
1995 2009          }
1996 2010  
1997 2011          group = sa_get_group(handle, groupname);
1998 2012          if (group != NULL) {
1999 2013                  ret = SA_DUPLICATE_NAME;
2000 2014          } else {
2001 2015                  if (sa_valid_group_name(groupname)) {
2002 2016                          node = xmlNewChild(impl_handle->tree, NULL,
2003 2017                              (xmlChar *)"group", NULL);
2004 2018                          if (node != NULL) {
2005 2019                                  (void) xmlSetProp(node, (xmlChar *)"name",
2006 2020                                      (xmlChar *)groupname);
2007 2021                                  /* default to the group being enabled */
2008 2022                                  (void) xmlSetProp(node, (xmlChar *)"state",
2009 2023                                      (xmlChar *)"enabled");
2010 2024                                  ret = sa_create_instance(impl_handle->scfhandle,
2011 2025                                      groupname);
2012 2026                                  if (ret == SA_OK) {
2013 2027                                          ret = sa_start_transaction(
2014 2028                                              impl_handle->scfhandle,
2015 2029                                              "operation");
2016 2030                                  }
2017 2031                                  if (ret == SA_OK) {
2018 2032                                          ret = sa_set_property(
2019 2033                                              impl_handle->scfhandle,
2020 2034                                              "state", "enabled");
2021 2035                                          if (ret == SA_OK) {
2022 2036                                                  ret = sa_end_transaction(
2023 2037                                                      impl_handle->scfhandle,
2024 2038                                                      impl_handle);
2025 2039                                          } else {
2026 2040                                                  sa_abort_transaction(
2027 2041                                                      impl_handle->scfhandle);
2028 2042                                          }
2029 2043                                  }
2030 2044                                  if (ret == SA_OK) {
2031 2045                                          /* initialize the RBAC strings */
2032 2046                                          ret = sa_start_transaction(
2033 2047                                              impl_handle->scfhandle,
2034 2048                                              "general");
2035 2049                                          if (ret == SA_OK) {
2036 2050                                                  (void) snprintf(rbacstr,
2037 2051                                                      sizeof (rbacstr), "%s.%s",
2038 2052                                                      SA_RBAC_MANAGE, groupname);
2039 2053                                                  ret = sa_set_property(
2040 2054                                                      impl_handle->scfhandle,
2041 2055                                                      "action_authorization",
2042 2056                                                      rbacstr);
2043 2057                                          }
2044 2058                                          if (ret == SA_OK) {
2045 2059                                                  (void) snprintf(rbacstr,
2046 2060                                                      sizeof (rbacstr), "%s.%s",
2047 2061                                                      SA_RBAC_VALUE, groupname);
2048 2062                                                  ret = sa_set_property(
2049 2063                                                      impl_handle->scfhandle,
2050 2064                                                      "value_authorization",
2051 2065                                                      rbacstr);
2052 2066                                          }
2053 2067                                          if (ret == SA_OK) {
2054 2068                                                  ret = sa_end_transaction(
2055 2069                                                      impl_handle->scfhandle,
2056 2070                                                      impl_handle);
2057 2071                                          } else {
2058 2072                                                  sa_abort_transaction(
2059 2073                                                      impl_handle->scfhandle);
2060 2074                                          }
2061 2075                                  }
2062 2076                                  if (ret != SA_OK) {
2063 2077                                          /*
2064 2078                                           * Couldn't commit the group
2065 2079                                           * so we need to undo
2066 2080                                           * internally.
2067 2081                                           */
2068 2082                                          xmlUnlinkNode(node);
2069 2083                                          xmlFreeNode(node);
2070 2084                                          node = NULL;
2071 2085                                  }
2072 2086                          } else {
2073 2087                                  ret = SA_NO_MEMORY;
2074 2088                          }
2075 2089                  } else {
2076 2090                          ret = SA_INVALID_NAME;
2077 2091                  }
2078 2092          }
2079 2093  err:
2080 2094          if (error != NULL)
2081 2095                  *error = ret;
2082 2096          return ((sa_group_t)node);
2083 2097  }
2084 2098  
2085 2099  /*
2086 2100   * sa_remove_group(group)
2087 2101   *
2088 2102   * Remove the specified group. This deletes from the SMF repository.
2089 2103   * All property groups and properties are removed.
2090 2104   */
2091 2105  
2092 2106  int
2093 2107  sa_remove_group(sa_group_t group)
2094 2108  {
2095 2109          char *name;
2096 2110          int ret = SA_OK;
2097 2111          sa_handle_impl_t impl_handle;
2098 2112  
2099 2113          impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2100 2114          if (impl_handle != NULL) {
2101 2115                  name = sa_get_group_attr(group, "name");
2102 2116                  if (name != NULL) {
2103 2117                          ret = sa_delete_instance(impl_handle->scfhandle, name);
2104 2118                          sa_free_attr_string(name);
2105 2119                  }
2106 2120                  xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
2107 2121                  xmlFreeNode((xmlNodePtr)group);   /* now it is gone */
2108 2122          } else {
2109 2123                  ret = SA_SYSTEM_ERR;
2110 2124          }
2111 2125          return (ret);
2112 2126  }
2113 2127  
2114 2128  /*
2115 2129   * sa_update_config()
2116 2130   *
2117 2131   * Used to update legacy files that need to be updated in bulk
2118 2132   * Currently, this is a placeholder and will go away in a future
2119 2133   * release.
2120 2134   */
2121 2135  
2122 2136  int
2123 2137  sa_update_config(sa_handle_t handle)
2124 2138  {
2125 2139          /*
2126 2140           * do legacy files first so we can tell when they change.
2127 2141           * This will go away when we start updating individual records
2128 2142           * rather than the whole file.
2129 2143           */
2130 2144          update_legacy_config(handle);
2131 2145          return (SA_OK);
2132 2146  }
2133 2147  
2134 2148  /*
2135 2149   * get_node_attr(node, tag)
2136 2150   *
2137 2151   * Get the specified tag(attribute) if it exists on the node.  This is
2138 2152   * used internally by a number of attribute oriented functions.
2139 2153   */
2140 2154  
2141 2155  static char *
2142 2156  get_node_attr(void *nodehdl, char *tag)
2143 2157  {
2144 2158          xmlNodePtr node = (xmlNodePtr)nodehdl;
2145 2159          xmlChar *name = NULL;
2146 2160  
2147 2161          if (node != NULL)
2148 2162                  name = xmlGetProp(node, (xmlChar *)tag);
2149 2163          return ((char *)name);
2150 2164  }
2151 2165  
2152 2166  /*
2153 2167   * set_node_attr(node, tag)
2154 2168   *
2155 2169   * Set the specified tag(attribute) to the specified value This is
2156 2170   * used internally by a number of attribute oriented functions. It
2157 2171   * doesn't update the repository, only the internal document state.
2158 2172   */
2159 2173  
2160 2174  void
2161 2175  set_node_attr(void *nodehdl, char *tag, char *value)
2162 2176  {
2163 2177          xmlNodePtr node = (xmlNodePtr)nodehdl;
2164 2178          if (node != NULL && tag != NULL) {
2165 2179                  if (value != NULL)
2166 2180                          (void) xmlSetProp(node, (xmlChar *)tag,
2167 2181                              (xmlChar *)value);
2168 2182                  else
2169 2183                          (void) xmlUnsetProp(node, (xmlChar *)tag);
2170 2184          }
2171 2185  }
2172 2186  
2173 2187  /*
2174 2188   * sa_get_group_attr(group, tag)
2175 2189   *
2176 2190   * Get the specied attribute, if defined, for the group.
2177 2191   */
2178 2192  
2179 2193  char *
2180 2194  sa_get_group_attr(sa_group_t group, char *tag)
2181 2195  {
2182 2196          return (get_node_attr((void *)group, tag));
2183 2197  }
2184 2198  
2185 2199  /*
2186 2200   * sa_set_group_attr(group, tag, value)
2187 2201   *
2188 2202   * set the specified tag/attribute on the group using value as its
2189 2203   * value.
2190 2204   *
2191 2205   * This will result in setting the property in the SMF repository as
2192 2206   * well as in the internal document.
2193 2207   */
2194 2208  
2195 2209  int
2196 2210  sa_set_group_attr(sa_group_t group, char *tag, char *value)
2197 2211  {
2198 2212          int ret;
2199 2213          char *groupname;
2200 2214          sa_handle_impl_t impl_handle;
2201 2215  
2202 2216          /*
2203 2217           * ZFS group/subgroup doesn't need the handle so shortcut.
2204 2218           */
2205 2219          if (sa_group_is_zfs(group)) {
2206 2220                  set_node_attr((void *)group, tag, value);
2207 2221                  return (SA_OK);
2208 2222          }
2209 2223  
2210 2224          impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2211 2225          if (impl_handle != NULL) {
2212 2226                  groupname = sa_get_group_attr(group, "name");
2213 2227                  ret = sa_get_instance(impl_handle->scfhandle, groupname);
2214 2228                  if (ret == SA_OK) {
2215 2229                          set_node_attr((void *)group, tag, value);
2216 2230                          ret = sa_start_transaction(impl_handle->scfhandle,
2217 2231                              "operation");
2218 2232                          if (ret == SA_OK) {
2219 2233                                  ret = sa_set_property(impl_handle->scfhandle,
2220 2234                                      tag, value);
2221 2235                                  if (ret == SA_OK)
2222 2236                                          ret = sa_end_transaction(
2223 2237                                              impl_handle->scfhandle,
2224 2238                                              impl_handle);
2225 2239                                  else
2226 2240                                          sa_abort_transaction(
2227 2241                                              impl_handle->scfhandle);
2228 2242                          }
2229 2243                          if (ret == SA_SYSTEM_ERR)
2230 2244                                  ret = SA_NO_PERMISSION;
2231 2245                  }
2232 2246                  if (groupname != NULL)
2233 2247                          sa_free_attr_string(groupname);
2234 2248          } else {
2235 2249                  ret = SA_SYSTEM_ERR;
2236 2250          }
2237 2251          return (ret);
2238 2252  }
2239 2253  
2240 2254  /*
2241 2255   * sa_get_share_attr(share, tag)
2242 2256   *
2243 2257   * Return the value of the tag/attribute set on the specified
2244 2258   * share. Returns NULL if the tag doesn't exist.
2245 2259   */
2246 2260  
2247 2261  char *
2248 2262  sa_get_share_attr(sa_share_t share, char *tag)
2249 2263  {
2250 2264          return (get_node_attr((void *)share, tag));
2251 2265  }
2252 2266  
2253 2267  /*
2254 2268   * _sa_set_share_description(share, description)
2255 2269   *
2256 2270   * Add a description tag with text contents to the specified share.  A
2257 2271   * separate XML tag is used rather than a property. This can also be
2258 2272   * used with resources.
2259 2273   */
2260 2274  
2261 2275  xmlNodePtr
2262 2276  _sa_set_share_description(void *share, char *content)
2263 2277  {
2264 2278          xmlNodePtr node;
2265 2279          node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description",
2266 2280              NULL);
2267 2281          xmlNodeSetContent(node, (xmlChar *)content);
2268 2282          return (node);
2269 2283  }
2270 2284  
2271 2285  /*
2272 2286   * sa_set_share_attr(share, tag, value)
2273 2287   *
2274 2288   * Set the share attribute specified by tag to the specified value. In
2275 2289   * the case of "resource", enforce a no duplicates in a group rule. If
2276 2290   * the share is not transient, commit the changes to the repository
2277 2291   * else just update the share internally.
2278 2292   */
2279 2293  
2280 2294  int
2281 2295  sa_set_share_attr(sa_share_t share, char *tag, char *value)
2282 2296  {
2283 2297          sa_group_t group;
2284 2298          sa_share_t resource;
2285 2299          int ret = SA_OK;
2286 2300  
2287 2301          group = sa_get_parent_group(share);
2288 2302  
2289 2303          /*
2290 2304           * There are some attributes that may have specific
2291 2305           * restrictions on them. Initially, only "resource" has
2292 2306           * special meaning that needs to be checked. Only one instance
2293 2307           * of a resource name may exist within a group.
2294 2308           */
2295 2309  
2296 2310          if (strcmp(tag, "resource") == 0) {
2297 2311                  resource = sa_get_resource(group, value);
2298 2312                  if (resource != share && resource != NULL)
2299 2313                          ret = SA_DUPLICATE_NAME;
2300 2314          }
2301 2315          if (ret == SA_OK) {
2302 2316                  set_node_attr((void *)share, tag, value);
2303 2317                  if (group != NULL) {
2304 2318                          char *type;
2305 2319                          /* we can probably optimize this some */
2306 2320                          type = sa_get_share_attr(share, "type");
2307 2321                          if (type == NULL || strcmp(type, "transient") != 0) {
2308 2322                                  sa_handle_impl_t impl_handle;
2309 2323                                  impl_handle =
2310 2324                                      (sa_handle_impl_t)sa_find_group_handle(
2311 2325                                      group);
2312 2326                                  if (impl_handle != NULL) {
2313 2327                                          ret = sa_commit_share(
2314 2328                                              impl_handle->scfhandle, group,
2315 2329                                              share);
2316 2330                                  } else {
2317 2331                                          ret = SA_SYSTEM_ERR;
2318 2332                                  }
2319 2333                          }
2320 2334                          if (type != NULL)
2321 2335                                  sa_free_attr_string(type);
2322 2336                  }
2323 2337          }
2324 2338          return (ret);
2325 2339  }
2326 2340  
2327 2341  /*
2328 2342   * sa_get_property_attr(prop, tag)
2329 2343   *
2330 2344   * Get the value of the specified property attribute. Standard
2331 2345   * attributes are "type" and "value".
2332 2346   */
2333 2347  
2334 2348  char *
2335 2349  sa_get_property_attr(sa_property_t prop, char *tag)
2336 2350  {
2337 2351          return (get_node_attr((void *)prop, tag));
2338 2352  }
2339 2353  
2340 2354  /*
2341 2355   * sa_get_optionset_attr(prop, tag)
2342 2356   *
2343 2357   * Get the value of the specified property attribute. Standard
2344 2358   * attribute is "type".
2345 2359   */
2346 2360  
2347 2361  char *
2348 2362  sa_get_optionset_attr(sa_property_t optionset, char *tag)
2349 2363  {
2350 2364          return (get_node_attr((void *)optionset, tag));
2351 2365  
2352 2366  }
2353 2367  
2354 2368  /*
2355 2369   * sa_set_optionset_attr(optionset, tag, value)
2356 2370   *
2357 2371   * Set the specified attribute(tag) to the specified value on the
2358 2372   * optionset.
2359 2373   */
2360 2374  
2361 2375  void
2362 2376  sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value)
2363 2377  {
2364 2378          set_node_attr((void *)optionset, tag, value);
2365 2379  }
2366 2380  
2367 2381  /*
2368 2382   * sa_free_attr_string(string)
2369 2383   *
2370 2384   * Free the string that was returned in one of the sa_get_*_attr()
2371 2385   * functions.
2372 2386   */
2373 2387  
2374 2388  void
2375 2389  sa_free_attr_string(char *string)
2376 2390  {
2377 2391          xmlFree((xmlChar *)string);
2378 2392  }
2379 2393  
2380 2394  /*
2381 2395   * sa_get_optionset(group, proto)
2382 2396   *
2383 2397   * Return the optionset, if it exists, that is associated with the
2384 2398   * specified protocol.
2385 2399   */
2386 2400  
2387 2401  sa_optionset_t
2388 2402  sa_get_optionset(void *group, char *proto)
2389 2403  {
2390 2404          xmlNodePtr node;
2391 2405          xmlChar *value = NULL;
2392 2406  
2393 2407          for (node = ((xmlNodePtr)group)->children; node != NULL;
2394 2408              node = node->next) {
2395 2409                  if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) {
2396 2410                          value = xmlGetProp(node, (xmlChar *)"type");
2397 2411                          if (proto != NULL) {
2398 2412                                  if (value != NULL &&
2399 2413                                      xmlStrcmp(value, (xmlChar *)proto) == 0) {
2400 2414                                          break;
2401 2415                                  }
2402 2416                                  if (value != NULL) {
2403 2417                                          xmlFree(value);
2404 2418                                          value = NULL;
2405 2419                                  }
2406 2420                          } else {
2407 2421                                  break;
2408 2422                          }
2409 2423                  }
2410 2424          }
2411 2425          if (value != NULL)
2412 2426                  xmlFree(value);
2413 2427          return ((sa_optionset_t)node);
2414 2428  }
2415 2429  
2416 2430  /*
2417 2431   * sa_get_next_optionset(optionset)
2418 2432   *
2419 2433   * Return the next optionset in the group. NULL if this was the last.
2420 2434   */
2421 2435  
2422 2436  sa_optionset_t
2423 2437  sa_get_next_optionset(sa_optionset_t optionset)
2424 2438  {
2425 2439          xmlNodePtr node;
2426 2440  
2427 2441          for (node = ((xmlNodePtr)optionset)->next; node != NULL;
2428 2442              node = node->next) {
2429 2443                  if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) {
2430 2444                          break;
2431 2445                  }
2432 2446          }
2433 2447          return ((sa_optionset_t)node);
2434 2448  }
2435 2449  
2436 2450  /*
2437 2451   * sa_get_security(group, sectype, proto)
2438 2452   *
2439 2453   * Return the security optionset. The internal name is a hold over
2440 2454   * from the implementation and will be changed before the API is
2441 2455   * finalized. This is really a named optionset that can be negotiated
2442 2456   * as a group of properties (like NFS security options).
2443 2457   */
2444 2458  
2445 2459  sa_security_t
2446 2460  sa_get_security(sa_group_t group, char *sectype, char *proto)
2447 2461  {
2448 2462          xmlNodePtr node;
2449 2463          xmlChar *value = NULL;
2450 2464  
2451 2465          for (node = ((xmlNodePtr)group)->children; node != NULL;
2452 2466              node = node->next) {
2453 2467                  if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) {
2454 2468                          if (proto != NULL) {
2455 2469                                  value = xmlGetProp(node, (xmlChar *)"type");
2456 2470                                  if (value == NULL ||
2457 2471                                      (value != NULL &&
2458 2472                                      xmlStrcmp(value, (xmlChar *)proto) != 0)) {
2459 2473                                          /* it doesn't match so continue */
2460 2474                                          xmlFree(value);
2461 2475                                          value = NULL;
2462 2476                                          continue;
2463 2477                                  }
2464 2478                          }
2465 2479                          if (value != NULL) {
2466 2480                                  xmlFree(value);
2467 2481                                  value = NULL;
2468 2482                          }
2469 2483                          /* potential match */
2470 2484                          if (sectype != NULL) {
2471 2485                                  value = xmlGetProp(node, (xmlChar *)"sectype");
2472 2486                                  if (value != NULL &&
2473 2487                                      xmlStrcmp(value, (xmlChar *)sectype) == 0) {
2474 2488                                          break;
2475 2489                                  }
2476 2490                          } else {
2477 2491                                  break;
2478 2492                          }
2479 2493                  }
2480 2494                  if (value != NULL) {
2481 2495                          xmlFree(value);
2482 2496                          value = NULL;
2483 2497                  }
2484 2498          }
2485 2499          if (value != NULL)
2486 2500                  xmlFree(value);
2487 2501          return ((sa_security_t)node);
2488 2502  }
2489 2503  
2490 2504  /*
2491 2505   * sa_get_next_security(security)
2492 2506   *
2493 2507   * Get the next security optionset if one exists.
2494 2508   */
2495 2509  
2496 2510  sa_security_t
2497 2511  sa_get_next_security(sa_security_t security)
2498 2512  {
2499 2513          xmlNodePtr node;
2500 2514  
2501 2515          for (node = ((xmlNodePtr)security)->next; node != NULL;
2502 2516              node = node->next) {
2503 2517                  if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) {
2504 2518                          break;
2505 2519                  }
2506 2520          }
2507 2521          return ((sa_security_t)node);
2508 2522  }
2509 2523  
2510 2524  /*
2511 2525   * sa_get_property(optionset, prop)
2512 2526   *
2513 2527   * Get the property object with the name specified in prop from the
2514 2528   * optionset.
2515 2529   */
2516 2530  
2517 2531  sa_property_t
2518 2532  sa_get_property(sa_optionset_t optionset, char *prop)
2519 2533  {
2520 2534          xmlNodePtr node = (xmlNodePtr)optionset;
2521 2535          xmlChar *value = NULL;
2522 2536  
2523 2537          if (optionset == NULL)
2524 2538                  return (NULL);
2525 2539  
2526 2540          for (node = node->children; node != NULL;
2527 2541              node = node->next) {
2528 2542                  if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
2529 2543                          if (prop == NULL)
2530 2544                                  break;
2531 2545                          value = xmlGetProp(node, (xmlChar *)"type");
2532 2546                          if (value != NULL &&
2533 2547                              xmlStrcmp(value, (xmlChar *)prop) == 0) {
2534 2548                                  break;
2535 2549                          }
2536 2550                          if (value != NULL) {
2537 2551                                  xmlFree(value);
2538 2552                                  value = NULL;
2539 2553                          }
2540 2554                  }
2541 2555          }
2542 2556          if (value != NULL)
2543 2557                  xmlFree(value);
2544 2558          if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) {
2545 2559                  /*
2546 2560                   * avoid a non option node -- it is possible to be a
2547 2561                   * text node
2548 2562                   */
2549 2563                  node = NULL;
2550 2564          }
2551 2565          return ((sa_property_t)node);
2552 2566  }
2553 2567  
2554 2568  /*
2555 2569   * sa_get_next_property(property)
2556 2570   *
2557 2571   * Get the next property following the specified property. NULL if
2558 2572   * this was the last.
2559 2573   */
2560 2574  
2561 2575  sa_property_t
2562 2576  sa_get_next_property(sa_property_t property)
2563 2577  {
2564 2578          xmlNodePtr node;
2565 2579  
2566 2580          for (node = ((xmlNodePtr)property)->next; node != NULL;
2567 2581              node = node->next) {
2568 2582                  if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
2569 2583                          break;
2570 2584                  }
2571 2585          }
2572 2586          return ((sa_property_t)node);
2573 2587  }
2574 2588  
2575 2589  /*
2576 2590   * sa_set_share_description(share, content)
2577 2591   *
2578 2592   * Set the description of share to content.
2579 2593   */
2580 2594  
2581 2595  int
2582 2596  sa_set_share_description(sa_share_t share, char *content)
2583 2597  {
2584 2598          xmlNodePtr node;
2585 2599          sa_group_t group;
2586 2600          int ret = SA_OK;
2587 2601  
2588 2602          for (node = ((xmlNodePtr)share)->children; node != NULL;
2589 2603              node = node->next) {
2590 2604                  if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
2591 2605                          break;
2592 2606                  }
2593 2607          }
2594 2608          /* no existing description but want to add */
2595 2609          if (node == NULL && content != NULL) {
2596 2610                  /* add a description */
2597 2611                  node = _sa_set_share_description(share, content);
2598 2612          } else if (node != NULL && content != NULL) {
2599 2613                  /* update a description */
2600 2614                  xmlNodeSetContent(node, (xmlChar *)content);
2601 2615          } else if (node != NULL && content == NULL) {
2602 2616                  /* remove an existing description */
2603 2617                  xmlUnlinkNode(node);
2604 2618                  xmlFreeNode(node);
2605 2619          }
2606 2620          group = sa_get_parent_group(share);
2607 2621          if (group != NULL &&
2608 2622              sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
2609 2623                  sa_handle_impl_t impl_handle;
2610 2624                  impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2611 2625                  if (impl_handle != NULL) {
2612 2626                          ret = sa_commit_share(impl_handle->scfhandle, group,
2613 2627                              share);
2614 2628                  } else {
2615 2629                          ret = SA_SYSTEM_ERR;
2616 2630                  }
2617 2631          }
2618 2632          return (ret);
2619 2633  }
2620 2634  
2621 2635  /*
2622 2636   * fixproblemchars(string)
2623 2637   *
2624 2638   * don't want any newline or tab characters in the text since these
2625 2639   * could break display of data and legacy file formats.
2626 2640   */
2627 2641  static void
2628 2642  fixproblemchars(char *str)
2629 2643  {
2630 2644          int c;
2631 2645          for (c = *str; c != '\0'; c = *++str) {
2632 2646                  if (c == '\t' || c == '\n')
2633 2647                          *str = ' ';
2634 2648                  else if (c == '"')
2635 2649                          *str = '\'';
2636 2650          }
2637 2651  }
2638 2652  
2639 2653  /*
2640 2654   * sa_get_share_description(share)
2641 2655   *
2642 2656   * Return the description text for the specified share if it
2643 2657   * exists. NULL if no description exists.
2644 2658   */
2645 2659  
2646 2660  char *
2647 2661  sa_get_share_description(sa_share_t share)
2648 2662  {
2649 2663          xmlChar *description = NULL;
2650 2664          xmlNodePtr node;
2651 2665  
2652 2666          for (node = ((xmlNodePtr)share)->children; node != NULL;
2653 2667              node = node->next) {
2654 2668                  if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
2655 2669                          break;
2656 2670                  }
2657 2671          }
2658 2672          if (node != NULL) {
2659 2673                  description = xmlNodeGetContent(node);
2660 2674                  fixproblemchars((char *)description);
2661 2675          }
2662 2676          return ((char *)description);
2663 2677  }
2664 2678  
2665 2679  /*
2666 2680   * sa_free(share_description(description)
2667 2681   *
2668 2682   * Free the description string.
2669 2683   */
2670 2684  
2671 2685  void
2672 2686  sa_free_share_description(char *description)
2673 2687  {
2674 2688          xmlFree((xmlChar *)description);
2675 2689  }
2676 2690  
2677 2691  /*
2678 2692   * sa_create_optionset(group, proto)
2679 2693   *
2680 2694   * Create an optionset for the specified protocol in the specied
2681 2695   * group. This is manifested as a property group within SMF.
2682 2696   */
2683 2697  
2684 2698  sa_optionset_t
2685 2699  sa_create_optionset(sa_group_t group, char *proto)
2686 2700  {
2687 2701          sa_optionset_t optionset;
2688 2702          sa_group_t parent = group;
2689 2703          sa_share_t share = NULL;
2690 2704          int err = SA_OK;
2691 2705          char *id = NULL;
2692 2706  
2693 2707          optionset = sa_get_optionset(group, proto);
2694 2708          if (optionset != NULL) {
2695 2709                  /* can't have a duplicate protocol */
2696 2710                  optionset = NULL;
2697 2711          } else {
2698 2712                  /*
2699 2713                   * Account for resource names being slightly
2700 2714                   * different.
2701 2715                   */
2702 2716                  if (sa_is_share(group)) {
2703 2717                          /*
2704 2718                           * Transient shares do not have an "id" so not an
2705 2719                           * error to not find one.
2706 2720                           */
2707 2721                          id = sa_get_share_attr((sa_share_t)group, "id");
2708 2722                  } else if (sa_is_resource(group)) {
2709 2723                          share = sa_get_resource_parent(
2710 2724                              (sa_resource_t)group);
2711 2725                          id = sa_get_resource_attr(share, "id");
2712 2726  
2713 2727                          /* id can be NULL if the group is transient (ZFS) */
2714 2728                          if (id == NULL && sa_is_persistent(group))
2715 2729                                  err = SA_NO_MEMORY;
2716 2730                  }
2717 2731                  if (err == SA_NO_MEMORY) {
2718 2732                          /*
2719 2733                           * Couldn't get the id for the share or
2720 2734                           * resource. While this could be a
2721 2735                           * configuration issue, it is most likely an
2722 2736                           * out of memory. In any case, fail the create.
2723 2737                           */
2724 2738                          return (NULL);
2725 2739                  }
2726 2740  
2727 2741                  optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group,
2728 2742                      NULL, (xmlChar *)"optionset", NULL);
2729 2743                  /*
2730 2744                   * only put to repository if on a group and we were
2731 2745                   * able to create an optionset.
2732 2746                   */
2733 2747                  if (optionset != NULL) {
2734 2748                          char oname[SA_STRSIZE];
2735 2749                          char *groupname;
2736 2750  
2737 2751                          /*
2738 2752                           * Need to get parent group in all cases, but also get
2739 2753                           * the share if this is a resource.
2740 2754                           */
2741 2755                          if (sa_is_share(group)) {
2742 2756                                  parent = sa_get_parent_group((sa_share_t)group);
2743 2757                          } else if (sa_is_resource(group)) {
2744 2758                                  share = sa_get_resource_parent(
2745 2759                                      (sa_resource_t)group);
2746 2760                                  parent = sa_get_parent_group(share);
2747 2761                          }
2748 2762  
2749 2763                          sa_set_optionset_attr(optionset, "type", proto);
2750 2764  
2751 2765                          (void) sa_optionset_name(optionset, oname,
2752 2766                              sizeof (oname), id);
2753 2767                          groupname = sa_get_group_attr(parent, "name");
2754 2768                          if (groupname != NULL && sa_is_persistent(group)) {
2755 2769                                  sa_handle_impl_t impl_handle;
2756 2770                                  impl_handle =
2757 2771                                      (sa_handle_impl_t)sa_find_group_handle(
2758 2772                                      group);
2759 2773                                  assert(impl_handle != NULL);
2760 2774                                  if (impl_handle != NULL) {
2761 2775                                          (void) sa_get_instance(
2762 2776                                              impl_handle->scfhandle, groupname);
2763 2777                                          (void) sa_create_pgroup(
2764 2778                                              impl_handle->scfhandle, oname);
2765 2779                                  }
2766 2780                          }
2767 2781                          if (groupname != NULL)
2768 2782                                  sa_free_attr_string(groupname);
2769 2783                  }
2770 2784          }
2771 2785  
2772 2786          if (id != NULL)
2773 2787                  sa_free_attr_string(id);
2774 2788          return (optionset);
2775 2789  }
2776 2790  
2777 2791  /*
2778 2792   * sa_get_property_parent(property)
2779 2793   *
2780 2794   * Given a property, return the object it is a property of. This will
2781 2795   * be an optionset of some type.
2782 2796   */
2783 2797  
2784 2798  static sa_optionset_t
2785 2799  sa_get_property_parent(sa_property_t property)
2786 2800  {
2787 2801          xmlNodePtr node = NULL;
2788 2802  
2789 2803          if (property != NULL)
2790 2804                  node = ((xmlNodePtr)property)->parent;
2791 2805          return ((sa_optionset_t)node);
2792 2806  }
2793 2807  
2794 2808  /*
2795 2809   * sa_get_optionset_parent(optionset)
2796 2810   *
2797 2811   * Return the parent of the specified optionset. This could be a group
2798 2812   * or a share.
2799 2813   */
2800 2814  
2801 2815  static sa_group_t
2802 2816  sa_get_optionset_parent(sa_optionset_t optionset)
2803 2817  {
2804 2818          xmlNodePtr node = NULL;
2805 2819  
2806 2820          if (optionset != NULL)
2807 2821                  node = ((xmlNodePtr)optionset)->parent;
2808 2822          return ((sa_group_t)node);
2809 2823  }
2810 2824  
2811 2825  /*
2812 2826   * zfs_needs_update(share)
2813 2827   *
2814 2828   * In order to avoid making multiple updates to a ZFS share when
2815 2829   * setting properties, the share attribute "changed" will be set to
2816 2830   * true when a property is added or modified.  When done adding
2817 2831   * properties, we can then detect that an update is needed.  We then
2818 2832   * clear the state here to detect additional changes.
2819 2833   */
2820 2834  
2821 2835  static int
2822 2836  zfs_needs_update(sa_share_t share)
2823 2837  {
2824 2838          char *attr;
2825 2839          int result = 0;
2826 2840  
2827 2841          attr = sa_get_share_attr(share, "changed");
2828 2842          if (attr != NULL) {
2829 2843                  sa_free_attr_string(attr);
2830 2844                  result = 1;
2831 2845          }
2832 2846          set_node_attr((void *)share, "changed", NULL);
2833 2847          return (result);
2834 2848  }
2835 2849  
2836 2850  /*
2837 2851   * zfs_set_update(share)
2838 2852   *
2839 2853   * Set the changed attribute of the share to true.
2840 2854   */
2841 2855  
2842 2856  static void
2843 2857  zfs_set_update(sa_share_t share)
2844 2858  {
2845 2859          set_node_attr((void *)share, "changed", "true");
2846 2860  }
2847 2861  
2848 2862  /*
2849 2863   * sa_commit_properties(optionset, clear)
2850 2864   *
2851 2865   * Check if SMF or ZFS config and either update or abort the pending
2852 2866   * changes.
2853 2867   */
2854 2868  
2855 2869  int
2856 2870  sa_commit_properties(sa_optionset_t optionset, int clear)
2857 2871  {
2858 2872          sa_group_t group;
2859 2873          sa_group_t parent;
2860 2874          int zfs = 0;
2861 2875          int needsupdate = 0;
2862 2876          int ret = SA_OK;
2863 2877          sa_handle_impl_t impl_handle;
2864 2878  
2865 2879          group = sa_get_optionset_parent(optionset);
2866 2880          if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) {
2867 2881                  /* only update ZFS if on a share */
2868 2882                  parent = sa_get_parent_group(group);
2869 2883                  zfs++;
2870 2884                  if (parent != NULL && is_zfs_group(parent))
2871 2885                          needsupdate = zfs_needs_update(group);
2872 2886                  else
2873 2887                          zfs = 0;
2874 2888          }
2875 2889          if (zfs) {
2876 2890                  if (!clear && needsupdate)
2877 2891                          ret = sa_zfs_update((sa_share_t)group);
2878 2892          } else {
2879 2893                  impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2880 2894                  if (impl_handle != NULL) {
2881 2895                          if (clear) {
2882 2896                                  (void) sa_abort_transaction(
2883 2897                                      impl_handle->scfhandle);
2884 2898                          } else {
2885 2899                                  ret = sa_end_transaction(
2886 2900                                      impl_handle->scfhandle, impl_handle);
2887 2901                          }
2888 2902                  } else {
2889 2903                          ret = SA_SYSTEM_ERR;
2890 2904                  }
2891 2905          }
2892 2906          return (ret);
2893 2907  }
2894 2908  
2895 2909  /*
2896 2910   * sa_destroy_optionset(optionset)
2897 2911   *
2898 2912   * Remove the optionset from its group. Update the repository to
2899 2913   * reflect this change.
2900 2914   */
2901 2915  
2902 2916  int
2903 2917  sa_destroy_optionset(sa_optionset_t optionset)
2904 2918  {
2905 2919          char name[SA_STRSIZE];
2906 2920          int len;
2907 2921          int ret;
2908 2922          char *id = NULL;
2909 2923          sa_group_t group;
2910 2924          int ispersist = 1;
2911 2925  
2912 2926          /* now delete the prop group */
2913 2927          group = sa_get_optionset_parent(optionset);
2914 2928          if (group != NULL) {
2915 2929                  if (sa_is_resource(group)) {
2916 2930                          sa_resource_t resource = group;
2917 2931                          sa_share_t share = sa_get_resource_parent(resource);
2918 2932                          group = sa_get_parent_group(share);
2919 2933                          id = sa_get_share_attr(share, "id");
2920 2934                  } else if (sa_is_share(group)) {
2921 2935                          id = sa_get_share_attr((sa_share_t)group, "id");
2922 2936                  }
2923 2937                  ispersist = sa_is_persistent(group);
2924 2938          }
2925 2939          if (ispersist) {
2926 2940                  sa_handle_impl_t impl_handle;
2927 2941                  len = sa_optionset_name(optionset, name, sizeof (name), id);
2928 2942                  impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
2929 2943                  if (impl_handle != NULL) {
2930 2944                          if (len > 0) {
2931 2945                                  ret = sa_delete_pgroup(impl_handle->scfhandle,
2932 2946                                      name);
2933 2947                          }
2934 2948                  } else {
2935 2949                          ret = SA_SYSTEM_ERR;
2936 2950                  }
2937 2951          }
2938 2952          xmlUnlinkNode((xmlNodePtr)optionset);
2939 2953          xmlFreeNode((xmlNodePtr)optionset);
2940 2954          if (id != NULL)
2941 2955                  sa_free_attr_string(id);
2942 2956          return (ret);
2943 2957  }
2944 2958  
2945 2959  /* private to the implementation */
2946 2960  int
2947 2961  _sa_remove_optionset(sa_optionset_t optionset)
2948 2962  {
2949 2963          int ret = SA_OK;
2950 2964  
2951 2965          xmlUnlinkNode((xmlNodePtr)optionset);
2952 2966          xmlFreeNode((xmlNodePtr)optionset);
2953 2967          return (ret);
2954 2968  }
2955 2969  
2956 2970  /*
2957 2971   * sa_create_security(group, sectype, proto)
2958 2972   *
2959 2973   * Create a security optionset (one that has a type name and a
2960 2974   * proto). Security is left over from a pure NFS implementation. The
2961 2975   * naming will change in the future when the API is released.
2962 2976   */
2963 2977  sa_security_t
2964 2978  sa_create_security(sa_group_t group, char *sectype, char *proto)
2965 2979  {
2966 2980          sa_security_t security;
2967 2981          char *id = NULL;
2968 2982          sa_group_t parent;
2969 2983          char *groupname = NULL;
2970 2984  
2971 2985          if (group != NULL && sa_is_share(group)) {
2972 2986                  id = sa_get_share_attr((sa_share_t)group, "id");
2973 2987                  parent = sa_get_parent_group(group);
2974 2988                  if (parent != NULL)
2975 2989                          groupname = sa_get_group_attr(parent, "name");
2976 2990          } else if (group != NULL) {
2977 2991                  groupname = sa_get_group_attr(group, "name");
2978 2992          }
2979 2993  
2980 2994          security = sa_get_security(group, sectype, proto);
2981 2995          if (security != NULL) {
2982 2996                  /* can't have a duplicate security option */
2983 2997                  security = NULL;
2984 2998          } else {
2985 2999                  security = (sa_security_t)xmlNewChild((xmlNodePtr)group,
2986 3000                      NULL, (xmlChar *)"security", NULL);
2987 3001                  if (security != NULL) {
2988 3002                          char oname[SA_STRSIZE];
2989 3003                          sa_set_security_attr(security, "type", proto);
2990 3004  
2991 3005                          sa_set_security_attr(security, "sectype", sectype);
2992 3006                          (void) sa_security_name(security, oname,
2993 3007                              sizeof (oname), id);
2994 3008                          if (groupname != NULL && sa_is_persistent(group)) {
2995 3009                                  sa_handle_impl_t impl_handle;
2996 3010                                  impl_handle =
2997 3011                                      (sa_handle_impl_t)sa_find_group_handle(
2998 3012                                      group);
2999 3013                                  if (impl_handle != NULL) {
3000 3014                                          (void) sa_get_instance(
3001 3015                                              impl_handle->scfhandle, groupname);
3002 3016                                          (void) sa_create_pgroup(
3003 3017                                              impl_handle->scfhandle, oname);
3004 3018                                  }
3005 3019                          }
3006 3020                  }
3007 3021          }
3008 3022          if (id != NULL)
3009 3023                  sa_free_attr_string(id);
3010 3024          if (groupname != NULL)
3011 3025                  sa_free_attr_string(groupname);
3012 3026          return (security);
3013 3027  }
3014 3028  
3015 3029  /*
3016 3030   * sa_destroy_security(security)
3017 3031   *
3018 3032   * Remove the specified optionset from the document and the
3019 3033   * configuration.
3020 3034   */
3021 3035  
3022 3036  int
3023 3037  sa_destroy_security(sa_security_t security)
3024 3038  {
3025 3039          char name[SA_STRSIZE];
3026 3040          int len;
3027 3041          int ret = SA_OK;
3028 3042          char *id = NULL;
3029 3043          sa_group_t group;
3030 3044          int iszfs = 0;
3031 3045          int ispersist = 1;
3032 3046  
3033 3047          group = sa_get_optionset_parent(security);
3034 3048  
3035 3049          if (group != NULL)
3036 3050                  iszfs = sa_group_is_zfs(group);
3037 3051  
3038 3052          if (group != NULL && !iszfs) {
3039 3053                  if (sa_is_share(group))
3040 3054                          ispersist = sa_is_persistent(group);
3041 3055                  id = sa_get_share_attr((sa_share_t)group, "id");
3042 3056          }
3043 3057          if (ispersist) {
3044 3058                  len = sa_security_name(security, name, sizeof (name), id);
3045 3059                  if (!iszfs && len > 0) {
3046 3060                          sa_handle_impl_t impl_handle;
3047 3061                          impl_handle =
3048 3062                              (sa_handle_impl_t)sa_find_group_handle(group);
3049 3063                          if (impl_handle != NULL) {
3050 3064                                  ret = sa_delete_pgroup(impl_handle->scfhandle,
3051 3065                                      name);
3052 3066                          } else {
3053 3067                                  ret = SA_SYSTEM_ERR;
3054 3068                          }
3055 3069                  }
3056 3070          }
3057 3071          xmlUnlinkNode((xmlNodePtr)security);
3058 3072          xmlFreeNode((xmlNodePtr)security);
3059 3073          if (iszfs)
3060 3074                  ret = sa_zfs_update(group);
3061 3075          if (id != NULL)
3062 3076                  sa_free_attr_string(id);
3063 3077          return (ret);
3064 3078  }
3065 3079  
3066 3080  /*
3067 3081   * sa_get_security_attr(optionset, tag)
3068 3082   *
3069 3083   * Return the specified attribute value from the optionset.
3070 3084   */
3071 3085  
3072 3086  char *
3073 3087  sa_get_security_attr(sa_property_t optionset, char *tag)
3074 3088  {
3075 3089          return (get_node_attr((void *)optionset, tag));
3076 3090  
3077 3091  }
3078 3092  
3079 3093  /*
3080 3094   * sa_set_security_attr(optionset, tag, value)
3081 3095   *
3082 3096   * Set the optioset attribute specied by tag to the specified value.
3083 3097   */
3084 3098  
3085 3099  void
3086 3100  sa_set_security_attr(sa_group_t optionset, char *tag, char *value)
3087 3101  {
3088 3102          set_node_attr((void *)optionset, tag, value);
3089 3103  }
3090 3104  
3091 3105  /*
3092 3106   * is_nodetype(node, type)
3093 3107   *
3094 3108   * Check to see if node is of the type specified.
3095 3109   */
3096 3110  
3097 3111  static int
3098 3112  is_nodetype(void *node, char *type)
3099 3113  {
3100 3114          return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0);
3101 3115  }
3102 3116  
3103 3117  /*
3104 3118   * add_or_update()
3105 3119   *
3106 3120   * Add or update a property. Pulled out of sa_set_prop_by_prop for
3107 3121   * readability.
3108 3122   */
3109 3123  static int
3110 3124  add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value,
3111 3125      scf_transaction_entry_t *entry, char *name, char *valstr)
3112 3126  {
3113 3127          int ret = SA_SYSTEM_ERR;
3114 3128  
3115 3129          if (value != NULL) {
3116 3130                  if (type == SA_PROP_OP_ADD)
3117 3131                          ret = scf_transaction_property_new(scf_handle->trans,
3118 3132                              entry, name, SCF_TYPE_ASTRING);
3119 3133                  else
3120 3134                          ret = scf_transaction_property_change(scf_handle->trans,
3121 3135                              entry, name, SCF_TYPE_ASTRING);
3122 3136                  if (ret == 0) {
3123 3137                          ret = scf_value_set_astring(value, valstr);
3124 3138                          if (ret == 0)
3125 3139                                  ret = scf_entry_add_value(entry, value);
3126 3140                          if (ret == 0)
3127 3141                                  return (ret);
3128 3142                          scf_value_destroy(value);
3129 3143                  } else {
3130 3144                          scf_entry_destroy(entry);
3131 3145                  }
3132 3146          }
3133 3147          return (SA_SYSTEM_ERR);
3134 3148  }
3135 3149  
3136 3150  /*
3137 3151   * sa_set_prop_by_prop(optionset, group, prop, type)
3138 3152   *
3139 3153   * Add/remove/update the specified property prop into the optionset or
3140 3154   * share. If a share, sort out which property group based on GUID. In
3141 3155   * all cases, the appropriate transaction is set (or ZFS share is
3142 3156   * marked as needing an update)
3143 3157   */
3144 3158  
3145 3159  static int
3146 3160  sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
3147 3161      sa_property_t prop, int type)
3148 3162  {
3149 3163          char *name;
3150 3164          char *valstr;
3151 3165          int ret = SA_OK;
3152 3166          scf_transaction_entry_t *entry;
3153 3167          scf_value_t *value;
3154 3168          int opttype; /* 1 == optionset, 0 == security */
3155 3169          char *id = NULL;
3156 3170          int iszfs = 0;
3157 3171          sa_group_t parent = NULL;
3158 3172          sa_share_t share = NULL;
3159 3173          sa_handle_impl_t impl_handle;
3160 3174          scfutilhandle_t  *scf_handle;
3161 3175  
3162 3176          if (!sa_is_persistent(group)) {
3163 3177                  /*
3164 3178                   * if the group/share is not persistent we don't need
3165 3179                   * to do anything here
3166 3180                   */
3167 3181                  return (SA_OK);
3168 3182          }
3169 3183          impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
3170 3184          if (impl_handle == NULL || impl_handle->scfhandle == NULL)
3171 3185                  return (SA_SYSTEM_ERR);
3172 3186          scf_handle = impl_handle->scfhandle;
3173 3187          name = sa_get_property_attr(prop, "type");
3174 3188          valstr = sa_get_property_attr(prop, "value");
3175 3189          entry = scf_entry_create(scf_handle->handle);
3176 3190          opttype = is_nodetype((void *)optionset, "optionset");
3177 3191  
3178 3192          /*
3179 3193           * Check for share vs. resource since they need slightly
3180 3194           * different treatment given the hierarchy.
3181 3195           */
3182 3196          if (valstr != NULL && entry != NULL) {
3183 3197                  if (sa_is_share(group)) {
3184 3198                          parent = sa_get_parent_group(group);
3185 3199                          share = (sa_share_t)group;
3186 3200                          if (parent != NULL)
3187 3201                                  iszfs = is_zfs_group(parent);
3188 3202                  } else if (sa_is_resource(group)) {
3189 3203                          share = sa_get_parent_group(group);
3190 3204                          if (share != NULL)
3191 3205                                  parent = sa_get_parent_group(share);
3192 3206                  } else {
3193 3207                          iszfs = is_zfs_group(group);
3194 3208                  }
3195 3209                  if (!iszfs) {
3196 3210                          if (scf_handle->trans == NULL) {
3197 3211                                  char oname[SA_STRSIZE];
3198 3212                                  char *groupname = NULL;
3199 3213                                  if (share != NULL) {
3200 3214                                          if (parent != NULL)
3201 3215                                                  groupname =
3202 3216                                                      sa_get_group_attr(parent,
3203 3217                                                      "name");
3204 3218                                          id = sa_get_share_attr(
3205 3219                                              (sa_share_t)share, "id");
3206 3220                                  } else {
3207 3221                                          groupname = sa_get_group_attr(group,
3208 3222                                              "name");
3209 3223                                  }
3210 3224                                  if (groupname != NULL) {
3211 3225                                          ret = sa_get_instance(scf_handle,
3212 3226                                              groupname);
3213 3227                                          sa_free_attr_string(groupname);
3214 3228                                  }
3215 3229                                  if (opttype)
3216 3230                                          (void) sa_optionset_name(optionset,
3217 3231                                              oname, sizeof (oname), id);
3218 3232                                  else
3219 3233                                          (void) sa_security_name(optionset,
3220 3234                                              oname, sizeof (oname), id);
3221 3235                                  ret = sa_start_transaction(scf_handle, oname);
3222 3236                                  if (id != NULL)
3223 3237                                          sa_free_attr_string(id);
3224 3238                          }
3225 3239                          if (ret == SA_OK) {
3226 3240                                  switch (type) {
3227 3241                                  case SA_PROP_OP_REMOVE:
3228 3242                                          ret = scf_transaction_property_delete(
3229 3243                                              scf_handle->trans, entry, name);
3230 3244                                          break;
3231 3245                                  case SA_PROP_OP_ADD:
3232 3246                                  case SA_PROP_OP_UPDATE:
3233 3247                                          value = scf_value_create(
3234 3248                                              scf_handle->handle);
3235 3249                                          ret = add_or_update(scf_handle, type,
3236 3250                                              value, entry, name, valstr);
3237 3251                                          break;
3238 3252                                  }
3239 3253                          }
3240 3254                  } else {
3241 3255                          /*
3242 3256                           * ZFS update. The calling function would have updated
3243 3257                           * the internal XML structure. Just need to flag it as
3244 3258                           * changed for ZFS.
3245 3259                           */
3246 3260                          zfs_set_update((sa_share_t)group);
3247 3261                  }
3248 3262          }
3249 3263  
3250 3264          if (name != NULL)
3251 3265                  sa_free_attr_string(name);
3252 3266          if (valstr != NULL)
3253 3267                  sa_free_attr_string(valstr);
3254 3268          else if (entry != NULL)
3255 3269                  scf_entry_destroy(entry);
3256 3270  
3257 3271          if (ret == -1)
3258 3272                  ret = SA_SYSTEM_ERR;
3259 3273  
3260 3274          return (ret);
3261 3275  }
3262 3276  
3263 3277  /*
3264 3278   * sa_create_section(name, value)
3265 3279   *
3266 3280   * Create a new section with the specified name and extra data.
3267 3281   */
3268 3282  
3269 3283  sa_property_t
3270 3284  sa_create_section(char *name, char *extra)
3271 3285  {
3272 3286          xmlNodePtr node;
3273 3287  
3274 3288          node = xmlNewNode(NULL, (xmlChar *)"section");
3275 3289          if (node != NULL) {
3276 3290                  if (name != NULL)
3277 3291                          (void) xmlSetProp(node, (xmlChar *)"name",
3278 3292                              (xmlChar *)name);
3279 3293                  if (extra != NULL)
3280 3294                          (void) xmlSetProp(node, (xmlChar *)"extra",
3281 3295                              (xmlChar *)extra);
3282 3296          }
3283 3297          return ((sa_property_t)node);
3284 3298  }
3285 3299  
3286 3300  void
3287 3301  sa_set_section_attr(sa_property_t sect, char *name, char *value)
3288 3302  {
3289 3303          (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value);
3290 3304  }
3291 3305  
3292 3306  /*
3293 3307   * sa_create_property(section, name, value)
3294 3308   *
3295 3309   * Create a new property with the specified name and value.
3296 3310   */
3297 3311  
3298 3312  sa_property_t
3299 3313  sa_create_property(char *name, char *value)
3300 3314  {
3301 3315          xmlNodePtr node;
3302 3316  
3303 3317          node = xmlNewNode(NULL, (xmlChar *)"option");
3304 3318          if (node != NULL) {
3305 3319                  (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name);
3306 3320                  (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value);
3307 3321          }
3308 3322          return ((sa_property_t)node);
3309 3323  }
3310 3324  
3311 3325  /*
3312 3326   * sa_add_property(object, property)
3313 3327   *
3314 3328   * Add the specified property to the object. Issue the appropriate
3315 3329   * transaction or mark a ZFS object as needing an update.
3316 3330   */
3317 3331  
3318 3332  int
3319 3333  sa_add_property(void *object, sa_property_t property)
3320 3334  {
3321 3335          int ret = SA_OK;
3322 3336          sa_group_t parent;
3323 3337          sa_group_t group;
3324 3338          char *proto;
3325 3339  
3326 3340          if (property != NULL) {
3327 3341                  sa_handle_t handle;
3328 3342                  handle = sa_find_group_handle((sa_group_t)object);
3329 3343                  /* It is legitimate to not find a handle */
3330 3344                  proto = sa_get_optionset_attr(object, "type");
3331 3345                  if ((ret = sa_valid_property(handle, object, proto,
3332 3346                      property)) == SA_OK) {
3333 3347                          property = (sa_property_t)xmlAddChild(
3334 3348                              (xmlNodePtr)object, (xmlNodePtr)property);
3335 3349                  } else {
3336 3350                          if (proto != NULL)
3337 3351                                  sa_free_attr_string(proto);
3338 3352                          return (ret);
3339 3353                  }
3340 3354                  if (proto != NULL)
3341 3355                          sa_free_attr_string(proto);
3342 3356          }
3343 3357  
3344 3358  
3345 3359          parent = sa_get_parent_group(object);
3346 3360          if (!sa_is_persistent(parent))
3347 3361                  return (ret);
3348 3362  
3349 3363          if (sa_is_resource(parent)) {
3350 3364                  /*
3351 3365                   * Resources are children of share.  Need to go up two
3352 3366                   * levels to find the group but the parent needs to be
3353 3367                   * the share at this point in order to get the "id".
3354 3368                   */
3355 3369                  parent = sa_get_parent_group(parent);
3356 3370                  group = sa_get_parent_group(parent);
3357 3371          } else if (sa_is_share(parent)) {
3358 3372                  group = sa_get_parent_group(parent);
3359 3373          } else {
3360 3374                  group = parent;
3361 3375          }
3362 3376  
3363 3377          if (property == NULL) {
3364 3378                  ret = SA_NO_MEMORY;
3365 3379          } else {
3366 3380                  char oname[SA_STRSIZE];
3367 3381  
3368 3382                  if (!is_zfs_group(group)) {
3369 3383                          char *id = NULL;
3370 3384                          sa_handle_impl_t impl_handle;
3371 3385                          scfutilhandle_t  *scf_handle;
3372 3386  
3373 3387                          impl_handle = (sa_handle_impl_t)sa_find_group_handle(
3374 3388                              group);
3375 3389                          if (impl_handle == NULL ||
3376 3390                              impl_handle->scfhandle == NULL)
3377 3391                                  ret = SA_SYSTEM_ERR;
3378 3392                          if (ret == SA_OK) {
3379 3393                                  scf_handle = impl_handle->scfhandle;
3380 3394                                  if (sa_is_share((sa_group_t)parent)) {
3381 3395                                          id = sa_get_share_attr(
3382 3396                                              (sa_share_t)parent, "id");
3383 3397                                  }
3384 3398                                  if (scf_handle->trans == NULL) {
3385 3399                                          if (is_nodetype(object, "optionset")) {
3386 3400                                                  (void) sa_optionset_name(
3387 3401                                                      (sa_optionset_t)object,
3388 3402                                                      oname, sizeof (oname), id);
3389 3403                                          } else {
3390 3404                                                  (void) sa_security_name(
3391 3405                                                      (sa_optionset_t)object,
3392 3406                                                      oname, sizeof (oname), id);
3393 3407                                          }
3394 3408                                          ret = sa_start_transaction(scf_handle,
3395 3409                                              oname);
3396 3410                                  }
3397 3411                                  if (ret == SA_OK) {
3398 3412                                          char *name;
3399 3413                                          char *value;
3400 3414                                          name = sa_get_property_attr(property,
3401 3415                                              "type");
3402 3416                                          value = sa_get_property_attr(property,
3403 3417                                              "value");
3404 3418                                          if (name != NULL && value != NULL) {
3405 3419                                                  if (scf_handle->scf_state ==
3406 3420                                                      SCH_STATE_INIT) {
3407 3421                                                          ret = sa_set_property(
3408 3422                                                              scf_handle, name,
3409 3423                                                              value);
3410 3424                                                  }
3411 3425                                          } else {
3412 3426                                                  ret = SA_CONFIG_ERR;
3413 3427                                          }
3414 3428                                          if (name != NULL)
3415 3429                                                  sa_free_attr_string(
3416 3430                                                      name);
3417 3431                                          if (value != NULL)
3418 3432                                                  sa_free_attr_string(value);
3419 3433                                  }
3420 3434                                  if (id != NULL)
3421 3435                                          sa_free_attr_string(id);
3422 3436                          }
3423 3437                  } else {
3424 3438                          /*
3425 3439                           * ZFS is a special case. We do want
3426 3440                           * to allow editing property/security
3427 3441                           * lists since we can have a better
3428 3442                           * syntax and we also want to keep
3429 3443                           * things consistent when possible.
3430 3444                           *
3431 3445                           * Right now, we defer until the
3432 3446                           * sa_commit_properties so we can get
3433 3447                           * them all at once. We do need to
3434 3448                           * mark the share as "changed"
3435 3449                           */
3436 3450                          zfs_set_update((sa_share_t)parent);
3437 3451                  }
3438 3452          }
3439 3453          return (ret);
3440 3454  }
3441 3455  
3442 3456  /*
3443 3457   * sa_remove_property(property)
3444 3458   *
3445 3459   * Remove the specied property from its containing object. Update the
3446 3460   * repository as appropriate.
3447 3461   */
3448 3462  
3449 3463  int
3450 3464  sa_remove_property(sa_property_t property)
3451 3465  {
3452 3466          int ret = SA_OK;
3453 3467  
3454 3468          if (property != NULL) {
3455 3469                  sa_optionset_t optionset;
3456 3470                  sa_group_t group;
3457 3471                  optionset = sa_get_property_parent(property);
3458 3472                  if (optionset != NULL) {
3459 3473                          group = sa_get_optionset_parent(optionset);
3460 3474                          if (group != NULL) {
3461 3475                                  ret = sa_set_prop_by_prop(optionset, group,
3462 3476                                      property, SA_PROP_OP_REMOVE);
3463 3477                          }
3464 3478                  }
3465 3479                  xmlUnlinkNode((xmlNodePtr)property);
3466 3480                  xmlFreeNode((xmlNodePtr)property);
3467 3481          } else {
3468 3482                  ret = SA_NO_SUCH_PROP;
3469 3483          }
3470 3484          return (ret);
3471 3485  }
3472 3486  
3473 3487  /*
3474 3488   * sa_update_property(property, value)
3475 3489   *
3476 3490   * Update the specified property to the new value.  If value is NULL,
3477 3491   * we currently treat this as a remove.
3478 3492   */
3479 3493  
3480 3494  int
3481 3495  sa_update_property(sa_property_t property, char *value)
3482 3496  {
3483 3497          int ret = SA_OK;
3484 3498          if (value == NULL) {
3485 3499                  return (sa_remove_property(property));
3486 3500          } else {
3487 3501                  sa_optionset_t optionset;
3488 3502                  sa_group_t group;
3489 3503                  set_node_attr((void *)property, "value", value);
3490 3504                  optionset = sa_get_property_parent(property);
3491 3505                  if (optionset != NULL) {
3492 3506                          group = sa_get_optionset_parent(optionset);
3493 3507                          if (group != NULL) {
3494 3508                                  ret = sa_set_prop_by_prop(optionset, group,
3495 3509                                      property, SA_PROP_OP_UPDATE);
3496 3510                          }
3497 3511                  } else {
3498 3512                          ret = SA_NO_SUCH_PROP;
3499 3513                  }
3500 3514          }
3501 3515          return (ret);
3502 3516  }
3503 3517  
3504 3518  /*
3505 3519   * sa_get_protocol_section(propset, prop)
3506 3520   *
3507 3521   * Get the specified protocol specific section. These are global to
3508 3522   * the protocol and not specific to a group or share.
3509 3523   */
3510 3524  
3511 3525  sa_protocol_properties_t
3512 3526  sa_get_protocol_section(sa_protocol_properties_t propset, char *section)
3513 3527  {
3514 3528          xmlNodePtr node = (xmlNodePtr)propset;
3515 3529          xmlChar *value = NULL;
3516 3530          char *proto;
3517 3531  
3518 3532          proto = sa_get_optionset_attr(propset, "type");
3519 3533          if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
3520 3534                  if (proto != NULL)
3521 3535                          sa_free_attr_string(proto);
3522 3536                  return (propset);
3523 3537          }
3524 3538  
3525 3539          for (node = node->children; node != NULL;
3526 3540              node = node->next) {
3527 3541                  if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) {
3528 3542                          if (section == NULL)
3529 3543                                  break;
3530 3544                          value = xmlGetProp(node, (xmlChar *)"name");
3531 3545                          if (value != NULL &&
3532 3546                              xmlStrcasecmp(value, (xmlChar *)section) == 0) {
3533 3547                                  break;
3534 3548                          }
3535 3549                          if (value != NULL) {
3536 3550                                  xmlFree(value);
3537 3551                                  value = NULL;
3538 3552                          }
3539 3553                  }
3540 3554          }
3541 3555          if (value != NULL)
3542 3556                  xmlFree(value);
3543 3557          if (proto != NULL)
3544 3558                  sa_free_attr_string(proto);
3545 3559          if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) {
3546 3560                  /*
3547 3561                   * avoid a non option node -- it is possible to be a
3548 3562                   * text node
3549 3563                   */
3550 3564                  node = NULL;
3551 3565          }
3552 3566          return ((sa_protocol_properties_t)node);
3553 3567  }
3554 3568  
3555 3569  /*
3556 3570   * sa_get_next_protocol_section(prop, find)
3557 3571   *
3558 3572   * Get the next protocol specific section in the list.
3559 3573   */
3560 3574  
3561 3575  sa_property_t
3562 3576  sa_get_next_protocol_section(sa_property_t prop, char *find)
3563 3577  {
3564 3578          xmlNodePtr node;
3565 3579          xmlChar *value = NULL;
3566 3580          char *proto;
3567 3581  
3568 3582          proto = sa_get_optionset_attr(prop, "type");
3569 3583          if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
3570 3584                  if (proto != NULL)
3571 3585                          sa_free_attr_string(proto);
3572 3586                  return ((sa_property_t)NULL);
3573 3587          }
3574 3588  
3575 3589          for (node = ((xmlNodePtr)prop)->next; node != NULL;
3576 3590              node = node->next) {
3577 3591                  if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) {
3578 3592                          if (find == NULL)
3579 3593                                  break;
3580 3594                          value = xmlGetProp(node, (xmlChar *)"name");
3581 3595                          if (value != NULL &&
3582 3596                              xmlStrcasecmp(value, (xmlChar *)find) == 0) {
3583 3597                                  break;
3584 3598                          }
3585 3599                          if (value != NULL) {
3586 3600                                  xmlFree(value);
3587 3601                                  value = NULL;
3588 3602                          }
3589 3603  
3590 3604                  }
3591 3605          }
3592 3606          if (value != NULL)
3593 3607                  xmlFree(value);
3594 3608          if (proto != NULL)
3595 3609                  sa_free_attr_string(proto);
3596 3610          return ((sa_property_t)node);
3597 3611  }
3598 3612  
3599 3613  /*
3600 3614   * sa_get_protocol_property(propset, prop)
3601 3615   *
3602 3616   * Get the specified protocol specific property. These are global to
3603 3617   * the protocol and not specific to a group or share.
3604 3618   */
3605 3619  
3606 3620  sa_property_t
3607 3621  sa_get_protocol_property(sa_protocol_properties_t propset, char *prop)
3608 3622  {
3609 3623          xmlNodePtr node = (xmlNodePtr)propset;
3610 3624          xmlChar *value = NULL;
3611 3625  
3612 3626          if (propset == NULL)
3613 3627                  return (NULL);
3614 3628  
3615 3629          for (node = node->children; node != NULL;
3616 3630              node = node->next) {
3617 3631                  if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
3618 3632                          if (prop == NULL)
3619 3633                                  break;
3620 3634                          value = xmlGetProp(node, (xmlChar *)"type");
3621 3635                          if (value != NULL &&
3622 3636                              xmlStrcasecmp(value, (xmlChar *)prop) == 0) {
3623 3637                                  break;
3624 3638                          }
3625 3639                          if (value != NULL) {
3626 3640                                  xmlFree(value);
3627 3641                                  value = NULL;
3628 3642                          }
3629 3643                  }
3630 3644          }
3631 3645          if (value != NULL)
3632 3646                  xmlFree(value);
3633 3647          if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) {
3634 3648                  /*
3635 3649                   * avoid a non option node -- it is possible to be a
3636 3650                   * text node
3637 3651                   */
3638 3652                  node = NULL;
3639 3653          }
3640 3654          return ((sa_property_t)node);
3641 3655  }
3642 3656  
3643 3657  /*
3644 3658   * sa_get_next_protocol_property(prop)
3645 3659   *
3646 3660   * Get the next protocol specific property in the list.
3647 3661   */
3648 3662  
3649 3663  sa_property_t
3650 3664  sa_get_next_protocol_property(sa_property_t prop, char *find)
3651 3665  {
3652 3666          xmlNodePtr node;
3653 3667          xmlChar *value = NULL;
3654 3668  
3655 3669          for (node = ((xmlNodePtr)prop)->next; node != NULL;
3656 3670              node = node->next) {
3657 3671                  if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
3658 3672                          if (find == NULL)
3659 3673                                  break;
3660 3674                          value = xmlGetProp(node, (xmlChar *)"type");
3661 3675                          if (value != NULL &&
3662 3676                              xmlStrcasecmp(value, (xmlChar *)find) == 0) {
3663 3677                                  break;
3664 3678                          }
3665 3679                          if (value != NULL) {
3666 3680                                  xmlFree(value);
3667 3681                                  value = NULL;
3668 3682                          }
3669 3683  
3670 3684                  }
3671 3685          }
3672 3686          if (value != NULL)
3673 3687                  xmlFree(value);
3674 3688          return ((sa_property_t)node);
3675 3689  }
3676 3690  
3677 3691  /*
3678 3692   * sa_set_protocol_property(prop, value)
3679 3693   *
3680 3694   * Set the specified property to have the new value.  The protocol
3681 3695   * specific plugin will then be called to update the property.
3682 3696   */
3683 3697  
3684 3698  int
3685 3699  sa_set_protocol_property(sa_property_t prop, char *section, char *value)
3686 3700  {
3687 3701          sa_protocol_properties_t propset;
3688 3702          char *proto;
3689 3703          int ret = SA_INVALID_PROTOCOL;
3690 3704  
3691 3705          propset = ((xmlNodePtr)prop)->parent;
3692 3706          if (propset != NULL) {
3693 3707                  proto = sa_get_optionset_attr(propset, "type");
3694 3708                  if (proto != NULL) {
3695 3709                          if (section != NULL)
3696 3710                                  set_node_attr((xmlNodePtr)prop, "section",
3697 3711                                      section);
3698 3712                          set_node_attr((xmlNodePtr)prop, "value", value);
3699 3713                          ret = sa_proto_set_property(proto, prop);
3700 3714                          sa_free_attr_string(proto);
3701 3715                  }
3702 3716          }
3703 3717          return (ret);
3704 3718  }
3705 3719  
3706 3720  /*
3707 3721   * sa_add_protocol_property(propset, prop)
3708 3722   *
3709 3723   * Add a new property to the protocol specific property set.
3710 3724   */
3711 3725  
3712 3726  int
3713 3727  sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop)
3714 3728  {
3715 3729          xmlNodePtr node;
3716 3730  
3717 3731          /* should check for legitimacy */
3718 3732          node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop);
3719 3733          if (node != NULL)
3720 3734                  return (SA_OK);
3721 3735          return (SA_NO_MEMORY);
3722 3736  }
3723 3737  
3724 3738  /*
3725 3739   * sa_create_protocol_properties(proto)
3726 3740   *
3727 3741   * Create a protocol specific property set.
3728 3742   */
3729 3743  
3730 3744  sa_protocol_properties_t
3731 3745  sa_create_protocol_properties(char *proto)
3732 3746  {
3733 3747          xmlNodePtr node;
3734 3748  
3735 3749          node = xmlNewNode(NULL, (xmlChar *)"propertyset");
3736 3750          if (node != NULL)
3737 3751                  (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
3738 3752          return (node);
3739 3753  }
3740 3754  
3741 3755  /*
3742 3756   * sa_get_share_resource(share, resource)
3743 3757   *
3744 3758   * Get the named resource from the share, if it exists. If resource is
3745 3759   * NULL, get the first resource.
3746 3760   */
3747 3761  
3748 3762  sa_resource_t
3749 3763  sa_get_share_resource(sa_share_t share, char *resource)
3750 3764  {
3751 3765          xmlNodePtr node = NULL;
3752 3766          xmlChar *name;
3753 3767  
3754 3768          if (share != NULL) {
3755 3769                  for (node = ((xmlNodePtr)share)->children; node != NULL;
3756 3770                      node = node->next) {
3757 3771                          if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) {
3758 3772                                  if (resource == NULL) {
3759 3773                                          /*
3760 3774                                           * We are looking for the first
3761 3775                                           * resource node and not a names
3762 3776                                           * resource.
3763 3777                                           */
3764 3778                                          break;
3765 3779                                  } else {
3766 3780                                          /* is it the correct share? */
3767 3781                                          name = xmlGetProp(node,
3768 3782                                              (xmlChar *)"name");
3769 3783                                          if (name != NULL &&
3770 3784                                              xmlStrcasecmp(name,
3771 3785                                              (xmlChar *)resource) == 0) {
3772 3786                                                  xmlFree(name);
3773 3787                                                  break;
3774 3788                                          }
3775 3789                                          xmlFree(name);
3776 3790                                  }
3777 3791                          }
3778 3792                  }
3779 3793          }
3780 3794          return ((sa_resource_t)node);
3781 3795  }
3782 3796  
3783 3797  /*
3784 3798   * sa_get_next_resource(resource)
3785 3799   *      Return the next share following the specified share
3786 3800   *      from the internal list of shares. Returns NULL if there
3787 3801   *      are no more shares.  The list is relative to the same
3788 3802   *      group.
3789 3803   */
3790 3804  sa_share_t
3791 3805  sa_get_next_resource(sa_resource_t resource)
3792 3806  {
3793 3807          xmlNodePtr node = NULL;
3794 3808  
3795 3809          if (resource != NULL) {
3796 3810                  for (node = ((xmlNodePtr)resource)->next; node != NULL;
3797 3811                      node = node->next) {
3798 3812                          if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
3799 3813                                  break;
3800 3814                  }
3801 3815          }
3802 3816          return ((sa_share_t)node);
3803 3817  }
3804 3818  
3805 3819  /*
3806 3820   * _sa_get_next_resource_index(share)
3807 3821   *
3808 3822   * get the next resource index number (one greater then current largest)
3809 3823   */
3810 3824  
3811 3825  static int
3812 3826  _sa_get_next_resource_index(sa_share_t share)
3813 3827  {
3814 3828          sa_resource_t resource;
3815 3829          int index = 0;
3816 3830          char *id;
3817 3831  
3818 3832          for (resource = sa_get_share_resource(share, NULL);
3819 3833              resource != NULL;
3820 3834              resource = sa_get_next_resource(resource)) {
3821 3835                  id = get_node_attr((void *)resource, "id");
3822 3836                  if (id != NULL) {
3823 3837                          int val;
3824 3838                          val = atoi(id);
3825 3839                          if (val > index)
3826 3840                                  index = val;
3827 3841                          sa_free_attr_string(id);
3828 3842                  }
3829 3843          }
3830 3844          return (index + 1);
3831 3845  }
3832 3846  
3833 3847  
3834 3848  /*
3835 3849   * sa_add_resource(share, resource, persist, &err)
3836 3850   *
3837 3851   * Adds a new resource name associated with share. The resource name
3838 3852   * must be unique in the system and will be case insensitive (eventually).
3839 3853   */
3840 3854  
3841 3855  sa_resource_t
3842 3856  sa_add_resource(sa_share_t share, char *resource, int persist, int *error)
3843 3857  {
3844 3858          xmlNodePtr node;
3845 3859          int err = SA_OK;
3846 3860          sa_resource_t res;
3847 3861          sa_group_t group;
3848 3862          sa_handle_t handle;
3849 3863          char istring[8]; /* just big enough for an integer value */
3850 3864          int index;
3851 3865  
3852 3866          group = sa_get_parent_group(share);
3853 3867          handle = sa_find_group_handle(group);
3854 3868          res = sa_find_resource(handle, resource);
3855 3869          if (res != NULL) {
3856 3870                  err = SA_DUPLICATE_NAME;
3857 3871                  res = NULL;
3858 3872          } else {
3859 3873                  node = xmlNewChild((xmlNodePtr)share, NULL,
3860 3874                      (xmlChar *)"resource", NULL);
3861 3875                  if (node != NULL) {
3862 3876                          (void) xmlSetProp(node, (xmlChar *)"name",
3863 3877                              (xmlChar *)resource);
3864 3878                          (void) xmlSetProp(node, (xmlChar *)"type", persist ?
3865 3879                              (xmlChar *)"persist" : (xmlChar *)"transient");
3866 3880                          if (persist != SA_SHARE_TRANSIENT) {
3867 3881                                  index = _sa_get_next_resource_index(share);
3868 3882                                  (void) snprintf(istring, sizeof (istring), "%d",
3869 3883                                      index);
3870 3884                                  (void) xmlSetProp(node, (xmlChar *)"id",
3871 3885                                      (xmlChar *)istring);
3872 3886  
3873 3887                                  if (!sa_is_persistent((sa_group_t)share))
3874 3888                                          goto done;
3875 3889  
3876 3890                                  if (!sa_group_is_zfs(group)) {
3877 3891                                          /* ZFS doesn't use resource names */
3878 3892                                          sa_handle_impl_t ihandle;
3879 3893  
3880 3894                                          ihandle = (sa_handle_impl_t)
3881 3895                                              sa_find_group_handle(
3882 3896                                              group);
3883 3897                                          if (ihandle != NULL)
3884 3898                                                  err = sa_commit_share(
3885 3899                                                      ihandle->scfhandle, group,
3886 3900                                                      share);
3887 3901                                          else
3888 3902                                                  err = SA_SYSTEM_ERR;
3889 3903                                  } else {
3890 3904                                          err = sa_zfs_update((sa_share_t)group);
3891 3905                                  }
3892 3906                          }
3893 3907                  }
3894 3908          }
3895 3909  done:
3896 3910          if (error != NULL)
3897 3911                  *error = err;
3898 3912          return ((sa_resource_t)node);
3899 3913  }
3900 3914  
3901 3915  /*
3902 3916   * sa_remove_resource(resource)
3903 3917   *
3904 3918   * Remove the resource name from the share (and the system)
3905 3919   */
3906 3920  
3907 3921  int
3908 3922  sa_remove_resource(sa_resource_t resource)
3909 3923  {
3910 3924          sa_share_t share;
3911 3925          sa_group_t group;
3912 3926          char *type;
3913 3927          int ret = SA_OK;
3914 3928          boolean_t transient = B_FALSE;
3915 3929          sa_optionset_t opt;
3916 3930  
3917 3931          share = sa_get_resource_parent(resource);
3918 3932          type = sa_get_share_attr(share, "type");
3919 3933          group = sa_get_parent_group(share);
3920 3934  
3921 3935  
3922 3936          if (type != NULL) {
3923 3937                  if (strcmp(type, "persist") != 0)
3924 3938                          transient = B_TRUE;
3925 3939                  sa_free_attr_string(type);
3926 3940          }
3927 3941  
3928 3942          /* Disable the resource for all protocols. */
3929 3943          (void) sa_disable_resource(resource, NULL);
3930 3944  
3931 3945          /* Remove any optionsets from the resource. */
3932 3946          for (opt = sa_get_optionset(resource, NULL);
3933 3947              opt != NULL;
3934 3948              opt = sa_get_next_optionset(opt))
3935 3949                  (void) sa_destroy_optionset(opt);
3936 3950  
3937 3951          /* Remove from the share */
3938 3952          xmlUnlinkNode((xmlNode *)resource);
3939 3953          xmlFreeNode((xmlNode *)resource);
3940 3954  
3941 3955          /* only do SMF action if permanent and not ZFS */
3942 3956          if (transient)
3943 3957                  return (ret);
3944 3958  
3945 3959          if (!sa_group_is_zfs(group)) {
3946 3960                  sa_handle_impl_t ihandle;
3947 3961                  ihandle = (sa_handle_impl_t)sa_find_group_handle(group);
3948 3962                  if (ihandle != NULL)
3949 3963                          ret = sa_commit_share(ihandle->scfhandle, group, share);
3950 3964                  else
3951 3965                          ret = SA_SYSTEM_ERR;
3952 3966          } else {
3953 3967                  ret = sa_zfs_update((sa_share_t)group);
3954 3968          }
3955 3969  
3956 3970          return (ret);
3957 3971  }
3958 3972  
3959 3973  /*
3960 3974   * proto_rename_resource(handle, group, resource, newname)
3961 3975   *
3962 3976   * Helper function for sa_rename_resource that notifies the protocol
3963 3977   * of a resource name change prior to a config repository update.
3964 3978   */
3965 3979  static int
3966 3980  proto_rename_resource(sa_handle_t handle, sa_group_t group,
3967 3981      sa_resource_t resource, char *newname)
3968 3982  {
3969 3983          sa_optionset_t optionset;
3970 3984          int ret = SA_OK;
3971 3985          int err;
3972 3986  
3973 3987          for (optionset = sa_get_optionset(group, NULL);
3974 3988              optionset != NULL;
3975 3989              optionset = sa_get_next_optionset(optionset)) {
3976 3990                  char *type;
3977 3991                  type = sa_get_optionset_attr(optionset, "type");
3978 3992                  if (type != NULL) {
3979 3993                          err = sa_proto_rename_resource(handle, type, resource,
3980 3994                              newname);
3981 3995                          if (err != SA_OK)
3982 3996                                  ret = err;
3983 3997                          sa_free_attr_string(type);
3984 3998                  }
3985 3999          }
3986 4000          return (ret);
3987 4001  }
3988 4002  
3989 4003  /*
3990 4004   * sa_rename_resource(resource, newname)
3991 4005   *
3992 4006   * Rename the resource to the new name, if it is unique.
3993 4007   */
3994 4008  
3995 4009  int
3996 4010  sa_rename_resource(sa_resource_t resource, char *newname)
3997 4011  {
3998 4012          sa_share_t share;
3999 4013          sa_group_t group = NULL;
4000 4014          sa_resource_t target;
4001 4015          int ret = SA_CONFIG_ERR;
4002 4016          sa_handle_t handle = NULL;
4003 4017  
4004 4018          share = sa_get_resource_parent(resource);
4005 4019          if (share == NULL)
4006 4020                  return (ret);
4007 4021  
4008 4022          group = sa_get_parent_group(share);
4009 4023          if (group == NULL)
4010 4024                  return (ret);
4011 4025  
4012 4026          handle = (sa_handle_impl_t)sa_find_group_handle(group);
4013 4027          if (handle == NULL)
4014 4028                  return (ret);
4015 4029  
4016 4030          target = sa_find_resource(handle, newname);
4017 4031          if (target != NULL) {
4018 4032                  ret = SA_DUPLICATE_NAME;
4019 4033          } else {
4020 4034                  /*
4021 4035                   * Everything appears to be valid at this
4022 4036                   * point. Change the name of the active share and then
4023 4037                   * update the share in the appropriate repository.
4024 4038                   */
4025 4039                  ret = proto_rename_resource(handle, group, resource, newname);
4026 4040                  set_node_attr(resource, "name", newname);
4027 4041  
4028 4042                  if (!sa_is_persistent((sa_group_t)share))
4029 4043                          return (ret);
4030 4044  
4031 4045                  if (!sa_group_is_zfs(group)) {
4032 4046                          sa_handle_impl_t ihandle = (sa_handle_impl_t)handle;
4033 4047                          ret = sa_commit_share(ihandle->scfhandle, group,
4034 4048                              share);
4035 4049                  } else {
4036 4050                          ret = sa_zfs_update((sa_share_t)group);
4037 4051                  }
4038 4052          }
4039 4053          return (ret);
4040 4054  }
4041 4055  
4042 4056  /*
4043 4057   * sa_get_resource_attr(resource, tag)
4044 4058   *
4045 4059   * Get the named attribute of the resource. "name" and "id" are
4046 4060   * currently defined.  NULL if tag not defined.
4047 4061   */
4048 4062  
4049 4063  char *
4050 4064  sa_get_resource_attr(sa_resource_t resource, char *tag)
4051 4065  {
4052 4066          return (get_node_attr((void *)resource, tag));
4053 4067  }
4054 4068  
4055 4069  /*
4056 4070   * sa_set_resource_attr(resource, tag, value)
4057 4071   *
4058 4072   * Get the named attribute of the resource. "name" and "id" are
4059 4073   * currently defined.  NULL if tag not defined. Currently we don't do
4060 4074   * much, but additional checking may be needed in the future.
4061 4075   */
4062 4076  
4063 4077  int
4064 4078  sa_set_resource_attr(sa_resource_t resource, char *tag, char *value)
4065 4079  {
4066 4080          set_node_attr((void *)resource, tag, value);
4067 4081          return (SA_OK);
4068 4082  }
4069 4083  
4070 4084  /*
4071 4085   * sa_get_resource_parent(resource_t)
4072 4086   *
4073 4087   * Returns the share associated with the resource.
4074 4088   */
4075 4089  
4076 4090  sa_share_t
4077 4091  sa_get_resource_parent(sa_resource_t resource)
4078 4092  {
4079 4093          sa_share_t share = NULL;
4080 4094  
4081 4095          if (resource != NULL)
4082 4096                  share = (sa_share_t)((xmlNodePtr)resource)->parent;
4083 4097          return (share);
4084 4098  }
4085 4099  
4086 4100  /*
4087 4101   * find_resource(group, name)
4088 4102   *
4089 4103   * Find the resource within the group.
4090 4104   */
4091 4105  
4092 4106  static sa_resource_t
4093 4107  find_resource(sa_group_t group, char *resname)
4094 4108  {
4095 4109          sa_share_t share;
4096 4110          sa_resource_t resource = NULL;
4097 4111          char *name;
4098 4112  
4099 4113          /* Iterate over all the shares and resources in the group. */
4100 4114          for (share = sa_get_share(group, NULL);
4101 4115              share != NULL && resource == NULL;
4102 4116              share = sa_get_next_share(share)) {
4103 4117                  for (resource = sa_get_share_resource(share, NULL);
4104 4118                      resource != NULL;
4105 4119                      resource = sa_get_next_resource(resource)) {
4106 4120                          name = sa_get_resource_attr(resource, "name");
4107 4121                          if (name != NULL && xmlStrcasecmp((xmlChar*)name,
4108 4122                              (xmlChar*)resname) == 0) {
4109 4123                                  sa_free_attr_string(name);
4110 4124                                  break;
4111 4125                          }
4112 4126                          if (name != NULL) {
4113 4127                                  sa_free_attr_string(name);
4114 4128                          }
4115 4129                  }
4116 4130          }
4117 4131          return (resource);
4118 4132  }
4119 4133  
4120 4134  /*
4121 4135   * sa_find_resource(name)
4122 4136   *
4123 4137   * Find the named resource in the system.
4124 4138   */
4125 4139  
4126 4140  sa_resource_t
4127 4141  sa_find_resource(sa_handle_t handle, char *name)
4128 4142  {
4129 4143          sa_group_t group;
4130 4144          sa_group_t zgroup;
4131 4145          sa_resource_t resource = NULL;
4132 4146  
4133 4147          /*
4134 4148           * Iterate over all groups and zfs subgroups and check for
4135 4149           * resource name in them.
4136 4150           */
4137 4151          for (group = sa_get_group(handle, NULL); group != NULL;
4138 4152              group = sa_get_next_group(group)) {
4139 4153  
4140 4154                  if (is_zfs_group(group)) {
4141 4155                          for (zgroup =
4142 4156                              (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
4143 4157                              (xmlChar *)"group");
4144 4158                              zgroup != NULL && resource == NULL;
4145 4159                              zgroup = sa_get_next_group(zgroup)) {
4146 4160                                  resource = find_resource(zgroup, name);
4147 4161                          }
4148 4162                  } else {
4149 4163                          resource = find_resource(group, name);
4150 4164                  }
4151 4165                  if (resource != NULL)
4152 4166                          break;
4153 4167          }
4154 4168          return (resource);
4155 4169  }
4156 4170  
4157 4171  /*
4158 4172   * sa_get_resource(group, resource)
4159 4173   *
4160 4174   * Search all the shares in the specified group for a share with a
4161 4175   * resource name matching the one specified.
4162 4176   *
4163 4177   * In the future, it may be advantageous to allow group to be NULL and
4164 4178   * search all groups but that isn't needed at present.
4165 4179   */
4166 4180  
4167 4181  sa_resource_t
4168 4182  sa_get_resource(sa_group_t group, char *resource)
4169 4183  {
4170 4184          sa_share_t share = NULL;
4171 4185          sa_resource_t res = NULL;
4172 4186  
4173 4187          if (resource != NULL) {
4174 4188                  for (share = sa_get_share(group, NULL);
4175 4189                      share != NULL && res == NULL;
4176 4190                      share = sa_get_next_share(share)) {
4177 4191                          res = sa_get_share_resource(share, resource);
4178 4192                  }
4179 4193          }
4180 4194          return (res);
4181 4195  }
4182 4196  
4183 4197  /*
4184 4198   * get_protocol_list(optionset, object)
4185 4199   *
4186 4200   * Get the protocol optionset list for the object and add them as
4187 4201   * properties to optionset.
4188 4202   */
4189 4203  static int
4190 4204  get_protocol_list(sa_optionset_t optionset, void *object)
4191 4205  {
4192 4206          sa_property_t prop;
4193 4207          sa_optionset_t opts;
4194 4208          int ret = SA_OK;
4195 4209  
4196 4210          for (opts = sa_get_optionset(object, NULL);
4197 4211              opts != NULL;
4198 4212              opts = sa_get_next_optionset(opts)) {
4199 4213                  char *type;
4200 4214                  type = sa_get_optionset_attr(opts, "type");
4201 4215                  /*
4202 4216                   * It is possible to have a non-protocol optionset. We
4203 4217                   * skip any of those found.
4204 4218                   */
4205 4219                  if (type == NULL)
4206 4220                          continue;
4207 4221                  prop = sa_create_property(type, "true");
4208 4222                  sa_free_attr_string(type);
4209 4223                  if (prop != NULL)
4210 4224                          prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset,
4211 4225                              (xmlNodePtr)prop);
4212 4226                  /* If prop is NULL, don't bother continuing */
4213 4227                  if (prop == NULL) {
4214 4228                          ret = SA_NO_MEMORY;
4215 4229                          break;
4216 4230                  }
4217 4231          }
4218 4232          return (ret);
4219 4233  }
4220 4234  
4221 4235  /*
4222 4236   * sa_free_protoset(optionset)
4223 4237   *
4224 4238   * Free the protocol property optionset.
4225 4239   */
4226 4240  static void
4227 4241  sa_free_protoset(sa_optionset_t optionset)
4228 4242  {
4229 4243          if (optionset != NULL) {
4230 4244                  xmlUnlinkNode((xmlNodePtr) optionset);
4231 4245                  xmlFreeNode((xmlNodePtr) optionset);
4232 4246          }
4233 4247  }
4234 4248  
4235 4249  /*
4236 4250   * sa_optionset_t sa_get_active_protocols(object)
4237 4251   *
4238 4252   * Return a list of the protocols that are active for the object.
4239 4253   * This is currently an internal helper function, but could be
4240 4254   * made visible if there is enough demand for it.
4241 4255   *
4242 4256   * The function finds the parent group and extracts the protocol
4243 4257   * optionsets creating a new optionset with the protocols as properties.
4244 4258   *
4245 4259   * The caller must free the returned optionset.
4246 4260   */
4247 4261  
4248 4262  static sa_optionset_t
4249 4263  sa_get_active_protocols(void *object)
4250 4264  {
4251 4265          sa_optionset_t options;
4252 4266          sa_share_t share = NULL;
4253 4267          sa_group_t group = NULL;
4254 4268          sa_resource_t resource = NULL;
4255 4269          int ret = SA_OK;
4256 4270  
4257 4271          if (object == NULL)
4258 4272                  return (NULL);
4259 4273          options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset");
4260 4274          if (options == NULL)
4261 4275                  return (NULL);
4262 4276  
4263 4277          /*
4264 4278           * Find the objects up the tree that might have protocols
4265 4279           * enabled on them.
4266 4280           */
4267 4281          if (sa_is_resource(object)) {
4268 4282                  resource = (sa_resource_t)object;
4269 4283                  share = sa_get_resource_parent(resource);
4270 4284                  group = sa_get_parent_group(share);
4271 4285          } else if (sa_is_share(object)) {
4272 4286                  share = (sa_share_t)object;
4273 4287                  group = sa_get_parent_group(share);
4274 4288          } else {
4275 4289                  group = (sa_group_t)group;
4276 4290          }
4277 4291          if (resource != NULL)
4278 4292                  ret = get_protocol_list(options, resource);
4279 4293          if (ret == SA_OK && share != NULL)
4280 4294                  ret = get_protocol_list(options, share);
4281 4295          if (ret == SA_OK && group != NULL)
4282 4296                  ret = get_protocol_list(options, group);
4283 4297  
4284 4298          /*
4285 4299           * If there was an error, we won't have a complete list so
4286 4300           * abandon everything.  The caller will have to deal with the
4287 4301           * issue.
4288 4302           */
4289 4303          if (ret != SA_OK) {
4290 4304                  sa_free_protoset(options);
4291 4305                  options = NULL;
4292 4306          }
4293 4307          return (options);
4294 4308  }
4295 4309  
4296 4310  /*
4297 4311   * sa_enable_resource, protocol)
4298 4312   *      Disable the specified share to the specified protocol.
4299 4313   *      If protocol is NULL, then all protocols.
4300 4314   */
4301 4315  int
4302 4316  sa_enable_resource(sa_resource_t resource, char *protocol)
4303 4317  {
4304 4318          int ret = SA_OK;
4305 4319  
4306 4320          if (protocol != NULL) {
4307 4321                  ret = sa_proto_share_resource(protocol, resource);
4308 4322          } else {
4309 4323                  sa_optionset_t protoset;
4310 4324                  sa_property_t prop;
4311 4325                  char *proto;
4312 4326                  int err;
4313 4327  
4314 4328                  /* need to do all protocols */
4315 4329                  protoset = sa_get_active_protocols(resource);
4316 4330                  if (protoset == NULL)
4317 4331                          return (SA_NO_MEMORY);
4318 4332                  for (prop = sa_get_property(protoset, NULL);
4319 4333                      prop != NULL;
4320 4334                      prop = sa_get_next_property(prop)) {
4321 4335                          proto = sa_get_property_attr(prop, "type");
4322 4336                          if (proto == NULL) {
4323 4337                                  ret = SA_NO_MEMORY;
4324 4338                                  continue;
4325 4339                          }
4326 4340                          err = sa_proto_share_resource(proto, resource);
4327 4341                          if (err != SA_OK)
4328 4342                                  ret = err;
4329 4343                          sa_free_attr_string(proto);
4330 4344                  }
4331 4345                  sa_free_protoset(protoset);
4332 4346          }
4333 4347          if (ret == SA_OK)
4334 4348                  (void) sa_set_resource_attr(resource, "shared", NULL);
4335 4349  
4336 4350          return (ret);
4337 4351  }
4338 4352  
4339 4353  /*
4340 4354   * sa_disable_resource(resource, protocol)
4341 4355   *
4342 4356   *      Disable the specified share for the specified protocol.  If
4343 4357   *      protocol is NULL, then all protocols.  If the underlying
4344 4358   *      protocol doesn't implement disable at the resource level, we
4345 4359   *      disable at the share level.
4346 4360   */
4347 4361  int
4348 4362  sa_disable_resource(sa_resource_t resource, char *protocol)
4349 4363  {
4350 4364          int ret = SA_OK;
4351 4365  
4352 4366          if (protocol != NULL) {
4353 4367                  ret = sa_proto_unshare_resource(protocol, resource);
4354 4368                  if (ret == SA_NOT_IMPLEMENTED) {
4355 4369                          sa_share_t parent;
4356 4370                          /*
4357 4371                           * The protocol doesn't implement unshare
4358 4372                           * resource. That implies that resource names are
4359 4373                           * simple aliases for this protocol so we need to
4360 4374                           * unshare the share.
4361 4375                           */
4362 4376                          parent = sa_get_resource_parent(resource);
4363 4377                          if (parent != NULL)
4364 4378                                  ret = sa_disable_share(parent, protocol);
4365 4379                          else
4366 4380                                  ret = SA_CONFIG_ERR;
4367 4381                  }
4368 4382          } else {
4369 4383                  sa_optionset_t protoset;
4370 4384                  sa_property_t prop;
4371 4385                  char *proto;
4372 4386                  int err;
4373 4387  
4374 4388                  /* need to do all protocols */
4375 4389                  protoset = sa_get_active_protocols(resource);
4376 4390                  if (protoset == NULL)
4377 4391                          return (SA_NO_MEMORY);
4378 4392                  for (prop = sa_get_property(protoset, NULL);
4379 4393                      prop != NULL;
4380 4394                      prop = sa_get_next_property(prop)) {
4381 4395                          proto = sa_get_property_attr(prop, "type");
4382 4396                          if (proto == NULL) {
4383 4397                                  ret = SA_NO_MEMORY;
4384 4398                                  continue;
4385 4399                          }
4386 4400                          err = sa_proto_unshare_resource(proto, resource);
4387 4401                          if (err == SA_NOT_SUPPORTED) {
4388 4402                                  sa_share_t parent;
4389 4403                                  parent = sa_get_resource_parent(resource);
4390 4404                                  if (parent != NULL)
4391 4405                                          err = sa_disable_share(parent, proto);
4392 4406                                  else
4393 4407                                          err = SA_CONFIG_ERR;
4394 4408                          }
4395 4409                          if (err != SA_OK)
4396 4410                                  ret = err;
4397 4411                          sa_free_attr_string(proto);
4398 4412                  }
4399 4413                  sa_free_protoset(protoset);
4400 4414          }
4401 4415          if (ret == SA_OK)
4402 4416                  (void) sa_set_resource_attr(resource, "shared", NULL);
4403 4417  
4404 4418          return (ret);
4405 4419  }
4406 4420  
4407 4421  /*
4408 4422   * sa_set_resource_description(resource, content)
4409 4423   *
4410 4424   * Set the description of share to content.
4411 4425   */
4412 4426  
4413 4427  int
4414 4428  sa_set_resource_description(sa_resource_t resource, char *content)
4415 4429  {
4416 4430          xmlNodePtr node;
4417 4431          sa_group_t group;
4418 4432          sa_share_t share;
4419 4433          int ret = SA_OK;
4420 4434  
4421 4435          for (node = ((xmlNodePtr)resource)->children;
4422 4436              node != NULL;
4423 4437              node = node->next) {
4424 4438                  if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
4425 4439                          break;
4426 4440                  }
4427 4441          }
4428 4442  
4429 4443          /* no existing description but want to add */
4430 4444          if (node == NULL && content != NULL) {
4431 4445                  /* add a description */
4432 4446                  node = _sa_set_share_description(resource, content);
4433 4447          } else if (node != NULL && content != NULL) {
4434 4448                  /* update a description */
4435 4449                  xmlNodeSetContent(node, (xmlChar *)content);
4436 4450          } else if (node != NULL && content == NULL) {
4437 4451                  /* remove an existing description */
4438 4452                  xmlUnlinkNode(node);
4439 4453                  xmlFreeNode(node);
4440 4454          }
4441 4455  
4442 4456          share = sa_get_resource_parent(resource);
4443 4457          group = sa_get_parent_group(share);
4444 4458          if (group != NULL &&
4445 4459              sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
4446 4460                  sa_handle_impl_t impl_handle;
4447 4461                  impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
4448 4462                  if (impl_handle != NULL)
4449 4463                          ret = sa_commit_share(impl_handle->scfhandle,
4450 4464                              group, share);
4451 4465                  else
4452 4466                          ret = SA_SYSTEM_ERR;
4453 4467          }
4454 4468          return (ret);
4455 4469  }
4456 4470  
4457 4471  /*
4458 4472   * sa_get_resource_description(share)
4459 4473   *
4460 4474   * Return the description text for the specified share if it
4461 4475   * exists. NULL if no description exists.
4462 4476   */
4463 4477  
4464 4478  char *
4465 4479  sa_get_resource_description(sa_resource_t resource)
4466 4480  {
4467 4481          xmlChar *description = NULL;
4468 4482          xmlNodePtr node;
4469 4483  
4470 4484          for (node = ((xmlNodePtr)resource)->children; node != NULL;
4471 4485              node = node->next) {
4472 4486                  if (xmlStrcmp(node->name, (xmlChar *)"description") == 0)
4473 4487                          break;
4474 4488          }
4475 4489          if (node != NULL) {
4476 4490                  description = xmlNodeGetContent(node);
4477 4491                  fixproblemchars((char *)description);
4478 4492          }
4479 4493          return ((char *)description);
4480 4494  }
  
    | 
      ↓ open down ↓ | 
    3316 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX