Print this page
    
OS-4335 ipadm_door_call should work in a branded zone without chroot
OS-4336 ipmgmtd should work in a branded zone without chroot
Reviewed by: Robert Mustacchi <rm@joyent.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
          +++ new/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.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) 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2015 Joyent, Inc.
  24   25   * Copyright 2016 Argo Technologie SA.
  25   26   */
  26   27  
  27   28  /*
  28   29   * Contains DB walker functions, which are of type `db_wfunc_t';
  29   30   *
  30   31   * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
  31   32   *                              size_t bufsize, int *errp);
  32   33   *
  33   34   * ipadm_rw_db() walks through the data store, one line at a time and calls
  34   35   * these call back functions with:
  35   36   *      `cbarg'  - callback argument
  36   37   *      `db_nvl' - representing a line from DB in nvlist_t form
  37   38   *      `buf'    - character buffer to hold modified line
  38   39   *      `bufsize'- size of the buffer
  39   40   *      `errp' - captures any error inside the walker function.
  40   41   *
  41   42   * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
  42   43   * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
  43   44   * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
  44   45   * the modified `buf' is written back into DB.
  45   46   *
  46   47   * All the 'read' callback functions, retrieve the information from the DB, by
  47   48   * reading `db_nvl' and then populate the `cbarg'.
  48   49   */
  49   50  
  50   51  #include <stdlib.h>
  51   52  #include <strings.h>
  52   53  #include <errno.h>
  53   54  #include <assert.h>
  54   55  #include <sys/types.h>
  55   56  #include <sys/socket.h>
  56   57  #include <netinet/in.h>
  57   58  #include <arpa/inet.h>
  58   59  #include <unistd.h>
  59   60  #include "ipmgmt_impl.h"
  60   61  
  61   62  /* SCF related property group names and property names */
  62   63  #define IPMGMTD_APP_PG          "ipmgmtd"
  63   64  #define IPMGMTD_PROP_FBD        "first_boot_done"
  64   65  #define IPMGMTD_PROP_DBVER      "datastore_version"
  65   66  #define IPMGMTD_TRUESTR         "true"
  66   67  
  67   68  #define ATYPE   "_atype"                /* name of the address type nvpair */
  68   69  #define FLAGS   "_flags"                /* name of the flags nvpair */
  69   70  
  70   71  /*
  71   72   * flag used by ipmgmt_persist_aobjmap() to indicate address type is
  72   73   * IPADM_ADDR_IPV6_ADDRCONF.
  73   74   */
  74   75  #define IPMGMT_ATYPE_V6ACONF    0x1
  75   76  
  76   77  extern pthread_rwlock_t ipmgmt_dbconf_lock;
  77   78  
  78   79  /* signifies whether volatile copy of data store is in use */
  79   80  static boolean_t ipmgmt_rdonly_root = B_FALSE;
  80   81  
  81   82  /*
  82   83   * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
  83   84   * in private nvpairs `proto', `ifname' & `aobjname'.
  84   85   */
  85   86  static boolean_t
  86   87  ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
  87   88      const char *aobjname)
  88   89  {
  89   90          char            *db_proto = NULL, *db_ifname = NULL;
  90   91          char            *db_aobjname = NULL;
  91   92          nvpair_t        *nvp;
  92   93          char            *name;
  93   94  
  94   95          /* walk through db_nvl and retrieve all its private nvpairs */
  95   96          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
  96   97              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
  97   98                  name = nvpair_name(nvp);
  98   99                  if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
  99  100                          (void) nvpair_value_string(nvp, &db_proto);
 100  101                  else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 101  102                          (void) nvpair_value_string(nvp, &db_ifname);
 102  103                  else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
 103  104                          (void) nvpair_value_string(nvp, &db_aobjname);
 104  105          }
 105  106  
 106  107          if (proto != NULL && proto[0] == '\0')
 107  108                  proto = NULL;
 108  109          if (ifname != NULL && ifname[0] == '\0')
 109  110                  ifname = NULL;
 110  111          if (aobjname != NULL && aobjname[0] == '\0')
 111  112                  aobjname = NULL;
 112  113  
 113  114          if ((proto == NULL && db_proto != NULL) ||
 114  115              (proto != NULL && db_proto == NULL) ||
 115  116              (proto != NULL && db_proto != NULL &&
 116  117              strcmp(proto, db_proto) != 0)) {
 117  118                  /* no intersection - different protocols. */
 118  119                  return (B_FALSE);
 119  120          }
 120  121          if ((ifname == NULL && db_ifname != NULL) ||
 121  122              (ifname != NULL && db_ifname == NULL) ||
 122  123              (ifname != NULL && db_ifname != NULL &&
 123  124              strcmp(ifname, db_ifname) != 0)) {
 124  125                  /* no intersection - different interfaces. */
 125  126                  return (B_FALSE);
 126  127          }
 127  128          if ((aobjname == NULL && db_aobjname != NULL) ||
 128  129              (aobjname != NULL && db_aobjname == NULL) ||
 129  130              (aobjname != NULL && db_aobjname != NULL &&
 130  131              strcmp(aobjname, db_aobjname) != 0)) {
 131  132                  /* no intersection - different address objects */
 132  133                  return (B_FALSE);
 133  134          }
 134  135  
 135  136          return (B_TRUE);
 136  137  }
 137  138  
 138  139  /*
 139  140   * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
 140  141   */
 141  142  static boolean_t
 142  143  ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
 143  144  {
 144  145          nvpair_t        *nvp;
 145  146          char            *name;
 146  147          char            *proto = NULL, *ifname = NULL, *aobjname = NULL;
 147  148  
 148  149          /* walk through in_nvl and retrieve all its private nvpairs */
 149  150          for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
 150  151              nvp = nvlist_next_nvpair(in_nvl, nvp)) {
 151  152                  name = nvpair_name(nvp);
 152  153                  if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 153  154                          (void) nvpair_value_string(nvp, &proto);
 154  155                  else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 155  156                          (void) nvpair_value_string(nvp, &ifname);
 156  157                  else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
 157  158                          (void) nvpair_value_string(nvp, &aobjname);
 158  159          }
 159  160  
 160  161          return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
 161  162  }
 162  163  
 163  164  /*
 164  165   * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
 165  166   * in private nvpairs `proto', `ifname' & `aobjname'.
 166  167   */
 167  168  static boolean_t
 168  169  ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
 169  170      const char *ifname, char *aobjname)
 170  171  {
 171  172          char            *db_ifname = NULL, *db_proto = NULL;
 172  173          char            *db_aobjname = NULL;
 173  174          nvpair_t        *nvp;
 174  175          char            *name;
 175  176  
 176  177          /* walk through db_nvl and retrieve all private nvpairs */
 177  178          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 178  179              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 179  180                  name = nvpair_name(nvp);
 180  181                  if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 181  182                          (void) nvpair_value_string(nvp, &db_proto);
 182  183                  else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 183  184                          (void) nvpair_value_string(nvp, &db_ifname);
 184  185                  else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
 185  186                          (void) nvpair_value_string(nvp, &db_aobjname);
 186  187          }
 187  188  
 188  189          if (proto != NULL && proto[0] != '\0') {
 189  190                  if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
 190  191                          return (B_FALSE);
 191  192          }
 192  193          if (ifname != NULL && ifname[0] != '\0') {
 193  194                  if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
 194  195                          return (B_FALSE);
 195  196          }
 196  197          if (aobjname != NULL && aobjname[0] != '\0') {
 197  198                  if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
 198  199                          return (B_FALSE);
 199  200          }
 200  201  
 201  202          return (B_TRUE);
 202  203  }
 203  204  
 204  205  /*
 205  206   * Retrieves the property value from the DB. The property whose value is to be
 206  207   * retrieved is in `pargp->ia_pname'.
 207  208   */
 208  209  /* ARGSUSED */
 209  210  boolean_t
 210  211  ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 211  212      int *errp)
 212  213  {
 213  214          ipmgmt_prop_arg_t       *pargp = arg;
 214  215          boolean_t               cont = B_TRUE;
 215  216          char                    *pval;
 216  217          int                     err = 0;
 217  218  
 218  219          *errp = 0;
 219  220  
 220  221          if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
 221  222              pargp->ia_ifname, pargp->ia_aobjname))
 222  223                  return (B_TRUE);
 223  224  
 224  225          if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
 225  226              &pval)) == 0) {
 226  227                  (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
 227  228                  /*
 228  229                   * We have retrieved what we are looking for.
 229  230                   * Stop the walker.
 230  231                   */
 231  232                  cont = B_FALSE;
 232  233          } else {
 233  234                  if (err == ENOENT)
 234  235                          err = 0;
 235  236                  *errp = err;
 236  237          }
 237  238  
 238  239          return (cont);
 239  240  }
 240  241  
 241  242  /*
 242  243   * Removes the property value from the DB. The property whose value is to be
 243  244   * removed is in `pargp->ia_pname'.
 244  245   */
 245  246  /* ARGSUSED */
 246  247  boolean_t
 247  248  ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 248  249      int *errp)
 249  250  {
 250  251          ipmgmt_prop_arg_t       *pargp = arg;
 251  252  
 252  253          *errp = 0;
 253  254          if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
 254  255              pargp->ia_ifname, pargp->ia_aobjname))
 255  256                  return (B_TRUE);
 256  257  
 257  258          if (!nvlist_exists(db_nvl, pargp->ia_pname))
 258  259                  return (B_TRUE);
 259  260  
 260  261          /*
 261  262           * We found the property in the DB. If IPMGMT_REMOVE is not set then
 262  263           * delete the entry from the db. If it is set, then the property is a
 263  264           * multi-valued property so just remove the specified values from DB.
 264  265           */
 265  266          if (pargp->ia_flags & IPMGMT_REMOVE) {
 266  267                  char    *dbpval = NULL;
 267  268                  char    *inpval = pargp->ia_pval;
 268  269                  char    pval[MAXPROPVALLEN];
 269  270                  char    *val, *lasts;
 270  271  
 271  272                  *errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
 272  273                  if (*errp != 0)
 273  274                          return (B_FALSE);
 274  275  
 275  276                  /*
 276  277                   * multi-valued properties are represented as comma separated
 277  278                   * values. Use string tokenizer functions to split them and
 278  279                   * search for the value to be removed.
 279  280                   */
 280  281                  bzero(pval, sizeof (pval));
 281  282                  if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
 282  283                          if (strcmp(val, inpval) != 0)
 283  284                                  (void) strlcat(pval, val, MAXPROPVALLEN);
 284  285                          while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
 285  286                                  if (strcmp(val, inpval) != 0) {
 286  287                                          if (pval[0] != '\0')
 287  288                                                  (void) strlcat(pval, ",",
 288  289                                                      MAXPROPVALLEN);
 289  290                                          (void) strlcat(pval, val,
 290  291                                              MAXPROPVALLEN);
 291  292                                  }
 292  293                          }
 293  294                  } else {
 294  295                          if (strcmp(dbpval, inpval) != 0)
 295  296                                  *errp = ENOENT;
 296  297                          else
 297  298                                  buf[0] =  '\0';
 298  299                          return (B_FALSE);
 299  300                  }
 300  301                  *errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
 301  302                  if (*errp != 0)
 302  303                          return (B_FALSE);
 303  304  
 304  305                  (void) memset(buf, 0, buflen);
 305  306                  if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 306  307                          /* buffer overflow */
 307  308                          *errp = ENOBUFS;
 308  309                  }
 309  310          } else {
 310  311                  buf[0] = '\0';
 311  312          }
 312  313  
 313  314          /* stop the search */
 314  315          return (B_FALSE);
 315  316  }
 316  317  
 317  318  /*
 318  319   * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
 319  320   * found, when one of the following occurs first.
 320  321   * - the input aobjname matches the db aobjname. Return the db address.
 321  322   * - the input interface matches the db interface. Return all the
 322  323   *   matching db lines with addresses.
 323  324   */
 324  325  /* ARGSUSED */
 325  326  boolean_t
 326  327  ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 327  328      int *errp)
 328  329  {
 329  330          ipmgmt_getaddr_cbarg_t  *cbarg = arg;
 330  331          char            *db_aobjname = NULL;
 331  332          char            *db_ifname = NULL;
 332  333          nvlist_t        *db_addr = NULL;
 333  334          char            name[IPMGMT_STRSIZE];
 334  335          nvpair_t        *nvp;
 335  336          boolean_t       add_nvl = B_FALSE;
 336  337  
 337  338          /* Parse db nvlist */
 338  339          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 339  340              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 340  341                  if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
 341  342                          (void) nvpair_value_nvlist(nvp, &db_addr);
 342  343                  else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 343  344                          (void) nvpair_value_string(nvp, &db_ifname);
 344  345                  else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
 345  346                          (void) nvpair_value_string(nvp, &db_aobjname);
 346  347          }
 347  348  
 348  349          if (db_aobjname == NULL) /* Not an address */
 349  350                  return (B_TRUE);
 350  351  
 351  352          /* Check for a match between the aobjnames or the interface name */
 352  353          if (cbarg->cb_aobjname[0] != '\0') {
 353  354                  if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
 354  355                          add_nvl = B_TRUE;
 355  356          } else if (cbarg->cb_ifname[0] != '\0') {
 356  357                  if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
 357  358                          add_nvl = B_TRUE;
 358  359          } else {
 359  360                  add_nvl = B_TRUE;
 360  361          }
 361  362  
 362  363          if (add_nvl) {
 363  364                  (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
 364  365                      cbarg->cb_ocnt);
 365  366                  *errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
 366  367                  if (*errp == 0)
 367  368                          cbarg->cb_ocnt++;
 368  369          }
 369  370          return (B_TRUE);
 370  371  }
 371  372  
 372  373  /*
 373  374   * This function only gets called if a volatile filesystem version
 374  375   * of the configuration file has been created. This only happens in the
 375  376   * extremely rare case that a request has been made to update the configuration
 376  377   * file at boottime while the root filesystem was read-only. This is
  
    | 
      ↓ open down ↓ | 
    343 lines elided | 
    
      ↑ open up ↑ | 
  
 377  378   * really a rare occurrence now that we don't support UFS root filesystems
 378  379   * any longer. This function will periodically attempt to write the
 379  380   * configuration back to its location on the root filesystem. Success
 380  381   * will indicate that the filesystem is no longer read-only.
 381  382   */
 382  383  /* ARGSUSED */
 383  384  static void *
 384  385  ipmgmt_db_restore_thread(void *arg)
 385  386  {
 386  387          int err;
      388 +        char confpath[MAXPATHLEN];
      389 +        char tmpconfpath[MAXPATHLEN];
 387  390  
      391 +        ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
      392 +        ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
      393 +
 388  394          for (;;) {
 389  395                  (void) sleep(5);
 390  396                  (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
 391  397                  if (!ipmgmt_rdonly_root)
 392  398                          break;
 393      -                err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
      399 +                err = ipmgmt_cpfile(tmpconfpath, confpath, B_FALSE);
 394  400                  if (err == 0) {
 395  401                          ipmgmt_rdonly_root = B_FALSE;
 396  402                          break;
 397  403                  }
 398  404                  (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
 399  405          }
 400  406          (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
 401  407          return (NULL);
 402  408  }
 403  409  
 404  410  /*
 405  411   * This function takes the appropriate lock, read or write, based on the
 406  412   * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
 407  413   * by the fact that we are not always guaranteed to have a writable root
 408  414   * filesystem since it is possible that we are reading or writing during
 409  415   * bootime while the root filesystem is still read-only. This is, by far,
 410  416   * the exception case. Normally, this function will be called when the
 411  417   * root filesystem is writable. In the unusual case where this is not
 412  418   * true, the configuration file is copied to the volatile file system
 413  419   * and is updated there until the root filesystem becomes writable. At
 414  420   * that time the file will be moved back to its proper location by
  
    | 
      ↓ open down ↓ | 
    11 lines elided | 
    
      ↑ open up ↑ | 
  
 415  421   * ipmgmt_db_restore_thread().
 416  422   */
 417  423  extern int
 418  424  ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
 419  425  {
 420  426          int             err;
 421  427          boolean_t       writeop;
 422  428          mode_t          mode;
 423  429          pthread_t       tid;
 424  430          pthread_attr_t  attr;
      431 +        char            confpath[MAXPATHLEN];
      432 +        char            tmpconfpath[MAXPATHLEN];
 425  433  
      434 +        ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
      435 +        ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
      436 +
 426  437          writeop = (db_op != IPADM_DB_READ);
 427  438          if (writeop) {
 428  439                  (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
 429  440                  mode = IPADM_FILE_MODE;
 430  441          } else {
 431  442                  (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
 432  443                  mode = 0;
 433  444          }
 434  445  
 435  446          /*
 436  447           * Did a previous write attempt fail? If so, don't even try to
 437      -         * read/write to IPADM_DB_FILE.
      448 +         * read/write to the permanent configuration file.
 438  449           */
 439  450          if (!ipmgmt_rdonly_root) {
 440      -                err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
 441      -                    mode, db_op);
      451 +                err = ipadm_rw_db(db_walk_func, db_warg, confpath, mode, db_op);
 442  452                  if (err != EROFS)
 443  453                          goto done;
 444  454          }
 445  455  
 446  456          /*
 447  457           * If we haven't already copied the file to the volatile
 448  458           * file system, do so. This should only happen on a failed
 449      -         * writeop(i.e., we have acquired the write lock above).
      459 +         * writeop (i.e., we have acquired the write lock above).
 450  460           */
 451      -        if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
      461 +        if (access(tmpconfpath, F_OK) != 0) {
 452  462                  assert(writeop);
 453      -                err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
      463 +                err = ipmgmt_cpfile(confpath, tmpconfpath, B_TRUE);
 454  464                  if (err != 0)
 455  465                          goto done;
 456  466                  (void) pthread_attr_init(&attr);
 457  467                  (void) pthread_attr_setdetachstate(&attr,
 458  468                      PTHREAD_CREATE_DETACHED);
 459  469                  err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
 460  470                      NULL);
 461  471                  (void) pthread_attr_destroy(&attr);
 462  472                  if (err != 0) {
 463      -                        (void) unlink(IPADM_VOL_DB_FILE);
      473 +                        (void) unlink(tmpconfpath);
 464  474                          goto done;
 465  475                  }
 466  476                  ipmgmt_rdonly_root = B_TRUE;
 467  477          }
 468  478  
 469  479          /*
 470  480           * Read/write from the volatile copy.
 471  481           */
 472      -        err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
      482 +        err = ipadm_rw_db(db_walk_func, db_warg, tmpconfpath,
 473  483              mode, db_op);
 474  484  done:
 475  485          (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
 476  486          return (err);
 477  487  }
 478  488  
 479  489  /*
 480  490   * Used to add an entry towards the end of DB. It just returns B_TRUE for
 481  491   * every line of the DB. When we reach the end, ipadm_rw_db() adds the
 482  492   * line at the end.
 483  493   */
 484  494  /* ARGSUSED */
 485  495  boolean_t
 486  496  ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
 487  497  {
 488  498          return (B_TRUE);
 489  499  }
 490  500  
 491  501  /*
 492  502   * This function is used to update or create an entry in DB. The nvlist_t,
 493  503   * `in_nvl', represents the line we are looking for. Once we ensure the right
 494  504   * line from DB, we update that entry.
 495  505   */
 496  506  boolean_t
 497  507  ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 498  508      int *errp)
 499  509  {
 500  510          ipadm_dbwrite_cbarg_t   *cb = arg;
 501  511          uint_t                  flags = cb->dbw_flags;
 502  512          nvlist_t                *in_nvl = cb->dbw_nvl;
 503  513          nvpair_t                *nvp;
 504  514          char                    *name, *instrval = NULL, *dbstrval = NULL;
 505  515          char                    pval[MAXPROPVALLEN];
 506  516  
 507  517          *errp = 0;
 508  518          if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
 509  519                  return (B_TRUE);
 510  520  
 511  521          for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
 512  522              nvp = nvlist_next_nvpair(in_nvl, nvp)) {
 513  523                  name = nvpair_name(nvp);
 514  524                  if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
 515  525                          break;
 516  526          }
 517  527  
 518  528          if (nvp == NULL)
 519  529                  return (B_TRUE);
 520  530  
 521  531          assert(nvpair_type(nvp) == DATA_TYPE_STRING);
 522  532  
 523  533          if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
 524  534                  return (B_FALSE);
 525  535  
 526  536          /*
 527  537           * If IPMGMT_APPEND is set then we are dealing with multi-valued
 528  538           * properties. We append to the entry from the db, with the new value.
 529  539           */
 530  540          if (flags & IPMGMT_APPEND) {
 531  541                  if ((*errp = nvlist_lookup_string(db_nvl, name,
 532  542                      &dbstrval)) != 0)
 533  543                          return (B_FALSE);
 534  544                  (void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
 535  545                      instrval);
 536  546                  if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
 537  547                          return (B_FALSE);
 538  548          } else {
 539  549                  /* case of in-line update of a db entry */
 540  550                  if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
 541  551                          return (B_FALSE);
 542  552          }
 543  553  
 544  554          (void) memset(buf, 0, buflen);
 545  555          if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 546  556                  /* buffer overflow */
 547  557                  *errp = ENOBUFS;
 548  558          }
 549  559  
 550  560          /* we updated the DB entry, so do not continue */
 551  561          return (B_FALSE);
 552  562  }
 553  563  
 554  564  /*
 555  565   * For the given `cbarg->cb_ifname' interface, retrieves any persistent
 556  566   * interface information (used in 'ipadm show-if')
 557  567   */
 558  568  /* ARGSUSED */
 559  569  boolean_t
 560  570  ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 561  571      int *errp)
 562  572  {
 563  573          ipmgmt_getif_cbarg_t    *cbarg = arg;
 564  574          char                    *ifname = cbarg->cb_ifname;
 565  575          char                    *intf = NULL;
 566  576          ipadm_if_info_t         *ifp = NULL;
 567  577          sa_family_t             af;
 568  578          char                    *afstr;
 569  579  
 570  580          *errp = 0;
 571  581          if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
 572  582              nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
 573  583              (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
 574  584                  return (B_TRUE);
 575  585          }
 576  586          af = atoi(afstr);
 577  587          for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
 578  588                  if (strcmp(ifp->ifi_name, intf) == 0)
 579  589                          break;
 580  590          }
 581  591          if (ifp == NULL) {
 582  592                  ipadm_if_info_t *new;
 583  593  
 584  594                  if ((new = calloc(1, sizeof (*new))) == NULL) {
 585  595                          *errp = ENOMEM;
 586  596                          return (B_FALSE); /* don't continue the walk */
 587  597                  }
 588  598                  new->ifi_next = cbarg->cb_ifinfo;
 589  599                  cbarg->cb_ifinfo = new;
 590  600                  ifp = new;
 591  601                  (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
 592  602          }
 593  603  
 594  604          if (af == AF_INET) {
 595  605                  ifp->ifi_pflags |= IFIF_IPV4;
 596  606          } else {
 597  607                  assert(af == AF_INET6);
 598  608                  ifp->ifi_pflags |= IFIF_IPV6;
 599  609          }
 600  610  
 601  611          /* Terminate the walk if we found both v4 and v6 interfaces. */
 602  612          if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
 603  613              (ifp->ifi_pflags & IFIF_IPV6))
 604  614                  return (B_FALSE);
 605  615  
 606  616          return (B_TRUE);
 607  617  }
 608  618  
 609  619  /*
 610  620   * Deletes those entries from the database for which interface name
 611  621   * matches with the given `cbarg->cb_ifname'
 612  622   */
 613  623  /* ARGSUSED */
 614  624  boolean_t
 615  625  ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 616  626      int *errp)
 617  627  {
 618  628          ipmgmt_if_cbarg_t *cbarg = arg;
 619  629          boolean_t       isv6 = (cbarg->cb_family == AF_INET6);
 620  630          char            *ifname = cbarg->cb_ifname;
 621  631          char            *modstr = NULL;
 622  632          char            *afstr;
 623  633          char            *aobjname;
 624  634          uint_t          proto;
 625  635          ipmgmt_aobjmap_t *head;
 626  636          boolean_t       aobjfound = B_FALSE;
 627  637  
 628  638          *errp = 0;
 629  639  
 630  640          if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
 631  641                  return (B_TRUE);
 632  642  
 633  643          if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
 634  644                  if (atoi(afstr) == cbarg->cb_family)
 635  645                          goto delete;
 636  646                  return (B_TRUE);
 637  647          }
 638  648  
 639  649          /* Reset all the interface configurations for 'ifname' */
 640  650          if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
 641  651              nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
 642  652                  goto delete;
 643  653          }
 644  654          if (!isv6 &&
 645  655              (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 646  656              nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
 647  657                  goto delete;
 648  658          }
 649  659  
 650  660          if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
 651  661                  /*
 652  662                   * This must be an address property. Delete this
 653  663                   * line if there is a match in the address family.
 654  664                   */
 655  665                  head = aobjmap.aobjmap_head;
 656  666                  while (head != NULL) {
 657  667                          if (strcmp(head->am_aobjname, aobjname) == 0) {
 658  668                                  aobjfound = B_TRUE;
 659  669                                  if (head->am_family == cbarg->cb_family)
 660  670                                          goto delete;
 661  671                          }
 662  672                          head = head->am_next;
 663  673                  }
 664  674                  /*
 665  675                   * If aobjfound = B_FALSE, then this address is not
 666  676                   * available in active configuration. We should go ahead
 667  677                   * and delete it.
 668  678                   */
 669  679                  if (!aobjfound)
 670  680                          goto delete;
 671  681          }
 672  682  
 673  683          /*
 674  684           * If we are removing both v4 and v6 interface, then we get rid of
 675  685           * all the properties for that interface. On the other hand, if we
 676  686           * are deleting only v4 instance of an interface, then we delete v4
 677  687           * properties only.
 678  688           */
 679  689          if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
 680  690                  proto = ipadm_str2proto(modstr);
 681  691                  switch (proto) {
 682  692                  case MOD_PROTO_IPV6:
 683  693                          if (isv6)
 684  694                                  goto delete;
 685  695                          break;
 686  696                  case MOD_PROTO_IPV4:
 687  697                          if (!isv6)
 688  698                                  goto delete;
 689  699                          break;
 690  700                  case MOD_PROTO_IP:
 691  701                          /* this should never be the case, today */
 692  702                          assert(0);
 693  703                          break;
 694  704                  }
 695  705          }
 696  706          /* Not found a match yet. Continue processing the db */
 697  707          return (B_TRUE);
 698  708  delete:
 699  709          /* delete the line from the db */
 700  710          buf[0] = '\0';
 701  711          return (B_TRUE);
 702  712  }
 703  713  
 704  714  /*
 705  715   * Deletes those entries from the database for which address object name
 706  716   * matches with the given `cbarg->cb_aobjname'
 707  717   */
 708  718  /* ARGSUSED */
 709  719  boolean_t
 710  720  ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 711  721      int *errp)
 712  722  {
 713  723          ipmgmt_resetaddr_cbarg_t *cbarg = arg;
 714  724          char            *aobjname = cbarg->cb_aobjname;
 715  725  
 716  726          *errp = 0;
 717  727          if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
 718  728                  return (B_TRUE);
 719  729  
 720  730          /* delete the line from the db */
 721  731          buf[0] = '\0';
 722  732          return (B_TRUE);
 723  733  }
 724  734  
 725  735  /*
 726  736   * Retrieves all interface props, including addresses, for given interface(s).
 727  737   * `invl' contains the list of interfaces, for which information need to be
 728  738   * retrieved.
 729  739   */
 730  740  /* ARGSUSED */
 731  741  boolean_t
 732  742  ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 733  743      int *errp)
 734  744  {
 735  745          ipmgmt_initif_cbarg_t   *cbarg = arg;
 736  746          nvlist_t                *onvl = cbarg->cb_onvl;
 737  747          nvlist_t                *invl = cbarg->cb_invl;
 738  748          sa_family_t             in_af = cbarg->cb_family;
 739  749          char                    *db_ifname;
 740  750  
 741  751          *errp = 0;
 742  752          if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
 743  753              nvlist_exists(invl, db_ifname)) {
 744  754                  char            name[IPMGMT_STRSIZE];
 745  755                  sa_family_t     db_af = in_af;
 746  756                  uint_t          proto;
 747  757                  char            *pstr;
 748  758  
 749  759                  if (in_af != AF_UNSPEC) {
 750  760                          if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
 751  761                              &pstr) == 0) {
 752  762                                  proto = ipadm_str2proto(pstr);
 753  763                                  if (proto == MOD_PROTO_IPV4)
 754  764                                          db_af = AF_INET;
 755  765                                  else if (proto == MOD_PROTO_IPV6)
 756  766                                          db_af = AF_INET6;
 757  767                                  else
 758  768                                          db_af = in_af;
 759  769                          } else {
 760  770                                  if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 761  771                                      nvlist_exists(db_nvl, IPADM_NVP_DHCP))
 762  772                                          db_af = AF_INET;
 763  773                                  else
 764  774                                          db_af = AF_INET6;
 765  775                          }
 766  776                  }
 767  777                  if (in_af == db_af) {
 768  778                          (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
 769  779                              cbarg->cb_ocnt);
 770  780                          *errp = nvlist_add_nvlist(onvl, name, db_nvl);
 771  781                          if (*errp == 0)
 772  782                                  cbarg->cb_ocnt++;
 773  783                  }
 774  784          }
 775  785          return (B_TRUE);
 776  786  }
 777  787  
 778  788  /*
 779  789   * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
 780  790   * into `aobjmap' structure.
 781  791   */
 782  792  static int
 783  793  i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
 784  794  {
 785  795          ipmgmt_aobjmap_t        *new, *head;
 786  796  
 787  797          head = aobjmap.aobjmap_head;
 788  798          if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
 789  799                  return (ENOMEM);
 790  800          *new = *nodep;
 791  801          new->am_next = NULL;
 792  802  
 793  803          /* Add the node at the beginning of the list */
 794  804          if (head == NULL) {
 795  805                  aobjmap.aobjmap_head = new;
 796  806          } else {
 797  807                  new->am_next = aobjmap.aobjmap_head;
 798  808                  aobjmap.aobjmap_head = new;
 799  809          }
 800  810          return (0);
 801  811  }
 802  812  
 803  813  /*
 804  814   * A recursive function to generate alphabetized number given a decimal number.
 805  815   * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
 806  816   * 'ab', 'ac', et al.
 807  817   */
 808  818  static void
 809  819  i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
 810  820  {
 811  821          if (num >= 26)
 812  822                  i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
 813  823          if (*cp != endp) {
 814  824                  *cp[0] = 'a' + (num % 26);
 815  825                  (*cp)++;
 816  826          }
 817  827  }
 818  828  
 819  829  /*
 820  830   * This function generates an `aobjname', when required, and then does
 821  831   * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
 822  832   * through the `aobjmap' to check if an address object with the same
 823  833   * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
 824  834   * `aobjname's are not allowed.
 825  835   *
 826  836   * If `nodep->am_aobjname' is an empty string then the daemon generates an
 827  837   * `aobjname' using the `am_nextnum', which contains the next number to be
 828  838   * used to generate `aobjname'. `am_nextnum' is converted to base26 using
 829  839   * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
 830  840   *
 831  841   * `am_nextnum' will be 0 to begin with. Every time an address object that
 832  842   * needs `aobjname' is added it's incremented by 1. So for the first address
 833  843   * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
 834  844   * For the second address object on that interface `am_aobjname' will be net0/_b
 835  845   * and  `am_nextnum' will incremented to 2.
 836  846   */
 837  847  static int
 838  848  i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
 839  849  {
 840  850          ipmgmt_aobjmap_t        *head;
 841  851          uint32_t                nextnum;
 842  852  
 843  853          for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
 844  854                  if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
 845  855                          break;
 846  856          nextnum = (head == NULL ? 0 : head->am_nextnum);
 847  857  
 848  858          /*
 849  859           * if `aobjname' is empty, then the daemon has to generate the
 850  860           * next `aobjname' for the given interface and family.
 851  861           */
 852  862          if (nodep->am_aobjname[0] == '\0') {
 853  863                  char tmpstr[IPADM_AOBJ_USTRSIZ - 1];  /* 1 for leading  '_' */
 854  864                  char *cp = tmpstr;
 855  865                  char *endp = tmpstr + sizeof (tmpstr);
 856  866  
 857  867                  i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
 858  868  
 859  869                  if (cp == endp)
 860  870                          return (EINVAL);
 861  871                  cp[0] = '\0';
 862  872  
 863  873                  if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
 864  874                      nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
 865  875                          return (EINVAL);
 866  876                  }
 867  877                  nodep->am_nextnum = ++nextnum;
 868  878          } else {
 869  879                  for (head = aobjmap.aobjmap_head; head != NULL;
 870  880                      head = head->am_next) {
 871  881                          if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
 872  882                                  return (EEXIST);
 873  883                  }
 874  884                  nodep->am_nextnum = nextnum;
 875  885          }
 876  886          return (i_ipmgmt_add_amnode(nodep));
 877  887  }
 878  888  
 879  889  /*
 880  890   * Performs following operations on the global `aobjmap' linked list.
 881  891   * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
 882  892   * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
 883  893   * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
 884  894   * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
 885  895   */
 886  896  int
 887  897  ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
 888  898  {
 889  899          ipmgmt_aobjmap_t        *head, *prev, *matched = NULL;
 890  900          boolean_t               update = B_TRUE;
 891  901          int                     err = 0;
 892  902          ipadm_db_op_t           db_op;
 893  903  
 894  904          (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
 895  905  
 896  906          head = aobjmap.aobjmap_head;
 897  907          switch (op) {
 898  908          case ADDROBJ_ADD:
 899  909                  /*
 900  910                   * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
 901  911                   * update, else add the new node.
 902  912                   */
 903  913                  for (; head != NULL; head = head->am_next) {
 904  914                          /*
 905  915                           * For IPv6, we need to distinguish between the
 906  916                           * linklocal and non-linklocal nodes
 907  917                           */
 908  918                          if (strcmp(head->am_aobjname,
 909  919                              nodep->am_aobjname) == 0 &&
 910  920                              (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
 911  921                              head->am_linklocal == nodep->am_linklocal))
 912  922                                  break;
 913  923                  }
 914  924  
 915  925                  if (head != NULL) {
 916  926                          /* update the node */
 917  927                          (void) strlcpy(head->am_ifname, nodep->am_ifname,
 918  928                              sizeof (head->am_ifname));
 919  929                          head->am_lnum = nodep->am_lnum;
 920  930                          head->am_family = nodep->am_family;
 921  931                          head->am_flags = nodep->am_flags;
 922  932                          head->am_atype = nodep->am_atype;
 923  933                          if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
 924  934                                  head->am_ifid = nodep->am_ifid;
 925  935                                  head->am_linklocal = nodep->am_linklocal;
 926  936                          }
 927  937                  } else {
 928  938                          for (head = aobjmap.aobjmap_head; head != NULL;
 929  939                              head = head->am_next) {
 930  940                                  if (strcmp(head->am_ifname,
 931  941                                      nodep->am_ifname) == 0)
 932  942                                          break;
 933  943                          }
 934  944                          nodep->am_nextnum = (head == NULL ? 0 :
 935  945                              head->am_nextnum);
 936  946                          err = i_ipmgmt_add_amnode(nodep);
 937  947                  }
 938  948                  db_op = IPADM_DB_WRITE;
 939  949                  break;
 940  950          case ADDROBJ_DELETE:
 941  951                  prev = head;
 942  952                  while (head != NULL) {
 943  953                          if (strcmp(head->am_aobjname,
 944  954                              nodep->am_aobjname) == 0) {
 945  955                                  nodep->am_atype = head->am_atype;
 946  956                                  /*
 947  957                                   * There could be multiple IPV6_ADDRCONF nodes,
 948  958                                   * with same address object name, so check for
 949  959                                   * logical number also.
 950  960                                   */
 951  961                                  if (head->am_atype !=
 952  962                                      IPADM_ADDR_IPV6_ADDRCONF ||
 953  963                                      nodep->am_lnum == head->am_lnum)
 954  964                                          break;
 955  965                          }
 956  966                          prev = head;
 957  967                          head = head->am_next;
 958  968                  }
 959  969                  if (head != NULL) {
 960  970                          /*
 961  971                           * If the address object is in both active and
 962  972                           * persistent configuration and the user is deleting it
 963  973                           * only from active configuration then mark this node
 964  974                           * for deletion by reseting IPMGMT_ACTIVE bit.
 965  975                           * With this the same address object name cannot
 966  976                           * be reused until it is permanently removed.
 967  977                           */
 968  978                          if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
 969  979                              nodep->am_flags == IPMGMT_ACTIVE) {
 970  980                                  /* Update flags in the in-memory map. */
 971  981                                  head->am_flags &= ~IPMGMT_ACTIVE;
 972  982                                  head->am_lnum = -1;
 973  983  
 974  984                                  /* Update info in file. */
 975  985                                  db_op = IPADM_DB_WRITE;
 976  986                                  *nodep = *head;
 977  987                          } else {
 978  988                                  (void) strlcpy(nodep->am_ifname,
 979  989                                      head->am_ifname,
 980  990                                      sizeof (nodep->am_ifname));
 981  991                                  /* otherwise delete the node */
 982  992                                  if (head == aobjmap.aobjmap_head)
 983  993                                          aobjmap.aobjmap_head = head->am_next;
 984  994                                  else
 985  995                                          prev->am_next = head->am_next;
 986  996                                  free(head);
 987  997                                  db_op = IPADM_DB_DELETE;
 988  998                          }
 989  999                  } else {
 990 1000                          err = ENOENT;
 991 1001                  }
 992 1002                  break;
 993 1003          case ADDROBJ_LOOKUPADD:
 994 1004                  err = i_ipmgmt_lookupadd_amnode(nodep);
 995 1005                  update = B_FALSE;
 996 1006                  break;
 997 1007          case ADDROBJ_SETLIFNUM:
 998 1008                  update = B_FALSE;
 999 1009                  for (; head != NULL; head = head->am_next) {
1000 1010                          if (strcmp(head->am_ifname,
1001 1011                              nodep->am_ifname) == 0 &&
1002 1012                              head->am_family == nodep->am_family &&
1003 1013                              head->am_lnum == nodep->am_lnum) {
1004 1014                                  err = EEXIST;
1005 1015                                  break;
1006 1016                          }
1007 1017                          if (strcmp(head->am_aobjname,
1008 1018                              nodep->am_aobjname) == 0) {
1009 1019                                  matched = head;
1010 1020                          }
1011 1021                  }
1012 1022                  if (err == EEXIST)
1013 1023                          break;
1014 1024                  if (matched != NULL) {
1015 1025                          /* update the lifnum */
1016 1026                          matched->am_lnum = nodep->am_lnum;
1017 1027                  } else {
1018 1028                          err = ENOENT;
1019 1029                  }
1020 1030                  break;
1021 1031          default:
1022 1032                  assert(0);
1023 1033          }
1024 1034  
1025 1035          if (err == 0 && update)
1026 1036                  err = ipmgmt_persist_aobjmap(nodep, db_op);
1027 1037  
1028 1038          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
1029 1039  
1030 1040          return (err);
1031 1041  }
1032 1042  
1033 1043  /*
1034 1044   * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1035 1045   * The content to be written to DB must be represented as nvlist_t.
1036 1046   */
1037 1047  static int
1038 1048  i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
1039 1049  {
1040 1050          int     err;
1041 1051          char    strval[IPMGMT_STRSIZE];
1042 1052  
1043 1053          *nvl = NULL;
1044 1054          if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
1045 1055                  goto fail;
1046 1056  
1047 1057          if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
1048 1058              np->am_aobjname)) != 0)
1049 1059                  goto fail;
1050 1060  
1051 1061          if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
1052 1062              np->am_ifname)) != 0)
1053 1063                  goto fail;
1054 1064  
1055 1065          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
1056 1066          if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
1057 1067                  goto fail;
1058 1068  
1059 1069          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
1060 1070          if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
1061 1071                  goto fail;
1062 1072  
1063 1073          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
1064 1074          if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
1065 1075                  goto fail;
1066 1076  
1067 1077          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
1068 1078          if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
1069 1079                  goto fail;
1070 1080  
1071 1081          if (np->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1072 1082                  struct sockaddr_in6     *in6;
1073 1083  
1074 1084                  in6 = (struct sockaddr_in6 *)&np->am_ifid;
1075 1085                  if (np->am_linklocal &&
1076 1086                      IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1077 1087                          if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1078 1088                              "default")) != 0)
1079 1089                                  goto fail;
1080 1090                  } else {
1081 1091                          if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1082 1092                              IPMGMT_STRSIZE) == NULL) {
1083 1093                                  err = errno;
1084 1094                                  goto fail;
1085 1095                          }
1086 1096                          if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1087 1097                              strval)) != 0)
1088 1098                                  goto fail;
1089 1099                  }
1090 1100          } else {
1091 1101                  if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1092 1102                      "")) != 0)
1093 1103                          goto fail;
1094 1104          }
1095 1105          return (err);
1096 1106  fail:
1097 1107          nvlist_free(*nvl);
1098 1108          return (err);
1099 1109  }
1100 1110  
1101 1111  /*
1102 1112   * Read the aobjmap data store and build the in-memory representation
1103 1113   * of the aobjmap. We don't need to hold any locks while building this as
1104 1114   * we do this in very early stage of daemon coming up, even before the door
1105 1115   * is opened.
1106 1116   */
1107 1117  /* ARGSUSED */
1108 1118  extern boolean_t
1109 1119  ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1110 1120      int *errp)
1111 1121  {
1112 1122          nvpair_t                *nvp = NULL;
1113 1123          char                    *name, *strval = NULL;
1114 1124          ipmgmt_aobjmap_t        node;
1115 1125          struct sockaddr_in6     *in6;
1116 1126  
1117 1127          *errp = 0;
1118 1128          node.am_next = NULL;
1119 1129          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1120 1130              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1121 1131                  name = nvpair_name(nvp);
1122 1132  
1123 1133                  if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
1124 1134                          return (B_TRUE);
1125 1135                  if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
1126 1136                          (void) strlcpy(node.am_aobjname, strval,
1127 1137                              sizeof (node.am_aobjname));
1128 1138                  } else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
1129 1139                          (void) strlcpy(node.am_ifname, strval,
1130 1140                              sizeof (node.am_ifname));
1131 1141                  } else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
1132 1142                          node.am_lnum = atoi(strval);
1133 1143                  } else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
1134 1144                          node.am_family = (sa_family_t)atoi(strval);
1135 1145                  } else if (strcmp(FLAGS, name) == 0) {
1136 1146                          node.am_flags = atoi(strval);
1137 1147                  } else if (strcmp(ATYPE, name) == 0) {
1138 1148                          node.am_atype = (ipadm_addr_type_t)atoi(strval);
1139 1149                  } else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
1140 1150                          if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1141 1151                                  in6 = (struct sockaddr_in6 *)&node.am_ifid;
1142 1152                                  if (strcmp(strval, "default") == 0) {
1143 1153                                          bzero(in6, sizeof (node.am_ifid));
1144 1154                                          node.am_linklocal = B_TRUE;
1145 1155                                  } else {
1146 1156                                          (void) inet_pton(AF_INET6, strval,
1147 1157                                              &in6->sin6_addr);
1148 1158                                          if (IN6_IS_ADDR_UNSPECIFIED(
1149 1159                                              &in6->sin6_addr))
1150 1160                                                  node.am_linklocal = B_TRUE;
1151 1161                                  }
1152 1162                          }
1153 1163                  }
1154 1164          }
1155 1165  
1156 1166          /* we have all the information we need, add the node */
1157 1167          *errp = i_ipmgmt_add_amnode(&node);
1158 1168  
1159 1169          return (B_TRUE);
1160 1170  }
1161 1171  
1162 1172  /*
1163 1173   * Updates an entry from the temporary cache file, which matches the given
1164 1174   * address object name.
1165 1175   */
1166 1176  /* ARGSUSED */
1167 1177  static boolean_t
1168 1178  ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1169 1179      size_t buflen, int *errp)
1170 1180  {
1171 1181          ipadm_dbwrite_cbarg_t   *cb = arg;
1172 1182          nvlist_t                *in_nvl = cb->dbw_nvl;
1173 1183          uint32_t                flags = cb->dbw_flags;
1174 1184          char                    *db_lifnumstr = NULL, *in_lifnumstr = NULL;
1175 1185  
1176 1186          *errp = 0;
1177 1187          if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
1178 1188                  return (B_TRUE);
1179 1189  
1180 1190          if (flags & IPMGMT_ATYPE_V6ACONF) {
1181 1191                  if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1182 1192                      &db_lifnumstr) != 0 ||
1183 1193                      nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
1184 1194                      &in_lifnumstr) != 0 ||
1185 1195                      (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
1186 1196                      strcmp(db_lifnumstr, in_lifnumstr) != 0))
1187 1197                          return (B_TRUE);
1188 1198          }
1189 1199  
1190 1200          /* we found the match */
1191 1201          (void) memset(buf, 0, buflen);
1192 1202          if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
1193 1203                  /* buffer overflow */
1194 1204                  *errp = ENOBUFS;
1195 1205          }
1196 1206  
1197 1207          /* stop the walker */
1198 1208          return (B_FALSE);
1199 1209  }
1200 1210  
1201 1211  /*
1202 1212   * Deletes an entry from the temporary cache file, which matches the given
1203 1213   * address object name.
1204 1214   */
1205 1215  /* ARGSUSED */
1206 1216  static boolean_t
1207 1217  ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1208 1218      size_t buflen, int *errp)
1209 1219  {
1210 1220          ipmgmt_aobjmap_t        *nodep = arg;
1211 1221          char                    *db_lifnumstr = NULL;
1212 1222  
1213 1223          *errp = 0;
1214 1224          if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
1215 1225              nodep->am_aobjname))
1216 1226                  return (B_TRUE);
1217 1227  
1218 1228          if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1219 1229                  if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1220 1230                      &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
1221 1231                          return (B_TRUE);
1222 1232          }
1223 1233  
1224 1234          /* we found the match, delete the line from the db */
1225 1235          buf[0] = '\0';
1226 1236  
1227 1237          /* stop the walker */
1228 1238          return (B_FALSE);
1229 1239  }
  
    | 
      ↓ open down ↓ | 
    747 lines elided | 
    
      ↑ open up ↑ | 
  
1230 1240  
1231 1241  /*
1232 1242   * Adds or deletes aobjmap node information into a temporary cache file.
1233 1243   */
1234 1244  extern int
1235 1245  ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
1236 1246  {
1237 1247          int                     err;
1238 1248          ipadm_dbwrite_cbarg_t   cb;
1239 1249          nvlist_t                *nvl = NULL;
     1250 +        char                    aobjpath[MAXPATHLEN];
1240 1251  
     1252 +        ipmgmt_path(IPADM_PATH_ADDROBJ_MAP_DB, aobjpath, sizeof (aobjpath));
     1253 +
1241 1254          if (op == IPADM_DB_WRITE) {
1242 1255                  if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
1243 1256                          return (err);
1244 1257                  cb.dbw_nvl = nvl;
1245 1258                  if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
1246 1259                          cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
1247 1260                  else
1248 1261                          cb.dbw_flags = 0;
1249 1262  
1250      -                err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
1251      -                    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
     1263 +                err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb, aobjpath,
     1264 +                    IPADM_FILE_MODE, IPADM_DB_WRITE);
1252 1265                  nvlist_free(nvl);
1253 1266          } else {
1254 1267                  assert(op == IPADM_DB_DELETE);
1255 1268  
1256      -                err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
1257      -                    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
     1269 +                err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep, aobjpath,
     1270 +                    IPADM_FILE_MODE, IPADM_DB_DELETE);
1258 1271          }
1259 1272          return (err);
1260 1273  }
1261 1274  
1262 1275  /*
1263 1276   * upgrades the ipadm data-store. It renames all the old private protocol
1264 1277   * property names which start with leading protocol names to begin with
1265 1278   * IPADM_PRIV_PROP_PREFIX.
1266 1279   */
1267 1280  /* ARGSUSED */
1268 1281  boolean_t
1269 1282  ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1270 1283      int *errp)
1271 1284  {
1272 1285          nvpair_t        *nvp;
1273 1286          char            *name, *pname = NULL, *protostr = NULL, *pval = NULL;
1274 1287          uint_t          proto, nproto;
1275 1288          char            nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1276 1289  
1277 1290          *errp = 0;
1278 1291          /*
1279 1292           * We are interested in lines which contain protocol properties. We
1280 1293           * walk through other lines in the DB.
1281 1294           */
1282 1295          if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
1283 1296              nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
1284 1297                  return (B_TRUE);
1285 1298          }
1286 1299          assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
1287 1300  
1288 1301          /*
1289 1302           * extract the propname from the `db_nvl' and also extract the
1290 1303           * protocol from the `db_nvl'.
1291 1304           */
1292 1305          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1293 1306              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1294 1307                  name = nvpair_name(nvp);
1295 1308                  if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
1296 1309                          if (nvpair_value_string(nvp, &protostr) != 0)
1297 1310                                  return (B_TRUE);
1298 1311                  } else {
1299 1312                          assert(!IPADM_PRIV_NVP(name));
1300 1313                          pname = name;
1301 1314                          if (nvpair_value_string(nvp, &pval) != 0)
1302 1315                                  return (B_TRUE);
1303 1316                  }
1304 1317          }
1305 1318  
1306 1319          /* if the private property is in the right format return */
1307 1320          if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
1308 1321              strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1309 1322                  return (B_TRUE);
1310 1323          }
1311 1324          /* if it's a public property move onto the next property */
1312 1325          nproto = proto = ipadm_str2proto(protostr);
1313 1326          if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
1314 1327              &nproto) != 0) {
1315 1328                  return (B_TRUE);
1316 1329          }
1317 1330  
1318 1331          /* replace the old protocol with new protocol, if required */
1319 1332          if (nproto != proto) {
1320 1333                  protostr = ipadm_proto2str(nproto);
1321 1334                  if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
1322 1335                      protostr) != 0) {
1323 1336                          return (B_TRUE);
1324 1337                  }
1325 1338          }
1326 1339  
1327 1340          /* replace the old property name with new property name, if required */
1328 1341          /* add the prefix to property name */
1329 1342          (void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
1330 1343          if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
1331 1344              nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
1332 1345                  return (B_TRUE);
1333 1346          }
1334 1347          (void) memset(buf, 0, buflen);
1335 1348          if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1336 1349                  /* buffer overflow */
1337 1350                  *errp = ENOBUFS;
1338 1351          }
1339 1352          return (B_TRUE);
1340 1353  }
1341 1354  
1342 1355  /*
1343 1356   * Called during boot.
1344 1357   *
1345 1358   * Walk through the DB and apply all the global module properties. We plow
1346 1359   * through the DB even if we fail to apply property.
1347 1360   */
1348 1361  /* ARGSUSED */
1349 1362  static boolean_t
1350 1363  ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1351 1364      int *errp)
1352 1365  {
1353 1366          ipadm_handle_t  iph = cbarg;
1354 1367          nvpair_t        *nvp, *pnvp;
1355 1368          char            *strval = NULL, *name, *mod = NULL, *pname;
1356 1369          char            tmpstr[IPMGMT_STRSIZE];
1357 1370          uint_t          proto;
1358 1371  
1359 1372          /*
1360 1373           * We could have used nvl_exists() directly, however we need several
1361 1374           * calls to it and each call traverses the list. Since this codepath
1362 1375           * is exercised during boot, let's traverse the list ourselves and do
1363 1376           * the necessary checks.
1364 1377           */
1365 1378          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1366 1379              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1367 1380                  name = nvpair_name(nvp);
1368 1381                  if (IPADM_PRIV_NVP(name)) {
1369 1382                          if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1370 1383                              strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1371 1384                                  return (B_TRUE);
1372 1385                          else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1373 1386                              nvpair_value_string(nvp, &mod) != 0)
1374 1387                                  return (B_TRUE);
1375 1388                  } else {
1376 1389                          /* possible a property */
1377 1390                          pnvp = nvp;
1378 1391                  }
1379 1392          }
1380 1393  
1381 1394          /* if we are here than we found a global property */
1382 1395          assert(mod != NULL);
1383 1396          assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1384 1397  
1385 1398          proto = ipadm_str2proto(mod);
1386 1399          name = nvpair_name(pnvp);
1387 1400          if (nvpair_value_string(pnvp, &strval) == 0) {
1388 1401                  if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1389 1402                      strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1390 1403                          /* private protocol property */
1391 1404                          pname = &name[1];
1392 1405                  } else if (ipadm_legacy2new_propname(name, tmpstr,
1393 1406                      sizeof (tmpstr), &proto) == 0) {
1394 1407                          pname = tmpstr;
1395 1408                  } else {
1396 1409                          pname = name;
1397 1410                  }
1398 1411                  if (ipadm_set_prop(iph, pname, strval, proto,
1399 1412                      IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1400 1413                          ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1401 1414                              pname);
1402 1415                  }
1403 1416          }
1404 1417  
1405 1418          return (B_TRUE);
1406 1419  }
1407 1420  
1408 1421  /* initialize global module properties */
1409 1422  void
1410 1423  ipmgmt_init_prop()
1411 1424  {
1412 1425          ipadm_handle_t  iph = NULL;
1413 1426  
1414 1427          if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
1415 1428                  ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
1416 1429                      "persisted protocol properties");
1417 1430                  return;
1418 1431          }
1419 1432          /* ipmgmt_db_init() logs warnings if there are any issues */
1420 1433          (void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
1421 1434          ipadm_close(iph);
1422 1435  }
1423 1436  
1424 1437  void
1425 1438  ipmgmt_release_scf_resources(scf_resources_t *res)
1426 1439  {
1427 1440          scf_entry_destroy(res->sr_ent);
1428 1441          scf_transaction_destroy(res->sr_tx);
1429 1442          scf_value_destroy(res->sr_val);
1430 1443          scf_property_destroy(res->sr_prop);
1431 1444          scf_pg_destroy(res->sr_pg);
1432 1445          scf_instance_destroy(res->sr_inst);
1433 1446          (void) scf_handle_unbind(res->sr_handle);
1434 1447          scf_handle_destroy(res->sr_handle);
1435 1448  }
1436 1449  
1437 1450  /*
1438 1451   * It creates the necessary SCF handles and binds the given `fmri' to an
1439 1452   * instance. These resources are required for retrieving property value,
1440 1453   * creating property groups and modifying property values.
1441 1454   */
1442 1455  int
1443 1456  ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1444 1457  {
1445 1458          res->sr_tx = NULL;
1446 1459          res->sr_ent = NULL;
1447 1460          res->sr_inst = NULL;
1448 1461          res->sr_pg = NULL;
1449 1462          res->sr_prop = NULL;
1450 1463          res->sr_val = NULL;
1451 1464  
1452 1465          if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1453 1466                  return (-1);
1454 1467  
1455 1468          if (scf_handle_bind(res->sr_handle) != 0) {
1456 1469                  scf_handle_destroy(res->sr_handle);
1457 1470                  return (-1);
1458 1471          }
1459 1472          if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1460 1473                  goto failure;
1461 1474          if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1462 1475              res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1463 1476                  goto failure;
1464 1477          }
1465 1478          /* we will create the rest of the resources on demand */
1466 1479          return (0);
1467 1480  
1468 1481  failure:
1469 1482          ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
1470 1483              scf_strerror(scf_error()));
1471 1484          ipmgmt_release_scf_resources(res);
1472 1485          return (-1);
1473 1486  }
1474 1487  
1475 1488  /*
1476 1489   * persists the `pval' for a given property `pname' in SCF. The only supported
1477 1490   * SCF property types are INTEGER and ASTRING.
1478 1491   */
1479 1492  static int
1480 1493  ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
1481 1494      scf_type_t ptype)
1482 1495  {
1483 1496          int result = -1;
1484 1497          boolean_t new;
1485 1498  
1486 1499          if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
1487 1500                  goto failure;
1488 1501          switch (ptype) {
1489 1502          case SCF_TYPE_INTEGER:
1490 1503                  scf_value_set_integer(res->sr_val, *(int64_t *)pval);
1491 1504                  break;
1492 1505          case SCF_TYPE_ASTRING:
1493 1506                  if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
1494 1507                          ipmgmt_log(LOG_WARNING, "Error setting string value %s "
1495 1508                              "for property %s: %s", pval, pname,
1496 1509                              scf_strerror(scf_error()));
1497 1510                          goto failure;
1498 1511                  }
1499 1512                  break;
1500 1513          default:
1501 1514                  goto failure;
1502 1515          }
1503 1516  
1504 1517          if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
1505 1518                  goto failure;
1506 1519          if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
1507 1520                  goto failure;
1508 1521          if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
1509 1522                  goto failure;
1510 1523  
1511 1524  retry:
1512 1525          new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
1513 1526          if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
1514 1527                  goto failure;
1515 1528          if (new) {
1516 1529                  if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
1517 1530                      pname, ptype) == -1) {
1518 1531                          goto failure;
1519 1532                  }
1520 1533          } else {
1521 1534                  if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
1522 1535                      pname, ptype) == -1) {
1523 1536                          goto failure;
1524 1537                  }
1525 1538          }
1526 1539  
1527 1540          if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1528 1541                  goto failure;
1529 1542  
1530 1543          result = scf_transaction_commit(res->sr_tx);
1531 1544          if (result == 0) {
1532 1545                  scf_transaction_reset(res->sr_tx);
1533 1546                  if (scf_pg_update(res->sr_pg) == -1) {
1534 1547                          goto failure;
1535 1548                  }
1536 1549                  goto retry;
1537 1550          }
1538 1551          if (result == -1)
1539 1552                  goto failure;
1540 1553          return (0);
1541 1554  
1542 1555  failure:
1543 1556          ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
1544 1557              scf_strerror(scf_error()));
1545 1558          return (-1);
1546 1559  }
1547 1560  
1548 1561  /*
1549 1562   * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1550 1563   * places it in `pval'.
1551 1564   */
1552 1565  static int
1553 1566  ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1554 1567      void *pval, scf_type_t ptype)
1555 1568  {
1556 1569          ssize_t         numvals;
1557 1570          scf_simple_prop_t *prop;
1558 1571  
1559 1572          prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1560 1573          numvals = scf_simple_prop_numvalues(prop);
1561 1574          if (numvals <= 0)
1562 1575                  goto ret;
1563 1576          switch (ptype) {
1564 1577          case SCF_TYPE_INTEGER:
1565 1578                  *(int64_t **)pval = scf_simple_prop_next_integer(prop);
1566 1579                  break;
1567 1580          case SCF_TYPE_ASTRING:
1568 1581                  *(char **)pval = scf_simple_prop_next_astring(prop);
1569 1582                  break;
1570 1583          }
1571 1584  ret:
1572 1585          scf_simple_prop_free(prop);
1573 1586          return (numvals);
1574 1587  }
1575 1588  
1576 1589  /*
1577 1590   * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1578 1591   */
1579 1592  static int
1580 1593  ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1581 1594      void *pval, scf_type_t ptype)
1582 1595  {
1583 1596          scf_error_t             err;
1584 1597  
1585 1598          if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1586 1599                  ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1587 1600                      scf_strerror(scf_error()));
1588 1601                  return (-1);
1589 1602          }
1590 1603  
1591 1604          if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
1592 1605              0, res->sr_pg) != 0) {
1593 1606                  if ((err = scf_error()) != SCF_ERROR_EXISTS) {
1594 1607                          ipmgmt_log(LOG_WARNING,
1595 1608                              "Error adding property group '%s/%s': %s",
1596 1609                              pgname, pname, scf_strerror(err));
1597 1610                          return (-1);
1598 1611                  }
1599 1612                  /*
1600 1613                   * if the property group already exists, then we get the
1601 1614                   * composed view of the property group for the given instance.
1602 1615                   */
1603 1616                  if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
1604 1617                      res->sr_pg) != 0) {
1605 1618                          ipmgmt_log(LOG_WARNING, "Error getting composed view "
1606 1619                              "of the property group '%s/%s': %s", pgname, pname,
1607 1620                              scf_strerror(scf_error()));
1608 1621                          return (-1);
1609 1622                  }
1610 1623          }
1611 1624  
1612 1625          return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
1613 1626  }
1614 1627  
1615 1628  /*
1616 1629   * Returns B_TRUE, if the non-global zone is being booted for the first time
1617 1630   * after being installed. This is required to setup the ipadm data-store for
1618 1631   * the first boot of the non-global zone. Please see, PSARC 2010/166,
1619 1632   * for more info.
1620 1633   *
1621 1634   * Note that, this API cannot be used to determine first boot post image-update.
1622 1635   * 'pkg image-update' clones the current BE and the existing value of
1623 1636   * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1624 1637   * to B_TRUE.
1625 1638   */
1626 1639  boolean_t
1627 1640  ipmgmt_ngz_firstboot_postinstall()
1628 1641  {
1629 1642          scf_resources_t res;
1630 1643          boolean_t       bval = B_TRUE;
1631 1644          char            *strval;
1632 1645  
1633 1646          /* we always err on the side of caution */
1634 1647          if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
1635 1648                  return (bval);
1636 1649  
1637 1650          if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
1638 1651              SCF_TYPE_ASTRING) > 0) {
1639 1652                  bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
1640 1653                      B_FALSE : B_TRUE);
1641 1654          } else {
1642 1655                  /*
1643 1656                   * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1644 1657                   * Since we err on the side of caution, we ignore the return
1645 1658                   * error and return B_TRUE.
1646 1659                   */
1647 1660                  (void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
1648 1661                      IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1649 1662          }
1650 1663          ipmgmt_release_scf_resources(&res);
1651 1664          return (bval);
1652 1665  }
1653 1666  
1654 1667  /*
1655 1668   * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1656 1669   * Today we have to take care of, one case of, upgrading from version 0 to
1657 1670   * version 1, so we will use boolean_t as means to decide if upgrade is needed
1658 1671   * or not. Further, the upcoming projects might completely move the flatfile
1659 1672   * data-store into SCF and hence we shall keep this interface simple.
1660 1673   */
1661 1674  boolean_t
1662 1675  ipmgmt_needs_upgrade(scf_resources_t *res)
1663 1676  {
1664 1677          boolean_t       bval = B_TRUE;
1665 1678          int64_t         *verp;
1666 1679  
1667 1680          if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
1668 1681              &verp, SCF_TYPE_INTEGER) > 0) {
1669 1682                  if (*verp == IPADM_DB_VERSION)
1670 1683                          bval = B_FALSE;
1671 1684          }
1672 1685          /*
1673 1686           * 'datastore_version' doesn't exist. Which means that we need to
1674 1687           * upgrade the datastore. We will create 'datastore_version' and set
1675 1688           * the version value to IPADM_DB_VERSION, after we upgrade the file.
1676 1689           */
1677 1690          return (bval);
1678 1691  }
1679 1692  
1680 1693  /*
1681 1694   * This is called after the successful upgrade of the local data-store. With
1682 1695   * the data-store upgraded to recent version we don't have to do anything on
1683 1696   * subsequent reboots.
1684 1697   */
1685 1698  void
1686 1699  ipmgmt_update_dbver(scf_resources_t *res)
1687 1700  {
1688 1701          int64_t         version = IPADM_DB_VERSION;
1689 1702  
1690 1703          (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1691 1704              IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1692 1705  }
  
    | 
      ↓ open down ↓ | 
    425 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX