Print this page
    
7029 want per-process exploit mitigation features (secflags)
7030 want basic address space layout randomization (aslr)
7031 noexec_user_stack should be a secflag
7032 want a means to forbid mappings around NULL.
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/svc/svccfg/svccfg_libscf.c
          +++ new/usr/src/cmd/svc/svccfg/svccfg_libscf.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  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) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2015 Joyent, Inc.
  25   25   * Copyright 2012 Milan Jurik. All rights reserved.
  26   26   */
  27   27  
  28   28  
  29   29  #include <alloca.h>
  30   30  #include <assert.h>
  31   31  #include <ctype.h>
  32   32  #include <door.h>
  33   33  #include <errno.h>
  34   34  #include <fcntl.h>
  35   35  #include <fnmatch.h>
  36   36  #include <inttypes.h>
  37   37  #include <libintl.h>
  38   38  #include <libnvpair.h>
  39   39  #include <libscf.h>
  40   40  #include <libscf_priv.h>
  41   41  #include <libtecla.h>
  42   42  #include <libuutil.h>
  43   43  #include <limits.h>
  44   44  #include <locale.h>
  45   45  #include <stdarg.h>
  46   46  #include <string.h>
  47   47  #include <strings.h>
  48   48  #include <time.h>
  49   49  #include <unistd.h>
  50   50  #include <wait.h>
  51   51  #include <poll.h>
  52   52  
  53   53  #include <libxml/tree.h>
  54   54  
  55   55  #include <sys/param.h>
  56   56  
  57   57  #include <sys/stat.h>
  58   58  #include <sys/mman.h>
  59   59  
  60   60  #include "svccfg.h"
  61   61  #include "notify_params.h"
  62   62  #include "manifest_hash.h"
  63   63  #include "manifest_find.h"
  64   64  
  65   65  /* The colon namespaces in each entity (each followed by a newline). */
  66   66  #define COLON_NAMESPACES        ":properties\n"
  67   67  
  68   68  #define TEMP_FILE_PATTERN       "/tmp/svccfg-XXXXXX"
  69   69  
  70   70  /* These are characters which the lexer requires to be in double-quotes. */
  71   71  #define CHARS_TO_QUOTE          " \t\n\\>=\"()"
  72   72  
  73   73  #define HASH_SIZE               16
  74   74  #define HASH_PG_TYPE            "framework"
  75   75  #define HASH_PG_FLAGS           0
  76   76  #define HASH_PROP               "md5sum"
  77   77  
  78   78  /*
  79   79   * Indentation used in the output of the describe subcommand.
  80   80   */
  81   81  #define TMPL_VALUE_INDENT       "  "
  82   82  #define TMPL_INDENT             "    "
  83   83  #define TMPL_INDENT_2X          "        "
  84   84  #define TMPL_CHOICE_INDENT      "      "
  85   85  
  86   86  /*
  87   87   * Directory locations for manifests
  88   88   */
  89   89  #define VARSVC_DIR              "/var/svc/manifest"
  90   90  #define LIBSVC_DIR              "/lib/svc/manifest"
  91   91  #define VARSVC_PR               "var_svc_manifest"
  92   92  #define LIBSVC_PR               "lib_svc_manifest"
  93   93  #define MFSTFILEPR              "manifestfile"
  94   94  
  95   95  #define SUPPORTPROP             "support"
  96   96  
  97   97  #define MFSTHISTFILE            "/lib/svc/share/mfsthistory"
  98   98  
  99   99  #define MFSTFILE_MAX            16
 100  100  
 101  101  /*
 102  102   * These are the classes of elements which may appear as children of service
 103  103   * or instance elements in XML manifests.
 104  104   */
 105  105  struct entity_elts {
 106  106          xmlNodePtr      create_default_instance;
 107  107          xmlNodePtr      single_instance;
 108  108          xmlNodePtr      restarter;
 109  109          xmlNodePtr      dependencies;
 110  110          xmlNodePtr      dependents;
 111  111          xmlNodePtr      method_context;
 112  112          xmlNodePtr      exec_methods;
 113  113          xmlNodePtr      notify_params;
 114  114          xmlNodePtr      property_groups;
 115  115          xmlNodePtr      instances;
 116  116          xmlNodePtr      stability;
 117  117          xmlNodePtr      template;
 118  118  };
 119  119  
 120  120  /*
 121  121   * Likewise for property_group elements.
 122  122   */
 123  123  struct pg_elts {
 124  124          xmlNodePtr      stability;
 125  125          xmlNodePtr      propvals;
 126  126          xmlNodePtr      properties;
 127  127  };
 128  128  
 129  129  /*
 130  130   * Likewise for template elements.
 131  131   */
 132  132  struct template_elts {
 133  133          xmlNodePtr      common_name;
 134  134          xmlNodePtr      description;
 135  135          xmlNodePtr      documentation;
 136  136  };
 137  137  
 138  138  /*
 139  139   * Likewise for type (for notification parameters) elements.
 140  140   */
 141  141  struct params_elts {
 142  142          xmlNodePtr      paramval;
 143  143          xmlNodePtr      parameter;
 144  144  };
 145  145  
 146  146  /*
 147  147   * This structure is for snaplevel lists.  They are convenient because libscf
 148  148   * only allows traversing snaplevels in one direction.
 149  149   */
 150  150  struct snaplevel {
 151  151          uu_list_node_t  list_node;
 152  152          scf_snaplevel_t *sl;
 153  153  };
 154  154  
 155  155  /*
 156  156   * This is used for communication between lscf_service_export and
 157  157   * export_callback.
 158  158   */
 159  159  struct export_args {
 160  160          const char      *filename;
 161  161          int             flags;
 162  162  };
 163  163  
 164  164  /*
 165  165   * The service_manifest structure is used by the upgrade process
 166  166   * to create a list of service to manifest linkages from the manifests
 167  167   * in a set of given directories.
 168  168   */
 169  169  typedef struct service_manifest {
 170  170          const char      *servicename;
 171  171          uu_list_t       *mfstlist;
 172  172          size_t  mfstlist_sz;
 173  173  
 174  174          uu_avl_node_t   svcmfst_node;
 175  175  } service_manifest_t;
 176  176  
 177  177  /*
 178  178   * Structure to track the manifest file property group
 179  179   * and the manifest file associated with that property
 180  180   * group.  Also, a flag to keep the access once it has
 181  181   * been checked.
 182  182   */
 183  183  struct mpg_mfile {
 184  184          char    *mpg;
 185  185          char    *mfile;
 186  186          int     access;
 187  187  };
 188  188  
 189  189  const char * const scf_pg_general = SCF_PG_GENERAL;
 190  190  const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
 191  191  const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
 192  192  const char * const scf_property_external = "external";
 193  193  
 194  194  const char * const snap_initial = "initial";
 195  195  const char * const snap_lastimport = "last-import";
 196  196  const char * const snap_previous = "previous";
 197  197  const char * const snap_running = "running";
 198  198  
 199  199  scf_handle_t *g_hndl = NULL;    /* only valid after lscf_prep_hndl() */
 200  200  
 201  201  ssize_t max_scf_fmri_len;
 202  202  ssize_t max_scf_name_len;
 203  203  ssize_t max_scf_pg_type_len;
 204  204  ssize_t max_scf_value_len;
 205  205  static size_t max_scf_len;
 206  206  
 207  207  static scf_scope_t *cur_scope;
 208  208  static scf_service_t *cur_svc = NULL;
 209  209  static scf_instance_t *cur_inst = NULL;
 210  210  static scf_snapshot_t *cur_snap = NULL;
 211  211  static scf_snaplevel_t *cur_level = NULL;
 212  212  
 213  213  static uu_list_pool_t *snaplevel_pool;
 214  214  /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
 215  215  static uu_list_t *cur_levels;
 216  216  static struct snaplevel *cur_elt;               /* cur_elt->sl == cur_level */
 217  217  
 218  218  static FILE *tempfile = NULL;
 219  219  static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
 220  220  
 221  221  static const char *emsg_entity_not_selected;
 222  222  static const char *emsg_permission_denied;
 223  223  static const char *emsg_create_xml;
 224  224  static const char *emsg_cant_modify_snapshots;
 225  225  static const char *emsg_invalid_for_snapshot;
 226  226  static const char *emsg_read_only;
 227  227  static const char *emsg_deleted;
 228  228  static const char *emsg_invalid_pg_name;
 229  229  static const char *emsg_invalid_prop_name;
 230  230  static const char *emsg_no_such_pg;
 231  231  static const char *emsg_fmri_invalid_pg_name;
 232  232  static const char *emsg_fmri_invalid_pg_name_type;
 233  233  static const char *emsg_pg_added;
 234  234  static const char *emsg_pg_changed;
 235  235  static const char *emsg_pg_deleted;
 236  236  static const char *emsg_pg_mod_perm;
 237  237  static const char *emsg_pg_add_perm;
 238  238  static const char *emsg_pg_del_perm;
 239  239  static const char *emsg_snap_perm;
 240  240  static const char *emsg_dpt_dangling;
 241  241  static const char *emsg_dpt_no_dep;
 242  242  
 243  243  static int li_only = 0;
 244  244  static int no_refresh = 0;
 245  245  
 246  246  /* how long in ns we should wait between checks for a pg */
 247  247  static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
 248  248  
 249  249  /* import globals, to minimize allocations */
 250  250  static scf_scope_t *imp_scope = NULL;
 251  251  static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
 252  252  static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
 253  253  static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
 254  254  static scf_snapshot_t *imp_rsnap = NULL;
 255  255  static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
 256  256  static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
 257  257  static scf_property_t *imp_prop = NULL;
 258  258  static scf_iter_t *imp_iter = NULL;
 259  259  static scf_iter_t *imp_rpg_iter = NULL;
 260  260  static scf_iter_t *imp_up_iter = NULL;
 261  261  static scf_transaction_t *imp_tx = NULL;        /* always reset this */
 262  262  static char *imp_str = NULL;
 263  263  static size_t imp_str_sz;
 264  264  static char *imp_tsname = NULL;
 265  265  static char *imp_fe1 = NULL;            /* for fmri_equal() */
 266  266  static char *imp_fe2 = NULL;
 267  267  static uu_list_t *imp_deleted_dpts = NULL;      /* pgroup_t's to refresh */
 268  268  
 269  269  /* upgrade_dependents() globals */
 270  270  static scf_instance_t *ud_inst = NULL;
 271  271  static scf_snaplevel_t *ud_snpl = NULL;
 272  272  static scf_propertygroup_t *ud_pg = NULL;
 273  273  static scf_propertygroup_t *ud_cur_depts_pg = NULL;
 274  274  static scf_propertygroup_t *ud_run_dpts_pg = NULL;
 275  275  static int ud_run_dpts_pg_set = 0;
 276  276  static scf_property_t *ud_prop = NULL;
 277  277  static scf_property_t *ud_dpt_prop = NULL;
 278  278  static scf_value_t *ud_val = NULL;
 279  279  static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
 280  280  static scf_transaction_t *ud_tx = NULL;
 281  281  static char *ud_ctarg = NULL;
 282  282  static char *ud_oldtarg = NULL;
 283  283  static char *ud_name = NULL;
 284  284  
 285  285  /* export globals */
 286  286  static scf_instance_t *exp_inst;
 287  287  static scf_propertygroup_t *exp_pg;
 288  288  static scf_property_t *exp_prop;
 289  289  static scf_value_t *exp_val;
 290  290  static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
 291  291  static char *exp_str;
 292  292  static size_t exp_str_sz;
 293  293  
 294  294  /* cleanup globals */
 295  295  static uu_avl_pool_t *service_manifest_pool = NULL;
 296  296  static uu_avl_t *service_manifest_tree = NULL;
 297  297  
 298  298  static void scfdie_lineno(int lineno) __NORETURN;
 299  299  
 300  300  static char *start_method_names[] = {
 301  301          "start",
 302  302          "inetd_start",
 303  303          NULL
 304  304  };
 305  305  
 306  306  static struct uri_scheme {
 307  307          const char *scheme;
 308  308          const char *protocol;
 309  309  } uri_scheme[] = {
 310  310          { "mailto", "smtp" },
 311  311          { "snmp", "snmp" },
 312  312          { "syslog", "syslog" },
 313  313          { NULL, NULL }
 314  314  };
 315  315  #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
 316  316      sizeof (struct uri_scheme)) - 1)
 317  317  
 318  318  static int
 319  319  check_uri_scheme(const char *scheme)
 320  320  {
 321  321          int i;
 322  322  
 323  323          for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
 324  324                  if (strcmp(scheme, uri_scheme[i].scheme) == 0)
 325  325                          return (i);
 326  326          }
 327  327  
 328  328          return (-1);
 329  329  }
 330  330  
 331  331  static int
 332  332  check_uri_protocol(const char *p)
 333  333  {
 334  334          int i;
 335  335  
 336  336          for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
 337  337                  if (strcmp(p, uri_scheme[i].protocol) == 0)
 338  338                          return (i);
 339  339          }
 340  340  
 341  341          return (-1);
 342  342  }
 343  343  
 344  344  /*
 345  345   * For unexpected libscf errors.
 346  346   */
 347  347  #ifdef NDEBUG
 348  348  
 349  349  static void scfdie(void) __NORETURN;
 350  350  
 351  351  static void
 352  352  scfdie(void)
 353  353  {
 354  354          scf_error_t err = scf_error();
 355  355  
 356  356          if (err == SCF_ERROR_CONNECTION_BROKEN)
 357  357                  uu_die(gettext("Repository connection broken.  Exiting.\n"));
 358  358  
 359  359          uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
 360  360              scf_strerror(err));
 361  361  }
 362  362  
 363  363  #else
 364  364  
 365  365  #define scfdie()        scfdie_lineno(__LINE__)
 366  366  
 367  367  static void
 368  368  scfdie_lineno(int lineno)
 369  369  {
 370  370          scf_error_t err = scf_error();
 371  371  
 372  372          if (err == SCF_ERROR_CONNECTION_BROKEN)
 373  373                  uu_die(gettext("Repository connection broken.  Exiting.\n"));
 374  374  
 375  375          uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
 376  376              ": %s.\n"), lineno, scf_strerror(err));
 377  377  }
 378  378  
 379  379  #endif
 380  380  
 381  381  static void
 382  382  scfwarn(void)
 383  383  {
 384  384          warn(gettext("Unexpected libscf error: %s.\n"),
 385  385              scf_strerror(scf_error()));
 386  386  }
 387  387  
 388  388  /*
 389  389   * Clear a field of a structure.
 390  390   */
 391  391  static int
 392  392  clear_int(void *a, void *b)
 393  393  {
 394  394          /* LINTED */
 395  395          *(int *)((char *)a + (size_t)b) = 0;
 396  396  
 397  397          return (UU_WALK_NEXT);
 398  398  }
 399  399  
 400  400  static int
 401  401  scferror2errno(scf_error_t err)
 402  402  {
 403  403          switch (err) {
 404  404          case SCF_ERROR_BACKEND_ACCESS:
 405  405                  return (EACCES);
 406  406  
 407  407          case SCF_ERROR_BACKEND_READONLY:
 408  408                  return (EROFS);
 409  409  
 410  410          case SCF_ERROR_CONNECTION_BROKEN:
 411  411                  return (ECONNABORTED);
 412  412  
 413  413          case SCF_ERROR_CONSTRAINT_VIOLATED:
 414  414          case SCF_ERROR_INVALID_ARGUMENT:
 415  415                  return (EINVAL);
 416  416  
 417  417          case SCF_ERROR_DELETED:
 418  418                  return (ECANCELED);
 419  419  
 420  420          case SCF_ERROR_EXISTS:
 421  421                  return (EEXIST);
 422  422  
 423  423          case SCF_ERROR_NO_MEMORY:
 424  424                  return (ENOMEM);
 425  425  
 426  426          case SCF_ERROR_NO_RESOURCES:
 427  427                  return (ENOSPC);
 428  428  
 429  429          case SCF_ERROR_NOT_FOUND:
 430  430                  return (ENOENT);
 431  431  
 432  432          case SCF_ERROR_PERMISSION_DENIED:
 433  433                  return (EPERM);
 434  434  
 435  435          default:
 436  436  #ifndef NDEBUG
 437  437                  (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
 438  438                      __FILE__, __LINE__, err);
 439  439  #else
 440  440                  (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
 441  441  #endif
 442  442                  abort();
 443  443                  /* NOTREACHED */
 444  444          }
 445  445  }
 446  446  
 447  447  static int
 448  448  entity_get_pg(void *ent, int issvc, const char *name,
 449  449      scf_propertygroup_t *pg)
 450  450  {
 451  451          if (issvc)
 452  452                  return (scf_service_get_pg(ent, name, pg));
 453  453          else
 454  454                  return (scf_instance_get_pg(ent, name, pg));
 455  455  }
 456  456  
 457  457  static void
 458  458  entity_destroy(void *ent, int issvc)
 459  459  {
 460  460          if (issvc)
 461  461                  scf_service_destroy(ent);
 462  462          else
 463  463                  scf_instance_destroy(ent);
 464  464  }
 465  465  
 466  466  static int
 467  467  get_pg(const char *pg_name, scf_propertygroup_t *pg)
 468  468  {
 469  469          int ret;
 470  470  
 471  471          if (cur_level != NULL)
 472  472                  ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
 473  473          else if (cur_inst != NULL)
 474  474                  ret = scf_instance_get_pg(cur_inst, pg_name, pg);
 475  475          else
 476  476                  ret = scf_service_get_pg(cur_svc, pg_name, pg);
 477  477  
 478  478          return (ret);
 479  479  }
 480  480  
 481  481  /*
 482  482   * Find a snaplevel in a snapshot.  If get_svc is true, find the service
 483  483   * snaplevel.  Otherwise find the instance snaplevel.
 484  484   *
 485  485   * Returns
 486  486   *   0 - success
 487  487   *   ECONNABORTED - repository connection broken
 488  488   *   ECANCELED - instance containing snap was deleted
 489  489   *   ENOENT - snap has no snaplevels
 490  490   *          - requested snaplevel not found
 491  491   */
 492  492  static int
 493  493  get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
 494  494  {
 495  495          if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
 496  496                  switch (scf_error()) {
 497  497                  case SCF_ERROR_CONNECTION_BROKEN:
 498  498                  case SCF_ERROR_DELETED:
 499  499                  case SCF_ERROR_NOT_FOUND:
 500  500                          return (scferror2errno(scf_error()));
 501  501  
 502  502                  case SCF_ERROR_HANDLE_MISMATCH:
 503  503                  case SCF_ERROR_NOT_BOUND:
 504  504                  case SCF_ERROR_NOT_SET:
 505  505                  default:
 506  506                          bad_error("scf_snapshot_get_base_snaplevel",
 507  507                              scf_error());
 508  508                  }
 509  509          }
 510  510  
 511  511          for (;;) {
 512  512                  ssize_t ssz;
 513  513  
 514  514                  ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
 515  515                  if (ssz >= 0) {
 516  516                          if (!get_svc)
 517  517                                  return (0);
 518  518                  } else {
 519  519                          switch (scf_error()) {
 520  520                          case SCF_ERROR_CONSTRAINT_VIOLATED:
 521  521                                  if (get_svc)
 522  522                                          return (0);
 523  523                                  break;
 524  524  
 525  525                          case SCF_ERROR_DELETED:
 526  526                          case SCF_ERROR_CONNECTION_BROKEN:
 527  527                                  return (scferror2errno(scf_error()));
 528  528  
 529  529                          case SCF_ERROR_NOT_SET:
 530  530                          case SCF_ERROR_NOT_BOUND:
 531  531                          default:
 532  532                                  bad_error("scf_snaplevel_get_instance_name",
 533  533                                      scf_error());
 534  534                          }
 535  535                  }
 536  536  
 537  537                  if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
 538  538                          switch (scf_error()) {
 539  539                          case SCF_ERROR_NOT_FOUND:
 540  540                          case SCF_ERROR_CONNECTION_BROKEN:
 541  541                          case SCF_ERROR_DELETED:
 542  542                                  return (scferror2errno(scf_error()));
 543  543  
 544  544                          case SCF_ERROR_HANDLE_MISMATCH:
 545  545                          case SCF_ERROR_NOT_BOUND:
 546  546                          case SCF_ERROR_NOT_SET:
 547  547                          case SCF_ERROR_INVALID_ARGUMENT:
 548  548                          default:
 549  549                                  bad_error("scf_snaplevel_get_next_snaplevel",
 550  550                                      scf_error());
 551  551                          }
 552  552                  }
 553  553          }
 554  554  }
 555  555  
 556  556  /*
 557  557   * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
 558  558   * a running snapshot, and that snapshot has an instance snaplevel, set pg to
 559  559   * the property group named name in it.  If it doesn't have a running
 560  560   * snapshot, set pg to the instance's current property group named name.
 561  561   *
 562  562   * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
 563  563   * its instances.  If one has a running snapshot with a service snaplevel, set
 564  564   * pg to the property group named name in it.  If no such snaplevel could be
 565  565   * found, set pg to the service's current property group named name.
 566  566   *
 567  567   * iter, inst, snap, and snpl are required scratch objects.
 568  568   *
 569  569   * Returns
 570  570   *   0 - success
 571  571   *   ECONNABORTED - repository connection broken
 572  572   *   ECANCELED - ent was deleted
 573  573   *   ENOENT - no such property group
 574  574   *   EINVAL - name is an invalid property group name
 575  575   *   EBADF - found running snapshot is missing a snaplevel
 576  576   */
 577  577  static int
 578  578  entity_get_running_pg(void *ent, int issvc, const char *name,
 579  579      scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
 580  580      scf_snapshot_t *snap, scf_snaplevel_t *snpl)
 581  581  {
 582  582          int r;
 583  583  
 584  584          if (issvc) {
 585  585                  /* Search for an instance with a running snapshot. */
 586  586                  if (scf_iter_service_instances(iter, ent) != 0) {
 587  587                          switch (scf_error()) {
 588  588                          case SCF_ERROR_DELETED:
 589  589                          case SCF_ERROR_CONNECTION_BROKEN:
 590  590                                  return (scferror2errno(scf_error()));
 591  591  
 592  592                          case SCF_ERROR_NOT_SET:
 593  593                          case SCF_ERROR_NOT_BOUND:
 594  594                          case SCF_ERROR_HANDLE_MISMATCH:
 595  595                          default:
 596  596                                  bad_error("scf_iter_service_instances",
 597  597                                      scf_error());
 598  598                          }
 599  599                  }
 600  600  
 601  601                  for (;;) {
 602  602                          r = scf_iter_next_instance(iter, inst);
 603  603                          if (r == 0) {
 604  604                                  if (scf_service_get_pg(ent, name, pg) == 0)
 605  605                                          return (0);
 606  606  
 607  607                                  switch (scf_error()) {
 608  608                                  case SCF_ERROR_DELETED:
 609  609                                  case SCF_ERROR_NOT_FOUND:
 610  610                                  case SCF_ERROR_INVALID_ARGUMENT:
 611  611                                  case SCF_ERROR_CONNECTION_BROKEN:
 612  612                                          return (scferror2errno(scf_error()));
 613  613  
 614  614                                  case SCF_ERROR_NOT_BOUND:
 615  615                                  case SCF_ERROR_HANDLE_MISMATCH:
 616  616                                  case SCF_ERROR_NOT_SET:
 617  617                                  default:
 618  618                                          bad_error("scf_service_get_pg",
 619  619                                              scf_error());
 620  620                                  }
 621  621                          }
 622  622                          if (r != 1) {
 623  623                                  switch (scf_error()) {
 624  624                                  case SCF_ERROR_DELETED:
 625  625                                  case SCF_ERROR_CONNECTION_BROKEN:
 626  626                                          return (scferror2errno(scf_error()));
 627  627  
 628  628                                  case SCF_ERROR_INVALID_ARGUMENT:
 629  629                                  case SCF_ERROR_NOT_SET:
 630  630                                  case SCF_ERROR_NOT_BOUND:
 631  631                                  case SCF_ERROR_HANDLE_MISMATCH:
 632  632                                  default:
 633  633                                          bad_error("scf_iter_next_instance",
 634  634                                              scf_error());
 635  635                                  }
 636  636                          }
 637  637  
 638  638                          if (scf_instance_get_snapshot(inst, snap_running,
 639  639                              snap) == 0)
 640  640                                  break;
 641  641  
 642  642                          switch (scf_error()) {
 643  643                          case SCF_ERROR_NOT_FOUND:
 644  644                          case SCF_ERROR_DELETED:
 645  645                                  continue;
 646  646  
 647  647                          case SCF_ERROR_CONNECTION_BROKEN:
 648  648                                  return (ECONNABORTED);
 649  649  
 650  650                          case SCF_ERROR_HANDLE_MISMATCH:
 651  651                          case SCF_ERROR_INVALID_ARGUMENT:
 652  652                          case SCF_ERROR_NOT_SET:
 653  653                          case SCF_ERROR_NOT_BOUND:
 654  654                          default:
 655  655                                  bad_error("scf_instance_get_snapshot",
 656  656                                      scf_error());
 657  657                          }
 658  658                  }
 659  659          } else {
 660  660                  if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
 661  661                          switch (scf_error()) {
 662  662                          case SCF_ERROR_NOT_FOUND:
 663  663                                  break;
 664  664  
 665  665                          case SCF_ERROR_DELETED:
 666  666                          case SCF_ERROR_CONNECTION_BROKEN:
 667  667                                  return (scferror2errno(scf_error()));
 668  668  
 669  669                          case SCF_ERROR_NOT_BOUND:
 670  670                          case SCF_ERROR_HANDLE_MISMATCH:
 671  671                          case SCF_ERROR_INVALID_ARGUMENT:
 672  672                          case SCF_ERROR_NOT_SET:
 673  673                          default:
 674  674                                  bad_error("scf_instance_get_snapshot",
 675  675                                      scf_error());
 676  676                          }
 677  677  
 678  678                          if (scf_instance_get_pg(ent, name, pg) == 0)
 679  679                                  return (0);
 680  680  
 681  681                          switch (scf_error()) {
 682  682                          case SCF_ERROR_DELETED:
 683  683                          case SCF_ERROR_NOT_FOUND:
 684  684                          case SCF_ERROR_INVALID_ARGUMENT:
 685  685                          case SCF_ERROR_CONNECTION_BROKEN:
 686  686                                  return (scferror2errno(scf_error()));
 687  687  
 688  688                          case SCF_ERROR_NOT_BOUND:
 689  689                          case SCF_ERROR_HANDLE_MISMATCH:
 690  690                          case SCF_ERROR_NOT_SET:
 691  691                          default:
 692  692                                  bad_error("scf_instance_get_pg", scf_error());
 693  693                          }
 694  694                  }
 695  695          }
 696  696  
 697  697          r = get_snaplevel(snap, issvc, snpl);
 698  698          switch (r) {
 699  699          case 0:
 700  700                  break;
 701  701  
 702  702          case ECONNABORTED:
 703  703          case ECANCELED:
 704  704                  return (r);
 705  705  
 706  706          case ENOENT:
 707  707                  return (EBADF);
 708  708  
 709  709          default:
 710  710                  bad_error("get_snaplevel", r);
 711  711          }
 712  712  
 713  713          if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
 714  714                  return (0);
 715  715  
 716  716          switch (scf_error()) {
 717  717          case SCF_ERROR_DELETED:
 718  718          case SCF_ERROR_INVALID_ARGUMENT:
 719  719          case SCF_ERROR_CONNECTION_BROKEN:
 720  720          case SCF_ERROR_NOT_FOUND:
 721  721                  return (scferror2errno(scf_error()));
 722  722  
 723  723          case SCF_ERROR_NOT_BOUND:
 724  724          case SCF_ERROR_HANDLE_MISMATCH:
 725  725          case SCF_ERROR_NOT_SET:
 726  726          default:
 727  727                  bad_error("scf_snaplevel_get_pg", scf_error());
 728  728                  /* NOTREACHED */
 729  729          }
 730  730  }
 731  731  
 732  732  /*
 733  733   * To be registered with atexit().
 734  734   */
 735  735  static void
 736  736  remove_tempfile(void)
 737  737  {
 738  738          int ret;
 739  739  
 740  740          if (tempfile != NULL) {
 741  741                  if (fclose(tempfile) == EOF)
 742  742                          (void) warn(gettext("Could not close temporary file"));
 743  743                  tempfile = NULL;
 744  744          }
 745  745  
 746  746          if (tempfilename[0] != '\0') {
 747  747                  do {
 748  748                          ret = remove(tempfilename);
 749  749                  } while (ret == -1 && errno == EINTR);
 750  750                  if (ret == -1)
 751  751                          warn(gettext("Could not remove temporary file"));
 752  752                  tempfilename[0] = '\0';
 753  753          }
 754  754  }
 755  755  
 756  756  /*
 757  757   * Launch private svc.configd(1M) for manipulating alternate repositories.
 758  758   */
 759  759  static void
 760  760  start_private_repository(engine_state_t *est)
 761  761  {
 762  762          int fd, stat;
 763  763          struct door_info info;
 764  764          pid_t pid;
 765  765  
 766  766          /*
 767  767           * 1.  Create a temporary file for the door.
 768  768           */
 769  769          if (est->sc_repo_doorname != NULL)
 770  770                  free((void *)est->sc_repo_doorname);
 771  771  
 772  772          est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
 773  773          if (est->sc_repo_doorname == NULL)
 774  774                  uu_die(gettext("Could not acquire temporary filename"));
 775  775  
 776  776          fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
 777  777          if (fd < 0)
 778  778                  uu_die(gettext("Could not create temporary file for "
 779  779                      "repository server"));
 780  780  
 781  781          (void) close(fd);
 782  782  
 783  783          /*
 784  784           * 2.  Launch a configd with that door, using the specified
 785  785           * repository.
 786  786           */
 787  787          if ((est->sc_repo_pid = fork()) == 0) {
 788  788                  (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
 789  789                      "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
 790  790                      NULL);
 791  791                  uu_die(gettext("Could not execute %s"), est->sc_repo_server);
 792  792          } else if (est->sc_repo_pid == -1)
 793  793                  uu_die(gettext("Attempt to fork failed"));
 794  794  
 795  795          do {
 796  796                  pid = waitpid(est->sc_repo_pid, &stat, 0);
 797  797          } while (pid == -1 && errno == EINTR);
 798  798  
 799  799          if (pid == -1)
 800  800                  uu_die(gettext("Could not waitpid() for repository server"));
 801  801  
 802  802          if (!WIFEXITED(stat)) {
 803  803                  uu_die(gettext("Repository server failed (status %d).\n"),
 804  804                      stat);
 805  805          } else if (WEXITSTATUS(stat) != 0) {
 806  806                  uu_die(gettext("Repository server failed (exit %d).\n"),
 807  807                      WEXITSTATUS(stat));
 808  808          }
 809  809  
 810  810          /*
 811  811           * See if it was successful by checking if the door is a door.
 812  812           */
 813  813  
 814  814          fd = open(est->sc_repo_doorname, O_RDWR);
 815  815          if (fd < 0)
 816  816                  uu_die(gettext("Could not open door \"%s\""),
 817  817                      est->sc_repo_doorname);
 818  818  
 819  819          if (door_info(fd, &info) < 0)
 820  820                  uu_die(gettext("Unexpected door_info() error"));
 821  821  
 822  822          if (close(fd) == -1)
 823  823                  warn(gettext("Could not close repository door"),
 824  824                      strerror(errno));
 825  825  
 826  826          est->sc_repo_pid = info.di_target;
 827  827  }
 828  828  
 829  829  void
 830  830  lscf_cleanup(void)
 831  831  {
 832  832          /*
 833  833           * In the case where we've launched a private svc.configd(1M)
 834  834           * instance, we must terminate our child and remove the temporary
 835  835           * rendezvous point.
 836  836           */
 837  837          if (est->sc_repo_pid > 0) {
 838  838                  (void) kill(est->sc_repo_pid, SIGTERM);
 839  839                  (void) waitpid(est->sc_repo_pid, NULL, 0);
 840  840                  (void) unlink(est->sc_repo_doorname);
 841  841  
 842  842                  est->sc_repo_pid = 0;
 843  843          }
 844  844  }
 845  845  
 846  846  void
 847  847  unselect_cursnap(void)
 848  848  {
 849  849          void *cookie;
 850  850  
 851  851          cur_level = NULL;
 852  852  
 853  853          cookie = NULL;
 854  854          while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
 855  855                  scf_snaplevel_destroy(cur_elt->sl);
 856  856                  free(cur_elt);
 857  857          }
 858  858  
 859  859          scf_snapshot_destroy(cur_snap);
 860  860          cur_snap = NULL;
 861  861  }
 862  862  
 863  863  void
 864  864  lscf_prep_hndl(void)
 865  865  {
 866  866          if (g_hndl != NULL)
 867  867                  return;
 868  868  
 869  869          g_hndl = scf_handle_create(SCF_VERSION);
 870  870          if (g_hndl == NULL)
 871  871                  scfdie();
 872  872  
 873  873          if (est->sc_repo_filename != NULL)
 874  874                  start_private_repository(est);
 875  875  
 876  876          if (est->sc_repo_doorname != NULL) {
 877  877                  scf_value_t *repo_value;
 878  878                  int ret;
 879  879  
 880  880                  repo_value = scf_value_create(g_hndl);
 881  881                  if (repo_value == NULL)
 882  882                          scfdie();
 883  883  
 884  884                  ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
 885  885                  assert(ret == SCF_SUCCESS);
 886  886  
 887  887                  if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
 888  888                      SCF_SUCCESS)
 889  889                          scfdie();
 890  890  
 891  891                  scf_value_destroy(repo_value);
 892  892          }
 893  893  
 894  894          if (scf_handle_bind(g_hndl) != 0)
 895  895                  uu_die(gettext("Could not connect to repository server: %s.\n"),
 896  896                      scf_strerror(scf_error()));
 897  897  
 898  898          cur_scope = scf_scope_create(g_hndl);
 899  899          if (cur_scope == NULL)
 900  900                  scfdie();
 901  901  
 902  902          if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
 903  903                  scfdie();
 904  904  }
 905  905  
 906  906  static void
 907  907  repository_teardown(void)
 908  908  {
 909  909          if (g_hndl != NULL) {
 910  910                  if (cur_snap != NULL)
 911  911                          unselect_cursnap();
 912  912                  scf_instance_destroy(cur_inst);
 913  913                  scf_service_destroy(cur_svc);
 914  914                  scf_scope_destroy(cur_scope);
 915  915                  scf_handle_destroy(g_hndl);
 916  916                  cur_inst = NULL;
 917  917                  cur_svc = NULL;
 918  918                  cur_scope = NULL;
 919  919                  g_hndl = NULL;
 920  920                  lscf_cleanup();
 921  921          }
 922  922  }
 923  923  
 924  924  void
 925  925  lscf_set_repository(const char *repfile, int force)
 926  926  {
 927  927          repository_teardown();
 928  928  
 929  929          if (est->sc_repo_filename != NULL) {
 930  930                  free((void *)est->sc_repo_filename);
 931  931                  est->sc_repo_filename = NULL;
 932  932          }
 933  933  
 934  934          if ((force == 0) && (access(repfile, R_OK) != 0)) {
 935  935                  /*
 936  936                   * Repository file does not exist
 937  937                   * or has no read permission.
 938  938                   */
 939  939                  warn(gettext("Cannot access \"%s\": %s\n"),
 940  940                      repfile, strerror(errno));
 941  941          } else {
 942  942                  est->sc_repo_filename = safe_strdup(repfile);
 943  943          }
 944  944  
 945  945          lscf_prep_hndl();
 946  946  }
 947  947  
 948  948  void
 949  949  lscf_init()
 950  950  {
 951  951          if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
 952  952              (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
 953  953              (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
 954  954              0 ||
 955  955              (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
 956  956                  scfdie();
 957  957  
 958  958          max_scf_len = max_scf_fmri_len;
 959  959          if (max_scf_name_len > max_scf_len)
 960  960                  max_scf_len = max_scf_name_len;
 961  961          if (max_scf_pg_type_len > max_scf_len)
 962  962                  max_scf_len = max_scf_pg_type_len;
 963  963          /*
 964  964           * When a value of type opaque is represented as a string, the
 965  965           * string contains 2 characters for every byte of data.  That is
 966  966           * because the string contains the hex representation of the opaque
 967  967           * value.
 968  968           */
 969  969          if (2 * max_scf_value_len > max_scf_len)
 970  970                  max_scf_len = 2 * max_scf_value_len;
 971  971  
 972  972          if (atexit(remove_tempfile) != 0)
 973  973                  uu_die(gettext("Could not register atexit() function"));
 974  974  
 975  975          emsg_entity_not_selected = gettext("An entity is not selected.\n");
 976  976          emsg_permission_denied = gettext("Permission denied.\n");
 977  977          emsg_create_xml = gettext("Could not create XML node.\n");
 978  978          emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
 979  979          emsg_invalid_for_snapshot =
 980  980              gettext("Invalid operation on a snapshot.\n");
 981  981          emsg_read_only = gettext("Backend read-only.\n");
 982  982          emsg_deleted = gettext("Current selection has been deleted.\n");
 983  983          emsg_invalid_pg_name =
 984  984              gettext("Invalid property group name \"%s\".\n");
 985  985          emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
 986  986          emsg_no_such_pg = gettext("No such property group \"%s\".\n");
 987  987          emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
 988  988              "with invalid name \"%s\".\n");
 989  989          emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
 990  990              "group with invalid name \"%s\" or type \"%s\".\n");
 991  991          emsg_pg_added = gettext("%s changed unexpectedly "
 992  992              "(property group \"%s\" added).\n");
 993  993          emsg_pg_changed = gettext("%s changed unexpectedly "
 994  994              "(property group \"%s\" changed).\n");
 995  995          emsg_pg_deleted = gettext("%s changed unexpectedly "
 996  996              "(property group \"%s\" or an ancestor was deleted).\n");
 997  997          emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
 998  998              "in %s (permission denied).\n");
 999  999          emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 1000              "in %s (permission denied).\n");
1001 1001          emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 1002              "in %s (permission denied).\n");
1003 1003          emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 1004              "(permission denied).\n");
1005 1005          emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 1006              "new dependent \"%s\" because it already exists).  Warning: The "
1007 1007              "current dependent's target (%s) does not exist.\n");
1008 1008          emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 1009              "dependent \"%s\" because it already exists).  Warning: The "
1010 1010              "current dependent's target (%s) does not have a dependency named "
1011 1011              "\"%s\" as expected.\n");
1012 1012  
1013 1013          string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 1014              offsetof(string_list_t, node), NULL, 0);
1015 1015          snaplevel_pool = uu_list_pool_create("snaplevels",
1016 1016              sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 1017              NULL, 0);
1018 1018  }
1019 1019  
1020 1020  
1021 1021  static const char *
1022 1022  prop_to_typestr(const scf_property_t *prop)
1023 1023  {
1024 1024          scf_type_t ty;
1025 1025  
1026 1026          if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 1027                  scfdie();
1028 1028  
1029 1029          return (scf_type_to_string(ty));
1030 1030  }
1031 1031  
1032 1032  static scf_type_t
1033 1033  string_to_type(const char *type)
1034 1034  {
1035 1035          size_t len = strlen(type);
1036 1036          char *buf;
1037 1037  
1038 1038          if (len == 0 || type[len - 1] != ':')
1039 1039                  return (SCF_TYPE_INVALID);
1040 1040  
1041 1041          buf = (char *)alloca(len + 1);
1042 1042          (void) strlcpy(buf, type, len + 1);
1043 1043          buf[len - 1] = 0;
1044 1044  
1045 1045          return (scf_string_to_type(buf));
1046 1046  }
1047 1047  
1048 1048  static scf_value_t *
1049 1049  string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 1050  {
1051 1051          scf_value_t *v;
1052 1052          char *dup, *nstr;
1053 1053          size_t len;
1054 1054  
1055 1055          v = scf_value_create(g_hndl);
1056 1056          if (v == NULL)
1057 1057                  scfdie();
1058 1058  
1059 1059          len = strlen(str);
1060 1060          if (require_quotes &&
1061 1061              (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 1062                  semerr(gettext("Multiple string values or string values "
1063 1063                      "with spaces must be quoted with '\"'.\n"));
1064 1064                  scf_value_destroy(v);
1065 1065                  return (NULL);
1066 1066          }
1067 1067  
1068 1068          nstr = dup = safe_strdup(str);
1069 1069          if (dup[0] == '\"') {
1070 1070                  /*
1071 1071                   * Strip out the first and the last quote.
1072 1072                   */
1073 1073                  dup[len - 1] = '\0';
1074 1074                  nstr = dup + 1;
1075 1075          }
1076 1076  
1077 1077          if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 1078                  assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 1079                  semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 1080                      scf_type_to_string(ty), nstr);
1081 1081                  scf_value_destroy(v);
1082 1082                  v = NULL;
1083 1083          }
1084 1084          free(dup);
1085 1085          return (v);
1086 1086  }
1087 1087  
1088 1088  /*
1089 1089   * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 1090   * Optionally append a comment prefix ('#') to newlines ('\n').
1091 1091   */
1092 1092  static int
1093 1093  quote_and_print(const char *str, FILE *strm, int commentnl)
1094 1094  {
1095 1095          const char *cp;
1096 1096  
1097 1097          for (cp = str; *cp != '\0'; ++cp) {
1098 1098                  if (*cp == '"' || *cp == '\\')
1099 1099                          (void) putc('\\', strm);
1100 1100  
1101 1101                  (void) putc(*cp, strm);
1102 1102  
1103 1103                  if (commentnl && *cp == '\n') {
1104 1104                          (void) putc('#', strm);
1105 1105                  }
1106 1106          }
1107 1107  
1108 1108          return (ferror(strm));
1109 1109  }
1110 1110  
1111 1111  /*
1112 1112   * These wrappers around lowlevel functions provide consistent error checking
1113 1113   * and warnings.
1114 1114   */
1115 1115  static int
1116 1116  pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 1117  {
1118 1118          if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 1119                  return (0);
1120 1120  
1121 1121          if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 1122                  scfdie();
1123 1123  
1124 1124          if (g_verbose) {
1125 1125                  ssize_t len;
1126 1126                  char *fmri;
1127 1127  
1128 1128                  len = scf_pg_to_fmri(pg, NULL, 0);
1129 1129                  if (len < 0)
1130 1130                          scfdie();
1131 1131  
1132 1132                  fmri = safe_malloc(len + 1);
1133 1133  
1134 1134                  if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 1135                          scfdie();
1136 1136  
1137 1137                  warn(gettext("Expected property %s of property group %s is "
1138 1138                      "missing.\n"), propname, fmri);
1139 1139  
1140 1140                  free(fmri);
1141 1141          }
1142 1142  
1143 1143          return (-1);
1144 1144  }
1145 1145  
1146 1146  static int
1147 1147  prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 1148  {
1149 1149          scf_type_t pty;
1150 1150  
1151 1151          if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 1152                  scfdie();
1153 1153  
1154 1154          if (ty == pty)
1155 1155                  return (0);
1156 1156  
1157 1157          if (g_verbose) {
1158 1158                  ssize_t len;
1159 1159                  char *fmri;
1160 1160                  const char *tystr;
1161 1161  
1162 1162                  len = scf_property_to_fmri(prop, NULL, 0);
1163 1163                  if (len < 0)
1164 1164                          scfdie();
1165 1165  
1166 1166                  fmri = safe_malloc(len + 1);
1167 1167  
1168 1168                  if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 1169                          scfdie();
1170 1170  
1171 1171                  tystr = scf_type_to_string(ty);
1172 1172                  if (tystr == NULL)
1173 1173                          tystr = "?";
1174 1174  
1175 1175                  warn(gettext("Property %s is not of expected type %s.\n"),
1176 1176                      fmri, tystr);
1177 1177  
1178 1178                  free(fmri);
1179 1179          }
1180 1180  
1181 1181          return (-1);
1182 1182  }
1183 1183  
1184 1184  static int
1185 1185  prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 1186  {
1187 1187          scf_error_t err;
1188 1188  
1189 1189          if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 1190                  return (0);
1191 1191  
1192 1192          err = scf_error();
1193 1193  
1194 1194          if (err != SCF_ERROR_NOT_FOUND &&
1195 1195              err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 1196              err != SCF_ERROR_PERMISSION_DENIED)
1197 1197                  scfdie();
1198 1198  
1199 1199          if (g_verbose) {
1200 1200                  ssize_t len;
1201 1201                  char *fmri, *emsg;
1202 1202  
1203 1203                  len = scf_property_to_fmri(prop, NULL, 0);
1204 1204                  if (len < 0)
1205 1205                          scfdie();
1206 1206  
1207 1207                  fmri = safe_malloc(len + 1);
1208 1208  
1209 1209                  if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 1210                          scfdie();
1211 1211  
1212 1212                  if (err == SCF_ERROR_NOT_FOUND)
1213 1213                          emsg = gettext("Property %s has no values; expected "
1214 1214                              "one.\n");
1215 1215                  else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 1216                          emsg = gettext("Property %s has multiple values; "
1217 1217                              "expected one.\n");
1218 1218                  else
1219 1219                          emsg = gettext("No permission to read property %s.\n");
1220 1220  
1221 1221                  warn(emsg, fmri);
1222 1222  
1223 1223                  free(fmri);
1224 1224          }
1225 1225  
1226 1226          return (-1);
1227 1227  }
1228 1228  
1229 1229  
1230 1230  static boolean_t
1231 1231  snaplevel_is_instance(const scf_snaplevel_t *level)
1232 1232  {
1233 1233          if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 1234                  if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 1235                          scfdie();
1236 1236                  return (0);
1237 1237          } else {
1238 1238                  return (1);
1239 1239          }
1240 1240  }
1241 1241  
1242 1242  /*
1243 1243   * Decode FMRI into a service or instance, and put the result in *ep.  If
1244 1244   * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1245 1245   * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1246 1246   * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1247 1247   * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1248 1248   * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 1249   * whether *ep is a service.
1250 1250   */
1251 1251  static scf_error_t
1252 1252  fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 1253  {
1254 1254          char *fmri_copy;
1255 1255          const char *sstr, *istr, *pgstr;
1256 1256          scf_service_t *svc;
1257 1257          scf_instance_t *inst;
1258 1258  
1259 1259          fmri_copy = strdup(fmri);
1260 1260          if (fmri_copy == NULL)
1261 1261                  return (SCF_ERROR_NO_MEMORY);
1262 1262  
1263 1263          if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 1264              SCF_SUCCESS) {
1265 1265                  free(fmri_copy);
1266 1266                  return (SCF_ERROR_INVALID_ARGUMENT);
1267 1267          }
1268 1268  
1269 1269          free(fmri_copy);
1270 1270  
1271 1271          if (sstr == NULL || pgstr != NULL)
1272 1272                  return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273 1273  
1274 1274          if (istr == NULL) {
1275 1275                  svc = scf_service_create(h);
1276 1276                  if (svc == NULL)
1277 1277                          return (SCF_ERROR_NO_MEMORY);
1278 1278  
1279 1279                  if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 1280                      SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 1281                          if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 1282                                  scfdie();
1283 1283  
1284 1284                          return (SCF_ERROR_NOT_FOUND);
1285 1285                  }
1286 1286  
1287 1287                  *ep = svc;
1288 1288                  *isservice = 1;
1289 1289          } else {
1290 1290                  inst = scf_instance_create(h);
1291 1291                  if (inst == NULL)
1292 1292                          return (SCF_ERROR_NO_MEMORY);
1293 1293  
1294 1294                  if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 1295                      NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 1296                          if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 1297                                  scfdie();
1298 1298  
1299 1299                          return (SCF_ERROR_NOT_FOUND);
1300 1300                  }
1301 1301  
1302 1302                  *ep = inst;
1303 1303                  *isservice = 0;
1304 1304          }
1305 1305  
1306 1306          return (SCF_ERROR_NONE);
1307 1307  }
1308 1308  
1309 1309  /*
1310 1310   * Create the entity named by fmri.  Place a pointer to its libscf handle in
1311 1311   * *ep, and set or clear *isservicep if it is a service or an instance.
1312 1312   * Returns
1313 1313   *   SCF_ERROR_NONE - success
1314 1314   *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 1315   *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 1316   *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 1317   *   SCF_ERROR_NOT_FOUND - no such scope
1318 1318   *   SCF_ERROR_PERMISSION_DENIED
1319 1319   *   SCF_ERROR_BACKEND_READONLY
1320 1320   *   SCF_ERROR_BACKEND_ACCESS
1321 1321   */
1322 1322  static scf_error_t
1323 1323  create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 1324  {
1325 1325          char *fmri_copy;
1326 1326          const char *scstr, *sstr, *istr, *pgstr;
1327 1327          scf_scope_t *scope = NULL;
1328 1328          scf_service_t *svc = NULL;
1329 1329          scf_instance_t *inst = NULL;
1330 1330          scf_error_t scfe;
1331 1331  
1332 1332          fmri_copy = safe_strdup(fmri);
1333 1333  
1334 1334          if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 1335              0) {
1336 1336                  free(fmri_copy);
1337 1337                  return (SCF_ERROR_INVALID_ARGUMENT);
1338 1338          }
1339 1339  
1340 1340          if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 1341                  free(fmri_copy);
1342 1342                  return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343 1343          }
1344 1344  
1345 1345          *ep = NULL;
1346 1346  
1347 1347          if ((scope = scf_scope_create(h)) == NULL ||
1348 1348              (svc = scf_service_create(h)) == NULL ||
1349 1349              (inst = scf_instance_create(h)) == NULL) {
1350 1350                  scfe = SCF_ERROR_NO_MEMORY;
1351 1351                  goto out;
1352 1352          }
1353 1353  
1354 1354  get_scope:
1355 1355          if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 1356                  switch (scf_error()) {
1357 1357                  case SCF_ERROR_CONNECTION_BROKEN:
1358 1358                          scfdie();
1359 1359                          /* NOTREACHED */
1360 1360  
1361 1361                  case SCF_ERROR_NOT_FOUND:
1362 1362                          scfe = SCF_ERROR_NOT_FOUND;
1363 1363                          goto out;
1364 1364  
1365 1365                  case SCF_ERROR_HANDLE_MISMATCH:
1366 1366                  case SCF_ERROR_NOT_BOUND:
1367 1367                  case SCF_ERROR_INVALID_ARGUMENT:
1368 1368                  default:
1369 1369                          bad_error("scf_handle_get_scope", scf_error());
1370 1370                  }
1371 1371          }
1372 1372  
1373 1373  get_svc:
1374 1374          if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 1375                  switch (scf_error()) {
1376 1376                  case SCF_ERROR_CONNECTION_BROKEN:
1377 1377                          scfdie();
1378 1378                          /* NOTREACHED */
1379 1379  
1380 1380                  case SCF_ERROR_DELETED:
1381 1381                          goto get_scope;
1382 1382  
1383 1383                  case SCF_ERROR_NOT_FOUND:
1384 1384                          break;
1385 1385  
1386 1386                  case SCF_ERROR_HANDLE_MISMATCH:
1387 1387                  case SCF_ERROR_INVALID_ARGUMENT:
1388 1388                  case SCF_ERROR_NOT_BOUND:
1389 1389                  case SCF_ERROR_NOT_SET:
1390 1390                  default:
1391 1391                          bad_error("scf_scope_get_service", scf_error());
1392 1392                  }
1393 1393  
1394 1394                  if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 1395                          switch (scf_error()) {
1396 1396                          case SCF_ERROR_CONNECTION_BROKEN:
1397 1397                                  scfdie();
1398 1398                                  /* NOTREACHED */
1399 1399  
1400 1400                          case SCF_ERROR_DELETED:
1401 1401                                  goto get_scope;
1402 1402  
1403 1403                          case SCF_ERROR_PERMISSION_DENIED:
1404 1404                          case SCF_ERROR_BACKEND_READONLY:
1405 1405                          case SCF_ERROR_BACKEND_ACCESS:
1406 1406                                  scfe = scf_error();
1407 1407                                  goto out;
1408 1408  
1409 1409                          case SCF_ERROR_HANDLE_MISMATCH:
1410 1410                          case SCF_ERROR_INVALID_ARGUMENT:
1411 1411                          case SCF_ERROR_NOT_BOUND:
1412 1412                          case SCF_ERROR_NOT_SET:
1413 1413                          default:
1414 1414                                  bad_error("scf_scope_get_service", scf_error());
1415 1415                          }
1416 1416                  }
1417 1417          }
1418 1418  
1419 1419          if (istr == NULL) {
1420 1420                  scfe = SCF_ERROR_NONE;
1421 1421                  *ep = svc;
1422 1422                  *isservicep = 1;
1423 1423                  goto out;
1424 1424          }
1425 1425  
1426 1426  get_inst:
1427 1427          if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 1428                  switch (scf_error()) {
1429 1429                  case SCF_ERROR_CONNECTION_BROKEN:
1430 1430                          scfdie();
1431 1431                          /* NOTREACHED */
1432 1432  
1433 1433                  case SCF_ERROR_DELETED:
1434 1434                          goto get_svc;
1435 1435  
1436 1436                  case SCF_ERROR_NOT_FOUND:
1437 1437                          break;
1438 1438  
1439 1439                  case SCF_ERROR_HANDLE_MISMATCH:
1440 1440                  case SCF_ERROR_INVALID_ARGUMENT:
1441 1441                  case SCF_ERROR_NOT_BOUND:
1442 1442                  case SCF_ERROR_NOT_SET:
1443 1443                  default:
1444 1444                          bad_error("scf_service_get_instance", scf_error());
1445 1445                  }
1446 1446  
1447 1447                  if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 1448                          switch (scf_error()) {
1449 1449                          case SCF_ERROR_CONNECTION_BROKEN:
1450 1450                                  scfdie();
1451 1451                                  /* NOTREACHED */
1452 1452  
1453 1453                          case SCF_ERROR_DELETED:
1454 1454                                  goto get_svc;
1455 1455  
1456 1456                          case SCF_ERROR_PERMISSION_DENIED:
1457 1457                          case SCF_ERROR_BACKEND_READONLY:
1458 1458                          case SCF_ERROR_BACKEND_ACCESS:
1459 1459                                  scfe = scf_error();
1460 1460                                  goto out;
1461 1461  
1462 1462                          case SCF_ERROR_HANDLE_MISMATCH:
1463 1463                          case SCF_ERROR_INVALID_ARGUMENT:
1464 1464                          case SCF_ERROR_NOT_BOUND:
1465 1465                          case SCF_ERROR_NOT_SET:
1466 1466                          default:
1467 1467                                  bad_error("scf_service_add_instance",
1468 1468                                      scf_error());
1469 1469                          }
1470 1470                  }
1471 1471          }
1472 1472  
1473 1473          scfe = SCF_ERROR_NONE;
1474 1474          *ep = inst;
1475 1475          *isservicep = 0;
1476 1476  
1477 1477  out:
1478 1478          if (*ep != inst)
1479 1479                  scf_instance_destroy(inst);
1480 1480          if (*ep != svc)
1481 1481                  scf_service_destroy(svc);
1482 1482          scf_scope_destroy(scope);
1483 1483          free(fmri_copy);
1484 1484          return (scfe);
1485 1485  }
1486 1486  
1487 1487  /*
1488 1488   * Create or update a snapshot of inst.  snap is a required scratch object.
1489 1489   *
1490 1490   * Returns
1491 1491   *   0 - success
1492 1492   *   ECONNABORTED - repository connection broken
1493 1493   *   EPERM - permission denied
1494 1494   *   ENOSPC - configd is out of resources
1495 1495   *   ECANCELED - inst was deleted
1496 1496   *   -1 - unknown libscf error (message printed)
1497 1497   */
1498 1498  static int
1499 1499  take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 1500  {
1501 1501  again:
1502 1502          if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 1503                  if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 1504                          switch (scf_error()) {
1505 1505                          case SCF_ERROR_CONNECTION_BROKEN:
1506 1506                          case SCF_ERROR_PERMISSION_DENIED:
1507 1507                          case SCF_ERROR_NO_RESOURCES:
1508 1508                                  return (scferror2errno(scf_error()));
1509 1509  
1510 1510                          case SCF_ERROR_NOT_SET:
1511 1511                          case SCF_ERROR_INVALID_ARGUMENT:
1512 1512                          default:
1513 1513                                  bad_error("_scf_snapshot_take_attach",
1514 1514                                      scf_error());
1515 1515                          }
1516 1516                  }
1517 1517          } else {
1518 1518                  switch (scf_error()) {
1519 1519                  case SCF_ERROR_NOT_FOUND:
1520 1520                          break;
1521 1521  
1522 1522                  case SCF_ERROR_DELETED:
1523 1523                  case SCF_ERROR_CONNECTION_BROKEN:
1524 1524                          return (scferror2errno(scf_error()));
1525 1525  
1526 1526                  case SCF_ERROR_HANDLE_MISMATCH:
1527 1527                  case SCF_ERROR_NOT_BOUND:
1528 1528                  case SCF_ERROR_INVALID_ARGUMENT:
1529 1529                  case SCF_ERROR_NOT_SET:
1530 1530                  default:
1531 1531                          bad_error("scf_instance_get_snapshot", scf_error());
1532 1532                  }
1533 1533  
1534 1534                  if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 1535                          switch (scf_error()) {
1536 1536                          case SCF_ERROR_EXISTS:
1537 1537                                  goto again;
1538 1538  
1539 1539                          case SCF_ERROR_CONNECTION_BROKEN:
1540 1540                          case SCF_ERROR_NO_RESOURCES:
1541 1541                          case SCF_ERROR_PERMISSION_DENIED:
1542 1542                                  return (scferror2errno(scf_error()));
1543 1543  
1544 1544                          default:
1545 1545                                  scfwarn();
1546 1546                                  return (-1);
1547 1547  
1548 1548                          case SCF_ERROR_NOT_SET:
1549 1549                          case SCF_ERROR_INTERNAL:
1550 1550                          case SCF_ERROR_INVALID_ARGUMENT:
1551 1551                          case SCF_ERROR_HANDLE_MISMATCH:
1552 1552                                  bad_error("_scf_snapshot_take_new",
1553 1553                                      scf_error());
1554 1554                          }
1555 1555                  }
1556 1556          }
1557 1557  
1558 1558          return (0);
1559 1559  }
1560 1560  
1561 1561  static int
1562 1562  refresh_running_snapshot(void *entity)
1563 1563  {
1564 1564          scf_snapshot_t *snap;
1565 1565          int r;
1566 1566  
1567 1567          if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 1568                  scfdie();
1569 1569          r = take_snap(entity, snap_running, snap);
1570 1570          scf_snapshot_destroy(snap);
1571 1571  
1572 1572          return (r);
1573 1573  }
1574 1574  
1575 1575  /*
1576 1576   * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1577 1577   * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 1578   * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1579 1579   * for scratch space.  Returns
1580 1580   *   0 - success
1581 1581   *   ECONNABORTED - repository connection broken
1582 1582   *   ECANCELED - entity was deleted
1583 1583   *   EACCES - backend denied access
1584 1584   *   EPERM - permission denied
1585 1585   *   ENOSPC - repository server out of resources
1586 1586   *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1587 1587   */
1588 1588  static int
1589 1589  refresh_entity(int isservice, void *entity, const char *fmri,
1590 1590      scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 1591  {
1592 1592          scf_error_t scfe;
1593 1593          int r;
1594 1594  
1595 1595          if (!isservice) {
1596 1596                  /*
1597 1597                   * Let restarter handles refreshing and making new running
1598 1598                   * snapshot only if operating on a live repository and not
1599 1599                   * running in early import.
1600 1600                   */
1601 1601                  if (est->sc_repo_filename == NULL &&
1602 1602                      est->sc_repo_doorname == NULL &&
1603 1603                      est->sc_in_emi == 0) {
1604 1604                          if (_smf_refresh_instance_i(entity) == 0) {
1605 1605                                  if (g_verbose)
1606 1606                                          warn(gettext("Refreshed %s.\n"), fmri);
1607 1607                                  return (0);
1608 1608                          }
1609 1609  
1610 1610                          switch (scf_error()) {
1611 1611                          case SCF_ERROR_BACKEND_ACCESS:
1612 1612                                  return (EACCES);
1613 1613  
1614 1614                          case SCF_ERROR_PERMISSION_DENIED:
1615 1615                                  return (EPERM);
1616 1616  
1617 1617                          default:
1618 1618                                  return (-1);
1619 1619                          }
1620 1620                  } else {
1621 1621                          r = refresh_running_snapshot(entity);
1622 1622                          switch (r) {
1623 1623                          case 0:
1624 1624                                  break;
1625 1625  
1626 1626                          case ECONNABORTED:
1627 1627                          case ECANCELED:
1628 1628                          case EPERM:
1629 1629                          case ENOSPC:
1630 1630                                  break;
1631 1631  
1632 1632                          default:
1633 1633                                  bad_error("refresh_running_snapshot",
1634 1634                                      scf_error());
1635 1635                          }
1636 1636  
1637 1637                          return (r);
1638 1638                  }
1639 1639          }
1640 1640  
1641 1641          if (scf_iter_service_instances(iter, entity) != 0) {
1642 1642                  switch (scf_error()) {
1643 1643                  case SCF_ERROR_CONNECTION_BROKEN:
1644 1644                          return (ECONNABORTED);
1645 1645  
1646 1646                  case SCF_ERROR_DELETED:
1647 1647                          return (ECANCELED);
1648 1648  
1649 1649                  case SCF_ERROR_HANDLE_MISMATCH:
1650 1650                  case SCF_ERROR_NOT_BOUND:
1651 1651                  case SCF_ERROR_NOT_SET:
1652 1652                  default:
1653 1653                          bad_error("scf_iter_service_instances", scf_error());
1654 1654                  }
1655 1655          }
1656 1656  
1657 1657          for (;;) {
1658 1658                  r = scf_iter_next_instance(iter, inst);
1659 1659                  if (r == 0)
1660 1660                          break;
1661 1661                  if (r != 1) {
1662 1662                          switch (scf_error()) {
1663 1663                          case SCF_ERROR_CONNECTION_BROKEN:
1664 1664                                  return (ECONNABORTED);
1665 1665  
1666 1666                          case SCF_ERROR_DELETED:
1667 1667                                  return (ECANCELED);
1668 1668  
1669 1669                          case SCF_ERROR_HANDLE_MISMATCH:
1670 1670                          case SCF_ERROR_NOT_BOUND:
1671 1671                          case SCF_ERROR_NOT_SET:
1672 1672                          case SCF_ERROR_INVALID_ARGUMENT:
1673 1673                          default:
1674 1674                                  bad_error("scf_iter_next_instance",
1675 1675                                      scf_error());
1676 1676                          }
1677 1677                  }
1678 1678  
1679 1679                  /*
1680 1680                   * Similarly, just take a new running snapshot if operating on
1681 1681                   * a non-live repository or running during early import.
1682 1682                   */
1683 1683                  if (est->sc_repo_filename != NULL ||
1684 1684                      est->sc_repo_doorname != NULL ||
1685 1685                      est->sc_in_emi == 1) {
1686 1686                          r = refresh_running_snapshot(inst);
1687 1687                          switch (r) {
1688 1688                          case 0:
1689 1689                                  continue;
1690 1690  
1691 1691                          case ECONNABORTED:
1692 1692                          case ECANCELED:
1693 1693                          case EPERM:
1694 1694                          case ENOSPC:
1695 1695                                  break;
1696 1696                          default:
1697 1697                                  bad_error("refresh_running_snapshot",
1698 1698                                      scf_error());
1699 1699                          }
1700 1700  
1701 1701                          return (r);
1702 1702  
1703 1703                  }
1704 1704  
1705 1705                  if (_smf_refresh_instance_i(inst) == 0) {
1706 1706                          if (g_verbose) {
1707 1707                                  if (scf_instance_get_name(inst, name_buf,
1708 1708                                      max_scf_name_len + 1) < 0)
1709 1709                                          (void) strcpy(name_buf, "?");
1710 1710  
1711 1711                                  warn(gettext("Refreshed %s:%s.\n"),
1712 1712                                      fmri, name_buf);
1713 1713                          }
1714 1714                  } else {
1715 1715                          if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 1716                              g_verbose) {
1717 1717                                  scfe = scf_error();
1718 1718  
1719 1719                                  if (scf_instance_to_fmri(inst, name_buf,
1720 1720                                      max_scf_name_len + 1) < 0)
1721 1721                                          (void) strcpy(name_buf, "?");
1722 1722  
1723 1723                                  warn(gettext(
1724 1724                                      "Refresh of %s:%s failed: %s.\n"), fmri,
1725 1725                                      name_buf, scf_strerror(scfe));
1726 1726                          }
1727 1727                  }
1728 1728          }
1729 1729  
1730 1730          return (0);
1731 1731  }
1732 1732  
1733 1733  static void
1734 1734  private_refresh(void)
1735 1735  {
1736 1736          scf_instance_t *pinst = NULL;
1737 1737          scf_iter_t *piter = NULL;
1738 1738          ssize_t fmrilen;
1739 1739          size_t bufsz;
1740 1740          char *fmribuf;
1741 1741          void *ent;
1742 1742          int issvc;
1743 1743          int r;
1744 1744  
1745 1745          if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 1746                  return;
1747 1747  
1748 1748          assert(cur_svc != NULL);
1749 1749  
1750 1750          bufsz = max_scf_fmri_len + 1;
1751 1751          fmribuf = safe_malloc(bufsz);
1752 1752          if (cur_inst) {
1753 1753                  issvc = 0;
1754 1754                  ent = cur_inst;
1755 1755                  fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 1756          } else {
1757 1757                  issvc = 1;
1758 1758                  ent = cur_svc;
1759 1759                  fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 1760                  if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 1761                          scfdie();
1762 1762  
1763 1763                  if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 1764                          scfdie();
1765 1765          }
1766 1766          if (fmrilen < 0) {
1767 1767                  free(fmribuf);
1768 1768                  if (scf_error() != SCF_ERROR_DELETED)
1769 1769                          scfdie();
1770 1770  
1771 1771                  warn(emsg_deleted);
1772 1772                  return;
1773 1773          }
1774 1774          assert(fmrilen < bufsz);
1775 1775  
1776 1776          r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 1777          switch (r) {
1778 1778          case 0:
1779 1779                  break;
1780 1780  
1781 1781          case ECONNABORTED:
1782 1782                  warn(gettext("Could not refresh %s "
1783 1783                      "(repository connection broken).\n"), fmribuf);
1784 1784                  break;
1785 1785  
1786 1786          case ECANCELED:
1787 1787                  warn(emsg_deleted);
1788 1788                  break;
1789 1789  
1790 1790          case EPERM:
1791 1791                  warn(gettext("Could not refresh %s "
1792 1792                      "(permission denied).\n"), fmribuf);
1793 1793                  break;
1794 1794  
1795 1795          case ENOSPC:
1796 1796                  warn(gettext("Could not refresh %s "
1797 1797                      "(repository server out of resources).\n"),
1798 1798                      fmribuf);
1799 1799                  break;
1800 1800  
1801 1801          case EACCES:
1802 1802          default:
1803 1803                  bad_error("refresh_entity", scf_error());
1804 1804          }
1805 1805  
1806 1806          if (issvc) {
1807 1807                  scf_instance_destroy(pinst);
1808 1808                  scf_iter_destroy(piter);
1809 1809          }
1810 1810  
1811 1811          free(fmribuf);
1812 1812  }
1813 1813  
1814 1814  
1815 1815  static int
1816 1816  stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 1817  {
1818 1818          cbp->sc_err = scferror2errno(err);
1819 1819          return (UU_WALK_ERROR);
1820 1820  }
1821 1821  
1822 1822  static int
1823 1823  stash_scferror(scf_callback_t *cbp)
1824 1824  {
1825 1825          return (stash_scferror_err(cbp, scf_error()));
1826 1826  }
1827 1827  
1828 1828  static int select_inst(const char *);
1829 1829  static int select_svc(const char *);
1830 1830  
1831 1831  /*
1832 1832   * Take a property that does not have a type and check to see if a type
1833 1833   * exists or can be gleened from the current data.  Set the type.
1834 1834   *
1835 1835   * Check the current level (instance) and then check the higher level
1836 1836   * (service).  This could be the case for adding a new property to
1837 1837   * the instance that's going to "override" a service level property.
1838 1838   *
1839 1839   * For a property :
1840 1840   * 1. Take the type from an existing property
1841 1841   * 2. Take the type from a template entry
1842 1842   *
1843 1843   * If the type can not be found, then leave the type as is, and let the import
1844 1844   * report the problem of the missing type.
1845 1845   */
1846 1846  static int
1847 1847  find_current_prop_type(void *p, void *g)
1848 1848  {
1849 1849          property_t *prop = p;
1850 1850          scf_callback_t *lcb = g;
1851 1851          pgroup_t *pg = NULL;
1852 1852  
1853 1853          const char *fmri = NULL;
1854 1854          char *lfmri = NULL;
1855 1855          char *cur_selection = NULL;
1856 1856  
1857 1857          scf_propertygroup_t *sc_pg = NULL;
1858 1858          scf_property_t *sc_prop = NULL;
1859 1859          scf_pg_tmpl_t *t_pg = NULL;
1860 1860          scf_prop_tmpl_t *t_prop = NULL;
1861 1861          scf_type_t prop_type;
1862 1862  
1863 1863          value_t *vp;
1864 1864          int issvc = lcb->sc_service;
1865 1865          int r = UU_WALK_ERROR;
1866 1866  
1867 1867          if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 1868                  return (UU_WALK_NEXT);
1869 1869  
1870 1870          t_prop = scf_tmpl_prop_create(g_hndl);
1871 1871          sc_prop = scf_property_create(g_hndl);
1872 1872          if (sc_prop == NULL || t_prop == NULL) {
1873 1873                  warn(gettext("Unable to create the property to attempt and "
1874 1874                      "find a missing type.\n"));
1875 1875  
1876 1876                  scf_property_destroy(sc_prop);
1877 1877                  scf_tmpl_prop_destroy(t_prop);
1878 1878  
1879 1879                  return (UU_WALK_ERROR);
1880 1880          }
1881 1881  
1882 1882          if (lcb->sc_flags == 1) {
1883 1883                  pg = lcb->sc_parent;
1884 1884                  issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 1885                  fmri = pg->sc_parent->sc_fmri;
1886 1886  retry_pg:
1887 1887                  if (cur_svc && cur_selection == NULL) {
1888 1888                          cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 1889                          lscf_get_selection_str(cur_selection,
1890 1890                              max_scf_fmri_len + 1);
1891 1891  
1892 1892                          if (strcmp(cur_selection, fmri) != 0) {
1893 1893                                  lscf_select(fmri);
1894 1894                          } else {
1895 1895                                  free(cur_selection);
1896 1896                                  cur_selection = NULL;
1897 1897                          }
1898 1898                  } else {
1899 1899                          lscf_select(fmri);
1900 1900                  }
1901 1901  
1902 1902                  if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 1903                          warn(gettext("Unable to create property group to "
1904 1904                              "find a missing property type.\n"));
1905 1905  
1906 1906                          goto out;
1907 1907                  }
1908 1908  
1909 1909                  if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910 1910                          /*
1911 1911                           * If this is the sc_pg from the parent
1912 1912                           * let the caller clean up the sc_pg,
1913 1913                           * and just throw it away in this case.
1914 1914                           */
1915 1915                          if (sc_pg != lcb->sc_parent)
1916 1916                                  scf_pg_destroy(sc_pg);
1917 1917  
1918 1918                          sc_pg = NULL;
1919 1919                          if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 1920                                  warn(gettext("Unable to create template "
1921 1921                                      "property group to find a property "
1922 1922                                      "type.\n"));
1923 1923  
1924 1924                                  goto out;
1925 1925                          }
1926 1926  
1927 1927                          if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 1928                              pg->sc_pgroup_name, NULL, t_pg,
1929 1929                              SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930 1930                                  /*
1931 1931                                   * if instance get service and jump back
1932 1932                                   */
1933 1933                                  scf_tmpl_pg_destroy(t_pg);
1934 1934                                  t_pg = NULL;
1935 1935                                  if (issvc == 0) {
1936 1936                                          entity_t *e = pg->sc_parent->sc_parent;
1937 1937  
1938 1938                                          fmri = e->sc_fmri;
1939 1939                                          issvc = 1;
1940 1940                                          goto retry_pg;
1941 1941                                  } else {
1942 1942                                          goto out;
1943 1943                                  }
1944 1944                          }
1945 1945                  }
1946 1946          } else {
1947 1947                  sc_pg = lcb->sc_parent;
1948 1948          }
1949 1949  
1950 1950          /*
1951 1951           * Attempt to get the type from an existing property.  If the property
1952 1952           * cannot be found then attempt to get the type from a template entry
1953 1953           * for the property.
1954 1954           *
1955 1955           * Finally, if at the instance level look at the service level.
1956 1956           */
1957 1957          if (sc_pg != NULL &&
1958 1958              pg_get_prop(sc_pg, prop->sc_property_name,
1959 1959              sc_prop) == SCF_SUCCESS &&
1960 1960              scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 1961                  prop->sc_value_type = prop_type;
1962 1962  
1963 1963                  /*
1964 1964                   * Found a type, update the value types and validate
1965 1965                   * the actual value against this type.
1966 1966                   */
1967 1967                  for (vp = uu_list_first(prop->sc_property_values);
1968 1968                      vp != NULL;
1969 1969                      vp = uu_list_next(prop->sc_property_values, vp)) {
1970 1970                          vp->sc_type = prop->sc_value_type;
1971 1971                          lxml_store_value(vp, 0, NULL);
1972 1972                  }
1973 1973  
1974 1974                  r = UU_WALK_NEXT;
1975 1975                  goto out;
1976 1976          }
1977 1977  
1978 1978          /*
1979 1979           * If we get here with t_pg set to NULL then we had to have
1980 1980           * gotten an sc_pg but that sc_pg did not have the property
1981 1981           * we are looking for.   So if the t_pg is not null look up
1982 1982           * the template entry for the property.
1983 1983           *
1984 1984           * If the t_pg is null then need to attempt to get a matching
1985 1985           * template entry for the sc_pg, and see if there is a property
1986 1986           * entry for that template entry.
1987 1987           */
1988 1988  do_tmpl :
1989 1989          if (t_pg != NULL &&
1990 1990              scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 1991              t_prop, 0) == SCF_SUCCESS) {
1992 1992                  if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 1993                          prop->sc_value_type = prop_type;
1994 1994  
1995 1995                          /*
1996 1996                           * Found a type, update the value types and validate
1997 1997                           * the actual value against this type.
1998 1998                           */
1999 1999                          for (vp = uu_list_first(prop->sc_property_values);
2000 2000                              vp != NULL;
2001 2001                              vp = uu_list_next(prop->sc_property_values, vp)) {
2002 2002                                  vp->sc_type = prop->sc_value_type;
2003 2003                                  lxml_store_value(vp, 0, NULL);
2004 2004                          }
2005 2005  
2006 2006                          r = UU_WALK_NEXT;
2007 2007                          goto out;
2008 2008                  }
2009 2009          } else {
2010 2010                  if (t_pg == NULL && sc_pg) {
2011 2011                          if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 2012                                  warn(gettext("Unable to create template "
2013 2013                                      "property group to find a property "
2014 2014                                      "type.\n"));
2015 2015  
2016 2016                                  goto out;
2017 2017                          }
2018 2018  
2019 2019                          if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 2020                                  scf_tmpl_pg_destroy(t_pg);
2021 2021                                  t_pg = NULL;
2022 2022                          } else {
2023 2023                                  goto do_tmpl;
2024 2024                          }
2025 2025                  }
2026 2026          }
2027 2027  
2028 2028          if (issvc == 0) {
2029 2029                  scf_instance_t *i;
2030 2030                  scf_service_t *s;
2031 2031  
2032 2032                  issvc = 1;
2033 2033                  if (lcb->sc_flags == 1) {
2034 2034                          entity_t *e = pg->sc_parent->sc_parent;
2035 2035  
2036 2036                          fmri = e->sc_fmri;
2037 2037                          goto retry_pg;
2038 2038                  }
2039 2039  
2040 2040                  /*
2041 2041                   * because lcb->sc_flags was not set then this means
2042 2042                   * the pg was not used and can be used here.
2043 2043                   */
2044 2044                  if ((pg = internal_pgroup_new()) == NULL) {
2045 2045                          warn(gettext("Could not create internal property group "
2046 2046                              "to find a missing type."));
2047 2047  
2048 2048                          goto out;
2049 2049                  }
2050 2050  
2051 2051                  pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 2052                  if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 2053                      max_scf_name_len + 1) < 0)
2054 2054                                  goto out;
2055 2055  
2056 2056                  i = scf_instance_create(g_hndl);
2057 2057                  s = scf_service_create(g_hndl);
2058 2058                  if (i == NULL || s == NULL ||
2059 2059                      scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 2060                          warn(gettext("Could not get a service for the instance "
2061 2061                              "to find a missing type."));
2062 2062  
2063 2063                          goto out;
2064 2064                  }
2065 2065  
2066 2066                  /*
2067 2067                   * Check to see truly at the instance level.
2068 2068                   */
2069 2069                  lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 2070                  if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 2071                      scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 2072                          goto out;
2073 2073                  else
2074 2074                          fmri = (const char *)lfmri;
2075 2075  
2076 2076                  goto retry_pg;
2077 2077          }
2078 2078  
2079 2079  out :
2080 2080          if (sc_pg != lcb->sc_parent) {
2081 2081                  scf_pg_destroy(sc_pg);
2082 2082          }
2083 2083  
2084 2084          /*
2085 2085           * If this is true then the pg was allocated
2086 2086           * here, and the name was set so need to free
2087 2087           * the name and the pg.
2088 2088           */
2089 2089          if (pg != NULL && pg != lcb->sc_parent) {
2090 2090                  free((char *)pg->sc_pgroup_name);
2091 2091                  internal_pgroup_free(pg);
2092 2092          }
2093 2093  
2094 2094          if (cur_selection) {
2095 2095                  lscf_select(cur_selection);
2096 2096                  free(cur_selection);
2097 2097          }
2098 2098  
2099 2099          scf_tmpl_pg_destroy(t_pg);
2100 2100          scf_tmpl_prop_destroy(t_prop);
2101 2101          scf_property_destroy(sc_prop);
2102 2102  
2103 2103          if (r != UU_WALK_NEXT)
2104 2104                  warn(gettext("Could not find property type for \"%s\" "
2105 2105                      "from \"%s\"\n"), prop->sc_property_name,
2106 2106                      fmri != NULL ? fmri : lcb->sc_source_fmri);
2107 2107  
2108 2108          free(lfmri);
2109 2109  
2110 2110          return (r);
2111 2111  }
2112 2112  
2113 2113  /*
2114 2114   * Take a property group that does not have a type and check to see if a type
2115 2115   * exists or can be gleened from the current data.  Set the type.
2116 2116   *
2117 2117   * Check the current level (instance) and then check the higher level
2118 2118   * (service).  This could be the case for adding a new property to
2119 2119   * the instance that's going to "override" a service level property.
2120 2120   *
2121 2121   * For a property group
2122 2122   * 1. Take the type from an existing property group
2123 2123   * 2. Take the type from a template entry
2124 2124   *
2125 2125   * If the type can not be found, then leave the type as is, and let the import
2126 2126   * report the problem of the missing type.
2127 2127   */
2128 2128  static int
2129 2129  find_current_pg_type(void *p, void *sori)
2130 2130  {
2131 2131          entity_t *si = sori;
2132 2132          pgroup_t *pg = p;
2133 2133  
2134 2134          const char *ofmri, *fmri;
2135 2135          char *cur_selection = NULL;
2136 2136          char *pg_type = NULL;
2137 2137  
2138 2138          scf_propertygroup_t *sc_pg = NULL;
2139 2139          scf_pg_tmpl_t *t_pg = NULL;
2140 2140  
2141 2141          int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 2142          int r = UU_WALK_ERROR;
2143 2143  
2144 2144          ofmri = fmri = si->sc_fmri;
2145 2145          if (pg->sc_pgroup_type != NULL) {
2146 2146                  r = UU_WALK_NEXT;
2147 2147  
2148 2148                  goto out;
2149 2149          }
2150 2150  
2151 2151          sc_pg = scf_pg_create(g_hndl);
2152 2152          if (sc_pg == NULL) {
2153 2153                  warn(gettext("Unable to create property group to attempt "
2154 2154                      "and find a missing type.\n"));
2155 2155  
2156 2156                  return (UU_WALK_ERROR);
2157 2157          }
2158 2158  
2159 2159          /*
2160 2160           * Using get_pg() requires that the cur_svc/cur_inst be
2161 2161           * via lscf_select.  Need to preserve the current selection
2162 2162           * if going to use lscf_select() to set up the cur_svc/cur_inst
2163 2163           */
2164 2164          if (cur_svc) {
2165 2165                  cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 2166                  lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167 2167          }
2168 2168  
2169 2169          /*
2170 2170           * If the property group exists get the type, and set
2171 2171           * the pgroup_t type of that type.
2172 2172           *
2173 2173           * If not the check for a template pg_pattern entry
2174 2174           * and take the type from that.
2175 2175           */
2176 2176  retry_svc:
2177 2177          lscf_select(fmri);
2178 2178  
2179 2179          if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 2180                  pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 2181                  if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 2182                      max_scf_pg_type_len + 1) != -1) {
2183 2183                          pg->sc_pgroup_type = pg_type;
2184 2184  
2185 2185                          r = UU_WALK_NEXT;
2186 2186                          goto out;
2187 2187                  } else {
2188 2188                          free(pg_type);
2189 2189                  }
2190 2190          } else {
2191 2191                  if ((t_pg == NULL) &&
2192 2192                      (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 2193                          goto out;
2194 2194  
2195 2195                  if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 2196                      NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 2197                      scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 2198                          pg->sc_pgroup_type = pg_type;
2199 2199  
2200 2200                          r = UU_WALK_NEXT;
2201 2201                          goto out;
2202 2202                  }
2203 2203          }
2204 2204  
2205 2205          /*
2206 2206           * If type is not found at the instance level then attempt to
2207 2207           * find the type at the service level.
2208 2208           */
2209 2209          if (!issvc) {
2210 2210                  si = si->sc_parent;
2211 2211                  fmri = si->sc_fmri;
2212 2212                  issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 2213                  goto retry_svc;
2214 2214          }
2215 2215  
2216 2216  out :
2217 2217          if (cur_selection) {
2218 2218                  lscf_select(cur_selection);
2219 2219                  free(cur_selection);
2220 2220          }
2221 2221  
2222 2222          /*
2223 2223           * Now walk the properties of the property group to make sure that
2224 2224           * all properties have the correct type and values are valid for
2225 2225           * those types.
2226 2226           */
2227 2227          if (r == UU_WALK_NEXT) {
2228 2228                  scf_callback_t cb;
2229 2229  
2230 2230                  cb.sc_service = issvc;
2231 2231                  cb.sc_source_fmri = ofmri;
2232 2232                  if (sc_pg != NULL) {
2233 2233                          cb.sc_parent = sc_pg;
2234 2234                          cb.sc_flags = 0;
2235 2235                  } else {
2236 2236                          cb.sc_parent = pg;
2237 2237                          cb.sc_flags = 1;
2238 2238                  }
2239 2239  
2240 2240                  if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 2241                      &cb, UU_DEFAULT) != 0) {
2242 2242                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 2243                                  bad_error("uu_list_walk", uu_error());
2244 2244  
2245 2245                          r = UU_WALK_ERROR;
2246 2246                  }
2247 2247          } else {
2248 2248                  warn(gettext("Could not find property group type for "
2249 2249                      "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250 2250          }
2251 2251  
2252 2252          scf_tmpl_pg_destroy(t_pg);
2253 2253          scf_pg_destroy(sc_pg);
2254 2254  
2255 2255          return (r);
2256 2256  }
2257 2257  
2258 2258  /*
2259 2259   * Import.  These functions import a bundle into the repository.
2260 2260   */
2261 2261  
2262 2262  /*
2263 2263   * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2264 2264   * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2265 2265   * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2266 2266   * lcbdata->sc_err to
2267 2267   *   ENOMEM - out of memory
2268 2268   *   ECONNABORTED - repository connection broken
2269 2269   *   ECANCELED - sc_trans's property group was deleted
2270 2270   *   EINVAL - p's name is invalid (error printed)
2271 2271   *          - p has an invalid value (error printed)
2272 2272   */
2273 2273  static int
2274 2274  lscf_property_import(void *v, void *pvt)
2275 2275  {
2276 2276          property_t *p = v;
2277 2277          scf_callback_t *lcbdata = pvt;
2278 2278          value_t *vp;
2279 2279          scf_transaction_t *trans = lcbdata->sc_trans;
2280 2280          scf_transaction_entry_t *entr;
2281 2281          scf_value_t *val;
2282 2282          scf_type_t tp;
2283 2283  
2284 2284          if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 2285              lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 2286              strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 2287                  lcbdata->sc_enable = p;
2288 2288                  return (UU_WALK_NEXT);
2289 2289          }
2290 2290  
2291 2291          entr = scf_entry_create(lcbdata->sc_handle);
2292 2292          if (entr == NULL) {
2293 2293                  switch (scf_error()) {
2294 2294                  case SCF_ERROR_NO_MEMORY:
2295 2295                          return (stash_scferror(lcbdata));
2296 2296  
2297 2297                  case SCF_ERROR_INVALID_ARGUMENT:
2298 2298                  default:
2299 2299                          bad_error("scf_entry_create", scf_error());
2300 2300                  }
2301 2301          }
2302 2302  
2303 2303          tp = p->sc_value_type;
2304 2304  
2305 2305          if (scf_transaction_property_new(trans, entr,
2306 2306              p->sc_property_name, tp) != 0) {
2307 2307                  switch (scf_error()) {
2308 2308                  case SCF_ERROR_INVALID_ARGUMENT:
2309 2309                          semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 2310                          scf_entry_destroy(entr);
2311 2311                          return (stash_scferror(lcbdata));
2312 2312  
2313 2313                  case SCF_ERROR_EXISTS:
2314 2314                          break;
2315 2315  
2316 2316                  case SCF_ERROR_DELETED:
2317 2317                  case SCF_ERROR_CONNECTION_BROKEN:
2318 2318                          scf_entry_destroy(entr);
2319 2319                          return (stash_scferror(lcbdata));
2320 2320  
2321 2321                  case SCF_ERROR_NOT_BOUND:
2322 2322                  case SCF_ERROR_HANDLE_MISMATCH:
2323 2323                  case SCF_ERROR_NOT_SET:
2324 2324                  default:
2325 2325                          bad_error("scf_transaction_property_new", scf_error());
2326 2326                  }
2327 2327  
2328 2328                  if (scf_transaction_property_change_type(trans, entr,
2329 2329                      p->sc_property_name, tp) != 0) {
2330 2330                          switch (scf_error()) {
2331 2331                          case SCF_ERROR_DELETED:
2332 2332                          case SCF_ERROR_CONNECTION_BROKEN:
2333 2333                                  scf_entry_destroy(entr);
2334 2334                                  return (stash_scferror(lcbdata));
2335 2335  
2336 2336                          case SCF_ERROR_INVALID_ARGUMENT:
2337 2337                                  semerr(emsg_invalid_prop_name,
2338 2338                                      p->sc_property_name);
2339 2339                                  scf_entry_destroy(entr);
2340 2340                                  return (stash_scferror(lcbdata));
2341 2341  
2342 2342                          case SCF_ERROR_NOT_FOUND:
2343 2343                          case SCF_ERROR_NOT_SET:
2344 2344                          case SCF_ERROR_HANDLE_MISMATCH:
2345 2345                          case SCF_ERROR_NOT_BOUND:
2346 2346                          default:
2347 2347                                  bad_error(
2348 2348                                      "scf_transaction_property_change_type",
2349 2349                                      scf_error());
2350 2350                          }
2351 2351                  }
2352 2352          }
2353 2353  
2354 2354          for (vp = uu_list_first(p->sc_property_values);
2355 2355              vp != NULL;
2356 2356              vp = uu_list_next(p->sc_property_values, vp)) {
2357 2357                  val = scf_value_create(g_hndl);
2358 2358                  if (val == NULL) {
2359 2359                          switch (scf_error()) {
2360 2360                          case SCF_ERROR_NO_MEMORY:
2361 2361                                  return (stash_scferror(lcbdata));
2362 2362  
2363 2363                          case SCF_ERROR_INVALID_ARGUMENT:
2364 2364                          default:
2365 2365                                  bad_error("scf_value_create", scf_error());
2366 2366                          }
2367 2367                  }
2368 2368  
2369 2369                  switch (tp) {
2370 2370                  case SCF_TYPE_BOOLEAN:
2371 2371                          scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 2372                          break;
2373 2373                  case SCF_TYPE_COUNT:
2374 2374                          scf_value_set_count(val, vp->sc_u.sc_count);
2375 2375                          break;
2376 2376                  case SCF_TYPE_INTEGER:
2377 2377                          scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 2378                          break;
2379 2379                  default:
2380 2380                          assert(vp->sc_u.sc_string != NULL);
2381 2381                          if (scf_value_set_from_string(val, tp,
2382 2382                              vp->sc_u.sc_string) != 0) {
2383 2383                                  if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 2384                                          bad_error("scf_value_set_from_string",
2385 2385                                              scf_error());
2386 2386  
2387 2387                                  warn(gettext("Value \"%s\" is not a valid "
2388 2388                                      "%s.\n"), vp->sc_u.sc_string,
2389 2389                                      scf_type_to_string(tp));
2390 2390                                  scf_value_destroy(val);
2391 2391                                  return (stash_scferror(lcbdata));
2392 2392                          }
2393 2393                          break;
2394 2394                  }
2395 2395  
2396 2396                  if (scf_entry_add_value(entr, val) != 0)
2397 2397                          bad_error("scf_entry_add_value", scf_error());
2398 2398          }
2399 2399  
2400 2400          return (UU_WALK_NEXT);
2401 2401  }
2402 2402  
2403 2403  /*
2404 2404   * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2405 2405   * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 2406   * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 2407   * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2408 2408   * lcbdata->sc_err to
2409 2409   *   ECONNABORTED - repository connection broken
2410 2410   *   ENOMEM - out of memory
2411 2411   *   ENOSPC - svc.configd is out of resources
2412 2412   *   ECANCELED - sc_parent was deleted
2413 2413   *   EPERM - could not create property group (permission denied) (error printed)
2414 2414   *         - could not modify property group (permission denied) (error printed)
2415 2415   *         - could not delete property group (permission denied) (error printed)
2416 2416   *   EROFS - could not create property group (repository is read-only)
2417 2417   *         - could not delete property group (repository is read-only)
2418 2418   *   EACCES - could not create property group (backend access denied)
2419 2419   *          - could not delete property group (backend access denied)
2420 2420   *   EEXIST - could not create property group (already exists)
2421 2421   *   EINVAL - invalid property group name (error printed)
2422 2422   *          - invalid property name (error printed)
2423 2423   *          - invalid value (error printed)
2424 2424   *   EBUSY - new property group deleted (error printed)
2425 2425   *         - new property group changed (error printed)
2426 2426   *         - property group added (error printed)
2427 2427   *         - property group deleted (error printed)
2428 2428   */
2429 2429  static int
2430 2430  entity_pgroup_import(void *v, void *pvt)
2431 2431  {
2432 2432          pgroup_t *p = v;
2433 2433          scf_callback_t cbdata;
2434 2434          scf_callback_t *lcbdata = pvt;
2435 2435          void *ent = lcbdata->sc_parent;
2436 2436          int issvc = lcbdata->sc_service;
2437 2437          int r;
2438 2438  
2439 2439          const char * const pg_changed = gettext("%s changed unexpectedly "
2440 2440              "(new property group \"%s\" changed).\n");
2441 2441  
2442 2442          /* Never import deleted property groups. */
2443 2443          if (p->sc_pgroup_delete) {
2444 2444                  if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 2445                      entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 2446                          goto delete_pg;
2447 2447                  }
2448 2448                  return (UU_WALK_NEXT);
2449 2449          }
2450 2450  
2451 2451          if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 2452              strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 2453                  lcbdata->sc_general = p;
2454 2454                  return (UU_WALK_NEXT);
2455 2455          }
2456 2456  
2457 2457  add_pg:
2458 2458          if (issvc)
2459 2459                  r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 2460                      p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 2461          else
2462 2462                  r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 2463                      p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 2464          if (r != 0) {
2465 2465                  switch (scf_error()) {
2466 2466                  case SCF_ERROR_DELETED:
2467 2467                  case SCF_ERROR_CONNECTION_BROKEN:
2468 2468                  case SCF_ERROR_BACKEND_READONLY:
2469 2469                  case SCF_ERROR_BACKEND_ACCESS:
2470 2470                  case SCF_ERROR_NO_RESOURCES:
2471 2471                          return (stash_scferror(lcbdata));
2472 2472  
2473 2473                  case SCF_ERROR_EXISTS:
2474 2474                          if (lcbdata->sc_flags & SCI_FORCE)
2475 2475                                  break;
2476 2476                          return (stash_scferror(lcbdata));
2477 2477  
2478 2478                  case SCF_ERROR_INVALID_ARGUMENT:
2479 2479                          warn(emsg_fmri_invalid_pg_name_type,
2480 2480                              lcbdata->sc_source_fmri,
2481 2481                              p->sc_pgroup_name, p->sc_pgroup_type);
2482 2482                          return (stash_scferror(lcbdata));
2483 2483  
2484 2484                  case SCF_ERROR_PERMISSION_DENIED:
2485 2485                          warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 2486                              lcbdata->sc_target_fmri);
2487 2487                          return (stash_scferror(lcbdata));
2488 2488  
2489 2489                  case SCF_ERROR_NOT_BOUND:
2490 2490                  case SCF_ERROR_HANDLE_MISMATCH:
2491 2491                  case SCF_ERROR_NOT_SET:
2492 2492                  default:
2493 2493                          bad_error("scf_service_add_pg", scf_error());
2494 2494                  }
2495 2495  
2496 2496                  if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 2497                          switch (scf_error()) {
2498 2498                          case SCF_ERROR_CONNECTION_BROKEN:
2499 2499                          case SCF_ERROR_DELETED:
2500 2500                                  return (stash_scferror(lcbdata));
2501 2501  
2502 2502                          case SCF_ERROR_INVALID_ARGUMENT:
2503 2503                                  warn(emsg_fmri_invalid_pg_name,
2504 2504                                      lcbdata->sc_source_fmri,
2505 2505                                      p->sc_pgroup_name);
2506 2506                                  return (stash_scferror(lcbdata));
2507 2507  
2508 2508                          case SCF_ERROR_NOT_FOUND:
2509 2509                                  warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 2510                                      p->sc_pgroup_name);
2511 2511                                  lcbdata->sc_err = EBUSY;
2512 2512                                  return (UU_WALK_ERROR);
2513 2513  
2514 2514                          case SCF_ERROR_NOT_BOUND:
2515 2515                          case SCF_ERROR_HANDLE_MISMATCH:
2516 2516                          case SCF_ERROR_NOT_SET:
2517 2517                          default:
2518 2518                                  bad_error("entity_get_pg", scf_error());
2519 2519                          }
2520 2520                  }
2521 2521  
2522 2522                  if (lcbdata->sc_flags & SCI_KEEP)
2523 2523                          goto props;
2524 2524  
2525 2525  delete_pg:
2526 2526                  if (scf_pg_delete(imp_pg) != 0) {
2527 2527                          switch (scf_error()) {
2528 2528                          case SCF_ERROR_DELETED:
2529 2529                                  warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 2530                                      p->sc_pgroup_name);
2531 2531                                  lcbdata->sc_err = EBUSY;
2532 2532                                  return (UU_WALK_ERROR);
2533 2533  
2534 2534                          case SCF_ERROR_PERMISSION_DENIED:
2535 2535                                  warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 2536                                      lcbdata->sc_target_fmri);
2537 2537                                  return (stash_scferror(lcbdata));
2538 2538  
2539 2539                          case SCF_ERROR_BACKEND_READONLY:
2540 2540                          case SCF_ERROR_BACKEND_ACCESS:
2541 2541                          case SCF_ERROR_CONNECTION_BROKEN:
2542 2542                                  return (stash_scferror(lcbdata));
2543 2543  
2544 2544                          case SCF_ERROR_NOT_SET:
2545 2545                          default:
2546 2546                                  bad_error("scf_pg_delete", scf_error());
2547 2547                          }
2548 2548                  }
2549 2549  
2550 2550                  if (p->sc_pgroup_delete)
2551 2551                          return (UU_WALK_NEXT);
2552 2552  
2553 2553                  goto add_pg;
2554 2554          }
2555 2555  
2556 2556  props:
2557 2557  
2558 2558          /*
2559 2559           * Add properties to property group, if any.
2560 2560           */
2561 2561          cbdata.sc_handle = lcbdata->sc_handle;
2562 2562          cbdata.sc_parent = imp_pg;
2563 2563          cbdata.sc_flags = lcbdata->sc_flags;
2564 2564          cbdata.sc_trans = imp_tx;
2565 2565          cbdata.sc_enable = NULL;
2566 2566  
2567 2567          if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 2568                  switch (scf_error()) {
2569 2569                  case SCF_ERROR_BACKEND_ACCESS:
2570 2570                  case SCF_ERROR_BACKEND_READONLY:
2571 2571                  case SCF_ERROR_CONNECTION_BROKEN:
2572 2572                          return (stash_scferror(lcbdata));
2573 2573  
2574 2574                  case SCF_ERROR_DELETED:
2575 2575                          warn(pg_changed, lcbdata->sc_target_fmri,
2576 2576                              p->sc_pgroup_name);
2577 2577                          lcbdata->sc_err = EBUSY;
2578 2578                          return (UU_WALK_ERROR);
2579 2579  
2580 2580                  case SCF_ERROR_PERMISSION_DENIED:
2581 2581                          warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 2582                              lcbdata->sc_target_fmri);
2583 2583                          return (stash_scferror(lcbdata));
2584 2584  
2585 2585                  case SCF_ERROR_NOT_BOUND:
2586 2586                  case SCF_ERROR_NOT_SET:
2587 2587                  case SCF_ERROR_IN_USE:
2588 2588                  case SCF_ERROR_HANDLE_MISMATCH:
2589 2589                  default:
2590 2590                          bad_error("scf_transaction_start", scf_error());
2591 2591                  }
2592 2592          }
2593 2593  
2594 2594          if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 2595              UU_DEFAULT) != 0) {
2596 2596                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 2597                          bad_error("uu_list_walk", uu_error());
2598 2598                  scf_transaction_reset(imp_tx);
2599 2599  
2600 2600                  lcbdata->sc_err = cbdata.sc_err;
2601 2601                  if (cbdata.sc_err == ECANCELED) {
2602 2602                          warn(pg_changed, lcbdata->sc_target_fmri,
2603 2603                              p->sc_pgroup_name);
2604 2604                          lcbdata->sc_err = EBUSY;
2605 2605                  }
2606 2606                  return (UU_WALK_ERROR);
2607 2607          }
2608 2608  
2609 2609          if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 2610                  cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611 2611  
2612 2612                  /*
2613 2613                   * take the snapshot running snapshot then
2614 2614                   * import the stored general/enable property
2615 2615                   */
2616 2616                  r = take_snap(ent, snap_running, imp_rsnap);
2617 2617                  switch (r) {
2618 2618                  case 0:
2619 2619                          break;
2620 2620  
2621 2621                  case ECONNABORTED:
2622 2622                          warn(gettext("Could not take %s snapshot on import "
2623 2623                              "(repository connection broken).\n"),
2624 2624                              snap_running);
2625 2625                          lcbdata->sc_err = r;
2626 2626                          return (UU_WALK_ERROR);
2627 2627                  case ECANCELED:
2628 2628                          warn(emsg_deleted);
2629 2629                          lcbdata->sc_err = r;
2630 2630                          return (UU_WALK_ERROR);
2631 2631  
2632 2632                  case EPERM:
2633 2633                          warn(gettext("Could not take %s snapshot "
2634 2634                              "(permission denied).\n"), snap_running);
2635 2635                          lcbdata->sc_err = r;
2636 2636                          return (UU_WALK_ERROR);
2637 2637  
2638 2638                  case ENOSPC:
2639 2639                          warn(gettext("Could not take %s snapshot"
2640 2640                              "(repository server out of resources).\n"),
2641 2641                              snap_running);
2642 2642                          lcbdata->sc_err = r;
2643 2643                          return (UU_WALK_ERROR);
2644 2644  
2645 2645                  default:
2646 2646                          bad_error("take_snap", r);
2647 2647                  }
2648 2648  
2649 2649                  r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 2650                  if (r != UU_WALK_NEXT) {
2651 2651                          if (r != UU_WALK_ERROR)
2652 2652                                  bad_error("lscf_property_import", r);
2653 2653                          return (EINVAL);
2654 2654                  }
2655 2655          }
2656 2656  
2657 2657          r = scf_transaction_commit(imp_tx);
2658 2658          switch (r) {
2659 2659          case 1:
2660 2660                  r = UU_WALK_NEXT;
2661 2661                  break;
2662 2662  
2663 2663          case 0:
2664 2664                  warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 2665                  lcbdata->sc_err = EBUSY;
2666 2666                  r = UU_WALK_ERROR;
2667 2667                  break;
2668 2668  
2669 2669          case -1:
2670 2670                  switch (scf_error()) {
2671 2671                  case SCF_ERROR_BACKEND_READONLY:
2672 2672                  case SCF_ERROR_BACKEND_ACCESS:
2673 2673                  case SCF_ERROR_CONNECTION_BROKEN:
2674 2674                  case SCF_ERROR_NO_RESOURCES:
2675 2675                          r = stash_scferror(lcbdata);
2676 2676                          break;
2677 2677  
2678 2678                  case SCF_ERROR_DELETED:
2679 2679                          warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 2680                              p->sc_pgroup_name);
2681 2681                          lcbdata->sc_err = EBUSY;
2682 2682                          r = UU_WALK_ERROR;
2683 2683                          break;
2684 2684  
2685 2685                  case SCF_ERROR_PERMISSION_DENIED:
2686 2686                          warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 2687                              lcbdata->sc_target_fmri);
2688 2688                          r = stash_scferror(lcbdata);
2689 2689                          break;
2690 2690  
2691 2691                  case SCF_ERROR_NOT_SET:
2692 2692                  case SCF_ERROR_INVALID_ARGUMENT:
2693 2693                  case SCF_ERROR_NOT_BOUND:
2694 2694                  default:
2695 2695                          bad_error("scf_transaction_commit", scf_error());
2696 2696                  }
2697 2697                  break;
2698 2698  
2699 2699          default:
2700 2700                  bad_error("scf_transaction_commit", r);
2701 2701          }
2702 2702  
2703 2703          scf_transaction_destroy_children(imp_tx);
2704 2704  
2705 2705          return (r);
2706 2706  }
2707 2707  
2708 2708  /*
2709 2709   * Returns
2710 2710   *   0 - success
2711 2711   *   ECONNABORTED - repository connection broken
2712 2712   *   ENOMEM - out of memory
2713 2713   *   ENOSPC - svc.configd is out of resources
2714 2714   *   ECANCELED - inst was deleted
2715 2715   *   EPERM - could not create property group (permission denied) (error printed)
2716 2716   *         - could not modify property group (permission denied) (error printed)
2717 2717   *   EROFS - could not create property group (repository is read-only)
2718 2718   *   EACCES - could not create property group (backend access denied)
2719 2719   *   EEXIST - could not create property group (already exists)
2720 2720   *   EINVAL - invalid property group name (error printed)
2721 2721   *          - invalid property name (error printed)
2722 2722   *          - invalid value (error printed)
2723 2723   *   EBUSY - new property group changed (error printed)
2724 2724   */
2725 2725  static int
2726 2726  lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727 2727      const entity_t *isvc, int flags)
2728 2728  {
2729 2729          scf_callback_t cbdata;
2730 2730  
2731 2731          cbdata.sc_handle = scf_service_handle(svc);
2732 2732          cbdata.sc_parent = svc;
2733 2733          cbdata.sc_service = 1;
2734 2734          cbdata.sc_general = 0;
2735 2735          cbdata.sc_enable = 0;
2736 2736          cbdata.sc_flags = flags;
2737 2737          cbdata.sc_source_fmri = isvc->sc_fmri;
2738 2738          cbdata.sc_target_fmri = target_fmri;
2739 2739  
2740 2740          /*
2741 2741           * If the op is set, then add the flag to the callback
2742 2742           * flags for later use.
2743 2743           */
2744 2744          if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 2745                  switch (isvc->sc_op) {
2746 2746                  case SVCCFG_OP_IMPORT :
2747 2747                          cbdata.sc_flags |= SCI_OP_IMPORT;
2748 2748                          break;
2749 2749                  case SVCCFG_OP_APPLY :
2750 2750                          cbdata.sc_flags |= SCI_OP_APPLY;
2751 2751                          break;
2752 2752                  case SVCCFG_OP_RESTORE :
2753 2753                          cbdata.sc_flags |= SCI_OP_RESTORE;
2754 2754                          break;
2755 2755                  default :
2756 2756                          uu_die(gettext("lscf_import_service_pgs : "
2757 2757                              "Unknown op stored in the service entity\n"));
2758 2758  
2759 2759                  }
2760 2760          }
2761 2761  
2762 2762          if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 2763              UU_DEFAULT) != 0) {
2764 2764                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 2765                          bad_error("uu_list_walk", uu_error());
2766 2766  
2767 2767                  return (cbdata.sc_err);
2768 2768          }
2769 2769  
2770 2770          return (0);
2771 2771  }
2772 2772  
2773 2773  /*
2774 2774   * Returns
2775 2775   *   0 - success
2776 2776   *   ECONNABORTED - repository connection broken
2777 2777   *   ENOMEM - out of memory
2778 2778   *   ENOSPC - svc.configd is out of resources
2779 2779   *   ECANCELED - inst was deleted
2780 2780   *   EPERM - could not create property group (permission denied) (error printed)
2781 2781   *         - could not modify property group (permission denied) (error printed)
2782 2782   *   EROFS - could not create property group (repository is read-only)
2783 2783   *   EACCES - could not create property group (backend access denied)
2784 2784   *   EEXIST - could not create property group (already exists)
2785 2785   *   EINVAL - invalid property group name (error printed)
2786 2786   *          - invalid property name (error printed)
2787 2787   *          - invalid value (error printed)
2788 2788   *   EBUSY - new property group changed (error printed)
2789 2789   */
2790 2790  static int
2791 2791  lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792 2792      const entity_t *iinst, int flags)
2793 2793  {
2794 2794          scf_callback_t cbdata;
2795 2795  
2796 2796          cbdata.sc_handle = scf_instance_handle(inst);
2797 2797          cbdata.sc_parent = inst;
2798 2798          cbdata.sc_service = 0;
2799 2799          cbdata.sc_general = NULL;
2800 2800          cbdata.sc_enable = NULL;
2801 2801          cbdata.sc_flags = flags;
2802 2802          cbdata.sc_source_fmri = iinst->sc_fmri;
2803 2803          cbdata.sc_target_fmri = target_fmri;
2804 2804  
2805 2805          /*
2806 2806           * If the op is set, then add the flag to the callback
2807 2807           * flags for later use.
2808 2808           */
2809 2809          if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 2810                  switch (iinst->sc_op) {
2811 2811                  case SVCCFG_OP_IMPORT :
2812 2812                          cbdata.sc_flags |= SCI_OP_IMPORT;
2813 2813                          break;
2814 2814                  case SVCCFG_OP_APPLY :
2815 2815                          cbdata.sc_flags |= SCI_OP_APPLY;
2816 2816                          break;
2817 2817                  case SVCCFG_OP_RESTORE :
2818 2818                          cbdata.sc_flags |= SCI_OP_RESTORE;
2819 2819                          break;
2820 2820                  default :
2821 2821                          uu_die(gettext("lscf_import_instance_pgs : "
2822 2822                              "Unknown op stored in the instance entity\n"));
2823 2823                  }
2824 2824          }
2825 2825  
2826 2826          if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 2827              UU_DEFAULT) != 0) {
2828 2828                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 2829                          bad_error("uu_list_walk", uu_error());
2830 2830  
2831 2831                  return (cbdata.sc_err);
2832 2832          }
2833 2833  
2834 2834          if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 2835                  cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836 2836                  /*
2837 2837                   * If importing with the SCI_NOENABLED flag then
2838 2838                   * skip the delay, but if not then add the delay
2839 2839                   * of the enable property.
2840 2840                   */
2841 2841                  if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 2842                          cbdata.sc_flags |= SCI_DELAYENABLE;
2843 2843                  }
2844 2844  
2845 2845                  if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 2846                      != UU_WALK_NEXT)
2847 2847                          return (cbdata.sc_err);
2848 2848          }
2849 2849  
2850 2850          return (0);
2851 2851  }
2852 2852  
2853 2853  /*
2854 2854   * Report the reasons why we can't upgrade pg2 to pg1.
2855 2855   */
2856 2856  static void
2857 2857  report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858 2858      int new)
2859 2859  {
2860 2860          property_t *p1, *p2;
2861 2861  
2862 2862          assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863 2863  
2864 2864          if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 2865                  return;
2866 2866  
2867 2867          for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 2868              p1 != NULL;
2869 2869              p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 2870                  p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 2871                  if (p2 != NULL) {
2872 2872                          (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 2873                              new);
2874 2874                          continue;
2875 2875                  }
2876 2876  
2877 2877                  if (new)
2878 2878                          warn(gettext("Conflict upgrading %s (new property "
2879 2879                              "group \"%s\" is missing property \"%s\").\n"),
2880 2880                              fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 2881                  else
2882 2882                          warn(gettext("Conflict upgrading %s (property "
2883 2883                              "\"%s/%s\" is missing).\n"), fmri,
2884 2884                              pg1->sc_pgroup_name, p1->sc_property_name);
2885 2885          }
2886 2886  
2887 2887          /*
2888 2888           * Since pg1 should be from the manifest, any properties in pg2 which
2889 2889           * aren't in pg1 shouldn't be reported as conflicts.
2890 2890           */
2891 2891  }
2892 2892  
2893 2893  /*
2894 2894   * Add transaction entries to tx which will upgrade cur's pg according to old
2895 2895   * & new.
2896 2896   *
2897 2897   * Returns
2898 2898   *   0 - success
2899 2899   *   EINVAL - new has a property with an invalid name or value (message emitted)
2900 2900   *   ENOMEM - out of memory
2901 2901   */
2902 2902  static int
2903 2903  add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904 2904      pgroup_t *cur, int speak, const char *fmri)
2905 2905  {
2906 2906          property_t *p, *new_p, *cur_p;
2907 2907          scf_transaction_entry_t *e;
2908 2908          int r;
2909 2909          int is_general;
2910 2910          int is_protected;
2911 2911  
2912 2912          if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 2913              (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 2914                  bad_error("uu_list_walk", uu_error());
2915 2915  
2916 2916          is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917 2917  
2918 2918          for (p = uu_list_first(old->sc_pgroup_props);
2919 2919              p != NULL;
2920 2920              p = uu_list_next(old->sc_pgroup_props, p)) {
2921 2921                  /* p is a property in the old property group. */
2922 2922  
2923 2923                  /* Protect live properties. */
2924 2924                  is_protected = 0;
2925 2925                  if (is_general) {
2926 2926                          if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 2927                              0 ||
2928 2928                              strcmp(p->sc_property_name,
2929 2929                              SCF_PROPERTY_RESTARTER) == 0)
2930 2930                                  is_protected = 1;
2931 2931                  }
2932 2932  
2933 2933                  /* Look for the same property in the new properties. */
2934 2934                  new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 2935                  if (new_p != NULL) {
2936 2936                          new_p->sc_seen = 1;
2937 2937  
2938 2938                          /*
2939 2939                           * If the new property is the same as the old, don't do
2940 2940                           * anything (leave any user customizations).
2941 2941                           */
2942 2942                          if (prop_equal(p, new_p, NULL, NULL, 0))
2943 2943                                  continue;
2944 2944  
2945 2945                          if (new_p->sc_property_override)
2946 2946                                  goto upgrade;
2947 2947                  }
2948 2948  
2949 2949                  cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 2950                  if (cur_p == NULL) {
2951 2951                          /*
2952 2952                           * p has been deleted from the repository.  If we were
2953 2953                           * going to delete it anyway, do nothing.  Otherwise
2954 2954                           * report a conflict.
2955 2955                           */
2956 2956                          if (new_p == NULL)
2957 2957                                  continue;
2958 2958  
2959 2959                          if (is_protected)
2960 2960                                  continue;
2961 2961  
2962 2962                          warn(gettext("Conflict upgrading %s "
2963 2963                              "(property \"%s/%s\" is missing).\n"), fmri,
2964 2964                              old->sc_pgroup_name, p->sc_property_name);
2965 2965                          continue;
2966 2966                  }
2967 2967  
2968 2968                  if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969 2969                          /*
2970 2970                           * Conflict.  Don't warn if the property is already the
2971 2971                           * way we want it, though.
2972 2972                           */
2973 2973                          if (is_protected)
2974 2974                                  continue;
2975 2975  
2976 2976                          if (new_p == NULL)
2977 2977                                  (void) prop_equal(p, cur_p, fmri,
2978 2978                                      old->sc_pgroup_name, 0);
2979 2979                          else
2980 2980                                  (void) prop_equal(cur_p, new_p, fmri,
2981 2981                                      old->sc_pgroup_name, 0);
2982 2982                          continue;
2983 2983                  }
2984 2984  
2985 2985                  if (is_protected) {
2986 2986                          if (speak)
2987 2987                                  warn(gettext("%s: Refusing to upgrade "
2988 2988                                      "\"%s/%s\" (live property).\n"), fmri,
2989 2989                                      old->sc_pgroup_name, p->sc_property_name);
2990 2990                          continue;
2991 2991                  }
2992 2992  
2993 2993  upgrade:
2994 2994                  /* p hasn't been customized in the repository.  Upgrade it. */
2995 2995                  if (new_p == NULL) {
2996 2996                          /* p was deleted.  Delete from cur if unchanged. */
2997 2997                          if (speak)
2998 2998                                  warn(gettext(
2999 2999                                      "%s: Deleting property \"%s/%s\".\n"),
3000 3000                                      fmri, old->sc_pgroup_name,
3001 3001                                      p->sc_property_name);
3002 3002  
3003 3003                          e = scf_entry_create(g_hndl);
3004 3004                          if (e == NULL)
3005 3005                                  return (ENOMEM);
3006 3006  
3007 3007                          if (scf_transaction_property_delete(tx, e,
3008 3008                              p->sc_property_name) != 0) {
3009 3009                                  switch (scf_error()) {
3010 3010                                  case SCF_ERROR_DELETED:
3011 3011                                          scf_entry_destroy(e);
3012 3012                                          return (ECANCELED);
3013 3013  
3014 3014                                  case SCF_ERROR_CONNECTION_BROKEN:
3015 3015                                          scf_entry_destroy(e);
3016 3016                                          return (ECONNABORTED);
3017 3017  
3018 3018                                  case SCF_ERROR_NOT_FOUND:
3019 3019                                          /*
3020 3020                                           * This can happen if cur is from the
3021 3021                                           * running snapshot (and it differs
3022 3022                                           * from the live properties).
3023 3023                                           */
3024 3024                                          scf_entry_destroy(e);
3025 3025                                          break;
3026 3026  
3027 3027                                  case SCF_ERROR_HANDLE_MISMATCH:
3028 3028                                  case SCF_ERROR_NOT_BOUND:
3029 3029                                  case SCF_ERROR_NOT_SET:
3030 3030                                  case SCF_ERROR_INVALID_ARGUMENT:
3031 3031                                  default:
3032 3032                                          bad_error(
3033 3033                                              "scf_transaction_property_delete",
3034 3034                                              scf_error());
3035 3035                                  }
3036 3036                          }
3037 3037                  } else {
3038 3038                          scf_callback_t ctx;
3039 3039  
3040 3040                          if (speak)
3041 3041                                  warn(gettext(
3042 3042                                      "%s: Upgrading property \"%s/%s\".\n"),
3043 3043                                      fmri, old->sc_pgroup_name,
3044 3044                                      p->sc_property_name);
3045 3045  
3046 3046                          ctx.sc_handle = g_hndl;
3047 3047                          ctx.sc_trans = tx;
3048 3048                          ctx.sc_flags = 0;
3049 3049  
3050 3050                          r = lscf_property_import(new_p, &ctx);
3051 3051                          if (r != UU_WALK_NEXT) {
3052 3052                                  if (r != UU_WALK_ERROR)
3053 3053                                          bad_error("lscf_property_import", r);
3054 3054                                  return (EINVAL);
3055 3055                          }
3056 3056                  }
3057 3057          }
3058 3058  
3059 3059          /* Go over the properties which were added. */
3060 3060          for (new_p = uu_list_first(new->sc_pgroup_props);
3061 3061              new_p != NULL;
3062 3062              new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 3063                  if (new_p->sc_seen)
3064 3064                          continue;
3065 3065  
3066 3066                  /* This is a new property. */
3067 3067                  cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 3068                  if (cur_p == NULL) {
3069 3069                          scf_callback_t ctx;
3070 3070  
3071 3071                          ctx.sc_handle = g_hndl;
3072 3072                          ctx.sc_trans = tx;
3073 3073                          ctx.sc_flags = 0;
3074 3074  
3075 3075                          r = lscf_property_import(new_p, &ctx);
3076 3076                          if (r != UU_WALK_NEXT) {
3077 3077                                  if (r != UU_WALK_ERROR)
3078 3078                                          bad_error("lscf_property_import", r);
3079 3079                                  return (EINVAL);
3080 3080                          }
3081 3081                          continue;
3082 3082                  }
3083 3083  
3084 3084                  /*
3085 3085                   * Report a conflict if the new property differs from the
3086 3086                   * current one.  Unless it's general/enabled, since that's
3087 3087                   * never in the last-import snapshot.
3088 3088                   */
3089 3089                  if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 3090                      0 &&
3091 3091                      strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 3092                          continue;
3093 3093  
3094 3094                  (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095 3095          }
3096 3096  
3097 3097          return (0);
3098 3098  }
3099 3099  
3100 3100  /*
3101 3101   * Upgrade pg according to old & new.
3102 3102   *
3103 3103   * Returns
3104 3104   *   0 - success
3105 3105   *   ECONNABORTED - repository connection broken
3106 3106   *   ENOMEM - out of memory
3107 3107   *   ENOSPC - svc.configd is out of resources
3108 3108   *   ECANCELED - pg was deleted
3109 3109   *   EPERM - couldn't modify pg (permission denied)
3110 3110   *   EROFS - couldn't modify pg (backend read-only)
3111 3111   *   EACCES - couldn't modify pg (backend access denied)
3112 3112   *   EINVAL - new has a property with invalid name or value (error printed)
3113 3113   *   EBUSY - pg changed unexpectedly
3114 3114   */
3115 3115  static int
3116 3116  upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117 3117      pgroup_t *new, int speak, const char *fmri)
3118 3118  {
3119 3119          int r;
3120 3120  
3121 3121          if (scf_transaction_start(imp_tx, pg) != 0) {
3122 3122                  switch (scf_error()) {
3123 3123                  case SCF_ERROR_CONNECTION_BROKEN:
3124 3124                  case SCF_ERROR_DELETED:
3125 3125                  case SCF_ERROR_PERMISSION_DENIED:
3126 3126                  case SCF_ERROR_BACKEND_READONLY:
3127 3127                  case SCF_ERROR_BACKEND_ACCESS:
3128 3128                          return (scferror2errno(scf_error()));
3129 3129  
3130 3130                  case SCF_ERROR_HANDLE_MISMATCH:
3131 3131                  case SCF_ERROR_IN_USE:
3132 3132                  case SCF_ERROR_NOT_BOUND:
3133 3133                  case SCF_ERROR_NOT_SET:
3134 3134                  default:
3135 3135                          bad_error("scf_transaction_start", scf_error());
3136 3136                  }
3137 3137          }
3138 3138  
3139 3139          r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 3140          switch (r) {
3141 3141          case 0:
3142 3142                  break;
3143 3143  
3144 3144          case EINVAL:
3145 3145          case ENOMEM:
3146 3146                  scf_transaction_destroy_children(imp_tx);
3147 3147                  return (r);
3148 3148  
3149 3149          default:
3150 3150                  bad_error("add_upgrade_entries", r);
3151 3151          }
3152 3152  
3153 3153          r = scf_transaction_commit(imp_tx);
3154 3154  
3155 3155          scf_transaction_destroy_children(imp_tx);
3156 3156  
3157 3157          switch (r) {
3158 3158          case 1:
3159 3159                  break;
3160 3160  
3161 3161          case 0:
3162 3162                  return (EBUSY);
3163 3163  
3164 3164          case -1:
3165 3165                  switch (scf_error()) {
3166 3166                  case SCF_ERROR_CONNECTION_BROKEN:
3167 3167                  case SCF_ERROR_NO_RESOURCES:
3168 3168                  case SCF_ERROR_PERMISSION_DENIED:
3169 3169                  case SCF_ERROR_BACKEND_READONLY:
3170 3170                  case SCF_ERROR_BACKEND_ACCESS:
3171 3171                  case SCF_ERROR_DELETED:
3172 3172                          return (scferror2errno(scf_error()));
3173 3173  
3174 3174                  case SCF_ERROR_NOT_BOUND:
3175 3175                  case SCF_ERROR_INVALID_ARGUMENT:
3176 3176                  case SCF_ERROR_NOT_SET:
3177 3177                  default:
3178 3178                          bad_error("scf_transaction_commit", scf_error());
3179 3179                  }
3180 3180  
3181 3181          default:
3182 3182                  bad_error("scf_transaction_commit", r);
3183 3183          }
3184 3184  
3185 3185          return (0);
3186 3186  }
3187 3187  
3188 3188  /*
3189 3189   * Compares two entity FMRIs.  Returns
3190 3190   *
3191 3191   *   1 - equal
3192 3192   *   0 - not equal
3193 3193   *   -1 - f1 is invalid or not an entity
3194 3194   *   -2 - f2 is invalid or not an entity
3195 3195   */
3196 3196  static int
3197 3197  fmri_equal(const char *f1, const char *f2)
3198 3198  {
3199 3199          int r;
3200 3200          const char *s1, *i1, *pg1;
3201 3201          const char *s2, *i2, *pg2;
3202 3202  
3203 3203          if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 3204                  return (-1);
3205 3205          if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 3206                  return (-1);
3207 3207  
3208 3208          if (s1 == NULL || pg1 != NULL)
3209 3209                  return (-1);
3210 3210  
3211 3211          if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 3212                  return (-2);
3213 3213          if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 3214                  return (-2);
3215 3215  
3216 3216          if (s2 == NULL || pg2 != NULL)
3217 3217                  return (-2);
3218 3218  
3219 3219          r = strcmp(s1, s2);
3220 3220          if (r != 0)
3221 3221                  return (0);
3222 3222  
3223 3223          if (i1 == NULL && i2 == NULL)
3224 3224                  return (1);
3225 3225  
3226 3226          if (i1 == NULL || i2 == NULL)
3227 3227                  return (0);
3228 3228  
3229 3229          return (strcmp(i1, i2) == 0);
3230 3230  }
3231 3231  
3232 3232  /*
3233 3233   * Import a dependent by creating a dependency property group in the dependent
3234 3234   * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3235 3235   * dependents pg, and add an entry to create a new property for this
3236 3236   * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237 3237   *
3238 3238   * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3239 3239   * lcbdata->sc_err to
3240 3240   *   ECONNABORTED - repository connection broken
3241 3241   *   ENOMEM - out of memory
3242 3242   *   ENOSPC - configd is out of resources
3243 3243   *   EINVAL - target is invalid (error printed)
3244 3244   *          - target is not an entity (error printed)
3245 3245   *          - dependent has invalid name (error printed)
3246 3246   *          - invalid property name (error printed)
3247 3247   *          - invalid value (error printed)
3248 3248   *          - scope of target does not exist (error printed)
3249 3249   *   EPERM - couldn't create target (permission denied) (error printed)
3250 3250   *         - couldn't create dependency pg (permission denied) (error printed)
3251 3251   *         - couldn't modify dependency pg (permission denied) (error printed)
3252 3252   *   EROFS - couldn't create target (repository read-only)
3253 3253   *         - couldn't create dependency pg (repository read-only)
3254 3254   *   EACCES - couldn't create target (backend access denied)
3255 3255   *          - couldn't create dependency pg (backend access denied)
3256 3256   *   ECANCELED - sc_trans's pg was deleted
3257 3257   *   EALREADY - property for dependent already exists in sc_trans's pg
3258 3258   *   EEXIST - dependency pg already exists in target (error printed)
3259 3259   *   EBUSY - target deleted (error printed)
3260 3260   *         - property group changed during import (error printed)
3261 3261   */
3262 3262  static int
3263 3263  lscf_dependent_import(void *a1, void *pvt)
3264 3264  {
3265 3265          pgroup_t *pgrp = a1;
3266 3266          scf_callback_t *lcbdata = pvt;
3267 3267  
3268 3268          int isservice;
3269 3269          int ret;
3270 3270          scf_transaction_entry_t *e;
3271 3271          scf_value_t *val;
3272 3272          scf_callback_t dependent_cbdata;
3273 3273          scf_error_t scfe;
3274 3274  
3275 3275          /*
3276 3276           * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3277 3277           * it's invalid, we fail before modifying the repository.
3278 3278           */
3279 3279          scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 3280              &dependent_cbdata.sc_parent, &isservice);
3281 3281          switch (scfe) {
3282 3282          case SCF_ERROR_NONE:
3283 3283                  break;
3284 3284  
3285 3285          case SCF_ERROR_NO_MEMORY:
3286 3286                  return (stash_scferror_err(lcbdata, scfe));
3287 3287  
3288 3288          case SCF_ERROR_INVALID_ARGUMENT:
3289 3289                  semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 3290                      "invalid.\n"), pgrp->sc_pgroup_name);
3291 3291                  return (stash_scferror_err(lcbdata, scfe));
3292 3292  
3293 3293          case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 3294                  semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 3295                      "specifies neither a service nor an instance.\n"),
3296 3296                      pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 3297                  return (stash_scferror_err(lcbdata, scfe));
3298 3298  
3299 3299          case SCF_ERROR_NOT_FOUND:
3300 3300                  scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 3301                      &dependent_cbdata.sc_parent, &isservice);
3302 3302                  switch (scfe) {
3303 3303                  case SCF_ERROR_NONE:
3304 3304                          break;
3305 3305  
3306 3306                  case SCF_ERROR_NO_MEMORY:
3307 3307                  case SCF_ERROR_BACKEND_READONLY:
3308 3308                  case SCF_ERROR_BACKEND_ACCESS:
3309 3309                          return (stash_scferror_err(lcbdata, scfe));
3310 3310  
3311 3311                  case SCF_ERROR_NOT_FOUND:
3312 3312                          semerr(gettext("The scope in FMRI \"%s\" for the "
3313 3313                              "\"%s\" dependent does not exist.\n"),
3314 3314                              pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 3315                          lcbdata->sc_err = EINVAL;
3316 3316                          return (UU_WALK_ERROR);
3317 3317  
3318 3318                  case SCF_ERROR_PERMISSION_DENIED:
3319 3319                          warn(gettext(
3320 3320                              "Could not create %s (permission denied).\n"),
3321 3321                              pgrp->sc_pgroup_fmri);
3322 3322                          return (stash_scferror_err(lcbdata, scfe));
3323 3323  
3324 3324                  case SCF_ERROR_INVALID_ARGUMENT:
3325 3325                  case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 3326                  default:
3327 3327                          bad_error("create_entity", scfe);
3328 3328                  }
3329 3329                  break;
3330 3330  
3331 3331          default:
3332 3332                  bad_error("fmri_to_entity", scfe);
3333 3333          }
3334 3334  
3335 3335          if (lcbdata->sc_trans != NULL) {
3336 3336                  e = scf_entry_create(lcbdata->sc_handle);
3337 3337                  if (e == NULL) {
3338 3338                          if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 3339                                  bad_error("scf_entry_create", scf_error());
3340 3340  
3341 3341                          entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 3342                          return (stash_scferror(lcbdata));
3343 3343                  }
3344 3344  
3345 3345                  if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 3346                      pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 3347                          switch (scf_error()) {
3348 3348                          case SCF_ERROR_INVALID_ARGUMENT:
3349 3349                                  warn(gettext("Dependent of %s has invalid name "
3350 3350                                      "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 3351                                      pgrp->sc_pgroup_name);
3352 3352                                  /* FALLTHROUGH */
3353 3353  
3354 3354                          case SCF_ERROR_DELETED:
3355 3355                          case SCF_ERROR_CONNECTION_BROKEN:
3356 3356                                  scf_entry_destroy(e);
3357 3357                                  entity_destroy(dependent_cbdata.sc_parent,
3358 3358                                      isservice);
3359 3359                                  return (stash_scferror(lcbdata));
3360 3360  
3361 3361                          case SCF_ERROR_EXISTS:
3362 3362                                  scf_entry_destroy(e);
3363 3363                                  entity_destroy(dependent_cbdata.sc_parent,
3364 3364                                      isservice);
3365 3365                                  lcbdata->sc_err = EALREADY;
3366 3366                                  return (UU_WALK_ERROR);
3367 3367  
3368 3368                          case SCF_ERROR_NOT_BOUND:
3369 3369                          case SCF_ERROR_HANDLE_MISMATCH:
3370 3370                          case SCF_ERROR_NOT_SET:
3371 3371                          default:
3372 3372                                  bad_error("scf_transaction_property_new",
3373 3373                                      scf_error());
3374 3374                          }
3375 3375                  }
3376 3376  
3377 3377                  val = scf_value_create(lcbdata->sc_handle);
3378 3378                  if (val == NULL) {
3379 3379                          if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 3380                                  bad_error("scf_value_create", scf_error());
3381 3381  
3382 3382                          entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 3383                          return (stash_scferror(lcbdata));
3384 3384                  }
3385 3385  
3386 3386                  if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 3387                      pgrp->sc_pgroup_fmri) != 0)
3388 3388                          /* invalid should have been caught above */
3389 3389                          bad_error("scf_value_set_from_string", scf_error());
3390 3390  
3391 3391                  if (scf_entry_add_value(e, val) != 0)
3392 3392                          bad_error("scf_entry_add_value", scf_error());
3393 3393          }
3394 3394  
3395 3395          /* Add the property group to the target entity. */
3396 3396  
3397 3397          dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 3398          dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 3399          dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 3400          dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401 3401  
3402 3402          ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403 3403  
3404 3404          entity_destroy(dependent_cbdata.sc_parent, isservice);
3405 3405  
3406 3406          if (ret == UU_WALK_NEXT)
3407 3407                  return (ret);
3408 3408  
3409 3409          if (ret != UU_WALK_ERROR)
3410 3410                  bad_error("entity_pgroup_import", ret);
3411 3411  
3412 3412          switch (dependent_cbdata.sc_err) {
3413 3413          case ECANCELED:
3414 3414                  warn(gettext("%s deleted unexpectedly.\n"),
3415 3415                      pgrp->sc_pgroup_fmri);
3416 3416                  lcbdata->sc_err = EBUSY;
3417 3417                  break;
3418 3418  
3419 3419          case EEXIST:
3420 3420                  warn(gettext("Could not create \"%s\" dependency in %s "
3421 3421                      "(already exists).\n"), pgrp->sc_pgroup_name,
3422 3422                      pgrp->sc_pgroup_fmri);
3423 3423                  /* FALLTHROUGH */
3424 3424  
3425 3425          default:
3426 3426                  lcbdata->sc_err = dependent_cbdata.sc_err;
3427 3427          }
3428 3428  
3429 3429          return (UU_WALK_ERROR);
3430 3430  }
3431 3431  
3432 3432  static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433 3433      const scf_snaplevel_t *, scf_transaction_t *);
3434 3434  static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435 3435      const pgroup_t *);
3436 3436  
3437 3437  /*
3438 3438   * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3439 3439   * the current dependent targets from running (the snaplevel of a running
3440 3440   * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 3441   * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3442 3442   * dependent targets and dependency properties from li_dpts_pg (the
3443 3443   * "dependents" property group in snpl) and snpl (the snaplevel which
3444 3444   * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3445 3445   * snpl doesn't have a "dependents" property group, and any dependents in ient
3446 3446   * are new.
3447 3447   *
3448 3448   * Returns
3449 3449   *   0 - success
3450 3450   *   ECONNABORTED - repository connection broken
3451 3451   *   ENOMEM - out of memory
3452 3452   *   ENOSPC - configd is out of resources
3453 3453   *   ECANCELED - ent was deleted
3454 3454   *   ENODEV - the entity containing li_dpts_pg was deleted
3455 3455   *   EPERM - could not modify dependents pg (permission denied) (error printed)
3456 3456   *         - couldn't upgrade dependent (permission denied) (error printed)
3457 3457   *         - couldn't create dependent (permission denied) (error printed)
3458 3458   *   EROFS - could not modify dependents pg (repository read-only)
3459 3459   *         - couldn't upgrade dependent (repository read-only)
3460 3460   *         - couldn't create dependent (repository read-only)
3461 3461   *   EACCES - could not modify dependents pg (backend access denied)
3462 3462   *          - could not upgrade dependent (backend access denied)
3463 3463   *          - could not create dependent (backend access denied)
3464 3464   *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 3465   *         - dependent target deleted (error printed)
3466 3466   *         - dependent pg changed (error printed)
3467 3467   *   EINVAL - new dependent is invalid (error printed)
3468 3468   *   EBADF - snpl is corrupt (error printed)
3469 3469   *         - snpl has corrupt pg (error printed)
3470 3470   *         - dependency pg in target is corrupt (error printed)
3471 3471   *         - target has corrupt snapshot (error printed)
3472 3472   *   EEXIST - dependency pg already existed in target service (error printed)
3473 3473   */
3474 3474  static int
3475 3475  upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476 3476      const scf_snaplevel_t *snpl, const entity_t *ient,
3477 3477      const scf_snaplevel_t *running, void *ent)
3478 3478  {
3479 3479          pgroup_t *new_dpt_pgroup;
3480 3480          scf_callback_t cbdata;
3481 3481          int r, unseen, tx_started = 0;
3482 3482          int have_cur_depts;
3483 3483  
3484 3484          const char * const dependents = "dependents";
3485 3485  
3486 3486          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487 3487  
3488 3488          if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 3489                  /* Nothing to do. */
3490 3490                  return (0);
3491 3491  
3492 3492          /* Fetch the current version of the "dependents" property group. */
3493 3493          have_cur_depts = 1;
3494 3494          if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 3495                  switch (scf_error()) {
3496 3496                  case SCF_ERROR_NOT_FOUND:
3497 3497                          break;
3498 3498  
3499 3499                  case SCF_ERROR_DELETED:
3500 3500                  case SCF_ERROR_CONNECTION_BROKEN:
3501 3501                          return (scferror2errno(scf_error()));
3502 3502  
3503 3503                  case SCF_ERROR_NOT_SET:
3504 3504                  case SCF_ERROR_INVALID_ARGUMENT:
3505 3505                  case SCF_ERROR_HANDLE_MISMATCH:
3506 3506                  case SCF_ERROR_NOT_BOUND:
3507 3507                  default:
3508 3508                          bad_error("entity_get_pg", scf_error());
3509 3509                  }
3510 3510  
3511 3511                  have_cur_depts = 0;
3512 3512          }
3513 3513  
3514 3514          /* Fetch the running version of the "dependents" property group. */
3515 3515          ud_run_dpts_pg_set = 0;
3516 3516          if (running != NULL)
3517 3517                  r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 3518          else
3519 3519                  r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 3520          if (r == 0) {
3521 3521                  ud_run_dpts_pg_set = 1;
3522 3522          } else {
3523 3523                  switch (scf_error()) {
3524 3524                  case SCF_ERROR_NOT_FOUND:
3525 3525                          break;
3526 3526  
3527 3527                  case SCF_ERROR_DELETED:
3528 3528                  case SCF_ERROR_CONNECTION_BROKEN:
3529 3529                          return (scferror2errno(scf_error()));
3530 3530  
3531 3531                  case SCF_ERROR_NOT_SET:
3532 3532                  case SCF_ERROR_INVALID_ARGUMENT:
3533 3533                  case SCF_ERROR_HANDLE_MISMATCH:
3534 3534                  case SCF_ERROR_NOT_BOUND:
3535 3535                  default:
3536 3536                          bad_error(running ? "scf_snaplevel_get_pg" :
3537 3537                              "entity_get_pg", scf_error());
3538 3538                  }
3539 3539          }
3540 3540  
3541 3541          /*
3542 3542           * Clear the seen fields of the dependents, so we can tell which ones
3543 3543           * are new.
3544 3544           */
3545 3545          if (uu_list_walk(ient->sc_dependents, clear_int,
3546 3546              (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 3547                  bad_error("uu_list_walk", uu_error());
3548 3548  
3549 3549          if (li_dpts_pg != NULL) {
3550 3550                  /*
3551 3551                   * Each property in li_dpts_pg represents a dependent tag in
3552 3552                   * the old manifest.  For each, call upgrade_dependent(),
3553 3553                   * which will change ud_cur_depts_pg or dependencies in other
3554 3554                   * services as appropriate.  Note (a) that changes to
3555 3555                   * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 3556                   * made en masse, and (b) it's ok if the entity doesn't have
3557 3557                   * a current version of the "dependents" property group,
3558 3558                   * because we'll just consider all dependents as customized
3559 3559                   * (by being deleted).
3560 3560                   */
3561 3561  
3562 3562                  if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 3563                          switch (scf_error()) {
3564 3564                          case SCF_ERROR_DELETED:
3565 3565                                  return (ENODEV);
3566 3566  
3567 3567                          case SCF_ERROR_CONNECTION_BROKEN:
3568 3568                                  return (ECONNABORTED);
3569 3569  
3570 3570                          case SCF_ERROR_HANDLE_MISMATCH:
3571 3571                          case SCF_ERROR_NOT_BOUND:
3572 3572                          case SCF_ERROR_NOT_SET:
3573 3573                          default:
3574 3574                                  bad_error("scf_iter_pg_properties",
3575 3575                                      scf_error());
3576 3576                          }
3577 3577                  }
3578 3578  
3579 3579                  if (have_cur_depts &&
3580 3580                      scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 3581                          switch (scf_error()) {
3582 3582                          case SCF_ERROR_BACKEND_ACCESS:
3583 3583                          case SCF_ERROR_BACKEND_READONLY:
3584 3584                          case SCF_ERROR_CONNECTION_BROKEN:
3585 3585                                  return (scferror2errno(scf_error()));
3586 3586  
3587 3587                          case SCF_ERROR_DELETED:
3588 3588                                  warn(emsg_pg_deleted, ient->sc_fmri,
3589 3589                                      dependents);
3590 3590                                  return (EBUSY);
3591 3591  
3592 3592                          case SCF_ERROR_PERMISSION_DENIED:
3593 3593                                  warn(emsg_pg_mod_perm, dependents,
3594 3594                                      ient->sc_fmri);
3595 3595                                  return (scferror2errno(scf_error()));
3596 3596  
3597 3597                          case SCF_ERROR_HANDLE_MISMATCH:
3598 3598                          case SCF_ERROR_IN_USE:
3599 3599                          case SCF_ERROR_NOT_BOUND:
3600 3600                          case SCF_ERROR_NOT_SET:
3601 3601                          default:
3602 3602                                  bad_error("scf_transaction_start", scf_error());
3603 3603                          }
3604 3604                  }
3605 3605                  tx_started = have_cur_depts;
3606 3606  
3607 3607                  for (;;) {
3608 3608                          r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 3609                          if (r == 0)
3610 3610                                  break;
3611 3611                          if (r == 1) {
3612 3612                                  r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 3613                                      tx_started ? ud_tx : NULL);
3614 3614                                  switch (r) {
3615 3615                                  case 0:
3616 3616                                          continue;
3617 3617  
3618 3618                                  case ECONNABORTED:
3619 3619                                  case ENOMEM:
3620 3620                                  case ENOSPC:
3621 3621                                  case EBADF:
3622 3622                                  case EBUSY:
3623 3623                                  case EINVAL:
3624 3624                                  case EPERM:
3625 3625                                  case EROFS:
3626 3626                                  case EACCES:
3627 3627                                  case EEXIST:
3628 3628                                          break;
3629 3629  
3630 3630                                  case ECANCELED:
3631 3631                                          r = ENODEV;
3632 3632                                          break;
3633 3633  
3634 3634                                  default:
3635 3635                                          bad_error("upgrade_dependent", r);
3636 3636                                  }
3637 3637  
3638 3638                                  if (tx_started)
3639 3639                                          scf_transaction_destroy_children(ud_tx);
3640 3640                                  return (r);
3641 3641                          }
3642 3642                          if (r != -1)
3643 3643                                  bad_error("scf_iter_next_property", r);
3644 3644  
3645 3645                          switch (scf_error()) {
3646 3646                          case SCF_ERROR_DELETED:
3647 3647                                  r = ENODEV;
3648 3648                                  break;
3649 3649  
3650 3650                          case SCF_ERROR_CONNECTION_BROKEN:
3651 3651                                  r = ECONNABORTED;
3652 3652                                  break;
3653 3653  
3654 3654                          case SCF_ERROR_NOT_SET:
3655 3655                          case SCF_ERROR_INVALID_ARGUMENT:
3656 3656                          case SCF_ERROR_NOT_BOUND:
3657 3657                          case SCF_ERROR_HANDLE_MISMATCH:
3658 3658                          default:
3659 3659                                  bad_error("scf_iter_next_property",
3660 3660                                      scf_error());
3661 3661                          }
3662 3662  
3663 3663                          if (tx_started)
3664 3664                                  scf_transaction_destroy_children(ud_tx);
3665 3665                          return (r);
3666 3666                  }
3667 3667          }
3668 3668  
3669 3669          /* import unseen dependents */
3670 3670          unseen = 0;
3671 3671          for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 3672              new_dpt_pgroup != NULL;
3673 3673              new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 3674              new_dpt_pgroup)) {
3675 3675                  if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 3676                          unseen = 1;
3677 3677                          break;
3678 3678                  }
3679 3679          }
3680 3680  
3681 3681          /* If there are none, exit early. */
3682 3682          if (unseen == 0)
3683 3683                  goto commit;
3684 3684  
3685 3685          /* Set up for lscf_dependent_import() */
3686 3686          cbdata.sc_handle = g_hndl;
3687 3687          cbdata.sc_parent = ent;
3688 3688          cbdata.sc_service = issvc;
3689 3689          cbdata.sc_flags = 0;
3690 3690  
3691 3691          if (!have_cur_depts) {
3692 3692                  /*
3693 3693                   * We have new dependents to import, so we need a "dependents"
3694 3694                   * property group.
3695 3695                   */
3696 3696                  if (issvc)
3697 3697                          r = scf_service_add_pg(ent, dependents,
3698 3698                              SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 3699                  else
3700 3700                          r = scf_instance_add_pg(ent, dependents,
3701 3701                              SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 3702                  if (r != 0) {
3703 3703                          switch (scf_error()) {
3704 3704                          case SCF_ERROR_DELETED:
3705 3705                          case SCF_ERROR_CONNECTION_BROKEN:
3706 3706                          case SCF_ERROR_BACKEND_READONLY:
3707 3707                          case SCF_ERROR_BACKEND_ACCESS:
3708 3708                          case SCF_ERROR_NO_RESOURCES:
3709 3709                                  return (scferror2errno(scf_error()));
3710 3710  
3711 3711                          case SCF_ERROR_EXISTS:
3712 3712                                  warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 3713                                  return (EBUSY);
3714 3714  
3715 3715                          case SCF_ERROR_PERMISSION_DENIED:
3716 3716                                  warn(emsg_pg_add_perm, dependents,
3717 3717                                      ient->sc_fmri);
3718 3718                                  return (scferror2errno(scf_error()));
3719 3719  
3720 3720                          case SCF_ERROR_NOT_BOUND:
3721 3721                          case SCF_ERROR_HANDLE_MISMATCH:
3722 3722                          case SCF_ERROR_INVALID_ARGUMENT:
3723 3723                          case SCF_ERROR_NOT_SET:
3724 3724                          default:
3725 3725                                  bad_error("scf_service_add_pg", scf_error());
3726 3726                          }
3727 3727                  }
3728 3728          }
3729 3729  
3730 3730          cbdata.sc_trans = ud_tx;
3731 3731  
3732 3732          if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 3733                  switch (scf_error()) {
3734 3734                  case SCF_ERROR_CONNECTION_BROKEN:
3735 3735                  case SCF_ERROR_BACKEND_ACCESS:
3736 3736                  case SCF_ERROR_BACKEND_READONLY:
3737 3737                          return (scferror2errno(scf_error()));
3738 3738  
3739 3739                  case SCF_ERROR_DELETED:
3740 3740                          warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 3741                          return (EBUSY);
3742 3742  
3743 3743                  case SCF_ERROR_PERMISSION_DENIED:
3744 3744                          warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 3745                          return (scferror2errno(scf_error()));
3746 3746  
3747 3747                  case SCF_ERROR_HANDLE_MISMATCH:
3748 3748                  case SCF_ERROR_IN_USE:
3749 3749                  case SCF_ERROR_NOT_BOUND:
3750 3750                  case SCF_ERROR_NOT_SET:
3751 3751                  default:
3752 3752                          bad_error("scf_transaction_start", scf_error());
3753 3753                  }
3754 3754          }
3755 3755          tx_started = 1;
3756 3756  
3757 3757          for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 3758              new_dpt_pgroup != NULL;
3759 3759              new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 3760              new_dpt_pgroup)) {
3761 3761                  if (new_dpt_pgroup->sc_pgroup_seen)
3762 3762                          continue;
3763 3763  
3764 3764                  if (ud_run_dpts_pg_set) {
3765 3765                          /*
3766 3766                           * If the dependent is already there, then we have
3767 3767                           * a conflict.
3768 3768                           */
3769 3769                          if (scf_pg_get_property(ud_run_dpts_pg,
3770 3770                              new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 3771                                  r = handle_dependent_conflict(ient, ud_prop,
3772 3772                                      new_dpt_pgroup);
3773 3773                                  switch (r) {
3774 3774                                  case 0:
3775 3775                                          continue;
3776 3776  
3777 3777                                  case ECONNABORTED:
3778 3778                                  case ENOMEM:
3779 3779                                  case EBUSY:
3780 3780                                  case EBADF:
3781 3781                                  case EINVAL:
3782 3782                                          scf_transaction_destroy_children(ud_tx);
3783 3783                                          return (r);
3784 3784  
3785 3785                                  default:
3786 3786                                          bad_error("handle_dependent_conflict",
3787 3787                                              r);
3788 3788                                  }
3789 3789                          } else {
3790 3790                                  switch (scf_error()) {
3791 3791                                  case SCF_ERROR_NOT_FOUND:
3792 3792                                          break;
3793 3793  
3794 3794                                  case SCF_ERROR_INVALID_ARGUMENT:
3795 3795                                          warn(emsg_fmri_invalid_pg_name,
3796 3796                                              ient->sc_fmri,
3797 3797                                              new_dpt_pgroup->sc_pgroup_name);
3798 3798                                          scf_transaction_destroy_children(ud_tx);
3799 3799                                          return (EINVAL);
3800 3800  
3801 3801                                  case SCF_ERROR_DELETED:
3802 3802                                          warn(emsg_pg_deleted, ient->sc_fmri,
3803 3803                                              new_dpt_pgroup->sc_pgroup_name);
3804 3804                                          scf_transaction_destroy_children(ud_tx);
3805 3805                                          return (EBUSY);
3806 3806  
3807 3807                                  case SCF_ERROR_CONNECTION_BROKEN:
3808 3808                                          scf_transaction_destroy_children(ud_tx);
3809 3809                                          return (ECONNABORTED);
3810 3810  
3811 3811                                  case SCF_ERROR_NOT_BOUND:
3812 3812                                  case SCF_ERROR_HANDLE_MISMATCH:
3813 3813                                  case SCF_ERROR_NOT_SET:
3814 3814                                  default:
3815 3815                                          bad_error("scf_pg_get_property",
3816 3816                                              scf_error());
3817 3817                                  }
3818 3818                          }
3819 3819                  }
3820 3820  
3821 3821                  r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 3822                  if (r != UU_WALK_NEXT) {
3823 3823                          if (r != UU_WALK_ERROR)
3824 3824                                  bad_error("lscf_dependent_import", r);
3825 3825  
3826 3826                          if (cbdata.sc_err == EALREADY) {
3827 3827                                  /* Collisions were handled preemptively. */
3828 3828                                  bad_error("lscf_dependent_import",
3829 3829                                      cbdata.sc_err);
3830 3830                          }
3831 3831  
3832 3832                          scf_transaction_destroy_children(ud_tx);
3833 3833                          return (cbdata.sc_err);
3834 3834                  }
3835 3835          }
3836 3836  
3837 3837  commit:
3838 3838          if (!tx_started)
3839 3839                  return (0);
3840 3840  
3841 3841          r = scf_transaction_commit(ud_tx);
3842 3842  
3843 3843          scf_transaction_destroy_children(ud_tx);
3844 3844  
3845 3845          switch (r) {
3846 3846          case 1:
3847 3847                  return (0);
3848 3848  
3849 3849          case 0:
3850 3850                  warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 3851                  return (EBUSY);
3852 3852  
3853 3853          case -1:
3854 3854                  break;
3855 3855  
3856 3856          default:
3857 3857                  bad_error("scf_transaction_commit", r);
3858 3858          }
3859 3859  
3860 3860          switch (scf_error()) {
3861 3861          case SCF_ERROR_CONNECTION_BROKEN:
3862 3862          case SCF_ERROR_BACKEND_READONLY:
3863 3863          case SCF_ERROR_BACKEND_ACCESS:
3864 3864          case SCF_ERROR_NO_RESOURCES:
3865 3865                  return (scferror2errno(scf_error()));
3866 3866  
3867 3867          case SCF_ERROR_DELETED:
3868 3868                  warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 3869                  return (EBUSY);
3870 3870  
3871 3871          case SCF_ERROR_PERMISSION_DENIED:
3872 3872                  warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 3873                  return (scferror2errno(scf_error()));
3874 3874  
3875 3875          case SCF_ERROR_NOT_BOUND:
3876 3876          case SCF_ERROR_INVALID_ARGUMENT:
3877 3877          case SCF_ERROR_NOT_SET:
3878 3878          default:
3879 3879                  bad_error("scf_transaction_destroy", scf_error());
3880 3880                  /* NOTREACHED */
3881 3881          }
3882 3882  }
3883 3883  
3884 3884  /*
3885 3885   * Used to add the manifests to the list of currently supported manifests.
3886 3886   * We can modify the existing manifest list removing entries if the files
3887 3887   * don't exist.
3888 3888   *
3889 3889   * Get the old list and the new file name
3890 3890   * If the new file name is in the list return
3891 3891   * If not then add the file to the list.
3892 3892   * As we process the list check to see if the files in the old list exist
3893 3893   *      if not then remove the file from the list.
3894 3894   * Commit the list of manifest file names.
3895 3895   *
3896 3896   */
3897 3897  static int
3898 3898  upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899 3899      const scf_snaplevel_t *running, void *ent)
3900 3900  {
3901 3901          scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 3902          scf_property_t *ud_prop = NULL;
3903 3903          scf_iter_t *ud_prop_iter;
3904 3904          scf_value_t *fname_value;
3905 3905          scf_callback_t cbdata;
3906 3906          pgroup_t *mfst_pgroup;
3907 3907          property_t *mfst_prop;
3908 3908          property_t *old_prop;
3909 3909          char *pname;
3910 3910          char *fval;
3911 3911          char *old_pname;
3912 3912          char *old_fval;
3913 3913          int no_upgrade_pg;
3914 3914          int mfst_seen;
3915 3915          int r;
3916 3916  
3917 3917          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918 3918  
3919 3919          /*
3920 3920           * This should always be the service base on the code
3921 3921           * path, and the fact that the manifests pg is a service
3922 3922           * level property group only.
3923 3923           */
3924 3924          ud_mfsts_pg = scf_pg_create(g_hndl);
3925 3925          ud_prop = scf_property_create(g_hndl);
3926 3926          ud_prop_iter = scf_iter_create(g_hndl);
3927 3927          fname_value = scf_value_create(g_hndl);
3928 3928  
3929 3929          /* Fetch the "manifests" property group */
3930 3930          no_upgrade_pg = 0;
3931 3931          r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 3932              ud_mfsts_pg);
3933 3933          if (r != 0) {
3934 3934                  switch (scf_error()) {
3935 3935                  case SCF_ERROR_NOT_FOUND:
3936 3936                          no_upgrade_pg = 1;
3937 3937                          break;
3938 3938  
3939 3939                  case SCF_ERROR_DELETED:
3940 3940                  case SCF_ERROR_CONNECTION_BROKEN:
3941 3941                          return (scferror2errno(scf_error()));
3942 3942  
3943 3943                  case SCF_ERROR_NOT_SET:
3944 3944                  case SCF_ERROR_INVALID_ARGUMENT:
3945 3945                  case SCF_ERROR_HANDLE_MISMATCH:
3946 3946                  case SCF_ERROR_NOT_BOUND:
3947 3947                  default:
3948 3948                          bad_error(running ? "scf_snaplevel_get_pg" :
3949 3949                              "entity_get_pg", scf_error());
3950 3950                  }
3951 3951          }
3952 3952  
3953 3953          if (no_upgrade_pg) {
3954 3954                  cbdata.sc_handle = g_hndl;
3955 3955                  cbdata.sc_parent = ent;
3956 3956                  cbdata.sc_service = issvc;
3957 3957                  cbdata.sc_flags = SCI_FORCE;
3958 3958                  cbdata.sc_source_fmri = ient->sc_fmri;
3959 3959                  cbdata.sc_target_fmri = ient->sc_fmri;
3960 3960  
3961 3961                  if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 3962                          return (cbdata.sc_err);
3963 3963  
3964 3964                  return (0);
3965 3965          }
3966 3966  
3967 3967          /* Fetch the new manifests property group */
3968 3968          for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969 3969              mfst_pgroup != NULL;
3970 3970              mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971 3971                  if (strcmp(mfst_pgroup->sc_pgroup_name,
3972 3972                      SCF_PG_MANIFESTFILES) == 0)
3973 3973                          break;
3974 3974          }
3975 3975  
3976 3976          if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 3977              SCF_SUCCESS)
3978 3978                  return (-1);
3979 3979  
3980 3980          if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 3981                  return (ENOMEM);
3982 3982          if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 3983                  free(pname);
3984 3984                  return (ENOMEM);
3985 3985          }
3986 3986  
3987 3987          while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 3988                  mfst_seen = 0;
3989 3989                  if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 3990                          continue;
3991 3991  
3992 3992                  for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 3993                      mfst_prop != NULL;
3994 3994                      mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 3995                      mfst_prop)) {
3996 3996                          if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 3997                                  mfst_seen = 1;
3998 3998                          }
3999 3999                  }
4000 4000  
4001 4001                  /*
4002 4002                   * If the manifest is not seen then add it to the new mfst
4003 4003                   * property list to get proccessed into the repo.
4004 4004                   */
4005 4005                  if (mfst_seen == 0) {
4006 4006                          /*
4007 4007                           * If we cannot get the value then there is no
4008 4008                           * reason to attempt to attach the value to
4009 4009                           * the property group
4010 4010                           */
4011 4011                          if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 4012                              scf_value_get_astring(fname_value, fval,
4013 4013                              MAXPATHLEN) != -1)  {
4014 4014                                  old_pname = safe_strdup(pname);
4015 4015                                  old_fval = safe_strdup(fval);
4016 4016                                  old_prop = internal_property_create(old_pname,
4017 4017                                      SCF_TYPE_ASTRING, 1, old_fval);
4018 4018  
4019 4019                                  /*
4020 4020                                   * Already checked to see if the property exists
4021 4021                                   * in the group, and it does not.
4022 4022                                   */
4023 4023                                  (void) internal_attach_property(mfst_pgroup,
4024 4024                                      old_prop);
4025 4025                          }
4026 4026                  }
4027 4027          }
4028 4028          free(pname);
4029 4029          free(fval);
4030 4030  
4031 4031          cbdata.sc_handle = g_hndl;
4032 4032          cbdata.sc_parent = ent;
4033 4033          cbdata.sc_service = issvc;
4034 4034          cbdata.sc_flags = SCI_FORCE;
4035 4035          cbdata.sc_source_fmri = ient->sc_fmri;
4036 4036          cbdata.sc_target_fmri = ient->sc_fmri;
4037 4037  
4038 4038          if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 4039                  return (cbdata.sc_err);
4040 4040  
4041 4041          return (r);
4042 4042  }
4043 4043  
4044 4044  /*
4045 4045   * prop is taken to be a property in the "dependents" property group of snpl,
4046 4046   * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 4047   * to ient.  If prop is a valid dependents property, upgrade the dependent it
4048 4048   * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4049 4049   * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 4050   * of the entity ient represents (possibly in the running snapshot).  If it
4051 4051   * needs to be changed, an entry will be added to tx, if not NULL.
4052 4052   *
4053 4053   * Returns
4054 4054   *   0 - success
4055 4055   *   ECONNABORTED - repository connection broken
4056 4056   *   ENOMEM - out of memory
4057 4057   *   ENOSPC - configd was out of resources
4058 4058   *   ECANCELED - snpl's entity was deleted
4059 4059   *   EINVAL - dependent target is invalid (error printed)
4060 4060   *          - dependent is invalid (error printed)
4061 4061   *   EBADF - snpl is corrupt (error printed)
4062 4062   *         - snpl has corrupt pg (error printed)
4063 4063   *         - dependency pg in target is corrupt (error printed)
4064 4064   *         - running snapshot in dependent is missing snaplevel (error printed)
4065 4065   *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 4066   *         - couldn't create dependent (permission denied) (error printed)
4067 4067   *         - couldn't modify dependent pg (permission denied) (error printed)
4068 4068   *   EROFS - couldn't delete dependency pg (repository read-only)
4069 4069   *         - couldn't create dependent (repository read-only)
4070 4070   *   EACCES - couldn't delete dependency pg (backend access denied)
4071 4071   *          - couldn't create dependent (backend access denied)
4072 4072   *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 4073   *         - tx's pg was deleted (error printed)
4074 4074   *         - dependent pg was changed or deleted (error printed)
4075 4075   *   EEXIST - dependency pg already exists in new target (error printed)
4076 4076   */
4077 4077  static int
4078 4078  upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079 4079      const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 4080  {
4081 4081          pgroup_t pgrp;
4082 4082          scf_type_t ty;
4083 4083          pgroup_t *new_dpt_pgroup;
4084 4084          pgroup_t *old_dpt_pgroup = NULL;
4085 4085          pgroup_t *current_pg;
4086 4086          pgroup_t *dpt;
4087 4087          scf_callback_t cbdata;
4088 4088          int tissvc;
4089 4089          void *target_ent;
4090 4090          scf_error_t serr;
4091 4091          int r;
4092 4092          scf_transaction_entry_t *ent;
4093 4093  
4094 4094          const char * const cf_inval = gettext("Conflict upgrading %s "
4095 4095              "(dependent \"%s\" has invalid dependents property).\n");
4096 4096          const char * const cf_missing = gettext("Conflict upgrading %s "
4097 4097              "(dependent \"%s\" is missing).\n");
4098 4098          const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 4099              "(dependent \"%s\" has new dependency property group).\n");
4100 4100          const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 4101              "(dependent \"%s\" has new target).\n");
4102 4102          const char * const li_corrupt =
4103 4103              gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 4104          const char * const upgrading =
4105 4105              gettext("%s: Upgrading dependent \"%s\".\n");
4106 4106          const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 4107              "corrupt (missing snaplevel).\n");
4108 4108  
4109 4109          if (scf_property_type(prop, &ty) != 0) {
4110 4110                  switch (scf_error()) {
4111 4111                  case SCF_ERROR_DELETED:
4112 4112                  case SCF_ERROR_CONNECTION_BROKEN:
4113 4113                          return (scferror2errno(scf_error()));
4114 4114  
4115 4115                  case SCF_ERROR_NOT_BOUND:
4116 4116                  case SCF_ERROR_NOT_SET:
4117 4117                  default:
4118 4118                          bad_error("scf_property_type", scf_error());
4119 4119                  }
4120 4120          }
4121 4121  
4122 4122          if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 4123                  warn(li_corrupt, ient->sc_fmri);
4124 4124                  return (EBADF);
4125 4125          }
4126 4126  
4127 4127          /*
4128 4128           * prop represents a dependent in the old manifest.  It is named after
4129 4129           * the dependent.
4130 4130           */
4131 4131          if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 4132                  switch (scf_error()) {
4133 4133                  case SCF_ERROR_DELETED:
4134 4134                  case SCF_ERROR_CONNECTION_BROKEN:
4135 4135                          return (scferror2errno(scf_error()));
4136 4136  
4137 4137                  case SCF_ERROR_NOT_BOUND:
4138 4138                  case SCF_ERROR_NOT_SET:
4139 4139                  default:
4140 4140                          bad_error("scf_property_get_name", scf_error());
4141 4141                  }
4142 4142          }
4143 4143  
4144 4144          /* See if it's in the new manifest. */
4145 4145          pgrp.sc_pgroup_name = ud_name;
4146 4146          new_dpt_pgroup =
4147 4147              uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148 4148  
4149 4149          /* If it's not, delete it... if it hasn't been customized. */
4150 4150          if (new_dpt_pgroup == NULL) {
4151 4151                  if (!ud_run_dpts_pg_set)
4152 4152                          return (0);
4153 4153  
4154 4154                  if (scf_property_get_value(prop, ud_val) != 0) {
4155 4155                          switch (scf_error()) {
4156 4156                          case SCF_ERROR_NOT_FOUND:
4157 4157                          case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 4158                                  warn(li_corrupt, ient->sc_fmri);
4159 4159                                  return (EBADF);
4160 4160  
4161 4161                          case SCF_ERROR_DELETED:
4162 4162                          case SCF_ERROR_CONNECTION_BROKEN:
4163 4163                                  return (scferror2errno(scf_error()));
4164 4164  
4165 4165                          case SCF_ERROR_HANDLE_MISMATCH:
4166 4166                          case SCF_ERROR_NOT_BOUND:
4167 4167                          case SCF_ERROR_NOT_SET:
4168 4168                          case SCF_ERROR_PERMISSION_DENIED:
4169 4169                          default:
4170 4170                                  bad_error("scf_property_get_value",
4171 4171                                      scf_error());
4172 4172                          }
4173 4173                  }
4174 4174  
4175 4175                  if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 4176                      max_scf_value_len + 1) < 0)
4177 4177                          bad_error("scf_value_get_as_string", scf_error());
4178 4178  
4179 4179                  if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 4180                      0) {
4181 4181                          switch (scf_error()) {
4182 4182                          case SCF_ERROR_NOT_FOUND:
4183 4183                                  return (0);
4184 4184  
4185 4185                          case SCF_ERROR_CONNECTION_BROKEN:
4186 4186                                  return (scferror2errno(scf_error()));
4187 4187  
4188 4188                          case SCF_ERROR_DELETED:
4189 4189                                  warn(emsg_pg_deleted, ient->sc_fmri,
4190 4190                                      "dependents");
4191 4191                                  return (EBUSY);
4192 4192  
4193 4193                          case SCF_ERROR_INVALID_ARGUMENT:
4194 4194                          case SCF_ERROR_NOT_BOUND:
4195 4195                          case SCF_ERROR_HANDLE_MISMATCH:
4196 4196                          case SCF_ERROR_NOT_SET:
4197 4197                          default:
4198 4198                                  bad_error("scf_pg_get_property", scf_error());
4199 4199                          }
4200 4200                  }
4201 4201                  if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 4202                          switch (scf_error()) {
4203 4203                          case SCF_ERROR_NOT_FOUND:
4204 4204                          case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 4205                                  warn(cf_inval, ient->sc_fmri, ud_name);
4206 4206                                  return (0);
4207 4207  
4208 4208                          case SCF_ERROR_DELETED:
4209 4209                          case SCF_ERROR_CONNECTION_BROKEN:
4210 4210                                  return (scferror2errno(scf_error()));
4211 4211  
4212 4212                          case SCF_ERROR_HANDLE_MISMATCH:
4213 4213                          case SCF_ERROR_NOT_BOUND:
4214 4214                          case SCF_ERROR_NOT_SET:
4215 4215                          case SCF_ERROR_PERMISSION_DENIED:
4216 4216                          default:
4217 4217                                  bad_error("scf_property_get_value",
4218 4218                                      scf_error());
4219 4219                          }
4220 4220                  }
4221 4221  
4222 4222                  ty = scf_value_type(ud_val);
4223 4223                  assert(ty != SCF_TYPE_INVALID);
4224 4224                  if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 4225                          warn(cf_inval, ient->sc_fmri, ud_name);
4226 4226                          return (0);
4227 4227                  }
4228 4228  
4229 4229                  if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 4230                      max_scf_value_len + 1) < 0)
4231 4231                          bad_error("scf_value_get_as_string", scf_error());
4232 4232  
4233 4233                  r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 4234                  switch (r) {
4235 4235                  case 1:
4236 4236                          break;
4237 4237  
4238 4238                  case 0:
4239 4239                  case -1:        /* warn? */
4240 4240                          warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 4241                          return (0);
4242 4242  
4243 4243                  case -2:
4244 4244                          warn(li_corrupt, ient->sc_fmri);
4245 4245                          return (EBADF);
4246 4246  
4247 4247                  default:
4248 4248                          bad_error("fmri_equal", r);
4249 4249                  }
4250 4250  
4251 4251                  if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 4252                          switch (scf_error()) {
4253 4253                          case SCF_ERROR_NOT_FOUND:
4254 4254                                  warn(li_corrupt, ient->sc_fmri);
4255 4255                                  return (EBADF);
4256 4256  
4257 4257                          case SCF_ERROR_DELETED:
4258 4258                          case SCF_ERROR_CONNECTION_BROKEN:
4259 4259                                  return (scferror2errno(scf_error()));
4260 4260  
4261 4261                          case SCF_ERROR_NOT_BOUND:
4262 4262                          case SCF_ERROR_HANDLE_MISMATCH:
4263 4263                          case SCF_ERROR_INVALID_ARGUMENT:
4264 4264                          case SCF_ERROR_NOT_SET:
4265 4265                          default:
4266 4266                                  bad_error("scf_snaplevel_get_pg", scf_error());
4267 4267                          }
4268 4268                  }
4269 4269  
4270 4270                  r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 4271                      snap_lastimport);
4272 4272                  switch (r) {
4273 4273                  case 0:
4274 4274                          break;
4275 4275  
4276 4276                  case ECANCELED:
4277 4277                  case ECONNABORTED:
4278 4278                  case ENOMEM:
4279 4279                  case EBADF:
4280 4280                          return (r);
4281 4281  
4282 4282                  case EACCES:
4283 4283                  default:
4284 4284                          bad_error("load_pg", r);
4285 4285                  }
4286 4286  
4287 4287                  serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 4288                  switch (serr) {
4289 4289                  case SCF_ERROR_NONE:
4290 4290                          break;
4291 4291  
4292 4292                  case SCF_ERROR_NO_MEMORY:
4293 4293                          internal_pgroup_free(old_dpt_pgroup);
4294 4294                          return (ENOMEM);
4295 4295  
4296 4296                  case SCF_ERROR_NOT_FOUND:
4297 4297                          internal_pgroup_free(old_dpt_pgroup);
4298 4298                          goto delprop;
4299 4299  
4300 4300                  case SCF_ERROR_CONSTRAINT_VIOLATED:     /* caught above */
4301 4301                  case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
4302 4302                  default:
4303 4303                          bad_error("fmri_to_entity", serr);
4304 4304                  }
4305 4305  
4306 4306                  r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 4307                      ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 4308                  switch (r) {
4309 4309                  case 0:
4310 4310                          break;
4311 4311  
4312 4312                  case ECONNABORTED:
4313 4313                          internal_pgroup_free(old_dpt_pgroup);
4314 4314                          return (r);
4315 4315  
4316 4316                  case ECANCELED:
4317 4317                  case ENOENT:
4318 4318                          internal_pgroup_free(old_dpt_pgroup);
4319 4319                          goto delprop;
4320 4320  
4321 4321                  case EBADF:
4322 4322                          warn(r_no_lvl, ud_ctarg);
4323 4323                          internal_pgroup_free(old_dpt_pgroup);
4324 4324                          return (r);
4325 4325  
4326 4326                  case EINVAL:
4327 4327                  default:
4328 4328                          bad_error("entity_get_running_pg", r);
4329 4329                  }
4330 4330  
4331 4331                  /* load it */
4332 4332                  r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4333 4333                  switch (r) {
4334 4334                  case 0:
4335 4335                          break;
4336 4336  
4337 4337                  case ECANCELED:
4338 4338                          internal_pgroup_free(old_dpt_pgroup);
4339 4339                          goto delprop;
4340 4340  
4341 4341                  case ECONNABORTED:
4342 4342                  case ENOMEM:
4343 4343                  case EBADF:
4344 4344                          internal_pgroup_free(old_dpt_pgroup);
4345 4345                          return (r);
4346 4346  
4347 4347                  case EACCES:
4348 4348                  default:
4349 4349                          bad_error("load_pg", r);
4350 4350                  }
4351 4351  
4352 4352                  /* compare property groups */
4353 4353                  if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 4354                          warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 4355                          internal_pgroup_free(old_dpt_pgroup);
4356 4356                          internal_pgroup_free(current_pg);
4357 4357                          return (0);
4358 4358                  }
4359 4359  
4360 4360                  internal_pgroup_free(old_dpt_pgroup);
4361 4361                  internal_pgroup_free(current_pg);
4362 4362  
4363 4363                  if (g_verbose)
4364 4364                          warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 4365                              ient->sc_fmri, ud_name);
4366 4366  
4367 4367                  if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 4368                          switch (scf_error()) {
4369 4369                          case SCF_ERROR_NOT_FOUND:
4370 4370                          case SCF_ERROR_DELETED:
4371 4371                                  internal_pgroup_free(old_dpt_pgroup);
4372 4372                                  goto delprop;
4373 4373  
4374 4374                          case SCF_ERROR_CONNECTION_BROKEN:
4375 4375                                  internal_pgroup_free(old_dpt_pgroup);
4376 4376                                  return (ECONNABORTED);
4377 4377  
4378 4378                          case SCF_ERROR_NOT_SET:
4379 4379                          case SCF_ERROR_INVALID_ARGUMENT:
4380 4380                          case SCF_ERROR_HANDLE_MISMATCH:
4381 4381                          case SCF_ERROR_NOT_BOUND:
4382 4382                          default:
4383 4383                                  bad_error("entity_get_pg", scf_error());
4384 4384                          }
4385 4385                  }
4386 4386  
4387 4387                  if (scf_pg_delete(ud_pg) != 0) {
4388 4388                          switch (scf_error()) {
4389 4389                          case SCF_ERROR_DELETED:
4390 4390                                  break;
4391 4391  
4392 4392                          case SCF_ERROR_CONNECTION_BROKEN:
4393 4393                          case SCF_ERROR_BACKEND_READONLY:
4394 4394                          case SCF_ERROR_BACKEND_ACCESS:
4395 4395                                  return (scferror2errno(scf_error()));
4396 4396  
4397 4397                          case SCF_ERROR_PERMISSION_DENIED:
4398 4398                                  warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 4399                                  return (scferror2errno(scf_error()));
4400 4400  
4401 4401                          case SCF_ERROR_NOT_SET:
4402 4402                          default:
4403 4403                                  bad_error("scf_pg_delete", scf_error());
4404 4404                          }
4405 4405                  }
4406 4406  
4407 4407                  /*
4408 4408                   * This service was changed, so it must be refreshed.  But
4409 4409                   * since it's not mentioned in the new manifest, we have to
4410 4410                   * record its FMRI here for use later.  We record the name
4411 4411                   * & the entity (via sc_parent) in case we need to print error
4412 4412                   * messages during the refresh.
4413 4413                   */
4414 4414                  dpt = internal_pgroup_new();
4415 4415                  if (dpt == NULL)
4416 4416                          return (ENOMEM);
4417 4417                  dpt->sc_pgroup_name = strdup(ud_name);
4418 4418                  dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 4419                  if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 4420                          return (ENOMEM);
4421 4421                  dpt->sc_parent = (entity_t *)ient;
4422 4422                  if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 4423                          uu_die(gettext("libuutil error: %s\n"),
4424 4424                              uu_strerror(uu_error()));
4425 4425  
4426 4426  delprop:
4427 4427                  if (tx == NULL)
4428 4428                          return (0);
4429 4429  
4430 4430                  ent = scf_entry_create(g_hndl);
4431 4431                  if (ent == NULL)
4432 4432                          return (ENOMEM);
4433 4433  
4434 4434                  if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 4435                          scf_entry_destroy(ent);
4436 4436                          switch (scf_error()) {
4437 4437                          case SCF_ERROR_DELETED:
4438 4438                                  warn(emsg_pg_deleted, ient->sc_fmri,
4439 4439                                      "dependents");
4440 4440                                  return (EBUSY);
4441 4441  
4442 4442                          case SCF_ERROR_CONNECTION_BROKEN:
4443 4443                                  return (scferror2errno(scf_error()));
4444 4444  
4445 4445                          case SCF_ERROR_NOT_FOUND:
4446 4446                                  break;
4447 4447  
4448 4448                          case SCF_ERROR_HANDLE_MISMATCH:
4449 4449                          case SCF_ERROR_NOT_BOUND:
4450 4450                          case SCF_ERROR_INVALID_ARGUMENT:
4451 4451                          case SCF_ERROR_NOT_SET:
4452 4452                          default:
4453 4453                                  bad_error("scf_transaction_property_delete",
4454 4454                                      scf_error());
4455 4455                          }
4456 4456                  }
4457 4457  
4458 4458                  return (0);
4459 4459          }
4460 4460  
4461 4461          new_dpt_pgroup->sc_pgroup_seen = 1;
4462 4462  
4463 4463          /*
4464 4464           * Decide whether the dependent has changed in the manifest.
4465 4465           */
4466 4466          /* Compare the target. */
4467 4467          if (scf_property_get_value(prop, ud_val) != 0) {
4468 4468                  switch (scf_error()) {
4469 4469                  case SCF_ERROR_NOT_FOUND:
4470 4470                  case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 4471                          warn(li_corrupt, ient->sc_fmri);
4472 4472                          return (EBADF);
4473 4473  
4474 4474                  case SCF_ERROR_DELETED:
4475 4475                  case SCF_ERROR_CONNECTION_BROKEN:
4476 4476                          return (scferror2errno(scf_error()));
4477 4477  
4478 4478                  case SCF_ERROR_HANDLE_MISMATCH:
4479 4479                  case SCF_ERROR_NOT_BOUND:
4480 4480                  case SCF_ERROR_NOT_SET:
4481 4481                  case SCF_ERROR_PERMISSION_DENIED:
4482 4482                  default:
4483 4483                          bad_error("scf_property_get_value", scf_error());
4484 4484                  }
4485 4485          }
4486 4486  
4487 4487          if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488 4488              0)
4489 4489                  bad_error("scf_value_get_as_string", scf_error());
4490 4490  
4491 4491          /*
4492 4492           * If the fmri's are not equal then the old fmri will need to
4493 4493           * be refreshed to ensure that the changes are properly updated
4494 4494           * in that service.
4495 4495           */
4496 4496          r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 4497          switch (r) {
4498 4498          case 0:
4499 4499                  dpt = internal_pgroup_new();
4500 4500                  if (dpt == NULL)
4501 4501                          return (ENOMEM);
4502 4502                  dpt->sc_pgroup_name = strdup(ud_name);
4503 4503                  dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 4504                  if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 4505                          return (ENOMEM);
4506 4506                  dpt->sc_parent = (entity_t *)ient;
4507 4507                  if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 4508                          uu_die(gettext("libuutil error: %s\n"),
4509 4509                              uu_strerror(uu_error()));
4510 4510                  break;
4511 4511  
4512 4512          case 1:
4513 4513                  /* Compare the dependency pgs. */
4514 4514                  if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 4515                          switch (scf_error()) {
4516 4516                          case SCF_ERROR_NOT_FOUND:
4517 4517                                  warn(li_corrupt, ient->sc_fmri);
4518 4518                                  return (EBADF);
4519 4519  
4520 4520                          case SCF_ERROR_DELETED:
4521 4521                          case SCF_ERROR_CONNECTION_BROKEN:
4522 4522                                  return (scferror2errno(scf_error()));
4523 4523  
4524 4524                          case SCF_ERROR_NOT_BOUND:
4525 4525                          case SCF_ERROR_HANDLE_MISMATCH:
4526 4526                          case SCF_ERROR_INVALID_ARGUMENT:
4527 4527                          case SCF_ERROR_NOT_SET:
4528 4528                          default:
4529 4529                                  bad_error("scf_snaplevel_get_pg", scf_error());
4530 4530                          }
4531 4531                  }
4532 4532  
4533 4533                  r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 4534                      snap_lastimport);
4535 4535                  switch (r) {
4536 4536                  case 0:
4537 4537                          break;
4538 4538  
4539 4539                  case ECANCELED:
4540 4540                  case ECONNABORTED:
4541 4541                  case ENOMEM:
4542 4542                  case EBADF:
4543 4543                          return (r);
4544 4544  
4545 4545                  case EACCES:
4546 4546                  default:
4547 4547                          bad_error("load_pg", r);
4548 4548                  }
4549 4549  
4550 4550                  if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 4551                          /* no change, leave customizations */
4552 4552                          internal_pgroup_free(old_dpt_pgroup);
4553 4553                          return (0);
4554 4554                  }
4555 4555                  break;
4556 4556  
4557 4557          case -1:
4558 4558                  warn(li_corrupt, ient->sc_fmri);
4559 4559                  return (EBADF);
4560 4560  
4561 4561          case -2:
4562 4562                  warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 4563                      ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 4564                  return (EINVAL);
4565 4565  
4566 4566          default:
4567 4567                  bad_error("fmri_equal", r);
4568 4568          }
4569 4569  
4570 4570          /*
4571 4571           * The dependent has changed in the manifest.  Upgrade the current
4572 4572           * properties if they haven't been customized.
4573 4573           */
4574 4574  
4575 4575          /*
4576 4576           * If new_dpt_pgroup->sc_override, then act as though the property
4577 4577           * group hasn't been customized.
4578 4578           */
4579 4579          if (new_dpt_pgroup->sc_pgroup_override) {
4580 4580                  (void) strcpy(ud_ctarg, ud_oldtarg);
4581 4581                  goto nocust;
4582 4582          }
4583 4583  
4584 4584          if (!ud_run_dpts_pg_set) {
4585 4585                  warn(cf_missing, ient->sc_fmri, ud_name);
4586 4586                  r = 0;
4587 4587                  goto out;
4588 4588          } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 4589                  switch (scf_error()) {
4590 4590                  case SCF_ERROR_NOT_FOUND:
4591 4591                          warn(cf_missing, ient->sc_fmri, ud_name);
4592 4592                          r = 0;
4593 4593                          goto out;
4594 4594  
4595 4595                  case SCF_ERROR_CONNECTION_BROKEN:
4596 4596                          r = scferror2errno(scf_error());
4597 4597                          goto out;
4598 4598  
4599 4599                  case SCF_ERROR_DELETED:
4600 4600                          warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 4601                          r = EBUSY;
4602 4602                          goto out;
4603 4603  
4604 4604                  case SCF_ERROR_INVALID_ARGUMENT:
4605 4605                  case SCF_ERROR_NOT_BOUND:
4606 4606                  case SCF_ERROR_HANDLE_MISMATCH:
4607 4607                  case SCF_ERROR_NOT_SET:
4608 4608                  default:
4609 4609                          bad_error("scf_pg_get_property", scf_error());
4610 4610                  }
4611 4611          }
4612 4612  
4613 4613          if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 4614                  switch (scf_error()) {
4615 4615                  case SCF_ERROR_NOT_FOUND:
4616 4616                  case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 4617                          warn(cf_inval, ient->sc_fmri, ud_name);
4618 4618                          r = 0;
4619 4619                          goto out;
4620 4620  
4621 4621                  case SCF_ERROR_DELETED:
4622 4622                  case SCF_ERROR_CONNECTION_BROKEN:
4623 4623                          r = scferror2errno(scf_error());
4624 4624                          goto out;
4625 4625  
4626 4626                  case SCF_ERROR_HANDLE_MISMATCH:
4627 4627                  case SCF_ERROR_NOT_BOUND:
4628 4628                  case SCF_ERROR_NOT_SET:
4629 4629                  case SCF_ERROR_PERMISSION_DENIED:
4630 4630                  default:
4631 4631                          bad_error("scf_property_get_value", scf_error());
4632 4632                  }
4633 4633          }
4634 4634  
4635 4635          ty = scf_value_type(ud_val);
4636 4636          assert(ty != SCF_TYPE_INVALID);
4637 4637          if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 4638                  warn(cf_inval, ient->sc_fmri, ud_name);
4639 4639                  r = 0;
4640 4640                  goto out;
4641 4641          }
4642 4642          if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643 4643              0)
4644 4644                  bad_error("scf_value_get_as_string", scf_error());
4645 4645  
4646 4646          r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 4647          if (r == -1) {
4648 4648                  warn(cf_inval, ient->sc_fmri, ud_name);
4649 4649                  r = 0;
4650 4650                  goto out;
4651 4651          } else if (r == -2) {
4652 4652                  warn(li_corrupt, ient->sc_fmri);
4653 4653                  r = EBADF;
4654 4654                  goto out;
4655 4655          } else if (r == 0) {
4656 4656                  /*
4657 4657                   * Target has been changed.  Only abort now if it's been
4658 4658                   * changed to something other than what's in the manifest.
4659 4659                   */
4660 4660                  r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 4661                  if (r == -1) {
4662 4662                          warn(cf_inval, ient->sc_fmri, ud_name);
4663 4663                          r = 0;
4664 4664                          goto out;
4665 4665                  } else if (r == 0) {
4666 4666                          warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 4667                          r = 0;
4668 4668                          goto out;
4669 4669                  } else if (r != 1) {
4670 4670                          /* invalid sc_pgroup_fmri caught above */
4671 4671                          bad_error("fmri_equal", r);
4672 4672                  }
4673 4673  
4674 4674                  /*
4675 4675                   * Fetch the current dependency pg.  If it's what the manifest
4676 4676                   * says, then no problem.
4677 4677                   */
4678 4678                  serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 4679                  switch (serr) {
4680 4680                  case SCF_ERROR_NONE:
4681 4681                          break;
4682 4682  
4683 4683                  case SCF_ERROR_NOT_FOUND:
4684 4684                          warn(cf_missing, ient->sc_fmri, ud_name);
4685 4685                          r = 0;
4686 4686                          goto out;
4687 4687  
4688 4688                  case SCF_ERROR_NO_MEMORY:
4689 4689                          r = ENOMEM;
4690 4690                          goto out;
4691 4691  
4692 4692                  case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 4693                  case SCF_ERROR_INVALID_ARGUMENT:
4694 4694                  default:
4695 4695                          bad_error("fmri_to_entity", serr);
4696 4696                  }
4697 4697  
4698 4698                  r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 4699                      ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 4700                  switch (r) {
4701 4701                  case 0:
4702 4702                          break;
4703 4703  
4704 4704                  case ECONNABORTED:
4705 4705                          goto out;
4706 4706  
4707 4707                  case ECANCELED:
4708 4708                  case ENOENT:
4709 4709                          warn(cf_missing, ient->sc_fmri, ud_name);
4710 4710                          r = 0;
4711 4711                          goto out;
4712 4712  
4713 4713                  case EBADF:
4714 4714                          warn(r_no_lvl, ud_ctarg);
4715 4715                          goto out;
4716 4716  
4717 4717                  case EINVAL:
4718 4718                  default:
4719 4719                          bad_error("entity_get_running_pg", r);
4720 4720                  }
4721 4721  
4722 4722                  r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4723 4723                  switch (r) {
4724 4724                  case 0:
4725 4725                          break;
4726 4726  
4727 4727                  case ECANCELED:
4728 4728                          warn(cf_missing, ient->sc_fmri, ud_name);
4729 4729                          r = 0;
4730 4730                          goto out;
4731 4731  
4732 4732                  case ECONNABORTED:
4733 4733                  case ENOMEM:
4734 4734                  case EBADF:
4735 4735                          goto out;
4736 4736  
4737 4737                  case EACCES:
4738 4738                  default:
4739 4739                          bad_error("load_pg", r);
4740 4740                  }
4741 4741  
4742 4742                  if (!pg_equal(current_pg, new_dpt_pgroup))
4743 4743                          warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 4744                  internal_pgroup_free(current_pg);
4745 4745                  r = 0;
4746 4746                  goto out;
4747 4747          } else if (r != 1) {
4748 4748                  bad_error("fmri_equal", r);
4749 4749          }
4750 4750  
4751 4751  nocust:
4752 4752          /*
4753 4753           * Target has not been customized.  Check the dependency property
4754 4754           * group.
4755 4755           */
4756 4756  
4757 4757          if (old_dpt_pgroup == NULL) {
4758 4758                  if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 4759                      ud_pg) != 0) {
4760 4760                          switch (scf_error()) {
4761 4761                          case SCF_ERROR_NOT_FOUND:
4762 4762                                  warn(li_corrupt, ient->sc_fmri);
4763 4763                                  return (EBADF);
4764 4764  
4765 4765                          case SCF_ERROR_DELETED:
4766 4766                          case SCF_ERROR_CONNECTION_BROKEN:
4767 4767                                  return (scferror2errno(scf_error()));
4768 4768  
4769 4769                          case SCF_ERROR_NOT_BOUND:
4770 4770                          case SCF_ERROR_HANDLE_MISMATCH:
4771 4771                          case SCF_ERROR_INVALID_ARGUMENT:
4772 4772                          case SCF_ERROR_NOT_SET:
4773 4773                          default:
4774 4774                                  bad_error("scf_snaplevel_get_pg", scf_error());
4775 4775                          }
4776 4776                  }
4777 4777  
4778 4778                  r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 4779                      snap_lastimport);
4780 4780                  switch (r) {
4781 4781                  case 0:
4782 4782                          break;
4783 4783  
4784 4784                  case ECANCELED:
4785 4785                  case ECONNABORTED:
4786 4786                  case ENOMEM:
4787 4787                  case EBADF:
4788 4788                          return (r);
4789 4789  
4790 4790                  case EACCES:
4791 4791                  default:
4792 4792                          bad_error("load_pg", r);
4793 4793                  }
4794 4794          }
4795 4795          serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 4796          switch (serr) {
4797 4797          case SCF_ERROR_NONE:
4798 4798                  break;
4799 4799  
4800 4800          case SCF_ERROR_NOT_FOUND:
4801 4801                  warn(cf_missing, ient->sc_fmri, ud_name);
4802 4802                  r = 0;
4803 4803                  goto out;
4804 4804  
4805 4805          case SCF_ERROR_NO_MEMORY:
4806 4806                  r = ENOMEM;
4807 4807                  goto out;
4808 4808  
4809 4809          case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 4810          case SCF_ERROR_INVALID_ARGUMENT:
4811 4811          default:
4812 4812                  bad_error("fmri_to_entity", serr);
4813 4813          }
4814 4814  
4815 4815          r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 4816              ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 4817          switch (r) {
4818 4818          case 0:
4819 4819                  break;
4820 4820  
4821 4821          case ECONNABORTED:
4822 4822                  goto out;
4823 4823  
4824 4824          case ECANCELED:
4825 4825          case ENOENT:
4826 4826                  warn(cf_missing, ient->sc_fmri, ud_name);
4827 4827                  r = 0;
4828 4828                  goto out;
4829 4829  
4830 4830          case EBADF:
4831 4831                  warn(r_no_lvl, ud_ctarg);
4832 4832                  goto out;
4833 4833  
4834 4834          case EINVAL:
4835 4835          default:
4836 4836                  bad_error("entity_get_running_pg", r);
4837 4837          }
4838 4838  
4839 4839          r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4840 4840          switch (r) {
4841 4841          case 0:
4842 4842                  break;
4843 4843  
4844 4844          case ECANCELED:
4845 4845                  warn(cf_missing, ient->sc_fmri, ud_name);
4846 4846                  goto out;
4847 4847  
4848 4848          case ECONNABORTED:
4849 4849          case ENOMEM:
4850 4850          case EBADF:
4851 4851                  goto out;
4852 4852  
4853 4853          case EACCES:
4854 4854          default:
4855 4855                  bad_error("load_pg", r);
4856 4856          }
4857 4857  
4858 4858          if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 4859                  if (!pg_equal(current_pg, new_dpt_pgroup))
4860 4860                          warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 4861                  internal_pgroup_free(current_pg);
4862 4862                  r = 0;
4863 4863                  goto out;
4864 4864          }
4865 4865  
4866 4866          /* Uncustomized.  Upgrade. */
4867 4867  
4868 4868          r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 4869          switch (r) {
4870 4870          case 1:
4871 4871                  if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 4872                          /* Already upgraded. */
4873 4873                          internal_pgroup_free(current_pg);
4874 4874                          r = 0;
4875 4875                          goto out;
4876 4876                  }
4877 4877  
4878 4878                  internal_pgroup_free(current_pg);
4879 4879  
4880 4880                  /* upgrade current_pg */
4881 4881                  if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 4882                          switch (scf_error()) {
4883 4883                          case SCF_ERROR_CONNECTION_BROKEN:
4884 4884                                  r = scferror2errno(scf_error());
4885 4885                                  goto out;
4886 4886  
4887 4887                          case SCF_ERROR_DELETED:
4888 4888                                  warn(cf_missing, ient->sc_fmri, ud_name);
4889 4889                                  r = 0;
4890 4890                                  goto out;
4891 4891  
4892 4892                          case SCF_ERROR_NOT_FOUND:
4893 4893                                  break;
4894 4894  
4895 4895                          case SCF_ERROR_INVALID_ARGUMENT:
4896 4896                          case SCF_ERROR_NOT_BOUND:
4897 4897                          case SCF_ERROR_NOT_SET:
4898 4898                          case SCF_ERROR_HANDLE_MISMATCH:
4899 4899                          default:
4900 4900                                  bad_error("entity_get_pg", scf_error());
4901 4901                          }
4902 4902  
4903 4903                          if (tissvc)
4904 4904                                  r = scf_service_add_pg(target_ent, ud_name,
4905 4905                                      SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 4906                          else
4907 4907                                  r = scf_instance_add_pg(target_ent, ud_name,
4908 4908                                      SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 4909                          if (r != 0) {
4910 4910                                  switch (scf_error()) {
4911 4911                                  case SCF_ERROR_CONNECTION_BROKEN:
4912 4912                                  case SCF_ERROR_NO_RESOURCES:
4913 4913                                  case SCF_ERROR_BACKEND_READONLY:
4914 4914                                  case SCF_ERROR_BACKEND_ACCESS:
4915 4915                                          r = scferror2errno(scf_error());
4916 4916                                          goto out;
4917 4917  
4918 4918                                  case SCF_ERROR_DELETED:
4919 4919                                          warn(cf_missing, ient->sc_fmri,
4920 4920                                              ud_name);
4921 4921                                          r = 0;
4922 4922                                          goto out;
4923 4923  
4924 4924                                  case SCF_ERROR_PERMISSION_DENIED:
4925 4925                                          warn(emsg_pg_deleted, ud_ctarg,
4926 4926                                              ud_name);
4927 4927                                          r = EPERM;
4928 4928                                          goto out;
4929 4929  
4930 4930                                  case SCF_ERROR_EXISTS:
4931 4931                                          warn(emsg_pg_added, ud_ctarg, ud_name);
4932 4932                                          r = EBUSY;
4933 4933                                          goto out;
4934 4934  
4935 4935                                  case SCF_ERROR_NOT_BOUND:
4936 4936                                  case SCF_ERROR_HANDLE_MISMATCH:
4937 4937                                  case SCF_ERROR_INVALID_ARGUMENT:
4938 4938                                  case SCF_ERROR_NOT_SET:
4939 4939                                  default:
4940 4940                                          bad_error("entity_add_pg", scf_error());
4941 4941                                  }
4942 4942                          }
4943 4943                  }
4944 4944  
4945 4945                  r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4946 4946                  switch (r) {
4947 4947                  case 0:
4948 4948                          break;
4949 4949  
4950 4950                  case ECANCELED:
4951 4951                          warn(cf_missing, ient->sc_fmri, ud_name);
4952 4952                          goto out;
4953 4953  
4954 4954                  case ECONNABORTED:
4955 4955                  case ENOMEM:
4956 4956                  case EBADF:
4957 4957                          goto out;
4958 4958  
4959 4959                  case EACCES:
4960 4960                  default:
4961 4961                          bad_error("load_pg", r);
4962 4962                  }
4963 4963  
4964 4964                  if (g_verbose)
4965 4965                          warn(upgrading, ient->sc_fmri, ud_name);
4966 4966  
4967 4967                  r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 4968                      new_dpt_pgroup, 0, ient->sc_fmri);
4969 4969                  switch (r) {
4970 4970                  case 0:
4971 4971                          break;
4972 4972  
4973 4973                  case ECANCELED:
4974 4974                          warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 4975                          r = EBUSY;
4976 4976                          goto out;
4977 4977  
4978 4978                  case EPERM:
4979 4979                          warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 4980                          goto out;
4981 4981  
4982 4982                  case EBUSY:
4983 4983                          warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 4984                          goto out;
4985 4985  
4986 4986                  case ECONNABORTED:
4987 4987                  case ENOMEM:
4988 4988                  case ENOSPC:
4989 4989                  case EROFS:
4990 4990                  case EACCES:
4991 4991                  case EINVAL:
4992 4992                          goto out;
4993 4993  
4994 4994                  default:
4995 4995                          bad_error("upgrade_pg", r);
4996 4996                  }
4997 4997                  break;
4998 4998  
4999 4999          case 0: {
5000 5000                  scf_transaction_entry_t *ent;
5001 5001                  scf_value_t *val;
5002 5002  
5003 5003                  internal_pgroup_free(current_pg);
5004 5004  
5005 5005                  /* delete old pg */
5006 5006                  if (g_verbose)
5007 5007                          warn(upgrading, ient->sc_fmri, ud_name);
5008 5008  
5009 5009                  if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 5010                          switch (scf_error()) {
5011 5011                          case SCF_ERROR_CONNECTION_BROKEN:
5012 5012                                  r = scferror2errno(scf_error());
5013 5013                                  goto out;
5014 5014  
5015 5015                          case SCF_ERROR_DELETED:
5016 5016                                  warn(cf_missing, ient->sc_fmri, ud_name);
5017 5017                                  r = 0;
5018 5018                                  goto out;
5019 5019  
5020 5020                          case SCF_ERROR_NOT_FOUND:
5021 5021                                  break;
5022 5022  
5023 5023                          case SCF_ERROR_INVALID_ARGUMENT:
5024 5024                          case SCF_ERROR_NOT_BOUND:
5025 5025                          case SCF_ERROR_NOT_SET:
5026 5026                          case SCF_ERROR_HANDLE_MISMATCH:
5027 5027                          default:
5028 5028                                  bad_error("entity_get_pg", scf_error());
5029 5029                          }
5030 5030                  } else if (scf_pg_delete(ud_pg) != 0) {
5031 5031                          switch (scf_error()) {
5032 5032                          case SCF_ERROR_DELETED:
5033 5033                                  break;
5034 5034  
5035 5035                          case SCF_ERROR_CONNECTION_BROKEN:
5036 5036                          case SCF_ERROR_BACKEND_READONLY:
5037 5037                          case SCF_ERROR_BACKEND_ACCESS:
5038 5038                                  r = scferror2errno(scf_error());
5039 5039                                  goto out;
5040 5040  
5041 5041                          case SCF_ERROR_PERMISSION_DENIED:
5042 5042                                  warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 5043                                  r = scferror2errno(scf_error());
5044 5044                                  goto out;
5045 5045  
5046 5046                          case SCF_ERROR_NOT_SET:
5047 5047                          default:
5048 5048                                  bad_error("scf_pg_delete", scf_error());
5049 5049                          }
5050 5050                  }
5051 5051  
5052 5052                  /* import new one */
5053 5053                  cbdata.sc_handle = g_hndl;
5054 5054                  cbdata.sc_trans = NULL;         /* handled below */
5055 5055                  cbdata.sc_flags = 0;
5056 5056  
5057 5057                  r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 5058                  if (r != UU_WALK_NEXT) {
5059 5059                          if (r != UU_WALK_ERROR)
5060 5060                                  bad_error("lscf_dependent_import", r);
5061 5061  
5062 5062                          r = cbdata.sc_err;
5063 5063                          goto out;
5064 5064                  }
5065 5065  
5066 5066                  if (tx == NULL)
5067 5067                          break;
5068 5068  
5069 5069                  if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 5070                      (val = scf_value_create(g_hndl)) == NULL) {
5071 5071                          if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 5072                                  return (ENOMEM);
5073 5073  
5074 5074                          bad_error("scf_entry_create", scf_error());
5075 5075                  }
5076 5076  
5077 5077                  if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 5078                      SCF_TYPE_FMRI) != 0) {
5079 5079                          switch (scf_error()) {
5080 5080                          case SCF_ERROR_CONNECTION_BROKEN:
5081 5081                                  r = scferror2errno(scf_error());
5082 5082                                  goto out;
5083 5083  
5084 5084                          case SCF_ERROR_DELETED:
5085 5085                                  warn(emsg_pg_deleted, ient->sc_fmri,
5086 5086                                      "dependents");
5087 5087                                  r = EBUSY;
5088 5088                                  goto out;
5089 5089  
5090 5090                          case SCF_ERROR_NOT_FOUND:
5091 5091                                  break;
5092 5092  
5093 5093                          case SCF_ERROR_NOT_BOUND:
5094 5094                          case SCF_ERROR_HANDLE_MISMATCH:
5095 5095                          case SCF_ERROR_INVALID_ARGUMENT:
5096 5096                          case SCF_ERROR_NOT_SET:
5097 5097                          default:
5098 5098                                  bad_error("scf_transaction_property_"
5099 5099                                      "change_type", scf_error());
5100 5100                          }
5101 5101  
5102 5102                          if (scf_transaction_property_new(tx, ent, ud_name,
5103 5103                              SCF_TYPE_FMRI) != 0) {
5104 5104                                  switch (scf_error()) {
5105 5105                                  case SCF_ERROR_CONNECTION_BROKEN:
5106 5106                                          r = scferror2errno(scf_error());
5107 5107                                          goto out;
5108 5108  
5109 5109                                  case SCF_ERROR_DELETED:
5110 5110                                          warn(emsg_pg_deleted, ient->sc_fmri,
5111 5111                                              "dependents");
5112 5112                                          r = EBUSY;
5113 5113                                          goto out;
5114 5114  
5115 5115                                  case SCF_ERROR_EXISTS:
5116 5116                                          warn(emsg_pg_changed, ient->sc_fmri,
5117 5117                                              "dependents");
5118 5118                                          r = EBUSY;
5119 5119                                          goto out;
5120 5120  
5121 5121                                  case SCF_ERROR_INVALID_ARGUMENT:
5122 5122                                  case SCF_ERROR_HANDLE_MISMATCH:
5123 5123                                  case SCF_ERROR_NOT_BOUND:
5124 5124                                  case SCF_ERROR_NOT_SET:
5125 5125                                  default:
5126 5126                                          bad_error("scf_transaction_property_"
5127 5127                                              "new", scf_error());
5128 5128                                  }
5129 5129                          }
5130 5130                  }
5131 5131  
5132 5132                  if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 5133                      new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 5134                          /* invalid sc_pgroup_fmri caught above */
5135 5135                          bad_error("scf_value_set_from_string",
5136 5136                              scf_error());
5137 5137  
5138 5138                  if (scf_entry_add_value(ent, val) != 0)
5139 5139                          bad_error("scf_entry_add_value", scf_error());
5140 5140                  break;
5141 5141          }
5142 5142  
5143 5143          case -2:
5144 5144                  warn(li_corrupt, ient->sc_fmri);
5145 5145                  internal_pgroup_free(current_pg);
5146 5146                  r = EBADF;
5147 5147                  goto out;
5148 5148  
5149 5149          case -1:
5150 5150          default:
5151 5151                  /* invalid sc_pgroup_fmri caught above */
5152 5152                  bad_error("fmri_equal", r);
5153 5153          }
5154 5154  
5155 5155          r = 0;
5156 5156  
5157 5157  out:
5158 5158          if (old_dpt_pgroup != NULL)
5159 5159                  internal_pgroup_free(old_dpt_pgroup);
5160 5160  
5161 5161          return (r);
5162 5162  }
5163 5163  
5164 5164  /*
5165 5165   * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 5166   * would import it, except it seems to exist in the service anyway.  Compare
5167 5167   * the existent dependent with the one we would import, and report any
5168 5168   * differences (if there are none, be silent).  prop is the property which
5169 5169   * represents the existent dependent (in the dependents property group) in the
5170 5170   * entity corresponding to ient.
5171 5171   *
5172 5172   * Returns
5173 5173   *   0 - success (Sort of.  At least, we can continue importing.)
5174 5174   *   ECONNABORTED - repository connection broken
5175 5175   *   EBUSY - ancestor of prop was deleted (error printed)
5176 5176   *   ENOMEM - out of memory
5177 5177   *   EBADF - corrupt property group (error printed)
5178 5178   *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5179 5179   */
5180 5180  static int
5181 5181  handle_dependent_conflict(const entity_t * const ient,
5182 5182      const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 5183  {
5184 5184          int r;
5185 5185          scf_type_t ty;
5186 5186          scf_error_t scfe;
5187 5187          void *tptr;
5188 5188          int tissvc;
5189 5189          pgroup_t *pgroup;
5190 5190  
5191 5191          if (scf_property_get_value(prop, ud_val) != 0) {
5192 5192                  switch (scf_error()) {
5193 5193                  case SCF_ERROR_CONNECTION_BROKEN:
5194 5194                          return (scferror2errno(scf_error()));
5195 5195  
5196 5196                  case SCF_ERROR_DELETED:
5197 5197                          warn(emsg_pg_deleted, ient->sc_fmri,
5198 5198                              new_dpt_pgroup->sc_pgroup_name);
5199 5199                          return (EBUSY);
5200 5200  
5201 5201                  case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 5202                  case SCF_ERROR_NOT_FOUND:
5203 5203                          warn(gettext("Conflict upgrading %s (not importing "
5204 5204                              "dependent \"%s\" because it already exists.)  "
5205 5205                              "Warning: The \"%s/%2$s\" property has more or "
5206 5206                              "fewer than one value)).\n"), ient->sc_fmri,
5207 5207                              new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 5208                          return (0);
5209 5209  
5210 5210                  case SCF_ERROR_HANDLE_MISMATCH:
5211 5211                  case SCF_ERROR_NOT_BOUND:
5212 5212                  case SCF_ERROR_NOT_SET:
5213 5213                  case SCF_ERROR_PERMISSION_DENIED:
5214 5214                  default:
5215 5215                          bad_error("scf_property_get_value",
5216 5216                              scf_error());
5217 5217                  }
5218 5218          }
5219 5219  
5220 5220          ty = scf_value_type(ud_val);
5221 5221          assert(ty != SCF_TYPE_INVALID);
5222 5222          if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 5223                  warn(gettext("Conflict upgrading %s (not importing dependent "
5224 5224                      "\"%s\" because it already exists).  Warning: The "
5225 5225                      "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 5226                      ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 5227                      scf_type_to_string(ty), "dependents");
5228 5228                  return (0);
5229 5229          }
5230 5230  
5231 5231          if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232 5232              0)
5233 5233                  bad_error("scf_value_get_as_string", scf_error());
5234 5234  
5235 5235          r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 5236          switch (r) {
5237 5237          case 0:
5238 5238                  warn(gettext("Conflict upgrading %s (not importing dependent "
5239 5239                      "\"%s\" (target \"%s\") because it already exists with "
5240 5240                      "target \"%s\").\n"), ient->sc_fmri,
5241 5241                      new_dpt_pgroup->sc_pgroup_name,
5242 5242                      new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 5243                  return (0);
5244 5244  
5245 5245          case 1:
5246 5246                  break;
5247 5247  
5248 5248          case -1:
5249 5249                  warn(gettext("Conflict upgrading %s (not importing dependent "
5250 5250                      "\"%s\" because it already exists).  Warning: The current "
5251 5251                      "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 5252                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 5253                  return (0);
5254 5254  
5255 5255          case -2:
5256 5256                  warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 5257                      "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 5258                      new_dpt_pgroup->sc_pgroup_fmri);
5259 5259                  return (EINVAL);
5260 5260  
5261 5261          default:
5262 5262                  bad_error("fmri_equal", r);
5263 5263          }
5264 5264  
5265 5265          /* compare dependency pgs in target */
5266 5266          scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 5267          switch (scfe) {
5268 5268          case SCF_ERROR_NONE:
5269 5269                  break;
5270 5270  
5271 5271          case SCF_ERROR_NO_MEMORY:
5272 5272                  return (ENOMEM);
5273 5273  
5274 5274          case SCF_ERROR_NOT_FOUND:
5275 5275                  warn(emsg_dpt_dangling, ient->sc_fmri,
5276 5276                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 5277                  return (0);
5278 5278  
5279 5279          case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 5280          case SCF_ERROR_INVALID_ARGUMENT:
5281 5281          default:
5282 5282                  bad_error("fmri_to_entity", scfe);
5283 5283          }
5284 5284  
5285 5285          r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 5286              ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 5287          switch (r) {
5288 5288          case 0:
5289 5289                  break;
5290 5290  
5291 5291          case ECONNABORTED:
5292 5292                  return (r);
5293 5293  
5294 5294          case ECANCELED:
5295 5295                  warn(emsg_dpt_dangling, ient->sc_fmri,
5296 5296                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 5297                  return (0);
5298 5298  
5299 5299          case EBADF:
5300 5300                  if (tissvc)
5301 5301                          warn(gettext("%s has an instance with a \"%s\" "
5302 5302                              "snapshot which is missing a snaplevel.\n"),
5303 5303                              ud_ctarg, "running");
5304 5304                  else
5305 5305                          warn(gettext("%s has a \"%s\" snapshot which is "
5306 5306                              "missing a snaplevel.\n"), ud_ctarg, "running");
5307 5307                  /* FALLTHROUGH */
5308 5308  
5309 5309          case ENOENT:
5310 5310                  warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 5311                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 5312                      new_dpt_pgroup->sc_pgroup_name);
5313 5313                  return (0);
5314 5314  
5315 5315          case EINVAL:
5316 5316          default:
5317 5317                  bad_error("entity_get_running_pg", r);
5318 5318          }
5319 5319  
5320 5320          pgroup = internal_pgroup_new();
5321 5321          if (pgroup == NULL)
5322 5322                  return (ENOMEM);
5323 5323  
5324 5324          r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 5325          switch (r) {
5326 5326          case 0:
5327 5327                  break;
5328 5328  
5329 5329          case ECONNABORTED:
5330 5330          case EBADF:
5331 5331          case ENOMEM:
5332 5332                  internal_pgroup_free(pgroup);
5333 5333                  return (r);
5334 5334  
5335 5335          case ECANCELED:
5336 5336                  warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 5337                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 5338                      new_dpt_pgroup->sc_pgroup_name);
5339 5339                  internal_pgroup_free(pgroup);
5340 5340                  return (0);
5341 5341  
5342 5342          case EACCES:
5343 5343          default:
5344 5344                  bad_error("load_pg", r);
5345 5345          }
5346 5346  
5347 5347          /* report differences */
5348 5348          report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 5349          internal_pgroup_free(pgroup);
5350 5350          return (0);
5351 5351  }
5352 5352  
5353 5353  /*
5354 5354   * lipg is a property group in the last-import snapshot of ent, which is an
5355 5355   * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5356 5356   * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5357 5357   * in ents's property groups, compare and upgrade ent appropriately.
5358 5358   *
5359 5359   * Returns
5360 5360   *   0 - success
5361 5361   *   ECONNABORTED - repository connection broken
5362 5362   *   ENOMEM - out of memory
5363 5363   *   ENOSPC - configd is out of resources
5364 5364   *   EINVAL - ient has invalid dependent (error printed)
5365 5365   *          - ient has invalid pgroup_t (error printed)
5366 5366   *   ECANCELED - ent has been deleted
5367 5367   *   ENODEV - entity containing lipg has been deleted
5368 5368   *          - entity containing running has been deleted
5369 5369   *   EPERM - could not delete pg (permission denied) (error printed)
5370 5370   *         - couldn't upgrade dependents (permission denied) (error printed)
5371 5371   *         - couldn't import pg (permission denied) (error printed)
5372 5372   *         - couldn't upgrade pg (permission denied) (error printed)
5373 5373   *   EROFS - could not delete pg (repository read-only)
5374 5374   *         - couldn't upgrade dependents (repository read-only)
5375 5375   *         - couldn't import pg (repository read-only)
5376 5376   *         - couldn't upgrade pg (repository read-only)
5377 5377   *   EACCES - could not delete pg (backend access denied)
5378 5378   *          - couldn't upgrade dependents (backend access denied)
5379 5379   *          - couldn't import pg (backend access denied)
5380 5380   *          - couldn't upgrade pg (backend access denied)
5381 5381   *          - couldn't read property (backend access denied)
5382 5382   *   EBUSY - property group was added (error printed)
5383 5383   *         - property group was deleted (error printed)
5384 5384   *         - property group changed (error printed)
5385 5385   *         - "dependents" pg was added, changed, or deleted (error printed)
5386 5386   *         - dependent target deleted (error printed)
5387 5387   *         - dependent pg changed (error printed)
5388 5388   *   EBADF - imp_snpl is corrupt (error printed)
5389 5389   *         - ent has bad pg (error printed)
5390 5390   *   EEXIST - dependent collision in target service (error printed)
5391 5391   */
5392 5392  static int
5393 5393  process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394 5394      const scf_snaplevel_t *running)
5395 5395  {
5396 5396          int r;
5397 5397          pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 5398          scf_callback_t cbdata;
5399 5399  
5400 5400          const char * const cf_pg_missing =
5401 5401              gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 5402          const char * const deleting =
5403 5403              gettext("%s: Deleting property group \"%s\".\n");
5404 5404  
5405 5405          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406 5406  
5407 5407          /* Skip dependent property groups. */
5408 5408          if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 5409                  switch (scf_error()) {
5410 5410                  case SCF_ERROR_DELETED:
5411 5411                          return (ENODEV);
5412 5412  
5413 5413                  case SCF_ERROR_CONNECTION_BROKEN:
5414 5414                          return (ECONNABORTED);
5415 5415  
5416 5416                  case SCF_ERROR_NOT_SET:
5417 5417                  case SCF_ERROR_NOT_BOUND:
5418 5418                  default:
5419 5419                          bad_error("scf_pg_get_type", scf_error());
5420 5420                  }
5421 5421          }
5422 5422  
5423 5423          if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 5424                  if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 5425                          return (0);
5426 5426  
5427 5427                  switch (scf_error()) {
5428 5428                  case SCF_ERROR_NOT_FOUND:
5429 5429                          break;
5430 5430  
5431 5431                  case SCF_ERROR_CONNECTION_BROKEN:
5432 5432                          return (ECONNABORTED);
5433 5433  
5434 5434                  case SCF_ERROR_DELETED:
5435 5435                          return (ENODEV);
5436 5436  
5437 5437                  case SCF_ERROR_INVALID_ARGUMENT:
5438 5438                  case SCF_ERROR_NOT_BOUND:
5439 5439                  case SCF_ERROR_HANDLE_MISMATCH:
5440 5440                  case SCF_ERROR_NOT_SET:
5441 5441                  default:
5442 5442                          bad_error("scf_pg_get_property", scf_error());
5443 5443                  }
5444 5444          }
5445 5445  
5446 5446          /* lookup pg in new properties */
5447 5447          if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 5448                  switch (scf_error()) {
5449 5449                  case SCF_ERROR_DELETED:
5450 5450                          return (ENODEV);
5451 5451  
5452 5452                  case SCF_ERROR_CONNECTION_BROKEN:
5453 5453                          return (ECONNABORTED);
5454 5454  
5455 5455                  case SCF_ERROR_NOT_SET:
5456 5456                  case SCF_ERROR_NOT_BOUND:
5457 5457                  default:
5458 5458                          bad_error("scf_pg_get_name", scf_error());
5459 5459                  }
5460 5460          }
5461 5461  
5462 5462          pgrp.sc_pgroup_name = imp_str;
5463 5463          mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464 5464  
5465 5465          if (mpg != NULL)
5466 5466                  mpg->sc_pgroup_seen = 1;
5467 5467  
5468 5468          /* Special handling for dependents */
5469 5469          if (strcmp(imp_str, "dependents") == 0)
5470 5470                  return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471 5471  
5472 5472          if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 5473                  return (upgrade_manifestfiles(NULL, ient, running, ent));
5474 5474  
5475 5475          if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 5476                  /* property group was deleted from manifest */
5477 5477                  if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 5478                          switch (scf_error()) {
5479 5479                          case SCF_ERROR_NOT_FOUND:
5480 5480                                  return (0);
5481 5481  
5482 5482                          case SCF_ERROR_DELETED:
5483 5483                          case SCF_ERROR_CONNECTION_BROKEN:
5484 5484                                  return (scferror2errno(scf_error()));
5485 5485  
5486 5486                          case SCF_ERROR_INVALID_ARGUMENT:
5487 5487                          case SCF_ERROR_HANDLE_MISMATCH:
5488 5488                          case SCF_ERROR_NOT_BOUND:
5489 5489                          case SCF_ERROR_NOT_SET:
5490 5490                          default:
5491 5491                                  bad_error("entity_get_pg", scf_error());
5492 5492                          }
5493 5493                  }
5494 5494  
5495 5495                  if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 5496                          if (g_verbose)
5497 5497                                  warn(deleting, ient->sc_fmri, imp_str);
5498 5498                          if (scf_pg_delete(imp_pg2) == 0)
5499 5499                                  return (0);
5500 5500  
5501 5501                          switch (scf_error()) {
5502 5502                          case SCF_ERROR_DELETED:
5503 5503                                  return (0);
5504 5504  
5505 5505                          case SCF_ERROR_CONNECTION_BROKEN:
5506 5506                          case SCF_ERROR_BACKEND_READONLY:
5507 5507                          case SCF_ERROR_BACKEND_ACCESS:
5508 5508                                  return (scferror2errno(scf_error()));
5509 5509  
5510 5510                          case SCF_ERROR_PERMISSION_DENIED:
5511 5511                                  warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 5512                                  return (scferror2errno(scf_error()));
5513 5513  
5514 5514                          case SCF_ERROR_NOT_SET:
5515 5515                          default:
5516 5516                                  bad_error("scf_pg_delete", scf_error());
5517 5517                          }
5518 5518                  }
5519 5519  
5520 5520                  r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 5521                  switch (r) {
5522 5522                  case 0:
5523 5523                          break;
5524 5524  
5525 5525                  case ECANCELED:
5526 5526                          return (ENODEV);
5527 5527  
5528 5528                  case ECONNABORTED:
5529 5529                  case ENOMEM:
5530 5530                  case EBADF:
5531 5531                  case EACCES:
5532 5532                          return (r);
5533 5533  
5534 5534                  default:
5535 5535                          bad_error("load_pg", r);
5536 5536                  }
5537 5537  
5538 5538                  r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 5539                  switch (r) {
5540 5540                  case 0:
5541 5541                          break;
5542 5542  
5543 5543                  case ECANCELED:
5544 5544                  case ECONNABORTED:
5545 5545                  case ENOMEM:
5546 5546                  case EBADF:
5547 5547                  case EACCES:
5548 5548                          internal_pgroup_free(lipg_i);
5549 5549                          return (r);
5550 5550  
5551 5551                  default:
5552 5552                          bad_error("load_pg", r);
5553 5553                  }
5554 5554  
5555 5555                  if (pg_equal(lipg_i, curpg_i)) {
5556 5556                          if (g_verbose)
5557 5557                                  warn(deleting, ient->sc_fmri, imp_str);
5558 5558                          if (scf_pg_delete(imp_pg2) != 0) {
5559 5559                                  switch (scf_error()) {
5560 5560                                  case SCF_ERROR_DELETED:
5561 5561                                          break;
5562 5562  
5563 5563                                  case SCF_ERROR_CONNECTION_BROKEN:
5564 5564                                          internal_pgroup_free(lipg_i);
5565 5565                                          internal_pgroup_free(curpg_i);
5566 5566                                          return (ECONNABORTED);
5567 5567  
5568 5568                                  case SCF_ERROR_NOT_SET:
5569 5569                                  case SCF_ERROR_NOT_BOUND:
5570 5570                                  default:
5571 5571                                          bad_error("scf_pg_delete", scf_error());
5572 5572                                  }
5573 5573                          }
5574 5574                  } else {
5575 5575                          report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 5576                  }
5577 5577  
5578 5578                  internal_pgroup_free(lipg_i);
5579 5579                  internal_pgroup_free(curpg_i);
5580 5580  
5581 5581                  return (0);
5582 5582          }
5583 5583  
5584 5584          /*
5585 5585           * Only dependent pgs can have override set, and we skipped those
5586 5586           * above.
5587 5587           */
5588 5588          assert(!mpg->sc_pgroup_override);
5589 5589  
5590 5590          /* compare */
5591 5591          r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 5592          switch (r) {
5593 5593          case 0:
5594 5594                  break;
5595 5595  
5596 5596          case ECANCELED:
5597 5597                  return (ENODEV);
5598 5598  
5599 5599          case ECONNABORTED:
5600 5600          case EBADF:
5601 5601          case ENOMEM:
5602 5602          case EACCES:
5603 5603                  return (r);
5604 5604  
5605 5605          default:
5606 5606                  bad_error("load_pg", r);
5607 5607          }
5608 5608  
5609 5609          if (pg_equal(mpg, lipg_i)) {
5610 5610                  /* The manifest pg has not changed.  Move on. */
5611 5611                  r = 0;
5612 5612                  goto out;
5613 5613          }
5614 5614  
5615 5615          /* upgrade current properties according to lipg & mpg */
5616 5616          if (running != NULL)
5617 5617                  r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 5618          else
5619 5619                  r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 5620          if (r != 0) {
5621 5621                  switch (scf_error()) {
5622 5622                  case SCF_ERROR_CONNECTION_BROKEN:
5623 5623                          r = scferror2errno(scf_error());
5624 5624                          goto out;
5625 5625  
5626 5626                  case SCF_ERROR_DELETED:
5627 5627                          if (running != NULL)
5628 5628                                  r = ENODEV;
5629 5629                          else
5630 5630                                  r = ECANCELED;
5631 5631                          goto out;
5632 5632  
5633 5633                  case SCF_ERROR_NOT_FOUND:
5634 5634                          break;
5635 5635  
5636 5636                  case SCF_ERROR_INVALID_ARGUMENT:
5637 5637                  case SCF_ERROR_HANDLE_MISMATCH:
5638 5638                  case SCF_ERROR_NOT_BOUND:
5639 5639                  case SCF_ERROR_NOT_SET:
5640 5640                  default:
5641 5641                          bad_error("entity_get_pg", scf_error());
5642 5642                  }
5643 5643  
5644 5644                  warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645 5645  
5646 5646                  r = 0;
5647 5647                  goto out;
5648 5648          }
5649 5649  
5650 5650          r = load_pg_attrs(imp_pg2, &curpg_i);
5651 5651          switch (r) {
5652 5652          case 0:
5653 5653                  break;
5654 5654  
5655 5655          case ECANCELED:
5656 5656                  warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 5657                  r = 0;
5658 5658                  goto out;
5659 5659  
5660 5660          case ECONNABORTED:
5661 5661          case ENOMEM:
5662 5662                  goto out;
5663 5663  
5664 5664          default:
5665 5665                  bad_error("load_pg_attrs", r);
5666 5666          }
5667 5667  
5668 5668          if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 5669                  (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 5670                  internal_pgroup_free(curpg_i);
5671 5671                  r = 0;
5672 5672                  goto out;
5673 5673          }
5674 5674  
5675 5675          internal_pgroup_free(curpg_i);
5676 5676  
5677 5677          r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 5678          switch (r) {
5679 5679          case 0:
5680 5680                  break;
5681 5681  
5682 5682          case ECANCELED:
5683 5683                  warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 5684                  r = 0;
5685 5685                  goto out;
5686 5686  
5687 5687          case ECONNABORTED:
5688 5688          case EBADF:
5689 5689          case ENOMEM:
5690 5690          case EACCES:
5691 5691                  goto out;
5692 5692  
5693 5693          default:
5694 5694                  bad_error("load_pg", r);
5695 5695          }
5696 5696  
5697 5697          if (pg_equal(lipg_i, curpg_i) &&
5698 5698              !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 5699                  int do_delete = 1;
5700 5700  
5701 5701                  if (g_verbose)
5702 5702                          warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 5703                              ient->sc_fmri, mpg->sc_pgroup_name);
5704 5704  
5705 5705                  internal_pgroup_free(curpg_i);
5706 5706  
5707 5707                  if (running != NULL &&
5708 5708                      entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 5709                          switch (scf_error()) {
5710 5710                          case SCF_ERROR_DELETED:
5711 5711                                  r = ECANCELED;
5712 5712                                  goto out;
5713 5713  
5714 5714                          case SCF_ERROR_NOT_FOUND:
5715 5715                                  do_delete = 0;
5716 5716                                  break;
5717 5717  
5718 5718                          case SCF_ERROR_CONNECTION_BROKEN:
5719 5719                                  r = scferror2errno(scf_error());
5720 5720                                  goto out;
5721 5721  
5722 5722                          case SCF_ERROR_HANDLE_MISMATCH:
5723 5723                          case SCF_ERROR_INVALID_ARGUMENT:
5724 5724                          case SCF_ERROR_NOT_SET:
5725 5725                          case SCF_ERROR_NOT_BOUND:
5726 5726                          default:
5727 5727                                  bad_error("entity_get_pg", scf_error());
5728 5728                          }
5729 5729                  }
5730 5730  
5731 5731                  if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 5732                          switch (scf_error()) {
5733 5733                          case SCF_ERROR_DELETED:
5734 5734                                  break;
5735 5735  
5736 5736                          case SCF_ERROR_CONNECTION_BROKEN:
5737 5737                          case SCF_ERROR_BACKEND_READONLY:
5738 5738                          case SCF_ERROR_BACKEND_ACCESS:
5739 5739                                  r = scferror2errno(scf_error());
5740 5740                                  goto out;
5741 5741  
5742 5742                          case SCF_ERROR_PERMISSION_DENIED:
5743 5743                                  warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 5744                                      ient->sc_fmri);
5745 5745                                  r = scferror2errno(scf_error());
5746 5746                                  goto out;
5747 5747  
5748 5748                          case SCF_ERROR_NOT_SET:
5749 5749                          case SCF_ERROR_NOT_BOUND:
5750 5750                          default:
5751 5751                                  bad_error("scf_pg_delete", scf_error());
5752 5752                          }
5753 5753                  }
5754 5754  
5755 5755                  cbdata.sc_handle = g_hndl;
5756 5756                  cbdata.sc_parent = ent;
5757 5757                  cbdata.sc_service = issvc;
5758 5758                  cbdata.sc_flags = 0;
5759 5759                  cbdata.sc_source_fmri = ient->sc_fmri;
5760 5760                  cbdata.sc_target_fmri = ient->sc_fmri;
5761 5761  
5762 5762                  r = entity_pgroup_import(mpg, &cbdata);
5763 5763                  switch (r) {
5764 5764                  case UU_WALK_NEXT:
5765 5765                          r = 0;
5766 5766                          goto out;
5767 5767  
5768 5768                  case UU_WALK_ERROR:
5769 5769                          if (cbdata.sc_err == EEXIST) {
5770 5770                                  warn(emsg_pg_added, ient->sc_fmri,
5771 5771                                      mpg->sc_pgroup_name);
5772 5772                                  r = EBUSY;
5773 5773                          } else {
5774 5774                                  r = cbdata.sc_err;
5775 5775                          }
5776 5776                          goto out;
5777 5777  
5778 5778                  default:
5779 5779                          bad_error("entity_pgroup_import", r);
5780 5780                  }
5781 5781          }
5782 5782  
5783 5783          if (running != NULL &&
5784 5784              entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 5785                  switch (scf_error()) {
5786 5786                  case SCF_ERROR_CONNECTION_BROKEN:
5787 5787                  case SCF_ERROR_DELETED:
5788 5788                          r = scferror2errno(scf_error());
5789 5789                          goto out;
5790 5790  
5791 5791                  case SCF_ERROR_NOT_FOUND:
5792 5792                          break;
5793 5793  
5794 5794                  case SCF_ERROR_HANDLE_MISMATCH:
5795 5795                  case SCF_ERROR_INVALID_ARGUMENT:
5796 5796                  case SCF_ERROR_NOT_SET:
5797 5797                  case SCF_ERROR_NOT_BOUND:
5798 5798                  default:
5799 5799                          bad_error("entity_get_pg", scf_error());
5800 5800                  }
5801 5801  
5802 5802                  cbdata.sc_handle = g_hndl;
5803 5803                  cbdata.sc_parent = ent;
5804 5804                  cbdata.sc_service = issvc;
5805 5805                  cbdata.sc_flags = SCI_FORCE;
5806 5806                  cbdata.sc_source_fmri = ient->sc_fmri;
5807 5807                  cbdata.sc_target_fmri = ient->sc_fmri;
5808 5808  
5809 5809                  r = entity_pgroup_import(mpg, &cbdata);
5810 5810                  switch (r) {
5811 5811                  case UU_WALK_NEXT:
5812 5812                          r = 0;
5813 5813                          goto out;
5814 5814  
5815 5815                  case UU_WALK_ERROR:
5816 5816                          if (cbdata.sc_err == EEXIST) {
5817 5817                                  warn(emsg_pg_added, ient->sc_fmri,
5818 5818                                      mpg->sc_pgroup_name);
5819 5819                                  r = EBUSY;
5820 5820                          } else {
5821 5821                                  r = cbdata.sc_err;
5822 5822                          }
5823 5823                          goto out;
5824 5824  
5825 5825                  default:
5826 5826                          bad_error("entity_pgroup_import", r);
5827 5827                  }
5828 5828          }
5829 5829  
5830 5830          r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 5831          internal_pgroup_free(curpg_i);
5832 5832          switch (r) {
5833 5833          case 0:
5834 5834                  ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 5835                  break;
5836 5836  
5837 5837          case ECANCELED:
5838 5838                  warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 5839                  r = EBUSY;
5840 5840                  break;
5841 5841  
5842 5842          case EPERM:
5843 5843                  warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 5844                  break;
5845 5845  
5846 5846          case EBUSY:
5847 5847                  warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 5848                  break;
5849 5849  
5850 5850          case ECONNABORTED:
5851 5851          case ENOMEM:
5852 5852          case ENOSPC:
5853 5853          case EROFS:
5854 5854          case EACCES:
5855 5855          case EINVAL:
5856 5856                  break;
5857 5857  
5858 5858          default:
5859 5859                  bad_error("upgrade_pg", r);
5860 5860          }
5861 5861  
5862 5862  out:
5863 5863          internal_pgroup_free(lipg_i);
5864 5864          return (r);
5865 5865  }
5866 5866  
5867 5867  /*
5868 5868   * Upgrade the properties of ent according to snpl & ient.
5869 5869   *
5870 5870   * Returns
5871 5871   *   0 - success
5872 5872   *   ECONNABORTED - repository connection broken
5873 5873   *   ENOMEM - out of memory
5874 5874   *   ENOSPC - configd is out of resources
5875 5875   *   ECANCELED - ent was deleted
5876 5876   *   ENODEV - entity containing snpl was deleted
5877 5877   *          - entity containing running was deleted
5878 5878   *   EBADF - imp_snpl is corrupt (error printed)
5879 5879   *         - ent has corrupt pg (error printed)
5880 5880   *         - dependent has corrupt pg (error printed)
5881 5881   *         - dependent target has a corrupt snapshot (error printed)
5882 5882   *   EBUSY - pg was added, changed, or deleted (error printed)
5883 5883   *         - dependent target was deleted (error printed)
5884 5884   *         - dependent pg changed (error printed)
5885 5885   *   EINVAL - invalid property group name (error printed)
5886 5886   *          - invalid property name (error printed)
5887 5887   *          - invalid value (error printed)
5888 5888   *          - ient has invalid pgroup or dependent (error printed)
5889 5889   *   EPERM - could not create property group (permission denied) (error printed)
5890 5890   *         - could not modify property group (permission denied) (error printed)
5891 5891   *         - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 5892   *   EROFS - could not create property group (repository read-only)
5893 5893   *         - couldn't delete, upgrade, or import pg or dependent
5894 5894   *   EACCES - could not create property group (backend access denied)
5895 5895   *          - couldn't delete, upgrade, or import pg or dependent
5896 5896   *   EEXIST - dependent collision in target service (error printed)
5897 5897   */
5898 5898  static int
5899 5899  upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900 5900      entity_t *ient)
5901 5901  {
5902 5902          pgroup_t *pg, *rpg;
5903 5903          int r;
5904 5904          uu_list_t *pgs = ient->sc_pgroups;
5905 5905  
5906 5906          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907 5907  
5908 5908          /* clear sc_sceen for pgs */
5909 5909          if (uu_list_walk(pgs, clear_int,
5910 5910              (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 5911                  bad_error("uu_list_walk", uu_error());
5912 5912  
5913 5913          if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 5914                  switch (scf_error()) {
5915 5915                  case SCF_ERROR_DELETED:
5916 5916                          return (ENODEV);
5917 5917  
5918 5918                  case SCF_ERROR_CONNECTION_BROKEN:
5919 5919                          return (ECONNABORTED);
5920 5920  
5921 5921                  case SCF_ERROR_NOT_SET:
5922 5922                  case SCF_ERROR_NOT_BOUND:
5923 5923                  case SCF_ERROR_HANDLE_MISMATCH:
5924 5924                  default:
5925 5925                          bad_error("scf_iter_snaplevel_pgs", scf_error());
5926 5926                  }
5927 5927          }
5928 5928  
5929 5929          for (;;) {
5930 5930                  r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 5931                  if (r == 0)
5932 5932                          break;
5933 5933                  if (r == 1) {
5934 5934                          r = process_old_pg(imp_pg, ient, ent, running);
5935 5935                          switch (r) {
5936 5936                          case 0:
5937 5937                                  break;
5938 5938  
5939 5939                          case ECONNABORTED:
5940 5940                          case ENOMEM:
5941 5941                          case ENOSPC:
5942 5942                          case ECANCELED:
5943 5943                          case ENODEV:
5944 5944                          case EPERM:
5945 5945                          case EROFS:
5946 5946                          case EACCES:
5947 5947                          case EBADF:
5948 5948                          case EBUSY:
5949 5949                          case EINVAL:
5950 5950                          case EEXIST:
5951 5951                                  return (r);
5952 5952  
5953 5953                          default:
5954 5954                                  bad_error("process_old_pg", r);
5955 5955                          }
5956 5956                          continue;
5957 5957                  }
5958 5958                  if (r != -1)
5959 5959                          bad_error("scf_iter_next_pg", r);
5960 5960  
5961 5961                  switch (scf_error()) {
5962 5962                  case SCF_ERROR_DELETED:
5963 5963                          return (ENODEV);
5964 5964  
5965 5965                  case SCF_ERROR_CONNECTION_BROKEN:
5966 5966                          return (ECONNABORTED);
5967 5967  
5968 5968                  case SCF_ERROR_HANDLE_MISMATCH:
5969 5969                  case SCF_ERROR_NOT_BOUND:
5970 5970                  case SCF_ERROR_NOT_SET:
5971 5971                  case SCF_ERROR_INVALID_ARGUMENT:
5972 5972                  default:
5973 5973                          bad_error("scf_iter_next_pg", scf_error());
5974 5974                  }
5975 5975          }
5976 5976  
5977 5977          for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 5978                  if (pg->sc_pgroup_seen)
5979 5979                          continue;
5980 5980  
5981 5981                  /* pg is new */
5982 5982  
5983 5983                  if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 5984                          r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 5985                              ent);
5986 5986                          switch (r) {
5987 5987                          case 0:
5988 5988                                  break;
5989 5989  
5990 5990                          case ECONNABORTED:
5991 5991                          case ENOMEM:
5992 5992                          case ENOSPC:
5993 5993                          case ECANCELED:
5994 5994                          case ENODEV:
5995 5995                          case EBADF:
5996 5996                          case EBUSY:
5997 5997                          case EINVAL:
5998 5998                          case EPERM:
5999 5999                          case EROFS:
6000 6000                          case EACCES:
6001 6001                          case EEXIST:
6002 6002                                  return (r);
6003 6003  
6004 6004                          default:
6005 6005                                  bad_error("upgrade_dependents", r);
6006 6006                          }
6007 6007                          continue;
6008 6008                  }
6009 6009  
6010 6010                  if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 6011                          r = upgrade_manifestfiles(pg, ient, running, ent);
6012 6012                          switch (r) {
6013 6013                          case 0:
6014 6014                                  break;
6015 6015  
6016 6016                          case ECONNABORTED:
6017 6017                          case ENOMEM:
6018 6018                          case ENOSPC:
6019 6019                          case ECANCELED:
6020 6020                          case ENODEV:
6021 6021                          case EBADF:
6022 6022                          case EBUSY:
6023 6023                          case EINVAL:
6024 6024                          case EPERM:
6025 6025                          case EROFS:
6026 6026                          case EACCES:
6027 6027                          case EEXIST:
6028 6028                                  return (r);
6029 6029  
6030 6030                          default:
6031 6031                                  bad_error("upgrade_manifestfiles", r);
6032 6032                          }
6033 6033                          continue;
6034 6034                  }
6035 6035  
6036 6036                  if (running != NULL) {
6037 6037                          r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 6038                              imp_pg);
6039 6039                  } else {
6040 6040                          r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 6041                              imp_pg);
6042 6042                  }
6043 6043                  if (r != 0) {
6044 6044                          scf_callback_t cbdata;
6045 6045  
6046 6046                          switch (scf_error()) {
6047 6047                          case SCF_ERROR_NOT_FOUND:
6048 6048                                  break;
6049 6049  
6050 6050                          case SCF_ERROR_CONNECTION_BROKEN:
6051 6051                                  return (scferror2errno(scf_error()));
6052 6052  
6053 6053                          case SCF_ERROR_DELETED:
6054 6054                                  if (running != NULL)
6055 6055                                          return (ENODEV);
6056 6056                                  else
6057 6057                                          return (scferror2errno(scf_error()));
6058 6058  
6059 6059                          case SCF_ERROR_INVALID_ARGUMENT:
6060 6060                                  warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 6061                                      pg->sc_pgroup_name);
6062 6062                                  return (EINVAL);
6063 6063  
6064 6064                          case SCF_ERROR_NOT_SET:
6065 6065                          case SCF_ERROR_HANDLE_MISMATCH:
6066 6066                          case SCF_ERROR_NOT_BOUND:
6067 6067                          default:
6068 6068                                  bad_error("entity_get_pg", scf_error());
6069 6069                          }
6070 6070  
6071 6071                          /* User doesn't have pg, so import it. */
6072 6072  
6073 6073                          cbdata.sc_handle = g_hndl;
6074 6074                          cbdata.sc_parent = ent;
6075 6075                          cbdata.sc_service = issvc;
6076 6076                          cbdata.sc_flags = SCI_FORCE;
6077 6077                          cbdata.sc_source_fmri = ient->sc_fmri;
6078 6078                          cbdata.sc_target_fmri = ient->sc_fmri;
6079 6079  
6080 6080                          r = entity_pgroup_import(pg, &cbdata);
6081 6081                          switch (r) {
6082 6082                          case UU_WALK_NEXT:
6083 6083                                  ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 6084                                  continue;
6085 6085  
6086 6086                          case UU_WALK_ERROR:
6087 6087                                  if (cbdata.sc_err == EEXIST) {
6088 6088                                          warn(emsg_pg_added, ient->sc_fmri,
6089 6089                                              pg->sc_pgroup_name);
6090 6090                                          return (EBUSY);
6091 6091                                  }
6092 6092                                  return (cbdata.sc_err);
6093 6093  
6094 6094                          default:
6095 6095                                  bad_error("entity_pgroup_import", r);
6096 6096                          }
6097 6097                  }
6098 6098  
6099 6099                  /* report differences between pg & current */
6100 6100                  r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 6101                  switch (r) {
6102 6102                  case 0:
6103 6103                          break;
6104 6104  
6105 6105                  case ECANCELED:
6106 6106                          warn(emsg_pg_deleted, ient->sc_fmri,
6107 6107                              pg->sc_pgroup_name);
6108 6108                          return (EBUSY);
6109 6109  
6110 6110                  case ECONNABORTED:
6111 6111                  case EBADF:
6112 6112                  case ENOMEM:
6113 6113                  case EACCES:
6114 6114                          return (r);
6115 6115  
6116 6116                  default:
6117 6117                          bad_error("load_pg", r);
6118 6118                  }
6119 6119                  report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 6120                  internal_pgroup_free(rpg);
6121 6121                  rpg = NULL;
6122 6122          }
6123 6123  
6124 6124          return (0);
6125 6125  }
6126 6126  
6127 6127  /*
6128 6128   * Import an instance.  If it doesn't exist, create it.  If it has
6129 6129   * a last-import snapshot, upgrade its properties.  Finish by updating its
6130 6130   * last-import snapshot.  If it doesn't have a last-import snapshot then it
6131 6131   * could have been created for a dependent tag in another manifest.  Import the
6132 6132   * new properties.  If there's a conflict, don't override, like now?
6133 6133   *
6134 6134   * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6135 6135   * lcbdata->sc_err to
6136 6136   *   ECONNABORTED - repository connection broken
6137 6137   *   ENOMEM - out of memory
6138 6138   *   ENOSPC - svc.configd is out of resources
6139 6139   *   EEXIST - dependency collision in dependent service (error printed)
6140 6140   *   EPERM - couldn't create temporary instance (permission denied)
6141 6141   *         - couldn't import into temporary instance (permission denied)
6142 6142   *         - couldn't take snapshot (permission denied)
6143 6143   *         - couldn't upgrade properties (permission denied)
6144 6144   *         - couldn't import properties (permission denied)
6145 6145   *         - couldn't import dependents (permission denied)
6146 6146   *   EROFS - couldn't create temporary instance (repository read-only)
6147 6147   *         - couldn't import into temporary instance (repository read-only)
6148 6148   *         - couldn't upgrade properties (repository read-only)
6149 6149   *         - couldn't import properties (repository read-only)
6150 6150   *         - couldn't import dependents (repository read-only)
6151 6151   *   EACCES - couldn't create temporary instance (backend access denied)
6152 6152   *          - couldn't import into temporary instance (backend access denied)
6153 6153   *          - couldn't upgrade properties (backend access denied)
6154 6154   *          - couldn't import properties (backend access denied)
6155 6155   *          - couldn't import dependents (backend access denied)
6156 6156   *   EINVAL - invalid instance name (error printed)
6157 6157   *          - invalid pgroup_t's (error printed)
6158 6158   *          - invalid dependents (error printed)
6159 6159   *   EBUSY - temporary service deleted (error printed)
6160 6160   *         - temporary instance deleted (error printed)
6161 6161   *         - temporary instance changed (error printed)
6162 6162   *         - temporary instance already exists (error printed)
6163 6163   *         - instance deleted (error printed)
6164 6164   *   EBADF - instance has corrupt last-import snapshot (error printed)
6165 6165   *         - instance is corrupt (error printed)
6166 6166   *         - dependent has corrupt pg (error printed)
6167 6167   *         - dependent target has a corrupt snapshot (error printed)
6168 6168   *   -1 - unknown libscf error (error printed)
6169 6169   */
6170 6170  static int
6171 6171  lscf_instance_import(void *v, void *pvt)
6172 6172  {
6173 6173          entity_t *inst = v;
6174 6174          scf_callback_t ctx;
6175 6175          scf_callback_t *lcbdata = pvt;
6176 6176          scf_service_t *rsvc = lcbdata->sc_parent;
6177 6177          int r;
6178 6178          scf_snaplevel_t *running;
6179 6179          int flags = lcbdata->sc_flags;
6180 6180  
6181 6181          const char * const emsg_tdel =
6182 6182              gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 6183          const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 6184              "changed unexpectedly.\n");
6185 6185          const char * const emsg_del = gettext("%s changed unexpectedly "
6186 6186              "(instance \"%s\" was deleted.)\n");
6187 6187          const char * const emsg_badsnap = gettext(
6188 6188              "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 6189  
6190 6190          /*
6191 6191           * prepare last-import snapshot:
6192 6192           * create temporary instance (service was precreated)
6193 6193           * populate with properties from bundle
6194 6194           * take snapshot
6195 6195           */
6196 6196          if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 6197                  switch (scf_error()) {
6198 6198                  case SCF_ERROR_CONNECTION_BROKEN:
6199 6199                  case SCF_ERROR_NO_RESOURCES:
6200 6200                  case SCF_ERROR_BACKEND_READONLY:
6201 6201                  case SCF_ERROR_BACKEND_ACCESS:
6202 6202                          return (stash_scferror(lcbdata));
6203 6203  
6204 6204                  case SCF_ERROR_EXISTS:
6205 6205                          warn(gettext("Temporary service svc:/%s "
6206 6206                              "changed unexpectedly (instance \"%s\" added).\n"),
6207 6207                              imp_tsname, inst->sc_name);
6208 6208                          lcbdata->sc_err = EBUSY;
6209 6209                          return (UU_WALK_ERROR);
6210 6210  
6211 6211                  case SCF_ERROR_DELETED:
6212 6212                          warn(gettext("Temporary service svc:/%s "
6213 6213                              "was deleted unexpectedly.\n"), imp_tsname);
6214 6214                          lcbdata->sc_err = EBUSY;
6215 6215                          return (UU_WALK_ERROR);
6216 6216  
6217 6217                  case SCF_ERROR_INVALID_ARGUMENT:
6218 6218                          warn(gettext("Invalid instance name \"%s\".\n"),
6219 6219                              inst->sc_name);
6220 6220                          return (stash_scferror(lcbdata));
6221 6221  
6222 6222                  case SCF_ERROR_PERMISSION_DENIED:
6223 6223                          warn(gettext("Could not create temporary instance "
6224 6224                              "\"%s\" in svc:/%s (permission denied).\n"),
6225 6225                              inst->sc_name, imp_tsname);
6226 6226                          return (stash_scferror(lcbdata));
6227 6227  
6228 6228                  case SCF_ERROR_HANDLE_MISMATCH:
6229 6229                  case SCF_ERROR_NOT_BOUND:
6230 6230                  case SCF_ERROR_NOT_SET:
6231 6231                  default:
6232 6232                          bad_error("scf_service_add_instance", scf_error());
6233 6233                  }
6234 6234          }
6235 6235  
6236 6236          r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 6237              inst->sc_name);
6238 6238          if (r < 0)
6239 6239                  bad_error("snprintf", errno);
6240 6240  
6241 6241          r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 6242              lcbdata->sc_flags | SCI_NOENABLED);
6243 6243          switch (r) {
6244 6244          case 0:
6245 6245                  break;
6246 6246  
6247 6247          case ECANCELED:
6248 6248                  warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 6249                  lcbdata->sc_err = EBUSY;
6250 6250                  r = UU_WALK_ERROR;
6251 6251                  goto deltemp;
6252 6252  
6253 6253          case EEXIST:
6254 6254                  warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 6255                  lcbdata->sc_err = EBUSY;
6256 6256                  r = UU_WALK_ERROR;
6257 6257                  goto deltemp;
6258 6258  
6259 6259          case ECONNABORTED:
6260 6260                  goto connaborted;
6261 6261  
6262 6262          case ENOMEM:
6263 6263          case ENOSPC:
6264 6264          case EPERM:
6265 6265          case EROFS:
6266 6266          case EACCES:
6267 6267          case EINVAL:
6268 6268          case EBUSY:
6269 6269                  lcbdata->sc_err = r;
6270 6270                  r = UU_WALK_ERROR;
6271 6271                  goto deltemp;
6272 6272  
6273 6273          default:
6274 6274                  bad_error("lscf_import_instance_pgs", r);
6275 6275          }
6276 6276  
6277 6277          r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 6278              inst->sc_name);
6279 6279          if (r < 0)
6280 6280                  bad_error("snprintf", errno);
6281 6281  
6282 6282          ctx.sc_handle = lcbdata->sc_handle;
6283 6283          ctx.sc_parent = imp_tinst;
6284 6284          ctx.sc_service = 0;
6285 6285          ctx.sc_source_fmri = inst->sc_fmri;
6286 6286          ctx.sc_target_fmri = imp_str;
6287 6287          if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 6288              UU_DEFAULT) != 0) {
6289 6289                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 6290                          bad_error("uu_list_walk", uu_error());
6291 6291  
6292 6292                  switch (ctx.sc_err) {
6293 6293                  case ECONNABORTED:
6294 6294                          goto connaborted;
6295 6295  
6296 6296                  case ECANCELED:
6297 6297                          warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 6298                          lcbdata->sc_err = EBUSY;
6299 6299                          break;
6300 6300  
6301 6301                  case EEXIST:
6302 6302                          warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 6303                          lcbdata->sc_err = EBUSY;
6304 6304                          break;
6305 6305  
6306 6306                  default:
6307 6307                          lcbdata->sc_err = ctx.sc_err;
6308 6308                  }
6309 6309                  r = UU_WALK_ERROR;
6310 6310                  goto deltemp;
6311 6311          }
6312 6312  
6313 6313          if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 6314              inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 6315                  switch (scf_error()) {
6316 6316                  case SCF_ERROR_CONNECTION_BROKEN:
6317 6317                          goto connaborted;
6318 6318  
6319 6319                  case SCF_ERROR_NO_RESOURCES:
6320 6320                          r = stash_scferror(lcbdata);
6321 6321                          goto deltemp;
6322 6322  
6323 6323                  case SCF_ERROR_EXISTS:
6324 6324                          warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 6325                          lcbdata->sc_err = EBUSY;
6326 6326                          r = UU_WALK_ERROR;
6327 6327                          goto deltemp;
6328 6328  
6329 6329                  case SCF_ERROR_PERMISSION_DENIED:
6330 6330                          warn(gettext("Could not take \"%s\" snapshot of %s "
6331 6331                              "(permission denied).\n"), snap_lastimport,
6332 6332                              imp_str);
6333 6333                          r = stash_scferror(lcbdata);
6334 6334                          goto deltemp;
6335 6335  
6336 6336                  default:
6337 6337                          scfwarn();
6338 6338                          lcbdata->sc_err = -1;
6339 6339                          r = UU_WALK_ERROR;
6340 6340                          goto deltemp;
6341 6341  
6342 6342                  case SCF_ERROR_HANDLE_MISMATCH:
6343 6343                  case SCF_ERROR_INVALID_ARGUMENT:
6344 6344                  case SCF_ERROR_NOT_SET:
6345 6345                          bad_error("_scf_snapshot_take_new_named", scf_error());
6346 6346                  }
6347 6347          }
6348 6348  
6349 6349          if (lcbdata->sc_flags & SCI_FRESH)
6350 6350                  goto fresh;
6351 6351  
6352 6352          if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 6353                  if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 6354                      imp_lisnap) != 0) {
6355 6355                          switch (scf_error()) {
6356 6356                          case SCF_ERROR_DELETED:
6357 6357                                  warn(emsg_del, inst->sc_parent->sc_fmri,
6358 6358                                      inst->sc_name);
6359 6359                                  lcbdata->sc_err = EBUSY;
6360 6360                                  r = UU_WALK_ERROR;
6361 6361                                  goto deltemp;
6362 6362  
6363 6363                          case SCF_ERROR_NOT_FOUND:
6364 6364                                  flags |= SCI_FORCE;
6365 6365                                  goto nosnap;
6366 6366  
6367 6367                          case SCF_ERROR_CONNECTION_BROKEN:
6368 6368                                  goto connaborted;
6369 6369  
6370 6370                          case SCF_ERROR_INVALID_ARGUMENT:
6371 6371                          case SCF_ERROR_HANDLE_MISMATCH:
6372 6372                          case SCF_ERROR_NOT_BOUND:
6373 6373                          case SCF_ERROR_NOT_SET:
6374 6374                          default:
6375 6375                                  bad_error("scf_instance_get_snapshot",
6376 6376                                      scf_error());
6377 6377                          }
6378 6378                  }
6379 6379  
6380 6380                  /* upgrade */
6381 6381  
6382 6382                  /*
6383 6383                   * compare new properties with last-import properties
6384 6384                   * upgrade current properties
6385 6385                   */
6386 6386                  /* clear sc_sceen for pgs */
6387 6387                  if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 6388                      (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389 6389                      0)
6390 6390                          bad_error("uu_list_walk", uu_error());
6391 6391  
6392 6392                  r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 6393                  switch (r) {
6394 6394                  case 0:
6395 6395                          break;
6396 6396  
6397 6397                  case ECONNABORTED:
6398 6398                          goto connaborted;
6399 6399  
6400 6400                  case ECANCELED:
6401 6401                          warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 6402                          lcbdata->sc_err = EBUSY;
6403 6403                          r = UU_WALK_ERROR;
6404 6404                          goto deltemp;
6405 6405  
6406 6406                  case ENOENT:
6407 6407                          warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 6408                          lcbdata->sc_err = EBADF;
6409 6409                          r = UU_WALK_ERROR;
6410 6410                          goto deltemp;
6411 6411  
6412 6412                  default:
6413 6413                          bad_error("get_snaplevel", r);
6414 6414                  }
6415 6415  
6416 6416                  if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 6417                      imp_rsnap) != 0) {
6418 6418                          switch (scf_error()) {
6419 6419                          case SCF_ERROR_DELETED:
6420 6420                                  warn(emsg_del, inst->sc_parent->sc_fmri,
6421 6421                                      inst->sc_name);
6422 6422                                  lcbdata->sc_err = EBUSY;
6423 6423                                  r = UU_WALK_ERROR;
6424 6424                                  goto deltemp;
6425 6425  
6426 6426                          case SCF_ERROR_NOT_FOUND:
6427 6427                                  break;
6428 6428  
6429 6429                          case SCF_ERROR_CONNECTION_BROKEN:
6430 6430                                  goto connaborted;
6431 6431  
6432 6432                          case SCF_ERROR_INVALID_ARGUMENT:
6433 6433                          case SCF_ERROR_HANDLE_MISMATCH:
6434 6434                          case SCF_ERROR_NOT_BOUND:
6435 6435                          case SCF_ERROR_NOT_SET:
6436 6436                          default:
6437 6437                                  bad_error("scf_instance_get_snapshot",
6438 6438                                      scf_error());
6439 6439                          }
6440 6440  
6441 6441                          running = NULL;
6442 6442                  } else {
6443 6443                          r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 6444                          switch (r) {
6445 6445                          case 0:
6446 6446                                  running = imp_rsnpl;
6447 6447                                  break;
6448 6448  
6449 6449                          case ECONNABORTED:
6450 6450                                  goto connaborted;
6451 6451  
6452 6452                          case ECANCELED:
6453 6453                                  warn(emsg_del, inst->sc_parent->sc_fmri,
6454 6454                                      inst->sc_name);
6455 6455                                  lcbdata->sc_err = EBUSY;
6456 6456                                  r = UU_WALK_ERROR;
6457 6457                                  goto deltemp;
6458 6458  
6459 6459                          case ENOENT:
6460 6460                                  warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 6461                                  lcbdata->sc_err = EBADF;
6462 6462                                  r = UU_WALK_ERROR;
6463 6463                                  goto deltemp;
6464 6464  
6465 6465                          default:
6466 6466                                  bad_error("get_snaplevel", r);
6467 6467                          }
6468 6468                  }
6469 6469  
6470 6470                  r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 6471                  switch (r) {
6472 6472                  case 0:
6473 6473                          break;
6474 6474  
6475 6475                  case ECANCELED:
6476 6476                  case ENODEV:
6477 6477                          warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 6478                          lcbdata->sc_err = EBUSY;
6479 6479                          r = UU_WALK_ERROR;
6480 6480                          goto deltemp;
6481 6481  
6482 6482                  case ECONNABORTED:
6483 6483                          goto connaborted;
6484 6484  
6485 6485                  case ENOMEM:
6486 6486                  case ENOSPC:
6487 6487                  case EBADF:
6488 6488                  case EBUSY:
6489 6489                  case EINVAL:
6490 6490                  case EPERM:
6491 6491                  case EROFS:
6492 6492                  case EACCES:
6493 6493                  case EEXIST:
6494 6494                          lcbdata->sc_err = r;
6495 6495                          r = UU_WALK_ERROR;
6496 6496                          goto deltemp;
6497 6497  
6498 6498                  default:
6499 6499                          bad_error("upgrade_props", r);
6500 6500                  }
6501 6501  
6502 6502                  inst->sc_import_state = IMPORT_PROP_DONE;
6503 6503          } else {
6504 6504                  switch (scf_error()) {
6505 6505                  case SCF_ERROR_CONNECTION_BROKEN:
6506 6506                          goto connaborted;
6507 6507  
6508 6508                  case SCF_ERROR_NOT_FOUND:
6509 6509                          break;
6510 6510  
6511 6511                  case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
6512 6512                  case SCF_ERROR_HANDLE_MISMATCH:
6513 6513                  case SCF_ERROR_NOT_BOUND:
6514 6514                  case SCF_ERROR_NOT_SET:
6515 6515                  default:
6516 6516                          bad_error("scf_service_get_instance", scf_error());
6517 6517                  }
6518 6518  
6519 6519  fresh:
6520 6520                  /* create instance */
6521 6521                  if (scf_service_add_instance(rsvc, inst->sc_name,
6522 6522                      imp_inst) != 0) {
6523 6523                          switch (scf_error()) {
6524 6524                          case SCF_ERROR_CONNECTION_BROKEN:
6525 6525                                  goto connaborted;
6526 6526  
6527 6527                          case SCF_ERROR_NO_RESOURCES:
6528 6528                          case SCF_ERROR_BACKEND_READONLY:
6529 6529                          case SCF_ERROR_BACKEND_ACCESS:
6530 6530                                  r = stash_scferror(lcbdata);
6531 6531                                  goto deltemp;
6532 6532  
6533 6533                          case SCF_ERROR_EXISTS:
6534 6534                                  warn(gettext("%s changed unexpectedly "
6535 6535                                      "(instance \"%s\" added).\n"),
6536 6536                                      inst->sc_parent->sc_fmri, inst->sc_name);
6537 6537                                  lcbdata->sc_err = EBUSY;
6538 6538                                  r = UU_WALK_ERROR;
6539 6539                                  goto deltemp;
6540 6540  
6541 6541                          case SCF_ERROR_PERMISSION_DENIED:
6542 6542                                  warn(gettext("Could not create \"%s\" instance "
6543 6543                                      "in %s (permission denied).\n"),
6544 6544                                      inst->sc_name, inst->sc_parent->sc_fmri);
6545 6545                                  r = stash_scferror(lcbdata);
6546 6546                                  goto deltemp;
6547 6547  
6548 6548                          case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6549 6549                          case SCF_ERROR_HANDLE_MISMATCH:
6550 6550                          case SCF_ERROR_NOT_BOUND:
6551 6551                          case SCF_ERROR_NOT_SET:
6552 6552                          default:
6553 6553                                  bad_error("scf_service_add_instance",
6554 6554                                      scf_error());
6555 6555                          }
6556 6556                  }
6557 6557  
6558 6558  nosnap:
6559 6559                  /*
6560 6560                   * Create a last-import snapshot to serve as an attachment
6561 6561                   * point for the real one from the temporary instance.  Since
6562 6562                   * the contents is irrelevant, take it now, while the instance
6563 6563                   * is empty, to minimize svc.configd's work.
6564 6564                   */
6565 6565                  if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 6566                      imp_lisnap) != 0) {
6567 6567                          switch (scf_error()) {
6568 6568                          case SCF_ERROR_CONNECTION_BROKEN:
6569 6569                                  goto connaborted;
6570 6570  
6571 6571                          case SCF_ERROR_NO_RESOURCES:
6572 6572                                  r = stash_scferror(lcbdata);
6573 6573                                  goto deltemp;
6574 6574  
6575 6575                          case SCF_ERROR_EXISTS:
6576 6576                                  warn(gettext("%s changed unexpectedly "
6577 6577                                      "(snapshot \"%s\" added).\n"),
6578 6578                                      inst->sc_fmri, snap_lastimport);
6579 6579                                  lcbdata->sc_err = EBUSY;
6580 6580                                  r = UU_WALK_ERROR;
6581 6581                                  goto deltemp;
6582 6582  
6583 6583                          case SCF_ERROR_PERMISSION_DENIED:
6584 6584                                  warn(gettext("Could not take \"%s\" snapshot "
6585 6585                                      "of %s (permission denied).\n"),
6586 6586                                      snap_lastimport, inst->sc_fmri);
6587 6587                                  r = stash_scferror(lcbdata);
6588 6588                                  goto deltemp;
6589 6589  
6590 6590                          default:
6591 6591                                  scfwarn();
6592 6592                                  lcbdata->sc_err = -1;
6593 6593                                  r = UU_WALK_ERROR;
6594 6594                                  goto deltemp;
6595 6595  
6596 6596                          case SCF_ERROR_NOT_SET:
6597 6597                          case SCF_ERROR_INTERNAL:
6598 6598                          case SCF_ERROR_INVALID_ARGUMENT:
6599 6599                          case SCF_ERROR_HANDLE_MISMATCH:
6600 6600                                  bad_error("_scf_snapshot_take_new",
6601 6601                                      scf_error());
6602 6602                          }
6603 6603                  }
6604 6604  
6605 6605                  if (li_only)
6606 6606                          goto lionly;
6607 6607  
6608 6608                  inst->sc_import_state = IMPORT_PROP_BEGUN;
6609 6609  
6610 6610                  r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 6611                      flags);
6612 6612                  switch (r) {
6613 6613                  case 0:
6614 6614                          break;
6615 6615  
6616 6616                  case ECONNABORTED:
6617 6617                          goto connaborted;
6618 6618  
6619 6619                  case ECANCELED:
6620 6620                          warn(gettext("%s changed unexpectedly "
6621 6621                              "(instance \"%s\" deleted).\n"),
6622 6622                              inst->sc_parent->sc_fmri, inst->sc_name);
6623 6623                          lcbdata->sc_err = EBUSY;
6624 6624                          r = UU_WALK_ERROR;
6625 6625                          goto deltemp;
6626 6626  
6627 6627                  case EEXIST:
6628 6628                          warn(gettext("%s changed unexpectedly "
6629 6629                              "(property group added).\n"), inst->sc_fmri);
6630 6630                          lcbdata->sc_err = EBUSY;
6631 6631                          r = UU_WALK_ERROR;
6632 6632                          goto deltemp;
6633 6633  
6634 6634                  default:
6635 6635                          lcbdata->sc_err = r;
6636 6636                          r = UU_WALK_ERROR;
6637 6637                          goto deltemp;
6638 6638  
6639 6639                  case EINVAL:    /* caught above */
6640 6640                          bad_error("lscf_import_instance_pgs", r);
6641 6641                  }
6642 6642  
6643 6643                  ctx.sc_parent = imp_inst;
6644 6644                  ctx.sc_service = 0;
6645 6645                  ctx.sc_trans = NULL;
6646 6646                  ctx.sc_flags = 0;
6647 6647                  if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 6648                      &ctx, UU_DEFAULT) != 0) {
6649 6649                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 6650                                  bad_error("uu_list_walk", uu_error());
6651 6651  
6652 6652                          if (ctx.sc_err == ECONNABORTED)
6653 6653                                  goto connaborted;
6654 6654                          lcbdata->sc_err = ctx.sc_err;
6655 6655                          r = UU_WALK_ERROR;
6656 6656                          goto deltemp;
6657 6657                  }
6658 6658  
6659 6659                  inst->sc_import_state = IMPORT_PROP_DONE;
6660 6660  
6661 6661                  if (g_verbose)
6662 6662                          warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 6663                              snap_initial, inst->sc_fmri);
6664 6664                  r = take_snap(imp_inst, snap_initial, imp_snap);
6665 6665                  switch (r) {
6666 6666                  case 0:
6667 6667                          break;
6668 6668  
6669 6669                  case ECONNABORTED:
6670 6670                          goto connaborted;
6671 6671  
6672 6672                  case ENOSPC:
6673 6673                  case -1:
6674 6674                          lcbdata->sc_err = r;
6675 6675                          r = UU_WALK_ERROR;
6676 6676                          goto deltemp;
6677 6677  
6678 6678                  case ECANCELED:
6679 6679                          warn(gettext("%s changed unexpectedly "
6680 6680                              "(instance %s deleted).\n"),
6681 6681                              inst->sc_parent->sc_fmri, inst->sc_name);
6682 6682                          lcbdata->sc_err = r;
6683 6683                          r = UU_WALK_ERROR;
6684 6684                          goto deltemp;
6685 6685  
6686 6686                  case EPERM:
6687 6687                          warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 6688                          lcbdata->sc_err = r;
6689 6689                          r = UU_WALK_ERROR;
6690 6690                          goto deltemp;
6691 6691  
6692 6692                  default:
6693 6693                          bad_error("take_snap", r);
6694 6694                  }
6695 6695          }
6696 6696  
6697 6697  lionly:
6698 6698          if (lcbdata->sc_flags & SCI_NOSNAP)
6699 6699                  goto deltemp;
6700 6700  
6701 6701          /* transfer snapshot from temporary instance */
6702 6702          if (g_verbose)
6703 6703                  warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 6704                      snap_lastimport, inst->sc_fmri);
6705 6705          if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 6706                  switch (scf_error()) {
6707 6707                  case SCF_ERROR_CONNECTION_BROKEN:
6708 6708                          goto connaborted;
6709 6709  
6710 6710                  case SCF_ERROR_NO_RESOURCES:
6711 6711                          r = stash_scferror(lcbdata);
6712 6712                          goto deltemp;
6713 6713  
6714 6714                  case SCF_ERROR_PERMISSION_DENIED:
6715 6715                          warn(gettext("Could not take \"%s\" snapshot for %s "
6716 6716                              "(permission denied).\n"), snap_lastimport,
6717 6717                              inst->sc_fmri);
6718 6718                          r = stash_scferror(lcbdata);
6719 6719                          goto deltemp;
6720 6720  
6721 6721                  case SCF_ERROR_NOT_SET:
6722 6722                  case SCF_ERROR_HANDLE_MISMATCH:
6723 6723                  default:
6724 6724                          bad_error("_scf_snapshot_attach", scf_error());
6725 6725                  }
6726 6726          }
6727 6727  
6728 6728          inst->sc_import_state = IMPORT_COMPLETE;
6729 6729  
6730 6730          r = UU_WALK_NEXT;
6731 6731  
6732 6732  deltemp:
6733 6733          /* delete temporary instance */
6734 6734          if (scf_instance_delete(imp_tinst) != 0) {
6735 6735                  switch (scf_error()) {
6736 6736                  case SCF_ERROR_DELETED:
6737 6737                          break;
6738 6738  
6739 6739                  case SCF_ERROR_CONNECTION_BROKEN:
6740 6740                          goto connaborted;
6741 6741  
6742 6742                  case SCF_ERROR_NOT_SET:
6743 6743                  case SCF_ERROR_NOT_BOUND:
6744 6744                  default:
6745 6745                          bad_error("scf_instance_delete", scf_error());
6746 6746                  }
6747 6747          }
6748 6748  
6749 6749          return (r);
6750 6750  
6751 6751  connaborted:
6752 6752          warn(gettext("Could not delete svc:/%s:%s "
6753 6753              "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 6754          lcbdata->sc_err = ECONNABORTED;
6755 6755          return (UU_WALK_ERROR);
6756 6756  }
6757 6757  
6758 6758  /*
6759 6759   * When an instance is imported we end up telling configd about it. Once we tell
6760 6760   * configd about these changes, startd eventually notices. If this is a new
6761 6761   * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 6762   * property group. However, many of the other tools expect that this property
6763 6763   * group exists and has certain values.
6764 6764   *
6765 6765   * These values are added asynchronously by startd. We should not return from
6766 6766   * this routine until we can verify that the property group we need is there.
6767 6767   *
6768 6768   * Before we go ahead and verify this, we have to ask ourselves an important
6769 6769   * question: Is the early manifest service currently running?  Because if it is
6770 6770   * running and it has invoked us, then the service will never get a restarter
6771 6771   * property because svc.startd is blocked on EMI finishing before it lets itself
6772 6772   * fully connect to svc.configd. Of course, this means that this race condition
6773 6773   * is in fact impossible to 100% eliminate.
6774 6774   *
6775 6775   * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 6776   * the state of the EMI instance. If it is online it bails out and makes sure
6777 6777   * that it doesn't run again. In this case, we're going to do something similar,
6778 6778   * only if the state is online, then we're going to actually verify. EMI always
6779 6779   * has to be present, but it can be explicitly disabled to reduce the amount of
6780 6780   * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 6781   * about the implicit race condition and can go ahead and check things. If EMI
6782 6782   * is in some state that isn't online or disabled and isn't runinng, then we
6783 6783   * assume that things are rather bad and we're not going to get in your way,
6784 6784   * even if the rest of SMF does.
6785 6785   *
6786 6786   * Returns 0 on success or returns an errno.
6787 6787   */
6788 6788  #ifndef NATIVE_BUILD
6789 6789  static int
6790 6790  lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 6791  {
6792 6792          int ret, err;
6793 6793          struct timespec ts;
6794 6794          char *emi_state;
6795 6795  
6796 6796          /*
6797 6797           * smf_get_state does not distinguish between its different failure
6798 6798           * modes: memory allocation failures, SMF internal failures, and a lack
6799 6799           * of EMI entirely because it's been removed. In these cases, we're
6800 6800           * going to be conservative and opt to say that if we don't know, better
6801 6801           * to not block import or falsely warn to the user.
6802 6802           */
6803 6803          if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804 6804                  return (0);
6805 6805          }
6806 6806  
6807 6807          /*
6808 6808           * As per the block comment for this function check the state of EMI
6809 6809           */
6810 6810          if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811 6811              strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812 6812                  warn(gettext("Not validating instance %s:%s because EMI's "
6813 6813                      "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814 6814                  free(emi_state);
6815 6815                  return (0);
6816 6816          }
6817 6817  
6818 6818          free(emi_state);
6819 6819  
6820 6820          /*
6821 6821           * First we have to get the property.
6822 6822           */
6823 6823          if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824 6824                  ret = scf_error();
6825 6825                  warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826 6826                  return (ret);
6827 6827          }
6828 6828  
6829 6829          /*
6830 6830           * We should always be able to get the instance. It should already
6831 6831           * exist because we just created it or got it. There probably is a
6832 6832           * slim chance that someone may have come in and deleted it though from
6833 6833           * under us.
6834 6834           */
6835 6835          if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836 6836              != 0) {
6837 6837                  ret = scf_error();
6838 6838                  warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839 6839                  switch (ret) {
6840 6840                  case SCF_ERROR_DELETED:
6841 6841                          err = ENODEV;
6842 6842                          break;
6843 6843                  case SCF_ERROR_CONNECTION_BROKEN:
6844 6844                          warn(gettext("Lost repository connection\n"));
6845 6845                          err = ECONNABORTED;
6846 6846                          break;
6847 6847                  case SCF_ERROR_NOT_FOUND:
6848 6848                          warn(gettext("Instance \"%s\" disappeared out from "
6849 6849                              "under us.\n"), inst->sc_name);
6850 6850                          err = ENOENT;
6851 6851                          break;
6852 6852                  default:
6853 6853                          bad_error("scf_service_get_instance", ret);
6854 6854                  }
6855 6855  
6856 6856                  return (err);
6857 6857          }
6858 6858  
6859 6859          /*
6860 6860           * An astute observer may want to use _scf_wait_pg which would notify us
6861 6861           * of a property group change, unfortunately that does not work if the
6862 6862           * property group in question does not exist. So instead we have to
6863 6863           * manually poll and ask smf the best way to get to it.
6864 6864           */
6865 6865          while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866 6866              != SCF_SUCCESS) {
6867 6867                  ret = scf_error();
6868 6868                  if (ret != SCF_ERROR_NOT_FOUND) {
6869 6869                          warn(gettext("Failed to get restarter property "
6870 6870                              "group for instance: %s\n"), inst->sc_name);
6871 6871                          switch (ret) {
6872 6872                          case SCF_ERROR_DELETED:
6873 6873                                  err = ENODEV;
6874 6874                                  break;
6875 6875                          case SCF_ERROR_CONNECTION_BROKEN:
6876 6876                                  warn(gettext("Lost repository connection\n"));
6877 6877                                  err = ECONNABORTED;
6878 6878                                  break;
6879 6879                          default:
6880 6880                                  bad_error("scf_service_get_instance", ret);
6881 6881                          }
6882 6882  
6883 6883                          return (err);
6884 6884                  }
6885 6885  
6886 6886                  ts.tv_sec = pg_timeout / NANOSEC;
6887 6887                  ts.tv_nsec = pg_timeout % NANOSEC;
6888 6888  
6889 6889                  (void) nanosleep(&ts, NULL);
6890 6890          }
6891 6891  
6892 6892          /*
6893 6893           * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894 6894           * So in addition to the property group being present, we need to wait
6895 6895           * for the property to be there in some form.
6896 6896           *
6897 6897           * Note that a property group is a frozen snapshot in time. To properly
6898 6898           * get beyond this, you have to refresh the property group each time.
6899 6899           */
6900 6900          while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901 6901              imp_prop)) != 0) {
6902 6902  
6903 6903                  ret = scf_error();
6904 6904                  if (ret != SCF_ERROR_NOT_FOUND) {
6905 6905                          warn(gettext("Failed to get property %s from the "
6906 6906                              "restarter property group of instance %s\n"),
6907 6907                              SCF_PROPERTY_STATE, inst->sc_name);
6908 6908                          switch (ret) {
6909 6909                          case SCF_ERROR_CONNECTION_BROKEN:
6910 6910                                  warn(gettext("Lost repository connection\n"));
6911 6911                                  err = ECONNABORTED;
6912 6912                                  break;
6913 6913                          case SCF_ERROR_DELETED:
6914 6914                                  err = ENODEV;
6915 6915                                  break;
6916 6916                          default:
6917 6917                                  bad_error("scf_pg_get_property", ret);
6918 6918                          }
6919 6919  
6920 6920                          return (err);
6921 6921                  }
6922 6922  
6923 6923                  ts.tv_sec = pg_timeout / NANOSEC;
6924 6924                  ts.tv_nsec = pg_timeout % NANOSEC;
6925 6925  
6926 6926                  (void) nanosleep(&ts, NULL);
6927 6927  
6928 6928                  ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929 6929                  if (ret != SCF_SUCCESS) {
6930 6930                          warn(gettext("Failed to get restarter property "
6931 6931                              "group for instance: %s\n"), inst->sc_name);
6932 6932                          switch (ret) {
6933 6933                          case SCF_ERROR_DELETED:
6934 6934                                  err = ENODEV;
6935 6935                                  break;
6936 6936                          case SCF_ERROR_CONNECTION_BROKEN:
6937 6937                                  warn(gettext("Lost repository connection\n"));
6938 6938                                  err = ECONNABORTED;
6939 6939                                  break;
6940 6940                          default:
6941 6941                                  bad_error("scf_service_get_instance", ret);
6942 6942                          }
6943 6943  
6944 6944                          return (err);
6945 6945                  }
6946 6946          }
6947 6947  
6948 6948          /*
6949 6949           * We don't have to free the property groups or other values that we got
6950 6950           * because we stored them in global variables that are allocated and
6951 6951           * freed by the routines that call into these functions. Unless of
6952 6952           * course the rest of the code here that we are basing this on is
6953 6953           * mistaken.
6954 6954           */
6955 6955          return (0);
6956 6956  }
6957 6957  #endif
6958 6958  
6959 6959  /*
6960 6960   * If the service is missing, create it, import its properties, and import the
6961 6961   * instances.  Since the service is brand new, it should be empty, and if we
6962 6962   * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963 6963   *
6964 6964   * If the service exists, we want to upgrade its properties and import the
6965 6965   * instances.  Upgrade requires a last-import snapshot, though, which are
6966 6966   * children of instances, so first we'll have to go through the instances
6967 6967   * looking for a last-import snapshot.  If we don't find one then we'll just
6968 6968   * override-import the service properties (but don't delete existing
6969 6969   * properties: another service might have declared us as a dependent).  Before
6970 6970   * we change anything, though, we want to take the previous snapshots.  We
6971 6971   * also give lscf_instance_import() a leg up on taking last-import snapshots
6972 6972   * by importing the manifest's service properties into a temporary service.
6973 6973   *
6974 6974   * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6975 6975   * sets lcbdata->sc_err to
6976 6976   *   ECONNABORTED - repository connection broken
6977 6977   *   ENOMEM - out of memory
6978 6978   *   ENOSPC - svc.configd is out of resources
6979 6979   *   EPERM - couldn't create temporary service (error printed)
6980 6980   *         - couldn't import into temp service (error printed)
6981 6981   *         - couldn't create service (error printed)
6982 6982   *         - couldn't import dependent (error printed)
6983 6983   *         - couldn't take snapshot (error printed)
6984 6984   *         - couldn't create instance (error printed)
6985 6985   *         - couldn't create, modify, or delete pg (error printed)
6986 6986   *         - couldn't create, modify, or delete dependent (error printed)
6987 6987   *         - couldn't import instance (error printed)
6988 6988   *   EROFS - couldn't create temporary service (repository read-only)
6989 6989   *         - couldn't import into temporary service (repository read-only)
6990 6990   *         - couldn't create service (repository read-only)
6991 6991   *         - couldn't import dependent (repository read-only)
6992 6992   *         - couldn't create instance (repository read-only)
6993 6993   *         - couldn't create, modify, or delete pg or dependent
6994 6994   *         - couldn't import instance (repository read-only)
6995 6995   *   EACCES - couldn't create temporary service (backend access denied)
6996 6996   *          - couldn't import into temporary service (backend access denied)
6997 6997   *          - couldn't create service (backend access denied)
6998 6998   *          - couldn't import dependent (backend access denied)
6999 6999   *          - couldn't create instance (backend access denied)
7000 7000   *          - couldn't create, modify, or delete pg or dependent
7001 7001   *          - couldn't import instance (backend access denied)
7002 7002   *   EINVAL - service name is invalid (error printed)
7003 7003   *          - service name is too long (error printed)
7004 7004   *          - s has invalid pgroup (error printed)
7005 7005   *          - s has invalid dependent (error printed)
7006 7006   *          - instance name is invalid (error printed)
7007 7007   *          - instance entity_t is invalid (error printed)
7008 7008   *   EEXIST - couldn't create temporary service (already exists) (error printed)
7009 7009   *          - couldn't import dependent (dependency pg already exists) (printed)
7010 7010   *          - dependency collision in dependent service (error printed)
7011 7011   *   EBUSY - temporary service deleted (error printed)
7012 7012   *         - property group added to temporary service (error printed)
7013 7013   *         - new property group changed or was deleted (error printed)
7014 7014   *         - service was added unexpectedly (error printed)
7015 7015   *         - service was deleted unexpectedly (error printed)
7016 7016   *         - property group added to new service (error printed)
7017 7017   *         - instance added unexpectedly (error printed)
7018 7018   *         - instance deleted unexpectedly (error printed)
7019 7019   *         - dependent service deleted unexpectedly (error printed)
7020 7020   *         - pg was added, changed, or deleted (error printed)
7021 7021   *         - dependent pg changed (error printed)
7022 7022   *         - temporary instance added, changed, or deleted (error printed)
7023 7023   *   EBADF - a last-import snapshot is corrupt (error printed)
7024 7024   *         - the service is corrupt (error printed)
7025 7025   *         - a dependent is corrupt (error printed)
7026 7026   *         - an instance is corrupt (error printed)
7027 7027   *         - an instance has a corrupt last-import snapshot (error printed)
7028 7028   *         - dependent target has a corrupt snapshot (error printed)
7029 7029   *   -1 - unknown libscf error (error printed)
7030 7030   */
7031 7031  static int
7032 7032  lscf_service_import(void *v, void *pvt)
7033 7033  {
7034 7034          entity_t *s = v;
7035 7035          scf_callback_t cbdata;
7036 7036          scf_callback_t *lcbdata = pvt;
7037 7037          scf_scope_t *scope = lcbdata->sc_parent;
7038 7038          entity_t *inst, linst;
7039 7039          int r;
7040 7040          int fresh = 0;
7041 7041          scf_snaplevel_t *running;
7042 7042          int have_ge = 0;
7043 7043          boolean_t retried = B_FALSE;
7044 7044  
7045 7045          const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046 7046              "was deleted unexpectedly.\n");
7047 7047          const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048 7048              "changed unexpectedly (property group added).\n");
7049 7049          const char * const s_deleted =
7050 7050              gettext("%s was deleted unexpectedly.\n");
7051 7051          const char * const i_deleted =
7052 7052              gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053 7053          const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054 7054              "is corrupt (missing service snaplevel).\n");
7055 7055          const char * const s_mfile_upd =
7056 7056              gettext("Unable to update the manifest file connection "
7057 7057              "for %s\n");
7058 7058  
7059 7059          li_only = 0;
7060 7060          /* Validate the service name */
7061 7061          if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062 7062                  switch (scf_error()) {
7063 7063                  case SCF_ERROR_CONNECTION_BROKEN:
7064 7064                          return (stash_scferror(lcbdata));
7065 7065  
7066 7066                  case SCF_ERROR_INVALID_ARGUMENT:
7067 7067                          warn(gettext("\"%s\" is an invalid service name.  "
7068 7068                              "Cannot import.\n"), s->sc_name);
7069 7069                          return (stash_scferror(lcbdata));
7070 7070  
7071 7071                  case SCF_ERROR_NOT_FOUND:
7072 7072                          break;
7073 7073  
7074 7074                  case SCF_ERROR_HANDLE_MISMATCH:
7075 7075                  case SCF_ERROR_NOT_BOUND:
7076 7076                  case SCF_ERROR_NOT_SET:
7077 7077                  default:
7078 7078                          bad_error("scf_scope_get_service", scf_error());
7079 7079                  }
7080 7080          }
7081 7081  
7082 7082          /* create temporary service */
7083 7083          /*
7084 7084           * the size of the buffer was reduced to max_scf_name_len to prevent
7085 7085           * hitting bug 6681151.  After the bug fix, the size of the buffer
7086 7086           * should be restored to its original value (max_scf_name_len +1)
7087 7087           */
7088 7088          r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089 7089          if (r < 0)
7090 7090                  bad_error("snprintf", errno);
7091 7091          if (r > max_scf_name_len) {
7092 7092                  warn(gettext(
7093 7093                      "Service name \"%s\" is too long.  Cannot import.\n"),
7094 7094                      s->sc_name);
7095 7095                  lcbdata->sc_err = EINVAL;
7096 7096                  return (UU_WALK_ERROR);
7097 7097          }
7098 7098  
7099 7099  retry:
7100 7100          if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101 7101                  switch (scf_error()) {
7102 7102                  case SCF_ERROR_CONNECTION_BROKEN:
7103 7103                  case SCF_ERROR_NO_RESOURCES:
7104 7104                  case SCF_ERROR_BACKEND_READONLY:
7105 7105                  case SCF_ERROR_BACKEND_ACCESS:
7106 7106                          return (stash_scferror(lcbdata));
7107 7107  
7108 7108                  case SCF_ERROR_EXISTS:
7109 7109                          if (!retried) {
7110 7110                                  lscf_delete(imp_tsname, 0);
7111 7111                                  retried = B_TRUE;
7112 7112                                  goto retry;
7113 7113                          }
7114 7114                          warn(gettext(
7115 7115                              "Temporary service \"%s\" must be deleted before "
7116 7116                              "this manifest can be imported.\n"), imp_tsname);
7117 7117                          return (stash_scferror(lcbdata));
7118 7118  
7119 7119                  case SCF_ERROR_PERMISSION_DENIED:
7120 7120                          warn(gettext("Could not create temporary service "
7121 7121                              "\"%s\" (permission denied).\n"), imp_tsname);
7122 7122                          return (stash_scferror(lcbdata));
7123 7123  
7124 7124                  case SCF_ERROR_INVALID_ARGUMENT:
7125 7125                  case SCF_ERROR_HANDLE_MISMATCH:
7126 7126                  case SCF_ERROR_NOT_BOUND:
7127 7127                  case SCF_ERROR_NOT_SET:
7128 7128                  default:
7129 7129                          bad_error("scf_scope_add_service", scf_error());
7130 7130                  }
7131 7131          }
7132 7132  
7133 7133          r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134 7134          if (r < 0)
7135 7135                  bad_error("snprintf", errno);
7136 7136  
7137 7137          cbdata.sc_handle = lcbdata->sc_handle;
7138 7138          cbdata.sc_parent = imp_tsvc;
7139 7139          cbdata.sc_service = 1;
7140 7140          cbdata.sc_source_fmri = s->sc_fmri;
7141 7141          cbdata.sc_target_fmri = imp_str;
7142 7142          cbdata.sc_flags = 0;
7143 7143  
7144 7144          if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145 7145              UU_DEFAULT) != 0) {
7146 7146                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147 7147                          bad_error("uu_list_walk", uu_error());
7148 7148  
7149 7149                  lcbdata->sc_err = cbdata.sc_err;
7150 7150                  switch (cbdata.sc_err) {
7151 7151                  case ECONNABORTED:
7152 7152                          goto connaborted;
7153 7153  
7154 7154                  case ECANCELED:
7155 7155                          warn(ts_deleted, imp_tsname);
7156 7156                          lcbdata->sc_err = EBUSY;
7157 7157                          return (UU_WALK_ERROR);
7158 7158  
7159 7159                  case EEXIST:
7160 7160                          warn(ts_pg_added, imp_tsname);
7161 7161                          lcbdata->sc_err = EBUSY;
7162 7162                          return (UU_WALK_ERROR);
7163 7163                  }
7164 7164  
7165 7165                  r = UU_WALK_ERROR;
7166 7166                  goto deltemp;
7167 7167          }
7168 7168  
7169 7169          if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170 7170              UU_DEFAULT) != 0) {
7171 7171                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172 7172                          bad_error("uu_list_walk", uu_error());
7173 7173  
7174 7174                  lcbdata->sc_err = cbdata.sc_err;
7175 7175                  switch (cbdata.sc_err) {
7176 7176                  case ECONNABORTED:
7177 7177                          goto connaborted;
7178 7178  
7179 7179                  case ECANCELED:
7180 7180                          warn(ts_deleted, imp_tsname);
7181 7181                          lcbdata->sc_err = EBUSY;
7182 7182                          return (UU_WALK_ERROR);
7183 7183  
7184 7184                  case EEXIST:
7185 7185                          warn(ts_pg_added, imp_tsname);
7186 7186                          lcbdata->sc_err = EBUSY;
7187 7187                          return (UU_WALK_ERROR);
7188 7188                  }
7189 7189  
7190 7190                  r = UU_WALK_ERROR;
7191 7191                  goto deltemp;
7192 7192          }
7193 7193  
7194 7194          if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195 7195                  switch (scf_error()) {
7196 7196                  case SCF_ERROR_NOT_FOUND:
7197 7197                          break;
7198 7198  
7199 7199                  case SCF_ERROR_CONNECTION_BROKEN:
7200 7200                          goto connaborted;
7201 7201  
7202 7202                  case SCF_ERROR_INVALID_ARGUMENT:
7203 7203                  case SCF_ERROR_HANDLE_MISMATCH:
7204 7204                  case SCF_ERROR_NOT_BOUND:
7205 7205                  case SCF_ERROR_NOT_SET:
7206 7206                  default:
7207 7207                          bad_error("scf_scope_get_service", scf_error());
7208 7208                  }
7209 7209  
7210 7210                  if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211 7211                          switch (scf_error()) {
7212 7212                          case SCF_ERROR_CONNECTION_BROKEN:
7213 7213                                  goto connaborted;
7214 7214  
7215 7215                          case SCF_ERROR_NO_RESOURCES:
7216 7216                          case SCF_ERROR_BACKEND_READONLY:
7217 7217                          case SCF_ERROR_BACKEND_ACCESS:
7218 7218                                  r = stash_scferror(lcbdata);
7219 7219                                  goto deltemp;
7220 7220  
7221 7221                          case SCF_ERROR_EXISTS:
7222 7222                                  warn(gettext("Scope \"%s\" changed unexpectedly"
7223 7223                                      " (service \"%s\" added).\n"),
7224 7224                                      SCF_SCOPE_LOCAL, s->sc_name);
7225 7225                                  lcbdata->sc_err = EBUSY;
7226 7226                                  goto deltemp;
7227 7227  
7228 7228                          case SCF_ERROR_PERMISSION_DENIED:
7229 7229                                  warn(gettext("Could not create service \"%s\" "
7230 7230                                      "(permission denied).\n"), s->sc_name);
7231 7231                                  goto deltemp;
7232 7232  
7233 7233                          case SCF_ERROR_INVALID_ARGUMENT:
7234 7234                          case SCF_ERROR_HANDLE_MISMATCH:
7235 7235                          case SCF_ERROR_NOT_BOUND:
7236 7236                          case SCF_ERROR_NOT_SET:
7237 7237                          default:
7238 7238                                  bad_error("scf_scope_add_service", scf_error());
7239 7239                          }
7240 7240                  }
7241 7241  
7242 7242                  s->sc_import_state = IMPORT_PROP_BEGUN;
7243 7243  
7244 7244                  /* import service properties */
7245 7245                  cbdata.sc_handle = lcbdata->sc_handle;
7246 7246                  cbdata.sc_parent = imp_svc;
7247 7247                  cbdata.sc_service = 1;
7248 7248                  cbdata.sc_flags = lcbdata->sc_flags;
7249 7249                  cbdata.sc_source_fmri = s->sc_fmri;
7250 7250                  cbdata.sc_target_fmri = s->sc_fmri;
7251 7251  
7252 7252                  if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253 7253                      &cbdata, UU_DEFAULT) != 0) {
7254 7254                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255 7255                                  bad_error("uu_list_walk", uu_error());
7256 7256  
7257 7257                          lcbdata->sc_err = cbdata.sc_err;
7258 7258                          switch (cbdata.sc_err) {
7259 7259                          case ECONNABORTED:
7260 7260                                  goto connaborted;
7261 7261  
7262 7262                          case ECANCELED:
7263 7263                                  warn(s_deleted, s->sc_fmri);
7264 7264                                  lcbdata->sc_err = EBUSY;
7265 7265                                  return (UU_WALK_ERROR);
7266 7266  
7267 7267                          case EEXIST:
7268 7268                                  warn(gettext("%s changed unexpectedly "
7269 7269                                      "(property group added).\n"), s->sc_fmri);
7270 7270                                  lcbdata->sc_err = EBUSY;
7271 7271                                  return (UU_WALK_ERROR);
7272 7272  
7273 7273                          case EINVAL:
7274 7274                                  /* caught above */
7275 7275                                  bad_error("entity_pgroup_import",
7276 7276                                      cbdata.sc_err);
7277 7277                          }
7278 7278  
7279 7279                          r = UU_WALK_ERROR;
7280 7280                          goto deltemp;
7281 7281                  }
7282 7282  
7283 7283                  cbdata.sc_trans = NULL;
7284 7284                  cbdata.sc_flags = 0;
7285 7285                  if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286 7286                      &cbdata, UU_DEFAULT) != 0) {
7287 7287                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288 7288                                  bad_error("uu_list_walk", uu_error());
7289 7289  
7290 7290                          lcbdata->sc_err = cbdata.sc_err;
7291 7291                          if (cbdata.sc_err == ECONNABORTED)
7292 7292                                  goto connaborted;
7293 7293                          r = UU_WALK_ERROR;
7294 7294                          goto deltemp;
7295 7295                  }
7296 7296  
7297 7297                  s->sc_import_state = IMPORT_PROP_DONE;
7298 7298  
7299 7299                  /*
7300 7300                   * This is a new service, so we can't take previous snapshots
7301 7301                   * or upgrade service properties.
7302 7302                   */
7303 7303                  fresh = 1;
7304 7304                  goto instances;
7305 7305          }
7306 7306  
7307 7307          /* Clear sc_seen for the instances. */
7308 7308          if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309 7309              (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310 7310                  bad_error("uu_list_walk", uu_error());
7311 7311  
7312 7312          /*
7313 7313           * Take previous snapshots for all instances.  Even for ones not
7314 7314           * mentioned in the bundle, since we might change their service
7315 7315           * properties.
7316 7316           */
7317 7317          if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318 7318                  switch (scf_error()) {
7319 7319                  case SCF_ERROR_CONNECTION_BROKEN:
7320 7320                          goto connaborted;
7321 7321  
7322 7322                  case SCF_ERROR_DELETED:
7323 7323                          warn(s_deleted, s->sc_fmri);
7324 7324                          lcbdata->sc_err = EBUSY;
7325 7325                          r = UU_WALK_ERROR;
7326 7326                          goto deltemp;
7327 7327  
7328 7328                  case SCF_ERROR_HANDLE_MISMATCH:
7329 7329                  case SCF_ERROR_NOT_BOUND:
7330 7330                  case SCF_ERROR_NOT_SET:
7331 7331                  default:
7332 7332                          bad_error("scf_iter_service_instances", scf_error());
7333 7333                  }
7334 7334          }
7335 7335  
7336 7336          for (;;) {
7337 7337                  r = scf_iter_next_instance(imp_iter, imp_inst);
7338 7338                  if (r == 0)
7339 7339                          break;
7340 7340                  if (r != 1) {
7341 7341                          switch (scf_error()) {
7342 7342                          case SCF_ERROR_DELETED:
7343 7343                                  warn(s_deleted, s->sc_fmri);
7344 7344                                  lcbdata->sc_err = EBUSY;
7345 7345                                  r = UU_WALK_ERROR;
7346 7346                                  goto deltemp;
7347 7347  
7348 7348                          case SCF_ERROR_CONNECTION_BROKEN:
7349 7349                                  goto connaborted;
7350 7350  
7351 7351                          case SCF_ERROR_NOT_BOUND:
7352 7352                          case SCF_ERROR_HANDLE_MISMATCH:
7353 7353                          case SCF_ERROR_INVALID_ARGUMENT:
7354 7354                          case SCF_ERROR_NOT_SET:
7355 7355                          default:
7356 7356                                  bad_error("scf_iter_next_instance",
7357 7357                                      scf_error());
7358 7358                          }
7359 7359                  }
7360 7360  
7361 7361                  if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362 7362                          switch (scf_error()) {
7363 7363                          case SCF_ERROR_DELETED:
7364 7364                                  continue;
7365 7365  
7366 7366                          case SCF_ERROR_CONNECTION_BROKEN:
7367 7367                                  goto connaborted;
7368 7368  
7369 7369                          case SCF_ERROR_NOT_SET:
7370 7370                          case SCF_ERROR_NOT_BOUND:
7371 7371                          default:
7372 7372                                  bad_error("scf_instance_get_name", scf_error());
7373 7373                          }
7374 7374                  }
7375 7375  
7376 7376                  if (g_verbose)
7377 7377                          warn(gettext(
7378 7378                              "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379 7379                              snap_previous, s->sc_name, imp_str);
7380 7380  
7381 7381                  r = take_snap(imp_inst, snap_previous, imp_snap);
7382 7382                  switch (r) {
7383 7383                  case 0:
7384 7384                          break;
7385 7385  
7386 7386                  case ECANCELED:
7387 7387                          continue;
7388 7388  
7389 7389                  case ECONNABORTED:
7390 7390                          goto connaborted;
7391 7391  
7392 7392                  case EPERM:
7393 7393                          warn(gettext("Could not take \"%s\" snapshot of "
7394 7394                              "svc:/%s:%s (permission denied).\n"),
7395 7395                              snap_previous, s->sc_name, imp_str);
7396 7396                          lcbdata->sc_err = r;
7397 7397                          return (UU_WALK_ERROR);
7398 7398  
7399 7399                  case ENOSPC:
7400 7400                  case -1:
7401 7401                          lcbdata->sc_err = r;
7402 7402                          r = UU_WALK_ERROR;
7403 7403                          goto deltemp;
7404 7404  
7405 7405                  default:
7406 7406                          bad_error("take_snap", r);
7407 7407                  }
7408 7408  
7409 7409                  linst.sc_name = imp_str;
7410 7410                  inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411 7411                      &linst, NULL, NULL);
7412 7412                  if (inst != NULL) {
7413 7413                          inst->sc_import_state = IMPORT_PREVIOUS;
7414 7414                          inst->sc_seen = 1;
7415 7415                  }
7416 7416          }
7417 7417  
7418 7418          /*
7419 7419           * Create the new instances and take previous snapshots of
7420 7420           * them.  This is not necessary, but it maximizes data preservation.
7421 7421           */
7422 7422          for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423 7423              inst != NULL;
7424 7424              inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425 7425              inst)) {
7426 7426                  if (inst->sc_seen)
7427 7427                          continue;
7428 7428  
7429 7429                  if (scf_service_add_instance(imp_svc, inst->sc_name,
7430 7430                      imp_inst) != 0) {
7431 7431                          switch (scf_error()) {
7432 7432                          case SCF_ERROR_CONNECTION_BROKEN:
7433 7433                                  goto connaborted;
7434 7434  
7435 7435                          case SCF_ERROR_BACKEND_READONLY:
7436 7436                          case SCF_ERROR_BACKEND_ACCESS:
7437 7437                          case SCF_ERROR_NO_RESOURCES:
7438 7438                                  r = stash_scferror(lcbdata);
7439 7439                                  goto deltemp;
7440 7440  
7441 7441                          case SCF_ERROR_EXISTS:
7442 7442                                  warn(gettext("%s changed unexpectedly "
7443 7443                                      "(instance \"%s\" added).\n"), s->sc_fmri,
7444 7444                                      inst->sc_name);
7445 7445                                  lcbdata->sc_err = EBUSY;
7446 7446                                  r = UU_WALK_ERROR;
7447 7447                                  goto deltemp;
7448 7448  
7449 7449                          case SCF_ERROR_INVALID_ARGUMENT:
7450 7450                                  warn(gettext("Service \"%s\" has instance with "
7451 7451                                      "invalid name \"%s\".\n"), s->sc_name,
7452 7452                                      inst->sc_name);
7453 7453                                  r = stash_scferror(lcbdata);
7454 7454                                  goto deltemp;
7455 7455  
7456 7456                          case SCF_ERROR_PERMISSION_DENIED:
7457 7457                                  warn(gettext("Could not create instance \"%s\" "
7458 7458                                      "in %s (permission denied).\n"),
7459 7459                                      inst->sc_name, s->sc_fmri);
7460 7460                                  r = stash_scferror(lcbdata);
7461 7461                                  goto deltemp;
7462 7462  
7463 7463                          case SCF_ERROR_HANDLE_MISMATCH:
7464 7464                          case SCF_ERROR_NOT_BOUND:
7465 7465                          case SCF_ERROR_NOT_SET:
7466 7466                          default:
7467 7467                                  bad_error("scf_service_add_instance",
7468 7468                                      scf_error());
7469 7469                          }
7470 7470                  }
7471 7471  
7472 7472                  if (g_verbose)
7473 7473                          warn(gettext("Taking \"%s\" snapshot for "
7474 7474                              "new service %s.\n"), snap_previous, inst->sc_fmri);
7475 7475                  r = take_snap(imp_inst, snap_previous, imp_snap);
7476 7476                  switch (r) {
7477 7477                  case 0:
7478 7478                          break;
7479 7479  
7480 7480                  case ECANCELED:
7481 7481                          warn(i_deleted, s->sc_fmri, inst->sc_name);
7482 7482                          lcbdata->sc_err = EBUSY;
7483 7483                          r = UU_WALK_ERROR;
7484 7484                          goto deltemp;
7485 7485  
7486 7486                  case ECONNABORTED:
7487 7487                          goto connaborted;
7488 7488  
7489 7489                  case EPERM:
7490 7490                          warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491 7491                          lcbdata->sc_err = r;
7492 7492                          r = UU_WALK_ERROR;
7493 7493                          goto deltemp;
7494 7494  
7495 7495                  case ENOSPC:
7496 7496                  case -1:
7497 7497                          r = UU_WALK_ERROR;
7498 7498                          goto deltemp;
7499 7499  
7500 7500                  default:
7501 7501                          bad_error("take_snap", r);
7502 7502                  }
7503 7503          }
7504 7504  
7505 7505          s->sc_import_state = IMPORT_PREVIOUS;
7506 7506  
7507 7507          /*
7508 7508           * Upgrade service properties, if we can find a last-import snapshot.
7509 7509           * Any will do because we don't support different service properties
7510 7510           * in different manifests, so all snaplevels of the service in all of
7511 7511           * the last-import snapshots of the instances should be the same.
7512 7512           */
7513 7513          if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514 7514                  switch (scf_error()) {
7515 7515                  case SCF_ERROR_CONNECTION_BROKEN:
7516 7516                          goto connaborted;
7517 7517  
7518 7518                  case SCF_ERROR_DELETED:
7519 7519                          warn(s_deleted, s->sc_fmri);
7520 7520                          lcbdata->sc_err = EBUSY;
7521 7521                          r = UU_WALK_ERROR;
7522 7522                          goto deltemp;
7523 7523  
7524 7524                  case SCF_ERROR_HANDLE_MISMATCH:
7525 7525                  case SCF_ERROR_NOT_BOUND:
7526 7526                  case SCF_ERROR_NOT_SET:
7527 7527                  default:
7528 7528                          bad_error("scf_iter_service_instances", scf_error());
7529 7529                  }
7530 7530          }
7531 7531  
7532 7532          for (;;) {
7533 7533                  r = scf_iter_next_instance(imp_iter, imp_inst);
7534 7534                  if (r == -1) {
7535 7535                          switch (scf_error()) {
7536 7536                          case SCF_ERROR_DELETED:
7537 7537                                  warn(s_deleted, s->sc_fmri);
7538 7538                                  lcbdata->sc_err = EBUSY;
7539 7539                                  r = UU_WALK_ERROR;
7540 7540                                  goto deltemp;
7541 7541  
7542 7542                          case SCF_ERROR_CONNECTION_BROKEN:
7543 7543                                  goto connaborted;
7544 7544  
7545 7545                          case SCF_ERROR_NOT_BOUND:
7546 7546                          case SCF_ERROR_HANDLE_MISMATCH:
7547 7547                          case SCF_ERROR_INVALID_ARGUMENT:
7548 7548                          case SCF_ERROR_NOT_SET:
7549 7549                          default:
7550 7550                                  bad_error("scf_iter_next_instance",
7551 7551                                      scf_error());
7552 7552                          }
7553 7553                  }
7554 7554  
7555 7555                  if (r == 0) {
7556 7556                          /*
7557 7557                           * Didn't find any last-import snapshots.  Override-
7558 7558                           * import the properties.  Unless one of the instances
7559 7559                           * has a general/enabled property, in which case we're
7560 7560                           * probably running a last-import-capable svccfg for
7561 7561                           * the first time, and we should only take the
7562 7562                           * last-import snapshot.
7563 7563                           */
7564 7564                          if (have_ge) {
7565 7565                                  pgroup_t *mfpg;
7566 7566                                  scf_callback_t mfcbdata;
7567 7567  
7568 7568                                  li_only = 1;
7569 7569                                  no_refresh = 1;
7570 7570                                  /*
7571 7571                                   * Need to go ahead and import the manifestfiles
7572 7572                                   * pg if it exists. If the last-import snapshot
7573 7573                                   * upgrade code is ever removed this code can
7574 7574                                   * be removed as well.
7575 7575                                   */
7576 7576                                  mfpg = internal_pgroup_find(s,
7577 7577                                      SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578 7578  
7579 7579                                  if (mfpg) {
7580 7580                                          mfcbdata.sc_handle = g_hndl;
7581 7581                                          mfcbdata.sc_parent = imp_svc;
7582 7582                                          mfcbdata.sc_service = 1;
7583 7583                                          mfcbdata.sc_flags = SCI_FORCE;
7584 7584                                          mfcbdata.sc_source_fmri = s->sc_fmri;
7585 7585                                          mfcbdata.sc_target_fmri = s->sc_fmri;
7586 7586                                          if (entity_pgroup_import(mfpg,
7587 7587                                              &mfcbdata) != UU_WALK_NEXT) {
7588 7588                                                  warn(s_mfile_upd, s->sc_fmri);
7589 7589                                                  r = UU_WALK_ERROR;
7590 7590                                                  goto deltemp;
7591 7591                                          }
7592 7592                                  }
7593 7593                                  break;
7594 7594                          }
7595 7595  
7596 7596                          s->sc_import_state = IMPORT_PROP_BEGUN;
7597 7597  
7598 7598                          cbdata.sc_handle = g_hndl;
7599 7599                          cbdata.sc_parent = imp_svc;
7600 7600                          cbdata.sc_service = 1;
7601 7601                          cbdata.sc_flags = SCI_FORCE;
7602 7602                          cbdata.sc_source_fmri = s->sc_fmri;
7603 7603                          cbdata.sc_target_fmri = s->sc_fmri;
7604 7604                          if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605 7605                              &cbdata, UU_DEFAULT) != 0) {
7606 7606                                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607 7607                                          bad_error("uu_list_walk", uu_error());
7608 7608                                  lcbdata->sc_err = cbdata.sc_err;
7609 7609                                  switch (cbdata.sc_err) {
7610 7610                                  case ECONNABORTED:
7611 7611                                          goto connaborted;
7612 7612  
7613 7613                                  case ECANCELED:
7614 7614                                          warn(s_deleted, s->sc_fmri);
7615 7615                                          lcbdata->sc_err = EBUSY;
7616 7616                                          break;
7617 7617  
7618 7618                                  case EINVAL:    /* caught above */
7619 7619                                  case EEXIST:
7620 7620                                          bad_error("entity_pgroup_import",
7621 7621                                              cbdata.sc_err);
7622 7622                                  }
7623 7623  
7624 7624                                  r = UU_WALK_ERROR;
7625 7625                                  goto deltemp;
7626 7626                          }
7627 7627  
7628 7628                          cbdata.sc_trans = NULL;
7629 7629                          cbdata.sc_flags = 0;
7630 7630                          if (uu_list_walk(s->sc_dependents,
7631 7631                              lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632 7632                                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633 7633                                          bad_error("uu_list_walk", uu_error());
7634 7634                                  lcbdata->sc_err = cbdata.sc_err;
7635 7635                                  if (cbdata.sc_err == ECONNABORTED)
7636 7636                                          goto connaborted;
7637 7637                                  r = UU_WALK_ERROR;
7638 7638                                  goto deltemp;
7639 7639                          }
7640 7640                          break;
7641 7641                  }
7642 7642  
7643 7643                  if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644 7644                      imp_snap) != 0) {
7645 7645                          switch (scf_error()) {
7646 7646                          case SCF_ERROR_DELETED:
7647 7647                                  continue;
7648 7648  
7649 7649                          case SCF_ERROR_NOT_FOUND:
7650 7650                                  break;
7651 7651  
7652 7652                          case SCF_ERROR_CONNECTION_BROKEN:
7653 7653                                  goto connaborted;
7654 7654  
7655 7655                          case SCF_ERROR_HANDLE_MISMATCH:
7656 7656                          case SCF_ERROR_NOT_BOUND:
7657 7657                          case SCF_ERROR_INVALID_ARGUMENT:
7658 7658                          case SCF_ERROR_NOT_SET:
7659 7659                          default:
7660 7660                                  bad_error("scf_instance_get_snapshot",
7661 7661                                      scf_error());
7662 7662                          }
7663 7663  
7664 7664                          if (have_ge)
7665 7665                                  continue;
7666 7666  
7667 7667                          /*
7668 7668                           * Check for a general/enabled property.  This is how
7669 7669                           * we tell whether to import if there turn out to be
7670 7670                           * no last-import snapshots.
7671 7671                           */
7672 7672                          if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673 7673                              imp_pg) == 0) {
7674 7674                                  if (scf_pg_get_property(imp_pg,
7675 7675                                      SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676 7676                                          have_ge = 1;
7677 7677                                  } else {
7678 7678                                          switch (scf_error()) {
7679 7679                                          case SCF_ERROR_DELETED:
7680 7680                                          case SCF_ERROR_NOT_FOUND:
7681 7681                                                  continue;
7682 7682  
7683 7683                                          case SCF_ERROR_INVALID_ARGUMENT:
7684 7684                                          case SCF_ERROR_HANDLE_MISMATCH:
7685 7685                                          case SCF_ERROR_CONNECTION_BROKEN:
7686 7686                                          case SCF_ERROR_NOT_BOUND:
7687 7687                                          case SCF_ERROR_NOT_SET:
7688 7688                                          default:
7689 7689                                                  bad_error("scf_pg_get_property",
7690 7690                                                      scf_error());
7691 7691                                          }
7692 7692                                  }
7693 7693                          } else {
7694 7694                                  switch (scf_error()) {
7695 7695                                  case SCF_ERROR_DELETED:
7696 7696                                  case SCF_ERROR_NOT_FOUND:
7697 7697                                          continue;
7698 7698  
7699 7699                                  case SCF_ERROR_CONNECTION_BROKEN:
7700 7700                                          goto connaborted;
7701 7701  
7702 7702                                  case SCF_ERROR_NOT_BOUND:
7703 7703                                  case SCF_ERROR_NOT_SET:
7704 7704                                  case SCF_ERROR_INVALID_ARGUMENT:
7705 7705                                  case SCF_ERROR_HANDLE_MISMATCH:
7706 7706                                  default:
7707 7707                                          bad_error("scf_instance_get_pg",
7708 7708                                              scf_error());
7709 7709                                  }
7710 7710                          }
7711 7711                          continue;
7712 7712                  }
7713 7713  
7714 7714                  /* find service snaplevel */
7715 7715                  r = get_snaplevel(imp_snap, 1, imp_snpl);
7716 7716                  switch (r) {
7717 7717                  case 0:
7718 7718                          break;
7719 7719  
7720 7720                  case ECONNABORTED:
7721 7721                          goto connaborted;
7722 7722  
7723 7723                  case ECANCELED:
7724 7724                          continue;
7725 7725  
7726 7726                  case ENOENT:
7727 7727                          if (scf_instance_get_name(imp_inst, imp_str,
7728 7728                              imp_str_sz) < 0)
7729 7729                                  (void) strcpy(imp_str, "?");
7730 7730                          warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731 7731                          lcbdata->sc_err = EBADF;
7732 7732                          r = UU_WALK_ERROR;
7733 7733                          goto deltemp;
7734 7734  
7735 7735                  default:
7736 7736                          bad_error("get_snaplevel", r);
7737 7737                  }
7738 7738  
7739 7739                  if (scf_instance_get_snapshot(imp_inst, snap_running,
7740 7740                      imp_rsnap) != 0) {
7741 7741                          switch (scf_error()) {
7742 7742                          case SCF_ERROR_DELETED:
7743 7743                                  continue;
7744 7744  
7745 7745                          case SCF_ERROR_NOT_FOUND:
7746 7746                                  break;
7747 7747  
7748 7748                          case SCF_ERROR_CONNECTION_BROKEN:
7749 7749                                  goto connaborted;
7750 7750  
7751 7751                          case SCF_ERROR_INVALID_ARGUMENT:
7752 7752                          case SCF_ERROR_HANDLE_MISMATCH:
7753 7753                          case SCF_ERROR_NOT_BOUND:
7754 7754                          case SCF_ERROR_NOT_SET:
7755 7755                          default:
7756 7756                                  bad_error("scf_instance_get_snapshot",
7757 7757                                      scf_error());
7758 7758                          }
7759 7759                          running = NULL;
7760 7760                  } else {
7761 7761                          r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762 7762                          switch (r) {
7763 7763                          case 0:
7764 7764                                  running = imp_rsnpl;
7765 7765                                  break;
7766 7766  
7767 7767                          case ECONNABORTED:
7768 7768                                  goto connaborted;
7769 7769  
7770 7770                          case ECANCELED:
7771 7771                                  continue;
7772 7772  
7773 7773                          case ENOENT:
7774 7774                                  if (scf_instance_get_name(imp_inst, imp_str,
7775 7775                                      imp_str_sz) < 0)
7776 7776                                          (void) strcpy(imp_str, "?");
7777 7777                                  warn(badsnap, snap_running, s->sc_name,
7778 7778                                      imp_str);
7779 7779                                  lcbdata->sc_err = EBADF;
7780 7780                                  r = UU_WALK_ERROR;
7781 7781                                  goto deltemp;
7782 7782  
7783 7783                          default:
7784 7784                                  bad_error("get_snaplevel", r);
7785 7785                          }
7786 7786                  }
7787 7787  
7788 7788                  if (g_verbose) {
7789 7789                          if (scf_instance_get_name(imp_inst, imp_str,
7790 7790                              imp_str_sz) < 0)
7791 7791                                  (void) strcpy(imp_str, "?");
7792 7792                          warn(gettext("Upgrading properties of %s according to "
7793 7793                              "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794 7794                  }
7795 7795  
7796 7796                  /* upgrade service properties */
7797 7797                  r = upgrade_props(imp_svc, running, imp_snpl, s);
7798 7798                  if (r == 0)
7799 7799                          break;
7800 7800  
7801 7801                  switch (r) {
7802 7802                  case ECONNABORTED:
7803 7803                          goto connaborted;
7804 7804  
7805 7805                  case ECANCELED:
7806 7806                          warn(s_deleted, s->sc_fmri);
7807 7807                          lcbdata->sc_err = EBUSY;
7808 7808                          break;
7809 7809  
7810 7810                  case ENODEV:
7811 7811                          if (scf_instance_get_name(imp_inst, imp_str,
7812 7812                              imp_str_sz) < 0)
7813 7813                                  (void) strcpy(imp_str, "?");
7814 7814                          warn(i_deleted, s->sc_fmri, imp_str);
7815 7815                          lcbdata->sc_err = EBUSY;
7816 7816                          break;
7817 7817  
7818 7818                  default:
7819 7819                          lcbdata->sc_err = r;
7820 7820                  }
7821 7821  
7822 7822                  r = UU_WALK_ERROR;
7823 7823                  goto deltemp;
7824 7824          }
7825 7825  
7826 7826          s->sc_import_state = IMPORT_PROP_DONE;
7827 7827  
7828 7828  instances:
7829 7829          /* import instances */
7830 7830          cbdata.sc_handle = lcbdata->sc_handle;
7831 7831          cbdata.sc_parent = imp_svc;
7832 7832          cbdata.sc_service = 1;
7833 7833          cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834 7834          cbdata.sc_general = NULL;
7835 7835  
7836 7836          if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837 7837              lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838 7838                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839 7839                          bad_error("uu_list_walk", uu_error());
7840 7840  
7841 7841                  lcbdata->sc_err = cbdata.sc_err;
7842 7842                  if (cbdata.sc_err == ECONNABORTED)
7843 7843                          goto connaborted;
7844 7844                  r = UU_WALK_ERROR;
7845 7845                  goto deltemp;
7846 7846          }
7847 7847  
7848 7848          s->sc_import_state = IMPORT_COMPLETE;
7849 7849          r = UU_WALK_NEXT;
7850 7850  
7851 7851  deltemp:
7852 7852          /* delete temporary service */
7853 7853          if (scf_service_delete(imp_tsvc) != 0) {
7854 7854                  switch (scf_error()) {
7855 7855                  case SCF_ERROR_DELETED:
7856 7856                          break;
7857 7857  
7858 7858                  case SCF_ERROR_CONNECTION_BROKEN:
7859 7859                          goto connaborted;
7860 7860  
7861 7861                  case SCF_ERROR_EXISTS:
7862 7862                          warn(gettext(
7863 7863                              "Could not delete svc:/%s (instances exist).\n"),
7864 7864                              imp_tsname);
7865 7865                          break;
7866 7866  
7867 7867                  case SCF_ERROR_NOT_SET:
7868 7868                  case SCF_ERROR_NOT_BOUND:
7869 7869                  default:
7870 7870                          bad_error("scf_service_delete", scf_error());
7871 7871                  }
7872 7872          }
7873 7873  
7874 7874          return (r);
7875 7875  
7876 7876  connaborted:
7877 7877          warn(gettext("Could not delete svc:/%s "
7878 7878              "(repository connection broken).\n"), imp_tsname);
7879 7879          lcbdata->sc_err = ECONNABORTED;
7880 7880          return (UU_WALK_ERROR);
7881 7881  }
7882 7882  
7883 7883  static const char *
7884 7884  import_progress(int st)
7885 7885  {
7886 7886          switch (st) {
7887 7887          case 0:
7888 7888                  return (gettext("not reached."));
7889 7889  
7890 7890          case IMPORT_PREVIOUS:
7891 7891                  return (gettext("previous snapshot taken."));
7892 7892  
7893 7893          case IMPORT_PROP_BEGUN:
7894 7894                  return (gettext("some properties imported."));
7895 7895  
7896 7896          case IMPORT_PROP_DONE:
7897 7897                  return (gettext("properties imported."));
7898 7898  
7899 7899          case IMPORT_COMPLETE:
7900 7900                  return (gettext("imported."));
7901 7901  
7902 7902          case IMPORT_REFRESHED:
7903 7903                  return (gettext("refresh requested."));
7904 7904  
7905 7905          default:
7906 7906  #ifndef NDEBUG
7907 7907                  (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908 7908                      __FILE__, __LINE__, st);
7909 7909  #endif
7910 7910                  abort();
7911 7911                  /* NOTREACHED */
7912 7912          }
7913 7913  }
7914 7914  
7915 7915  /*
7916 7916   * Returns
7917 7917   *   0 - success
7918 7918   *     - fmri wasn't found (error printed)
7919 7919   *     - entity was deleted (error printed)
7920 7920   *     - backend denied access (error printed)
7921 7921   *   ENOMEM - out of memory (error printed)
7922 7922   *   ECONNABORTED - repository connection broken (error printed)
7923 7923   *   EPERM - permission denied (error printed)
7924 7924   *   -1 - unknown libscf error (error printed)
7925 7925   */
7926 7926  static int
7927 7927  imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 7928  {
7929 7929          scf_error_t serr;
7930 7930          void *ent;
7931 7931          int issvc;
7932 7932          int r;
7933 7933  
7934 7934          const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935 7935          const char *dpt_deleted = gettext("Could not refresh %s "
7936 7936              "(dependent \"%s\" of %s) (deleted).\n");
7937 7937  
7938 7938          serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939 7939          switch (serr) {
7940 7940          case SCF_ERROR_NONE:
7941 7941                  break;
7942 7942  
7943 7943          case SCF_ERROR_NO_MEMORY:
7944 7944                  if (name == NULL)
7945 7945                          warn(gettext("Could not refresh %s (out of memory).\n"),
7946 7946                              fmri);
7947 7947                  else
7948 7948                          warn(gettext("Could not refresh %s "
7949 7949                              "(dependent \"%s\" of %s) (out of memory).\n"),
7950 7950                              fmri, name, d_fmri);
7951 7951                  return (ENOMEM);
7952 7952  
7953 7953          case SCF_ERROR_NOT_FOUND:
7954 7954                  if (name == NULL)
7955 7955                          warn(deleted, fmri);
7956 7956                  else
7957 7957                          warn(dpt_deleted, fmri, name, d_fmri);
7958 7958                  return (0);
7959 7959  
7960 7960          case SCF_ERROR_INVALID_ARGUMENT:
7961 7961          case SCF_ERROR_CONSTRAINT_VIOLATED:
7962 7962          default:
7963 7963                  bad_error("fmri_to_entity", serr);
7964 7964          }
7965 7965  
7966 7966          r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967 7967          switch (r) {
7968 7968          case 0:
7969 7969                  break;
7970 7970  
7971 7971          case ECONNABORTED:
7972 7972                  if (name != NULL)
7973 7973                          warn(gettext("Could not refresh %s "
7974 7974                              "(dependent \"%s\" of %s) "
7975 7975                              "(repository connection broken).\n"), fmri, name,
7976 7976                              d_fmri);
7977 7977                  return (r);
7978 7978  
7979 7979          case ECANCELED:
7980 7980                  if (name == NULL)
7981 7981                          warn(deleted, fmri);
7982 7982                  else
7983 7983                          warn(dpt_deleted, fmri, name, d_fmri);
7984 7984                  return (0);
7985 7985  
7986 7986          case EACCES:
7987 7987                  if (!g_verbose)
7988 7988                          return (0);
7989 7989                  if (name == NULL)
7990 7990                          warn(gettext("Could not refresh %s "
7991 7991                              "(backend access denied).\n"), fmri);
7992 7992                  else
7993 7993                          warn(gettext("Could not refresh %s "
7994 7994                              "(dependent \"%s\" of %s) "
7995 7995                              "(backend access denied).\n"), fmri, name, d_fmri);
7996 7996                  return (0);
7997 7997  
7998 7998          case EPERM:
7999 7999                  if (name == NULL)
8000 8000                          warn(gettext("Could not refresh %s "
8001 8001                              "(permission denied).\n"), fmri);
8002 8002                  else
8003 8003                          warn(gettext("Could not refresh %s "
8004 8004                              "(dependent \"%s\" of %s) "
8005 8005                              "(permission denied).\n"), fmri, name, d_fmri);
8006 8006                  return (r);
8007 8007  
8008 8008          case ENOSPC:
8009 8009                  if (name == NULL)
8010 8010                          warn(gettext("Could not refresh %s "
8011 8011                              "(repository server out of resources).\n"),
8012 8012                              fmri);
8013 8013                  else
8014 8014                          warn(gettext("Could not refresh %s "
8015 8015                              "(dependent \"%s\" of %s) "
8016 8016                              "(repository server out of resources).\n"),
8017 8017                              fmri, name, d_fmri);
8018 8018                  return (r);
8019 8019  
8020 8020          case -1:
8021 8021                  scfwarn();
8022 8022                  return (r);
8023 8023  
8024 8024          default:
8025 8025                  bad_error("refresh_entity", r);
8026 8026          }
8027 8027  
8028 8028          if (issvc)
8029 8029                  scf_service_destroy(ent);
8030 8030          else
8031 8031                  scf_instance_destroy(ent);
8032 8032  
8033 8033          return (0);
8034 8034  }
8035 8035  
8036 8036  static int
8037 8037  alloc_imp_globals()
8038 8038  {
8039 8039          int r;
8040 8040  
8041 8041          const char * const emsg_nomem = gettext("Out of memory.\n");
8042 8042          const char * const emsg_nores =
8043 8043              gettext("svc.configd is out of resources.\n");
8044 8044  
8045 8045          imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046 8046              max_scf_name_len : max_scf_fmri_len) + 1;
8047 8047  
8048 8048          if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049 8049              (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050 8050              (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051 8051              (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052 8052              (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053 8053              (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054 8054              (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 8055              (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056 8056              (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057 8057              (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058 8058              (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059 8059              (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060 8060              (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061 8061              (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062 8062              (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063 8063              (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064 8064              (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065 8065              (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066 8066              (imp_str = malloc(imp_str_sz)) == NULL ||
8067 8067              (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068 8068              (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069 8069              (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070 8070              (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071 8071              (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072 8072              (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 8073              (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074 8074              (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075 8075              (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076 8076              (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077 8077              (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078 8078              (ud_val = scf_value_create(g_hndl)) == NULL ||
8079 8079              (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080 8080              (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081 8081              (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082 8082              (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083 8083              (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084 8084              (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085 8085                  if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086 8086                          warn(emsg_nores);
8087 8087                  else
8088 8088                          warn(emsg_nomem);
8089 8089  
8090 8090                  return (-1);
8091 8091          }
8092 8092  
8093 8093          r = load_init();
8094 8094          switch (r) {
8095 8095          case 0:
8096 8096                  break;
8097 8097  
8098 8098          case ENOMEM:
8099 8099                  warn(emsg_nomem);
8100 8100                  return (-1);
8101 8101  
8102 8102          default:
8103 8103                  bad_error("load_init", r);
8104 8104          }
8105 8105  
8106 8106          return (0);
8107 8107  }
8108 8108  
8109 8109  static void
8110 8110  free_imp_globals()
8111 8111  {
8112 8112          pgroup_t *old_dpt;
8113 8113          void *cookie;
8114 8114  
8115 8115          load_fini();
8116 8116  
8117 8117          free(ud_ctarg);
8118 8118          free(ud_oldtarg);
8119 8119          free(ud_name);
8120 8120          ud_ctarg = ud_oldtarg = ud_name = NULL;
8121 8121  
8122 8122          scf_transaction_destroy(ud_tx);
8123 8123          ud_tx = NULL;
8124 8124          scf_iter_destroy(ud_iter);
8125 8125          scf_iter_destroy(ud_iter2);
8126 8126          ud_iter = ud_iter2 = NULL;
8127 8127          scf_value_destroy(ud_val);
8128 8128          ud_val = NULL;
8129 8129          scf_property_destroy(ud_prop);
8130 8130          scf_property_destroy(ud_dpt_prop);
8131 8131          ud_prop = ud_dpt_prop = NULL;
8132 8132          scf_pg_destroy(ud_pg);
8133 8133          scf_pg_destroy(ud_cur_depts_pg);
8134 8134          scf_pg_destroy(ud_run_dpts_pg);
8135 8135          ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136 8136          scf_snaplevel_destroy(ud_snpl);
8137 8137          ud_snpl = NULL;
8138 8138          scf_instance_destroy(ud_inst);
8139 8139          ud_inst = NULL;
8140 8140  
8141 8141          free(imp_str);
8142 8142          free(imp_tsname);
8143 8143          free(imp_fe1);
8144 8144          free(imp_fe2);
8145 8145          imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146 8146  
8147 8147          cookie = NULL;
8148 8148          while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149 8149              NULL) {
8150 8150                  free((char *)old_dpt->sc_pgroup_name);
8151 8151                  free((char *)old_dpt->sc_pgroup_fmri);
8152 8152                  internal_pgroup_free(old_dpt);
8153 8153          }
8154 8154          uu_list_destroy(imp_deleted_dpts);
8155 8155  
8156 8156          scf_transaction_destroy(imp_tx);
8157 8157          imp_tx = NULL;
8158 8158          scf_iter_destroy(imp_iter);
8159 8159          scf_iter_destroy(imp_rpg_iter);
8160 8160          scf_iter_destroy(imp_up_iter);
8161 8161          imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162 8162          scf_property_destroy(imp_prop);
8163 8163          imp_prop = NULL;
8164 8164          scf_pg_destroy(imp_pg);
8165 8165          scf_pg_destroy(imp_pg2);
8166 8166          imp_pg = imp_pg2 = NULL;
8167 8167          scf_snaplevel_destroy(imp_snpl);
8168 8168          scf_snaplevel_destroy(imp_rsnpl);
8169 8169          imp_snpl = imp_rsnpl = NULL;
8170 8170          scf_snapshot_destroy(imp_snap);
8171 8171          scf_snapshot_destroy(imp_lisnap);
8172 8172          scf_snapshot_destroy(imp_tlisnap);
8173 8173          scf_snapshot_destroy(imp_rsnap);
8174 8174          imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175 8175          scf_instance_destroy(imp_inst);
8176 8176          scf_instance_destroy(imp_tinst);
8177 8177          imp_inst = imp_tinst = NULL;
8178 8178          scf_service_destroy(imp_svc);
8179 8179          scf_service_destroy(imp_tsvc);
8180 8180          imp_svc = imp_tsvc = NULL;
8181 8181          scf_scope_destroy(imp_scope);
8182 8182          imp_scope = NULL;
8183 8183  
8184 8184          load_fini();
8185 8185  }
8186 8186  
8187 8187  int
8188 8188  lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 8189  {
8190 8190          scf_callback_t cbdata;
8191 8191          int result = 0;
8192 8192          entity_t *svc, *inst;
8193 8193          uu_list_t *insts;
8194 8194          int r;
8195 8195          pgroup_t *old_dpt;
8196 8196          int annotation_set = 0;
8197 8197  
8198 8198          const char * const emsg_nomem = gettext("Out of memory.\n");
8199 8199          const char * const emsg_nores =
8200 8200              gettext("svc.configd is out of resources.\n");
8201 8201  
8202 8202          lscf_prep_hndl();
8203 8203  
8204 8204          if (alloc_imp_globals())
8205 8205                  goto out;
8206 8206  
8207 8207          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208 8208                  switch (scf_error()) {
8209 8209                  case SCF_ERROR_CONNECTION_BROKEN:
8210 8210                          warn(gettext("Repository connection broken.\n"));
8211 8211                          repository_teardown();
8212 8212                          result = -1;
8213 8213                          goto out;
8214 8214  
8215 8215                  case SCF_ERROR_NOT_FOUND:
8216 8216                  case SCF_ERROR_INVALID_ARGUMENT:
8217 8217                  case SCF_ERROR_NOT_BOUND:
8218 8218                  case SCF_ERROR_HANDLE_MISMATCH:
8219 8219                  default:
8220 8220                          bad_error("scf_handle_get_scope", scf_error());
8221 8221                  }
8222 8222          }
8223 8223  
8224 8224          /* Set up the auditing annotation. */
8225 8225          if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226 8226                  annotation_set = 1;
8227 8227          } else {
8228 8228                  switch (scf_error()) {
8229 8229                  case SCF_ERROR_CONNECTION_BROKEN:
8230 8230                          warn(gettext("Repository connection broken.\n"));
8231 8231                          repository_teardown();
8232 8232                          result = -1;
8233 8233                          goto out;
8234 8234  
8235 8235                  case SCF_ERROR_INVALID_ARGUMENT:
8236 8236                  case SCF_ERROR_NOT_BOUND:
8237 8237                  case SCF_ERROR_NO_RESOURCES:
8238 8238                  case SCF_ERROR_INTERNAL:
8239 8239                          bad_error("_scf_set_annotation", scf_error());
8240 8240                          /* NOTREACHED */
8241 8241  
8242 8242                  default:
8243 8243                          /*
8244 8244                           * Do not terminate import because of inability to
8245 8245                           * generate annotation audit event.
8246 8246                           */
8247 8247                          warn(gettext("_scf_set_annotation() unexpectedly "
8248 8248                              "failed with return code of %d\n"), scf_error());
8249 8249                          break;
8250 8250                  }
8251 8251          }
8252 8252  
8253 8253          /*
8254 8254           * Clear the sc_import_state's of all services & instances so we can
8255 8255           * report how far we got if we fail.
8256 8256           */
8257 8257          for (svc = uu_list_first(bndl->sc_bundle_services);
8258 8258              svc != NULL;
8259 8259              svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260 8260                  svc->sc_import_state = 0;
8261 8261  
8262 8262                  if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263 8263                      clear_int, (void *)offsetof(entity_t, sc_import_state),
8264 8264                      UU_DEFAULT) != 0)
8265 8265                          bad_error("uu_list_walk", uu_error());
8266 8266          }
8267 8267  
8268 8268          cbdata.sc_handle = g_hndl;
8269 8269          cbdata.sc_parent = imp_scope;
8270 8270          cbdata.sc_flags = flags;
8271 8271          cbdata.sc_general = NULL;
8272 8272  
8273 8273          if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274 8274              &cbdata, UU_DEFAULT) == 0) {
8275 8275                  char *eptr;
8276 8276                  /* Success.  Refresh everything. */
8277 8277  
8278 8278                  if (flags & SCI_NOREFRESH || no_refresh) {
8279 8279                          no_refresh = 0;
8280 8280                          result = 0;
8281 8281                          goto out;
8282 8282                  }
8283 8283  
8284 8284                  for (svc = uu_list_first(bndl->sc_bundle_services);
8285 8285                      svc != NULL;
8286 8286                      svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287 8287                          pgroup_t *dpt;
8288 8288  
8289 8289                          insts = svc->sc_u.sc_service.sc_service_instances;
8290 8290  
8291 8291                          for (inst = uu_list_first(insts);
8292 8292                              inst != NULL;
8293 8293                              inst = uu_list_next(insts, inst)) {
8294 8294                                  r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295 8295                                  switch (r) {
8296 8296                                  case 0:
8297 8297                                          break;
8298 8298  
8299 8299                                  case ENOMEM:
8300 8300                                  case ECONNABORTED:
8301 8301                                  case EPERM:
8302 8302                                  case -1:
8303 8303                                          goto progress;
8304 8304  
8305 8305                                  default:
8306 8306                                          bad_error("imp_refresh_fmri", r);
8307 8307                                  }
8308 8308  
8309 8309                                  inst->sc_import_state = IMPORT_REFRESHED;
8310 8310  
8311 8311                                  for (dpt = uu_list_first(inst->sc_dependents);
8312 8312                                      dpt != NULL;
8313 8313                                      dpt = uu_list_next(inst->sc_dependents,
8314 8314                                      dpt))
8315 8315                                          if (imp_refresh_fmri(
8316 8316                                              dpt->sc_pgroup_fmri,
8317 8317                                              dpt->sc_pgroup_name,
8318 8318                                              inst->sc_fmri) != 0)
8319 8319                                                  goto progress;
8320 8320                          }
8321 8321  
8322 8322                          for (dpt = uu_list_first(svc->sc_dependents);
8323 8323                              dpt != NULL;
8324 8324                              dpt = uu_list_next(svc->sc_dependents, dpt))
8325 8325                                  if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326 8326                                      dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327 8327                                          goto progress;
8328 8328                  }
8329 8329  
8330 8330                  for (old_dpt = uu_list_first(imp_deleted_dpts);
8331 8331                      old_dpt != NULL;
8332 8332                      old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333 8333                          if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334 8334                              old_dpt->sc_pgroup_name,
8335 8335                              old_dpt->sc_parent->sc_fmri) != 0)
8336 8336                                  goto progress;
8337 8337  
8338 8338                  result = 0;
8339 8339  
8340 8340                  /*
8341 8341                   * This snippet of code assumes that we are running svccfg as we
8342 8342                   * normally do -- witih svc.startd running. Of course, that is
8343 8343                   * not actually the case all the time because we also use a
8344 8344                   * varient of svc.configd and svccfg which are only meant to
8345 8345                   * run during the build process. During this time we have no
8346 8346                   * svc.startd, so this check would hang the build process.
8347 8347                   *
8348 8348                   * However, we've also given other consolidations, a bit of a
8349 8349                   * means to tie themselves into a knot. They're not properly
8350 8350                   * using the native build equivalents, but they've been getting
8351 8351                   * away with it anyways. Therefore, if we've found that
8352 8352                   * SVCCFG_REPOSITORY is set indicating that a separate configd
8353 8353                   * should be spun up, then we have to assume it's not using a
8354 8354                   * startd and we should not do this check.
8355 8355                   */
8356 8356  #ifndef NATIVE_BUILD
8357 8357                  /*
8358 8358                   * Verify that the restarter group is preset
8359 8359                   */
8360 8360                  eptr = getenv("SVCCFG_REPOSITORY");
8361 8361                  for (svc = uu_list_first(bndl->sc_bundle_services);
8362 8362                      svc != NULL && eptr == NULL;
8363 8363                      svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364 8364  
8365 8365                          insts = svc->sc_u.sc_service.sc_service_instances;
8366 8366  
8367 8367                          for (inst = uu_list_first(insts);
8368 8368                              inst != NULL;
8369 8369                              inst = uu_list_next(insts, inst)) {
8370 8370                                  if (lscf_instance_verify(imp_scope, svc,
8371 8371                                      inst) != 0)
8372 8372                                          goto progress;
8373 8373                          }
8374 8374                  }
8375 8375  #endif
8376 8376                  goto out;
8377 8377  
8378 8378          }
8379 8379  
8380 8380          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381 8381                  bad_error("uu_list_walk", uu_error());
8382 8382  
8383 8383  printerr:
8384 8384          /* If the error hasn't been printed yet, do so here. */
8385 8385          switch (cbdata.sc_err) {
8386 8386          case ECONNABORTED:
8387 8387                  warn(gettext("Repository connection broken.\n"));
8388 8388                  break;
8389 8389  
8390 8390          case ENOMEM:
8391 8391                  warn(emsg_nomem);
8392 8392                  break;
8393 8393  
8394 8394          case ENOSPC:
8395 8395                  warn(emsg_nores);
8396 8396                  break;
8397 8397  
8398 8398          case EROFS:
8399 8399                  warn(gettext("Repository is read-only.\n"));
8400 8400                  break;
8401 8401  
8402 8402          case EACCES:
8403 8403                  warn(gettext("Repository backend denied access.\n"));
8404 8404                  break;
8405 8405  
8406 8406          case EPERM:
8407 8407          case EINVAL:
8408 8408          case EEXIST:
8409 8409          case EBUSY:
8410 8410          case EBADF:
8411 8411          case -1:
8412 8412                  break;
8413 8413  
8414 8414          default:
8415 8415                  bad_error("lscf_service_import", cbdata.sc_err);
8416 8416          }
8417 8417  
8418 8418  progress:
8419 8419          warn(gettext("Import of %s failed.  Progress:\n"), filename);
8420 8420  
8421 8421          for (svc = uu_list_first(bndl->sc_bundle_services);
8422 8422              svc != NULL;
8423 8423              svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424 8424                  insts = svc->sc_u.sc_service.sc_service_instances;
8425 8425  
8426 8426                  warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8427 8427                      import_progress(svc->sc_import_state));
8428 8428  
8429 8429                  for (inst = uu_list_first(insts);
8430 8430                      inst != NULL;
8431 8431                      inst = uu_list_next(insts, inst))
8432 8432                          warn(gettext("    Instance \"%s\": %s\n"),
8433 8433                              inst->sc_name,
8434 8434                              import_progress(inst->sc_import_state));
8435 8435          }
8436 8436  
8437 8437          if (cbdata.sc_err == ECONNABORTED)
8438 8438                  repository_teardown();
8439 8439  
8440 8440  
8441 8441          result = -1;
8442 8442  
8443 8443  out:
8444 8444          if (annotation_set != 0) {
8445 8445                  /* Turn off annotation.  It is no longer needed. */
8446 8446                  (void) _scf_set_annotation(g_hndl, NULL, NULL);
8447 8447          }
8448 8448  
8449 8449          free_imp_globals();
8450 8450  
8451 8451          return (result);
8452 8452  }
8453 8453  
8454 8454  /*
8455 8455   * _lscf_import_err() summarize the error handling returned by
8456 8456   * lscf_import_{instance | service}_pgs
8457 8457   * Return values are:
8458 8458   * IMPORT_NEXT
8459 8459   * IMPORT_OUT
8460 8460   * IMPORT_BAD
8461 8461   */
8462 8462  
8463 8463  #define IMPORT_BAD      -1
8464 8464  #define IMPORT_NEXT     0
8465 8465  #define IMPORT_OUT      1
8466 8466  
8467 8467  static int
8468 8468  _lscf_import_err(int err, const char *fmri)
8469 8469  {
8470 8470          switch (err) {
8471 8471          case 0:
8472 8472                  if (g_verbose)
8473 8473                          warn(gettext("%s updated.\n"), fmri);
8474 8474                  return (IMPORT_NEXT);
8475 8475  
8476 8476          case ECONNABORTED:
8477 8477                  warn(gettext("Could not update %s "
8478 8478                      "(repository connection broken).\n"), fmri);
8479 8479                  return (IMPORT_OUT);
8480 8480  
8481 8481          case ENOMEM:
8482 8482                  warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483 8483                  return (IMPORT_OUT);
8484 8484  
8485 8485          case ENOSPC:
8486 8486                  warn(gettext("Could not update %s "
8487 8487                      "(repository server out of resources).\n"), fmri);
8488 8488                  return (IMPORT_OUT);
8489 8489  
8490 8490          case ECANCELED:
8491 8491                  warn(gettext(
8492 8492                      "Could not update %s (deleted).\n"), fmri);
8493 8493                  return (IMPORT_NEXT);
8494 8494  
8495 8495          case EPERM:
8496 8496          case EINVAL:
8497 8497          case EBUSY:
8498 8498                  return (IMPORT_NEXT);
8499 8499  
8500 8500          case EROFS:
8501 8501                  warn(gettext("Could not update %s (repository read-only).\n"),
8502 8502                      fmri);
8503 8503                  return (IMPORT_OUT);
8504 8504  
8505 8505          case EACCES:
8506 8506                  warn(gettext("Could not update %s "
8507 8507                      "(backend access denied).\n"), fmri);
8508 8508                  return (IMPORT_NEXT);
8509 8509  
8510 8510          case EEXIST:
8511 8511          default:
8512 8512                  return (IMPORT_BAD);
8513 8513          }
8514 8514  
8515 8515          /*NOTREACHED*/
8516 8516  }
8517 8517  
8518 8518  /*
8519 8519   * The global imp_svc and imp_inst should be set by the caller in the
8520 8520   * check to make sure the service and instance exist that the apply is
8521 8521   * working on.
8522 8522   */
8523 8523  static int
8524 8524  lscf_dependent_apply(void *dpg, void *e)
8525 8525  {
8526 8526          scf_callback_t cb;
8527 8527          pgroup_t *dpt_pgroup = dpg;
8528 8528          pgroup_t *deldpt;
8529 8529          entity_t *ent = e;
8530 8530          int tissvc;
8531 8531          void *sc_ent, *tent;
8532 8532          scf_error_t serr;
8533 8533          int r;
8534 8534  
8535 8535          const char * const dependents = "dependents";
8536 8536          const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537 8537  
8538 8538          if (issvc)
8539 8539                  sc_ent = imp_svc;
8540 8540          else
8541 8541                  sc_ent = imp_inst;
8542 8542  
8543 8543          if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544 8544              imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545 8545              scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546 8546              imp_prop) != 0) {
8547 8547                  switch (scf_error()) {
8548 8548                  case SCF_ERROR_NOT_FOUND:
8549 8549                  case SCF_ERROR_DELETED:
8550 8550                          break;
8551 8551  
8552 8552                  case SCF_ERROR_CONNECTION_BROKEN:
8553 8553                  case SCF_ERROR_NOT_SET:
8554 8554                  case SCF_ERROR_INVALID_ARGUMENT:
8555 8555                  case SCF_ERROR_HANDLE_MISMATCH:
8556 8556                  case SCF_ERROR_NOT_BOUND:
8557 8557                  default:
8558 8558                          bad_error("entity_get_pg", scf_error());
8559 8559                  }
8560 8560          } else {
8561 8561                  /*
8562 8562                   * Found the dependents/<wip dep> so check to
8563 8563                   * see if the service is different.  If so
8564 8564                   * store the service for later refresh, and
8565 8565                   * delete the wip dependency from the service
8566 8566                   */
8567 8567                  if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568 8568                          switch (scf_error()) {
8569 8569                                  case SCF_ERROR_DELETED:
8570 8570                                          break;
8571 8571  
8572 8572                                  case SCF_ERROR_CONNECTION_BROKEN:
8573 8573                                  case SCF_ERROR_NOT_SET:
8574 8574                                  case SCF_ERROR_INVALID_ARGUMENT:
8575 8575                                  case SCF_ERROR_HANDLE_MISMATCH:
8576 8576                                  case SCF_ERROR_NOT_BOUND:
8577 8577                                  default:
8578 8578                                          bad_error("scf_property_get_value",
8579 8579                                              scf_error());
8580 8580                          }
8581 8581                  }
8582 8582  
8583 8583                  if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584 8584                      max_scf_value_len + 1) < 0)
8585 8585                          bad_error("scf_value_get_as_string", scf_error());
8586 8586  
8587 8587                  r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588 8588                  switch (r) {
8589 8589                  case 1:
8590 8590                          break;
8591 8591                  case 0:
8592 8592                          if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593 8593                              &tissvc)) != SCF_ERROR_NONE) {
8594 8594                                  if (serr == SCF_ERROR_NOT_FOUND) {
8595 8595                                          break;
8596 8596                                  } else {
8597 8597                                          bad_error("fmri_to_entity", serr);
8598 8598                                  }
8599 8599                          }
8600 8600  
8601 8601                          if (entity_get_pg(tent, tissvc,
8602 8602                              dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603 8603                                  serr = scf_error();
8604 8604                                  if (serr == SCF_ERROR_NOT_FOUND ||
8605 8605                                      serr == SCF_ERROR_DELETED) {
8606 8606                                          break;
8607 8607                                  } else {
8608 8608                                          bad_error("entity_get_pg", scf_error());
8609 8609                                  }
8610 8610                          }
8611 8611  
8612 8612                          if (scf_pg_delete(imp_pg) != 0) {
8613 8613                                  serr = scf_error();
8614 8614                                  if (serr == SCF_ERROR_NOT_FOUND ||
8615 8615                                      serr == SCF_ERROR_DELETED) {
8616 8616                                          break;
8617 8617                                  } else {
8618 8618                                          bad_error("scf_pg_delete", scf_error());
8619 8619                                  }
8620 8620                          }
8621 8621  
8622 8622                          deldpt = internal_pgroup_new();
8623 8623                          if (deldpt == NULL)
8624 8624                                  return (ENOMEM);
8625 8625                          deldpt->sc_pgroup_name =
8626 8626                              strdup(dpt_pgroup->sc_pgroup_name);
8627 8627                          deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628 8628                          if (deldpt->sc_pgroup_name == NULL ||
8629 8629                              deldpt->sc_pgroup_fmri == NULL)
8630 8630                                  return (ENOMEM);
8631 8631                          deldpt->sc_parent = (entity_t *)ent;
8632 8632                          if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633 8633                              deldpt) != 0)
8634 8634                                  uu_die(gettext("libuutil error: %s\n"),
8635 8635                                      uu_strerror(uu_error()));
8636 8636  
8637 8637                          break;
8638 8638                  default:
8639 8639                          bad_error("fmri_equal", r);
8640 8640                  }
8641 8641          }
8642 8642  
8643 8643          cb.sc_handle = g_hndl;
8644 8644          cb.sc_parent = ent;
8645 8645          cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646 8646          cb.sc_source_fmri = ent->sc_fmri;
8647 8647          cb.sc_target_fmri = ent->sc_fmri;
8648 8648          cb.sc_trans = NULL;
8649 8649          cb.sc_flags = SCI_FORCE;
8650 8650  
8651 8651          if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652 8652                  return (UU_WALK_ERROR);
8653 8653  
8654 8654          r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655 8655          switch (r) {
8656 8656          case 0:
8657 8657                  break;
8658 8658  
8659 8659          case ENOMEM:
8660 8660          case ECONNABORTED:
8661 8661          case EPERM:
8662 8662          case -1:
8663 8663                  warn(gettext("Unable to refresh \"%s\"\n"),
8664 8664                      dpt_pgroup->sc_pgroup_fmri);
8665 8665                  return (UU_WALK_ERROR);
8666 8666  
8667 8667          default:
8668 8668                  bad_error("imp_refresh_fmri", r);
8669 8669          }
8670 8670  
8671 8671          return (UU_WALK_NEXT);
8672 8672  }
8673 8673  
8674 8674  /*
8675 8675   * Returns
8676 8676   *   0 - success
8677 8677   *   -1 - lscf_import_instance_pgs() failed.
8678 8678   */
8679 8679  int
8680 8680  lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 8681  {
8682 8682          pgroup_t *old_dpt;
8683 8683          entity_t *svc, *inst;
8684 8684          int annotation_set = 0;
8685 8685          int ret = 0;
8686 8686          int r = 0;
8687 8687  
8688 8688          lscf_prep_hndl();
8689 8689  
8690 8690          if ((ret = alloc_imp_globals()))
8691 8691                  goto out;
8692 8692  
8693 8693          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694 8694                  scfdie();
8695 8695  
8696 8696          /*
8697 8697           * Set the strings to be used for the security audit annotation
8698 8698           * event.
8699 8699           */
8700 8700          if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701 8701                  annotation_set = 1;
8702 8702          } else {
8703 8703                  switch (scf_error()) {
8704 8704                  case SCF_ERROR_CONNECTION_BROKEN:
8705 8705                          warn(gettext("Repository connection broken.\n"));
8706 8706                          goto out;
8707 8707  
8708 8708                  case SCF_ERROR_INVALID_ARGUMENT:
8709 8709                  case SCF_ERROR_NOT_BOUND:
8710 8710                  case SCF_ERROR_NO_RESOURCES:
8711 8711                  case SCF_ERROR_INTERNAL:
8712 8712                          bad_error("_scf_set_annotation", scf_error());
8713 8713                          /* NOTREACHED */
8714 8714  
8715 8715                  default:
8716 8716                          /*
8717 8717                           * Do not abort apply operation because of
8718 8718                           * inability to create annotation audit event.
8719 8719                           */
8720 8720                          warn(gettext("_scf_set_annotation() unexpectedly "
8721 8721                              "failed with return code of %d\n"), scf_error());
8722 8722                          break;
8723 8723                  }
8724 8724          }
8725 8725  
8726 8726          for (svc = uu_list_first(bndl->sc_bundle_services);
8727 8727              svc != NULL;
8728 8728              svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729 8729                  int refresh = 0;
8730 8730  
8731 8731                  if (scf_scope_get_service(imp_scope, svc->sc_name,
8732 8732                      imp_svc) != 0) {
8733 8733                          switch (scf_error()) {
8734 8734                          case SCF_ERROR_NOT_FOUND:
8735 8735                                  if (g_verbose)
8736 8736                                          warn(gettext("Ignoring nonexistent "
8737 8737                                              "service %s.\n"), svc->sc_name);
8738 8738                                  continue;
8739 8739  
8740 8740                          default:
8741 8741                                  scfdie();
8742 8742                          }
8743 8743                  }
8744 8744  
8745 8745                  /*
8746 8746                   * If there were missing types in the profile, then need to
8747 8747                   * attempt to find the types.
8748 8748                   */
8749 8749                  if (svc->sc_miss_type) {
8750 8750                          if (uu_list_numnodes(svc->sc_pgroups) &&
8751 8751                              uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752 8752                              svc, UU_DEFAULT) != 0) {
8753 8753                                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754 8754                                          bad_error("uu_list_walk", uu_error());
8755 8755  
8756 8756                                  ret = -1;
8757 8757                                  continue;
8758 8758                          }
8759 8759  
8760 8760                          for (inst = uu_list_first(
8761 8761                              svc->sc_u.sc_service.sc_service_instances);
8762 8762                              inst != NULL;
8763 8763                              inst = uu_list_next(
8764 8764                              svc->sc_u.sc_service.sc_service_instances, inst)) {
8765 8765                                  /*
8766 8766                                   * If the instance doesn't exist just
8767 8767                                   * skip to the next instance and let the
8768 8768                                   * import note the missing instance.
8769 8769                                   */
8770 8770                                  if (scf_service_get_instance(imp_svc,
8771 8771                                      inst->sc_name, imp_inst) != 0)
8772 8772                                          continue;
8773 8773  
8774 8774                                  if (uu_list_walk(inst->sc_pgroups,
8775 8775                                      find_current_pg_type, inst,
8776 8776                                      UU_DEFAULT) != 0) {
8777 8777                                          if (uu_error() !=
8778 8778                                              UU_ERROR_CALLBACK_FAILED)
8779 8779                                                  bad_error("uu_list_walk",
8780 8780                                                      uu_error());
8781 8781  
8782 8782                                          ret = -1;
8783 8783                                          inst->sc_miss_type = B_TRUE;
8784 8784                                  }
8785 8785                          }
8786 8786                  }
8787 8787  
8788 8788                  /*
8789 8789                   * if we have pgs in the profile, we need to refresh ALL
8790 8790                   * instances of the service
8791 8791                   */
8792 8792                  if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793 8793                          refresh = 1;
8794 8794                          r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795 8795                              SCI_FORCE | SCI_KEEP);
8796 8796                          switch (_lscf_import_err(r, svc->sc_fmri)) {
8797 8797                          case IMPORT_NEXT:
8798 8798                                  break;
8799 8799  
8800 8800                          case IMPORT_OUT:
8801 8801                                  goto out;
8802 8802  
8803 8803                          case IMPORT_BAD:
8804 8804                          default:
8805 8805                                  bad_error("lscf_import_service_pgs", r);
8806 8806                          }
8807 8807                  }
8808 8808  
8809 8809                  if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810 8810                          uu_list_walk(svc->sc_dependents,
8811 8811                              lscf_dependent_apply, svc, UU_DEFAULT);
8812 8812                  }
8813 8813  
8814 8814                  for (inst = uu_list_first(
8815 8815                      svc->sc_u.sc_service.sc_service_instances);
8816 8816                      inst != NULL;
8817 8817                      inst = uu_list_next(
8818 8818                      svc->sc_u.sc_service.sc_service_instances, inst)) {
8819 8819                          /*
8820 8820                           * This instance still has missing types
8821 8821                           * so skip it.
8822 8822                           */
8823 8823                          if (inst->sc_miss_type) {
8824 8824                                  if (g_verbose)
8825 8825                                          warn(gettext("Ignoring instance "
8826 8826                                              "%s:%s with missing types\n"),
8827 8827                                              inst->sc_parent->sc_name,
8828 8828                                              inst->sc_name);
8829 8829  
8830 8830                                  continue;
8831 8831                          }
8832 8832  
8833 8833                          if (scf_service_get_instance(imp_svc, inst->sc_name,
8834 8834                              imp_inst) != 0) {
8835 8835                                  switch (scf_error()) {
8836 8836                                  case SCF_ERROR_NOT_FOUND:
8837 8837                                          if (g_verbose)
8838 8838                                                  warn(gettext("Ignoring "
8839 8839                                                      "nonexistant instance "
8840 8840                                                      "%s:%s.\n"),
8841 8841                                                      inst->sc_parent->sc_name,
8842 8842                                                      inst->sc_name);
8843 8843                                          continue;
8844 8844  
8845 8845                                  default:
8846 8846                                          scfdie();
8847 8847                                  }
8848 8848                          }
8849 8849  
8850 8850                          /*
8851 8851                           * If the instance does not have a general/enabled
8852 8852                           * property and no last-import snapshot then the
8853 8853                           * instance is not a fully installed instance and
8854 8854                           * should not have a profile applied to it.
8855 8855                           *
8856 8856                           * This could happen if a service/instance declares
8857 8857                           * a dependent on behalf of another service/instance.
8858 8858                           *
8859 8859                           */
8860 8860                          if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861 8861                              imp_snap) != 0) {
8862 8862                                  if (scf_instance_get_pg(imp_inst,
8863 8863                                      SCF_PG_GENERAL, imp_pg) != 0 ||
8864 8864                                      scf_pg_get_property(imp_pg,
8865 8865                                      SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866 8866                                          if (g_verbose)
8867 8867                                                  warn(gettext("Ignoreing "
8868 8868                                                      "partial instance "
8869 8869                                                      "%s:%s.\n"),
8870 8870                                                      inst->sc_parent->sc_name,
8871 8871                                                      inst->sc_name);
8872 8872                                          continue;
8873 8873                                  }
8874 8874                          }
8875 8875  
8876 8876                          r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877 8877                              inst, SCI_FORCE | SCI_KEEP);
8878 8878                          switch (_lscf_import_err(r, inst->sc_fmri)) {
8879 8879                          case IMPORT_NEXT:
8880 8880                                  break;
8881 8881  
8882 8882                          case IMPORT_OUT:
8883 8883                                  goto out;
8884 8884  
8885 8885                          case IMPORT_BAD:
8886 8886                          default:
8887 8887                                  bad_error("lscf_import_instance_pgs", r);
8888 8888                          }
8889 8889  
8890 8890                          if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891 8891                                  uu_list_walk(inst->sc_dependents,
8892 8892                                      lscf_dependent_apply, inst, UU_DEFAULT);
8893 8893                          }
8894 8894  
8895 8895                          /* refresh only if there is no pgs in the service */
8896 8896                          if (refresh == 0)
8897 8897                                  (void) refresh_entity(0, imp_inst,
8898 8898                                      inst->sc_fmri, NULL, NULL, NULL);
8899 8899                  }
8900 8900  
8901 8901                  if (refresh == 1) {
8902 8902                          char *name_buf = safe_malloc(max_scf_name_len + 1);
8903 8903  
8904 8904                          (void) refresh_entity(1, imp_svc, svc->sc_name,
8905 8905                              imp_inst, imp_iter, name_buf);
8906 8906                          free(name_buf);
8907 8907                  }
8908 8908  
8909 8909                  for (old_dpt = uu_list_first(imp_deleted_dpts);
8910 8910                      old_dpt != NULL;
8911 8911                      old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912 8912                          if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913 8913                              old_dpt->sc_pgroup_name,
8914 8914                              old_dpt->sc_parent->sc_fmri) != 0) {
8915 8915                                  warn(gettext("Unable to refresh \"%s\"\n"),
8916 8916                                      old_dpt->sc_pgroup_fmri);
8917 8917                          }
8918 8918                  }
8919 8919          }
8920 8920  
8921 8921  out:
8922 8922          if (annotation_set) {
8923 8923                  /* Remove security audit annotation strings. */
8924 8924                  (void) _scf_set_annotation(g_hndl, NULL, NULL);
8925 8925          }
8926 8926  
8927 8927          free_imp_globals();
8928 8928          return (ret);
8929 8929  }
8930 8930  
8931 8931  
8932 8932  /*
8933 8933   * Export.  These functions create and output an XML tree of a service
8934 8934   * description from the repository.  This is largely the inverse of
8935 8935   * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936 8936   *
8937 8937   * - We must include any properties which are not represented specifically by
8938 8938   *   a service manifest, e.g., properties created by an admin post-import.  To
8939 8939   *   do so we'll iterate through all properties and deal with each
8940 8940   *   apropriately.
8941 8941   *
8942 8942   * - Children of services and instances must must be in the order set by the
8943 8943   *   DTD, but we iterate over the properties in undefined order.  The elements
8944 8944   *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8945 8945   *   number of classes of them, however, we'll keep the classes separate and
8946 8946   *   assemble them in order.
8947 8947   */
8948 8948  
8949 8949  /*
8950 8950   * Convenience function to handle xmlSetProp errors (and type casting).
8951 8951   */
8952 8952  static void
8953 8953  safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 8954  {
8955 8955          if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956 8956                  uu_die(gettext("Could not set XML property.\n"));
8957 8957  }
8958 8958  
8959 8959  /*
8960 8960   * Convenience function to set an XML attribute to the single value of an
8961 8961   * astring property.  If the value happens to be the default, don't set the
8962 8962   * attribute.  "dval" should be the default value supplied by the DTD, or
8963 8963   * NULL for no default.
8964 8964   */
8965 8965  static int
8966 8966  set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967 8967      const char *name, const char *dval)
8968 8968  {
8969 8969          scf_value_t *val;
8970 8970          ssize_t len;
8971 8971          char *str;
8972 8972  
8973 8973          val = scf_value_create(g_hndl);
8974 8974          if (val == NULL)
8975 8975                  scfdie();
8976 8976  
8977 8977          if (prop_get_val(prop, val) != 0) {
8978 8978                  scf_value_destroy(val);
8979 8979                  return (-1);
8980 8980          }
8981 8981  
8982 8982          len = scf_value_get_as_string(val, NULL, 0);
8983 8983          if (len < 0)
8984 8984                  scfdie();
8985 8985  
8986 8986          str = safe_malloc(len + 1);
8987 8987  
8988 8988          if (scf_value_get_as_string(val, str, len + 1) < 0)
8989 8989                  scfdie();
8990 8990  
8991 8991          scf_value_destroy(val);
8992 8992  
8993 8993          if (dval == NULL || strcmp(str, dval) != 0)
8994 8994                  safe_setprop(n, name, str);
8995 8995  
8996 8996          free(str);
8997 8997  
8998 8998          return (0);
8999 8999  }
9000 9000  
9001 9001  /*
9002 9002   * As above, but the attribute is always set.
9003 9003   */
9004 9004  static int
9005 9005  set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 9006  {
9007 9007          return (set_attr_from_prop_default(prop, n, name, NULL));
9008 9008  }
9009 9009  
9010 9010  /*
9011 9011   * Dump the given document onto f, with "'s replaced by ''s.
9012 9012   */
9013 9013  static int
9014 9014  write_service_bundle(xmlDocPtr doc, FILE *f)
9015 9015  {
9016 9016          xmlChar *mem;
9017 9017          int sz, i;
9018 9018  
9019 9019          mem = NULL;
9020 9020          xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021 9021  
9022 9022          if (mem == NULL) {
9023 9023                  semerr(gettext("Could not dump XML tree.\n"));
9024 9024                  return (-1);
9025 9025          }
9026 9026  
9027 9027          /*
9028 9028           * Fortunately libxml produces " instead of ", so we can blindly
9029 9029           * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9030 9030           * ' code?!
9031 9031           */
9032 9032          for (i = 0; i < sz; ++i) {
9033 9033                  char c = (char)mem[i];
9034 9034  
9035 9035                  if (c == '"')
9036 9036                          (void) fputc('\'', f);
9037 9037                  else if (c == '\'')
9038 9038                          (void) fwrite("'", sizeof ("'") - 1, 1, f);
9039 9039                  else
9040 9040                          (void) fputc(c, f);
9041 9041          }
9042 9042  
9043 9043          return (0);
9044 9044  }
9045 9045  
9046 9046  /*
9047 9047   * Create the DOM elements in elts necessary to (generically) represent prop
9048 9048   * (i.e., a property or propval element).  If the name of the property is
9049 9049   * known, it should be passed as name_arg.  Otherwise, pass NULL.
9050 9050   */
9051 9051  static void
9052 9052  export_property(scf_property_t *prop, const char *name_arg,
9053 9053      struct pg_elts *elts, int flags)
9054 9054  {
9055 9055          const char *type;
9056 9056          scf_error_t err = 0;
9057 9057          xmlNodePtr pnode, lnode;
9058 9058          char *lnname;
9059 9059          int ret;
9060 9060  
9061 9061          /* name */
9062 9062          if (name_arg != NULL) {
9063 9063                  (void) strcpy(exp_str, name_arg);
9064 9064          } else {
9065 9065                  if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066 9066                          scfdie();
9067 9067          }
9068 9068  
9069 9069          /* type */
9070 9070          type = prop_to_typestr(prop);
9071 9071          if (type == NULL)
9072 9072                  uu_die(gettext("Can't export property %s: unknown type.\n"),
9073 9073                      exp_str);
9074 9074  
9075 9075          /* If we're exporting values, and there's just one, export it here. */
9076 9076          if (!(flags & SCE_ALL_VALUES))
9077 9077                  goto empty;
9078 9078  
9079 9079          if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080 9080                  xmlNodePtr n;
9081 9081  
9082 9082                  /* Single value, so use propval */
9083 9083                  n = xmlNewNode(NULL, (xmlChar *)"propval");
9084 9084                  if (n == NULL)
9085 9085                          uu_die(emsg_create_xml);
9086 9086  
9087 9087                  safe_setprop(n, name_attr, exp_str);
9088 9088                  safe_setprop(n, type_attr, type);
9089 9089  
9090 9090                  if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091 9091                          scfdie();
9092 9092                  safe_setprop(n, value_attr, exp_str);
9093 9093  
9094 9094                  if (elts->propvals == NULL)
9095 9095                          elts->propvals = n;
9096 9096                  else
9097 9097                          (void) xmlAddSibling(elts->propvals, n);
9098 9098  
9099 9099                  return;
9100 9100          }
9101 9101  
9102 9102          err = scf_error();
9103 9103  
9104 9104          if (err == SCF_ERROR_PERMISSION_DENIED) {
9105 9105                  semerr(emsg_permission_denied);
9106 9106                  return;
9107 9107          }
9108 9108  
9109 9109          if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110 9110              err != SCF_ERROR_NOT_FOUND &&
9111 9111              err != SCF_ERROR_PERMISSION_DENIED)
9112 9112                  scfdie();
9113 9113  
9114 9114  empty:
9115 9115          /* Multiple (or no) values, so use property */
9116 9116          pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117 9117          if (pnode == NULL)
9118 9118                  uu_die(emsg_create_xml);
9119 9119  
9120 9120          safe_setprop(pnode, name_attr, exp_str);
9121 9121          safe_setprop(pnode, type_attr, type);
9122 9122  
9123 9123          if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124 9124                  lnname = uu_msprintf("%s_list", type);
9125 9125                  if (lnname == NULL)
9126 9126                          uu_die(gettext("Could not create string"));
9127 9127  
9128 9128                  lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129 9129                  if (lnode == NULL)
9130 9130                          uu_die(emsg_create_xml);
9131 9131  
9132 9132                  uu_free(lnname);
9133 9133  
9134 9134                  if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135 9135                          scfdie();
9136 9136  
9137 9137                  while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138 9138                      1) {
9139 9139                          xmlNodePtr vn;
9140 9140  
9141 9141                          vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142 9142                              NULL);
9143 9143                          if (vn == NULL)
9144 9144                                  uu_die(emsg_create_xml);
9145 9145  
9146 9146                          if (scf_value_get_as_string(exp_val, exp_str,
9147 9147                              exp_str_sz) < 0)
9148 9148                                  scfdie();
9149 9149                          safe_setprop(vn, value_attr, exp_str);
9150 9150                  }
9151 9151                  if (ret != 0)
9152 9152                          scfdie();
9153 9153          }
9154 9154  
9155 9155          if (elts->properties == NULL)
9156 9156                  elts->properties = pnode;
9157 9157          else
9158 9158                  (void) xmlAddSibling(elts->properties, pnode);
9159 9159  }
9160 9160  
9161 9161  /*
9162 9162   * Add a property_group element for this property group to elts.
9163 9163   */
9164 9164  static void
9165 9165  export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 9166  {
9167 9167          xmlNodePtr n;
9168 9168          struct pg_elts elts;
9169 9169          int ret;
9170 9170          boolean_t read_protected;
9171 9171  
9172 9172          n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173 9173  
9174 9174          /* name */
9175 9175          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176 9176                  scfdie();
9177 9177          safe_setprop(n, name_attr, exp_str);
9178 9178  
9179 9179          /* type */
9180 9180          if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181 9181                  scfdie();
9182 9182          safe_setprop(n, type_attr, exp_str);
9183 9183  
9184 9184          /* properties */
9185 9185          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186 9186                  scfdie();
9187 9187  
9188 9188          (void) memset(&elts, 0, sizeof (elts));
9189 9189  
9190 9190          /*
9191 9191           * If this property group is not read protected, we always want to
9192 9192           * output all the values.  Otherwise, we only output the values if the
9193 9193           * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194 9194           */
9195 9195          if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196 9196                  scfdie();
9197 9197  
9198 9198          if (!read_protected)
9199 9199                  flags |= SCE_ALL_VALUES;
9200 9200  
9201 9201          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202 9202                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203 9203                          scfdie();
9204 9204  
9205 9205                  if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206 9206                          xmlNodePtr m;
9207 9207  
9208 9208                          m = xmlNewNode(NULL, (xmlChar *)"stability");
9209 9209                          if (m == NULL)
9210 9210                                  uu_die(emsg_create_xml);
9211 9211  
9212 9212                          if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213 9213                                  elts.stability = m;
9214 9214                                  continue;
9215 9215                          }
9216 9216  
9217 9217                          xmlFreeNode(m);
9218 9218                  }
9219 9219  
9220 9220                  export_property(exp_prop, NULL, &elts, flags);
9221 9221          }
9222 9222          if (ret == -1)
9223 9223                  scfdie();
9224 9224  
9225 9225          (void) xmlAddChild(n, elts.stability);
9226 9226          (void) xmlAddChildList(n, elts.propvals);
9227 9227          (void) xmlAddChildList(n, elts.properties);
9228 9228  
9229 9229          if (eelts->property_groups == NULL)
9230 9230                  eelts->property_groups = n;
9231 9231          else
9232 9232                  (void) xmlAddSibling(eelts->property_groups, n);
9233 9233  }
9234 9234  
9235 9235  /*
9236 9236   * Create an XML node representing the dependency described by the given
9237 9237   * property group and put it in eelts.  Unless the dependency is not valid, in
9238 9238   * which case create a generic property_group element which represents it and
9239 9239   * put it in eelts.
9240 9240   */
9241 9241  static void
9242 9242  export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 9243  {
9244 9244          xmlNodePtr n;
9245 9245          int err = 0, ret;
9246 9246          struct pg_elts elts;
9247 9247  
9248 9248          n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249 9249          if (n == NULL)
9250 9250                  uu_die(emsg_create_xml);
9251 9251  
9252 9252          /*
9253 9253           * If the external flag is present, skip this dependency because it
9254 9254           * should have been created by another manifest.
9255 9255           */
9256 9256          if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257 9257                  if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258 9258                      prop_get_val(exp_prop, exp_val) == 0) {
9259 9259                          uint8_t b;
9260 9260  
9261 9261                          if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262 9262                                  scfdie();
9263 9263  
9264 9264                          if (b)
9265 9265                                  return;
9266 9266                  }
9267 9267          } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268 9268                  scfdie();
9269 9269  
9270 9270          /* Get the required attributes. */
9271 9271  
9272 9272          /* name */
9273 9273          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274 9274                  scfdie();
9275 9275          safe_setprop(n, name_attr, exp_str);
9276 9276  
9277 9277          /* grouping */
9278 9278          if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279 9279              set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280 9280                  err = 1;
9281 9281  
9282 9282          /* restart_on */
9283 9283          if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284 9284              set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285 9285                  err = 1;
9286 9286  
9287 9287          /* type */
9288 9288          if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289 9289              set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290 9290                  err = 1;
9291 9291  
9292 9292          /*
9293 9293           * entities: Not required, but if we create no children, it will be
9294 9294           * created as empty on import, so fail if it's missing.
9295 9295           */
9296 9296          if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297 9297              prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298 9298                  scf_iter_t *eiter;
9299 9299                  int ret2;
9300 9300  
9301 9301                  eiter = scf_iter_create(g_hndl);
9302 9302                  if (eiter == NULL)
9303 9303                          scfdie();
9304 9304  
9305 9305                  if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306 9306                          scfdie();
9307 9307  
9308 9308                  while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309 9309                          xmlNodePtr ch;
9310 9310  
9311 9311                          if (scf_value_get_astring(exp_val, exp_str,
9312 9312                              exp_str_sz) < 0)
9313 9313                                  scfdie();
9314 9314  
9315 9315                          /*
9316 9316                           * service_fmri's must be first, so we can add them
9317 9317                           * here.
9318 9318                           */
9319 9319                          ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320 9320                              NULL);
9321 9321                          if (ch == NULL)
9322 9322                                  uu_die(emsg_create_xml);
9323 9323  
9324 9324                          safe_setprop(ch, value_attr, exp_str);
9325 9325                  }
9326 9326                  if (ret2 == -1)
9327 9327                          scfdie();
9328 9328  
9329 9329                  scf_iter_destroy(eiter);
9330 9330          } else
9331 9331                  err = 1;
9332 9332  
9333 9333          if (err) {
9334 9334                  xmlFreeNode(n);
9335 9335  
9336 9336                  export_pg(pg, eelts, SCE_ALL_VALUES);
9337 9337  
9338 9338                  return;
9339 9339          }
9340 9340  
9341 9341          /* Iterate through the properties & handle each. */
9342 9342          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343 9343                  scfdie();
9344 9344  
9345 9345          (void) memset(&elts, 0, sizeof (elts));
9346 9346  
9347 9347          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348 9348                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349 9349                          scfdie();
9350 9350  
9351 9351                  if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352 9352                      strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353 9353                      strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354 9354                      strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355 9355                          continue;
9356 9356                  } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357 9357                          xmlNodePtr m;
9358 9358  
9359 9359                          m = xmlNewNode(NULL, (xmlChar *)"stability");
9360 9360                          if (m == NULL)
9361 9361                                  uu_die(emsg_create_xml);
9362 9362  
9363 9363                          if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364 9364                                  elts.stability = m;
9365 9365                                  continue;
9366 9366                          }
9367 9367  
9368 9368                          xmlFreeNode(m);
9369 9369                  }
9370 9370  
9371 9371                  export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372 9372          }
9373 9373          if (ret == -1)
9374 9374                  scfdie();
9375 9375  
9376 9376          (void) xmlAddChild(n, elts.stability);
9377 9377          (void) xmlAddChildList(n, elts.propvals);
9378 9378          (void) xmlAddChildList(n, elts.properties);
9379 9379  
9380 9380          if (eelts->dependencies == NULL)
9381 9381                  eelts->dependencies = n;
9382 9382          else
9383 9383                  (void) xmlAddSibling(eelts->dependencies, n);
9384 9384  }
9385 9385  
9386 9386  static xmlNodePtr
9387 9387  export_method_environment(scf_propertygroup_t *pg)
9388 9388  {
9389 9389          xmlNodePtr env;
9390 9390          int ret;
9391 9391          int children = 0;
9392 9392  
9393 9393          if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394 9394                  return (NULL);
9395 9395  
9396 9396          env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397 9397          if (env == NULL)
9398 9398                  uu_die(emsg_create_xml);
9399 9399  
9400 9400          if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401 9401                  scfdie();
9402 9402  
9403 9403          if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404 9404                  scfdie();
9405 9405  
9406 9406          while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407 9407                  xmlNodePtr ev;
9408 9408                  char *cp;
9409 9409  
9410 9410                  if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411 9411                          scfdie();
9412 9412  
9413 9413                  if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414 9414                          warn(gettext("Invalid environment variable \"%s\".\n"),
9415 9415                              exp_str);
9416 9416                          continue;
9417 9417                  } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418 9418                          warn(gettext("Invalid environment variable \"%s\"; "
9419 9419                              "\"SMF_\" prefix is reserved.\n"), exp_str);
9420 9420                          continue;
9421 9421                  }
9422 9422  
9423 9423                  *cp = '\0';
9424 9424                  cp++;
9425 9425  
9426 9426                  ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427 9427                  if (ev == NULL)
9428 9428                          uu_die(emsg_create_xml);
9429 9429  
9430 9430                  safe_setprop(ev, name_attr, exp_str);
9431 9431                  safe_setprop(ev, value_attr, cp);
9432 9432                  children++;
9433 9433          }
9434 9434  
9435 9435          if (ret != 0)
9436 9436                  scfdie();
9437 9437  
9438 9438          if (children == 0) {
9439 9439                  xmlFreeNode(env);
9440 9440                  return (NULL);
9441 9441          }
9442 9442  
9443 9443          return (env);
9444 9444  }
9445 9445  
9446 9446  /*
9447 9447   * As above, but for a method property group.
9448 9448   */
9449 9449  static void
9450 9450  export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 9451  {
9452 9452          xmlNodePtr n, env;
9453 9453          char *str;
9454 9454          int err = 0, nonenv, ret;
9455 9455          uint8_t use_profile;
9456 9456          struct pg_elts elts;
9457 9457          xmlNodePtr ctxt = NULL;
9458 9458  
9459 9459          n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460 9460  
9461 9461          /* Get the required attributes. */
9462 9462  
9463 9463          /* name */
9464 9464          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465 9465                  scfdie();
9466 9466          safe_setprop(n, name_attr, exp_str);
9467 9467  
9468 9468          /* type */
9469 9469          if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470 9470              set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471 9471                  err = 1;
9472 9472  
9473 9473          /* exec */
9474 9474          if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475 9475              set_attr_from_prop(exp_prop, n, "exec") != 0)
9476 9476                  err = 1;
9477 9477  
9478 9478          /* timeout */
9479 9479          if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480 9480              prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481 9481              prop_get_val(exp_prop, exp_val) == 0) {
9482 9482                  uint64_t c;
9483 9483  
9484 9484                  if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485 9485                          scfdie();
9486 9486  
9487 9487                  str = uu_msprintf("%llu", c);
9488 9488                  if (str == NULL)
9489 9489                          uu_die(gettext("Could not create string"));
9490 9490  
9491 9491                  safe_setprop(n, "timeout_seconds", str);
9492 9492                  free(str);
9493 9493          } else
9494 9494                  err = 1;
9495 9495  
9496 9496          if (err) {
9497 9497                  xmlFreeNode(n);
9498 9498  
9499 9499                  export_pg(pg, eelts, SCE_ALL_VALUES);
9500 9500  
9501 9501                  return;
9502 9502          }
9503 9503  
9504 9504  
9505 9505          /*
9506 9506           * If we're going to have a method_context child, we need to know
9507 9507           * before we iterate through the properties.  Since method_context's
9508 9508           * are optional, we don't want to complain about any properties
  
    | ↓ open down ↓ | 9508 lines elided | ↑ open up ↑ | 
9509 9509           * missing if none of them are there.  Thus we can't use the
9510 9510           * convenience functions.
9511 9511           */
9512 9512          nonenv =
9513 9513              scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514 9514              SCF_SUCCESS ||
9515 9515              scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516 9516              SCF_SUCCESS ||
9517 9517              scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9518 9518              SCF_SUCCESS ||
     9519 +            scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
     9520 +            SCF_SUCCESS ||
9519 9521              scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 9522              SCF_SUCCESS;
9521 9523  
9522 9524          if (nonenv) {
9523 9525                  ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 9526                  if (ctxt == NULL)
9525 9527                          uu_die(emsg_create_xml);
9526 9528  
9527 9529                  if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 9530                      0 &&
9529 9531                      set_attr_from_prop_default(exp_prop, ctxt,
9530 9532                      "working_directory", ":default") != 0)
9531 9533                          err = 1;
9532 9534  
  
    | ↓ open down ↓ | 4 lines elided | ↑ open up ↑ | 
9533 9535                  if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 9536                      set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 9537                      ":default") != 0)
9536 9538                          err = 1;
9537 9539  
9538 9540                  if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 9541                      0 &&
9540 9542                      set_attr_from_prop_default(exp_prop, ctxt,
9541 9543                      "resource_pool", ":default") != 0)
9542 9544                          err = 1;
     9545 +
     9546 +                if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
     9547 +                    set_attr_from_prop_default(exp_prop, ctxt,
     9548 +                    "security_flags", ":default") != 0)
     9549 +                        err = 1;
     9550 +
9543 9551                  /*
9544 9552                   * We only want to complain about profile or credential
9545 9553                   * properties if we will use them.  To determine that we must
9546 9554                   * examine USE_PROFILE.
9547 9555                   */
9548 9556                  if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9549 9557                      prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9550 9558                      prop_get_val(exp_prop, exp_val) == 0) {
9551 9559                          if (scf_value_get_boolean(exp_val, &use_profile) !=
9552 9560                              SCF_SUCCESS) {
9553 9561                                  scfdie();
9554 9562                          }
9555 9563  
9556 9564                          if (use_profile) {
9557 9565                                  xmlNodePtr prof;
9558 9566  
9559 9567                                  prof = xmlNewChild(ctxt, NULL,
9560 9568                                      (xmlChar *)"method_profile", NULL);
9561 9569                                  if (prof == NULL)
9562 9570                                          uu_die(emsg_create_xml);
9563 9571  
9564 9572                                  if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9565 9573                                      exp_prop) != 0 ||
9566 9574                                      set_attr_from_prop(exp_prop, prof,
9567 9575                                      name_attr) != 0)
9568 9576                                          err = 1;
9569 9577                          } else {
9570 9578                                  xmlNodePtr cred;
9571 9579  
9572 9580                                  cred = xmlNewChild(ctxt, NULL,
9573 9581                                      (xmlChar *)"method_credential", NULL);
9574 9582                                  if (cred == NULL)
9575 9583                                          uu_die(emsg_create_xml);
9576 9584  
9577 9585                                  if (pg_get_prop(pg, SCF_PROPERTY_USER,
9578 9586                                      exp_prop) != 0 ||
9579 9587                                      set_attr_from_prop(exp_prop, cred,
9580 9588                                      "user") != 0) {
9581 9589                                          err = 1;
9582 9590                                  }
9583 9591  
9584 9592                                  if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9585 9593                                      exp_prop) == 0 &&
9586 9594                                      set_attr_from_prop_default(exp_prop, cred,
9587 9595                                      "group", ":default") != 0)
9588 9596                                          err = 1;
9589 9597  
9590 9598                                  if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9591 9599                                      exp_prop) == 0 &&
9592 9600                                      set_attr_from_prop_default(exp_prop, cred,
9593 9601                                      "supp_groups", ":default") != 0)
9594 9602                                          err = 1;
9595 9603  
9596 9604                                  if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9597 9605                                      exp_prop) == 0 &&
9598 9606                                      set_attr_from_prop_default(exp_prop, cred,
9599 9607                                      "privileges", ":default") != 0)
9600 9608                                          err = 1;
9601 9609  
9602 9610                                  if (pg_get_prop(pg,
9603 9611                                      SCF_PROPERTY_LIMIT_PRIVILEGES,
9604 9612                                      exp_prop) == 0 &&
9605 9613                                      set_attr_from_prop_default(exp_prop, cred,
9606 9614                                      "limit_privileges", ":default") != 0)
9607 9615                                          err = 1;
9608 9616                          }
9609 9617                  }
9610 9618          }
9611 9619  
9612 9620          if ((env = export_method_environment(pg)) != NULL) {
9613 9621                  if (ctxt == NULL) {
9614 9622                          ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9615 9623                          if (ctxt == NULL)
9616 9624                                  uu_die(emsg_create_xml);
9617 9625                  }
9618 9626                  (void) xmlAddChild(ctxt, env);
9619 9627          }
9620 9628  
9621 9629          if (env != NULL || (nonenv && err == 0))
9622 9630                  (void) xmlAddChild(n, ctxt);
9623 9631          else
9624 9632                  xmlFreeNode(ctxt);
9625 9633  
9626 9634          nonenv = (err == 0);
9627 9635  
9628 9636          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9629 9637                  scfdie();
9630 9638  
9631 9639          (void) memset(&elts, 0, sizeof (elts));
9632 9640  
9633 9641          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9634 9642                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9635 9643                          scfdie();
9636 9644  
9637 9645                  if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9638 9646                      strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9639 9647                      strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9640 9648                          continue;
9641 9649                  } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9642 9650                          xmlNodePtr m;
9643 9651  
9644 9652                          m = xmlNewNode(NULL, (xmlChar *)"stability");
9645 9653                          if (m == NULL)
9646 9654                                  uu_die(emsg_create_xml);
9647 9655  
9648 9656                          if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9649 9657                                  elts.stability = m;
9650 9658                                  continue;
9651 9659                          }
9652 9660  
9653 9661                          xmlFreeNode(m);
9654 9662                  } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
  
    | ↓ open down ↓ | 102 lines elided | ↑ open up ↑ | 
9655 9663                      0 ||
9656 9664                      strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9657 9665                      strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9658 9666                      strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9659 9667                          if (nonenv)
9660 9668                                  continue;
9661 9669                  } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9662 9670                      strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9663 9671                      strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9664 9672                      strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9665      -                    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
     9673 +                    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
     9674 +                    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9666 9675                          if (nonenv && !use_profile)
9667 9676                                  continue;
9668 9677                  } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9669 9678                          if (nonenv && use_profile)
9670 9679                                  continue;
9671 9680                  } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9672 9681                          if (env != NULL)
9673 9682                                  continue;
9674 9683                  }
9675 9684  
9676 9685                  export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9677 9686          }
9678 9687          if (ret == -1)
9679 9688                  scfdie();
9680 9689  
9681 9690          (void) xmlAddChild(n, elts.stability);
9682 9691          (void) xmlAddChildList(n, elts.propvals);
9683 9692          (void) xmlAddChildList(n, elts.properties);
9684 9693  
9685 9694          if (eelts->exec_methods == NULL)
9686 9695                  eelts->exec_methods = n;
9687 9696          else
9688 9697                  (void) xmlAddSibling(eelts->exec_methods, n);
9689 9698  }
9690 9699  
9691 9700  static void
9692 9701  export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9693 9702      struct entity_elts *eelts)
9694 9703  {
9695 9704          xmlNodePtr pgnode;
9696 9705  
9697 9706          pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9698 9707          if (pgnode == NULL)
9699 9708                  uu_die(emsg_create_xml);
9700 9709  
9701 9710          safe_setprop(pgnode, name_attr, name);
9702 9711          safe_setprop(pgnode, type_attr, type);
9703 9712  
9704 9713          (void) xmlAddChildList(pgnode, elts->propvals);
9705 9714          (void) xmlAddChildList(pgnode, elts->properties);
9706 9715  
9707 9716          if (eelts->property_groups == NULL)
9708 9717                  eelts->property_groups = pgnode;
9709 9718          else
9710 9719                  (void) xmlAddSibling(eelts->property_groups, pgnode);
9711 9720  }
9712 9721  
9713 9722  /*
9714 9723   * Process the general property group for a service.  This is the one with the
9715 9724   * goodies.
9716 9725   */
9717 9726  static void
9718 9727  export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9719 9728  {
9720 9729          struct pg_elts elts;
9721 9730          int ret;
9722 9731  
9723 9732          /*
9724 9733           * In case there are properties which don't correspond to child
9725 9734           * entities of the service entity, we'll set up a pg_elts structure to
9726 9735           * put them in.
9727 9736           */
9728 9737          (void) memset(&elts, 0, sizeof (elts));
9729 9738  
9730 9739          /* Walk the properties, looking for special ones. */
9731 9740          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9732 9741                  scfdie();
9733 9742  
9734 9743          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9735 9744                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9736 9745                          scfdie();
9737 9746  
9738 9747                  if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9739 9748                          if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9740 9749                              prop_get_val(exp_prop, exp_val) == 0) {
9741 9750                                  uint8_t b;
9742 9751  
9743 9752                                  if (scf_value_get_boolean(exp_val, &b) !=
9744 9753                                      SCF_SUCCESS)
9745 9754                                          scfdie();
9746 9755  
9747 9756                                  if (b) {
9748 9757                                          selts->single_instance =
9749 9758                                              xmlNewNode(NULL,
9750 9759                                              (xmlChar *)"single_instance");
9751 9760                                          if (selts->single_instance == NULL)
9752 9761                                                  uu_die(emsg_create_xml);
9753 9762                                  }
9754 9763  
9755 9764                                  continue;
9756 9765                          }
9757 9766                  } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9758 9767                          xmlNodePtr rnode, sfnode;
9759 9768  
9760 9769                          rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9761 9770                          if (rnode == NULL)
9762 9771                                  uu_die(emsg_create_xml);
9763 9772  
9764 9773                          sfnode = xmlNewChild(rnode, NULL,
9765 9774                              (xmlChar *)"service_fmri", NULL);
9766 9775                          if (sfnode == NULL)
9767 9776                                  uu_die(emsg_create_xml);
9768 9777  
9769 9778                          if (set_attr_from_prop(exp_prop, sfnode,
9770 9779                              value_attr) == 0) {
9771 9780                                  selts->restarter = rnode;
9772 9781                                  continue;
9773 9782                          }
9774 9783  
9775 9784                          xmlFreeNode(rnode);
9776 9785                  } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9777 9786                      0) {
9778 9787                          xmlNodePtr s;
9779 9788  
9780 9789                          s = xmlNewNode(NULL, (xmlChar *)"stability");
9781 9790                          if (s == NULL)
9782 9791                                  uu_die(emsg_create_xml);
9783 9792  
9784 9793                          if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9785 9794                                  selts->stability = s;
9786 9795                                  continue;
9787 9796                          }
9788 9797  
9789 9798                          xmlFreeNode(s);
9790 9799                  }
9791 9800  
9792 9801                  export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9793 9802          }
9794 9803          if (ret == -1)
9795 9804                  scfdie();
9796 9805  
9797 9806          if (elts.propvals != NULL || elts.properties != NULL)
9798 9807                  export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9799 9808                      selts);
9800 9809  }
9801 9810  
9802 9811  static void
9803 9812  export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9804 9813  {
9805 9814          xmlNodePtr n, prof, cred, env;
9806 9815          uint8_t use_profile;
9807 9816          int ret, err = 0;
9808 9817  
9809 9818          n = xmlNewNode(NULL, (xmlChar *)"method_context");
9810 9819  
9811 9820          env = export_method_environment(pg);
9812 9821  
9813 9822          /* Need to know whether we'll use a profile or not. */
9814 9823          if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9815 9824              prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9816 9825              prop_get_val(exp_prop, exp_val) == 0) {
9817 9826                  if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9818 9827                          scfdie();
9819 9828  
9820 9829                  if (use_profile)
9821 9830                          prof =
9822 9831                              xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9823 9832                              NULL);
9824 9833                  else
9825 9834                          cred =
9826 9835                              xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9827 9836                              NULL);
9828 9837          }
9829 9838  
9830 9839          if (env != NULL)
9831 9840                  (void) xmlAddChild(n, env);
9832 9841  
9833 9842          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9834 9843                  scfdie();
9835 9844  
9836 9845          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9837 9846                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9838 9847                          scfdie();
9839 9848  
9840 9849                  if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
  
    | ↓ open down ↓ | 165 lines elided | ↑ open up ↑ | 
9841 9850                          if (set_attr_from_prop(exp_prop, n,
9842 9851                              "working_directory") != 0)
9843 9852                                  err = 1;
9844 9853                  } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9845 9854                          if (set_attr_from_prop(exp_prop, n, "project") != 0)
9846 9855                                  err = 1;
9847 9856                  } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9848 9857                          if (set_attr_from_prop(exp_prop, n,
9849 9858                              "resource_pool") != 0)
9850 9859                                  err = 1;
     9860 +                } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
     9861 +                        if (set_attr_from_prop(exp_prop, n,
     9862 +                            "security_flags") != 0)
     9863 +                                err = 1;
9851 9864                  } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9852 9865                          /* EMPTY */
9853 9866                  } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9854 9867                          if (use_profile ||
9855 9868                              set_attr_from_prop(exp_prop, cred, "user") != 0)
9856 9869                                  err = 1;
9857 9870                  } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9858 9871                          if (use_profile ||
9859 9872                              set_attr_from_prop(exp_prop, cred, "group") != 0)
9860 9873                                  err = 1;
9861 9874                  } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9862 9875                          if (use_profile || set_attr_from_prop(exp_prop, cred,
9863 9876                              "supp_groups") != 0)
9864 9877                                  err = 1;
9865 9878                  } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9866 9879                          if (use_profile || set_attr_from_prop(exp_prop, cred,
9867 9880                              "privileges") != 0)
9868 9881                                  err = 1;
9869 9882                  } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9870 9883                      0) {
9871 9884                          if (use_profile || set_attr_from_prop(exp_prop, cred,
9872 9885                              "limit_privileges") != 0)
9873 9886                                  err = 1;
9874 9887                  } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9875 9888                          if (!use_profile || set_attr_from_prop(exp_prop,
9876 9889                              prof, name_attr) != 0)
9877 9890                                  err = 1;
9878 9891                  } else {
9879 9892                          /* Can't have generic properties in method_context's */
9880 9893                          err = 1;
9881 9894                  }
9882 9895          }
9883 9896          if (ret == -1)
9884 9897                  scfdie();
9885 9898  
9886 9899          if (err && env == NULL) {
9887 9900                  xmlFreeNode(n);
9888 9901                  export_pg(pg, elts, SCE_ALL_VALUES);
9889 9902                  return;
9890 9903          }
9891 9904  
9892 9905          elts->method_context = n;
9893 9906  }
9894 9907  
9895 9908  /*
9896 9909   * Given a dependency property group in the tfmri entity (target fmri), return
9897 9910   * a dependent element which represents it.
9898 9911   */
9899 9912  static xmlNodePtr
9900 9913  export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9901 9914  {
9902 9915          uint8_t b;
9903 9916          xmlNodePtr n, sf;
9904 9917          int err = 0, ret;
9905 9918          struct pg_elts pgelts;
9906 9919  
9907 9920          /*
9908 9921           * If external isn't set to true then exporting the service will
9909 9922           * export this as a normal dependency, so we should stop to avoid
9910 9923           * duplication.
9911 9924           */
9912 9925          if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9913 9926              scf_property_get_value(exp_prop, exp_val) != 0 ||
9914 9927              scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9915 9928                  if (g_verbose) {
9916 9929                          warn(gettext("Dependent \"%s\" cannot be exported "
9917 9930                              "properly because the \"%s\" property of the "
9918 9931                              "\"%s\" dependency of %s is not set to true.\n"),
9919 9932                              name, scf_property_external, name, tfmri);
9920 9933                  }
9921 9934  
9922 9935                  return (NULL);
9923 9936          }
9924 9937  
9925 9938          n = xmlNewNode(NULL, (xmlChar *)"dependent");
9926 9939          if (n == NULL)
9927 9940                  uu_die(emsg_create_xml);
9928 9941  
9929 9942          safe_setprop(n, name_attr, name);
9930 9943  
9931 9944          /* Get the required attributes */
9932 9945          if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9933 9946              set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9934 9947                  err = 1;
9935 9948  
9936 9949          if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9937 9950              set_attr_from_prop(exp_prop, n, "grouping") != 0)
9938 9951                  err = 1;
9939 9952  
9940 9953          if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9941 9954              prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9942 9955              prop_get_val(exp_prop, exp_val) == 0) {
9943 9956                  /* EMPTY */
9944 9957          } else
9945 9958                  err = 1;
9946 9959  
9947 9960          if (err) {
9948 9961                  xmlFreeNode(n);
9949 9962                  return (NULL);
9950 9963          }
9951 9964  
9952 9965          sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9953 9966          if (sf == NULL)
9954 9967                  uu_die(emsg_create_xml);
9955 9968  
9956 9969          safe_setprop(sf, value_attr, tfmri);
9957 9970  
9958 9971          /*
9959 9972           * Now add elements for the other properties.
9960 9973           */
9961 9974          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9962 9975                  scfdie();
9963 9976  
9964 9977          (void) memset(&pgelts, 0, sizeof (pgelts));
9965 9978  
9966 9979          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9967 9980                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9968 9981                          scfdie();
9969 9982  
9970 9983                  if (strcmp(exp_str, scf_property_external) == 0 ||
9971 9984                      strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9972 9985                      strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9973 9986                      strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9974 9987                          continue;
9975 9988                  } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9976 9989                          if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9977 9990                              prop_get_val(exp_prop, exp_val) == 0) {
9978 9991                                  char type[sizeof ("service") + 1];
9979 9992  
9980 9993                                  if (scf_value_get_astring(exp_val, type,
9981 9994                                      sizeof (type)) < 0)
9982 9995                                          scfdie();
9983 9996  
9984 9997                                  if (strcmp(type, "service") == 0)
9985 9998                                          continue;
9986 9999                          }
9987 10000                  } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9988 10001                          xmlNodePtr s;
9989 10002  
9990 10003                          s = xmlNewNode(NULL, (xmlChar *)"stability");
9991 10004                          if (s == NULL)
9992 10005                                  uu_die(emsg_create_xml);
9993 10006  
9994 10007                          if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9995 10008                                  pgelts.stability = s;
9996 10009                                  continue;
9997 10010                          }
9998 10011  
9999 10012                          xmlFreeNode(s);
10000 10013                  }
10001 10014  
10002 10015                  export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10003 10016          }
10004 10017          if (ret == -1)
10005 10018                  scfdie();
10006 10019  
10007 10020          (void) xmlAddChild(n, pgelts.stability);
10008 10021          (void) xmlAddChildList(n, pgelts.propvals);
10009 10022          (void) xmlAddChildList(n, pgelts.properties);
10010 10023  
10011 10024          return (n);
10012 10025  }
10013 10026  
10014 10027  static void
10015 10028  export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10016 10029  {
10017 10030          scf_propertygroup_t *opg;
10018 10031          scf_iter_t *iter;
10019 10032          char *type, *fmri;
10020 10033          int ret;
10021 10034          struct pg_elts pgelts;
10022 10035          xmlNodePtr n;
10023 10036          scf_error_t serr;
10024 10037  
10025 10038          if ((opg = scf_pg_create(g_hndl)) == NULL ||
10026 10039              (iter = scf_iter_create(g_hndl)) == NULL)
10027 10040                  scfdie();
10028 10041  
10029 10042          /* Can't use exp_prop_iter due to export_dependent(). */
10030 10043          if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10031 10044                  scfdie();
10032 10045  
10033 10046          type = safe_malloc(max_scf_pg_type_len + 1);
10034 10047  
10035 10048          /* Get an extra byte so we can tell if values are too long. */
10036 10049          fmri = safe_malloc(max_scf_fmri_len + 2);
10037 10050  
10038 10051          (void) memset(&pgelts, 0, sizeof (pgelts));
10039 10052  
10040 10053          while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10041 10054                  void *entity;
10042 10055                  int isservice;
10043 10056                  scf_type_t ty;
10044 10057  
10045 10058                  if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10046 10059                          scfdie();
10047 10060  
10048 10061                  if ((ty != SCF_TYPE_ASTRING &&
10049 10062                      prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10050 10063                      prop_get_val(exp_prop, exp_val) != 0) {
10051 10064                          export_property(exp_prop, NULL, &pgelts,
10052 10065                              SCE_ALL_VALUES);
10053 10066                          continue;
10054 10067                  }
10055 10068  
10056 10069                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10057 10070                          scfdie();
10058 10071  
10059 10072                  if (scf_value_get_astring(exp_val, fmri,
10060 10073                      max_scf_fmri_len + 2) < 0)
10061 10074                          scfdie();
10062 10075  
10063 10076                  /* Look for a dependency group in the target fmri. */
10064 10077                  serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10065 10078                  switch (serr) {
10066 10079                  case SCF_ERROR_NONE:
10067 10080                          break;
10068 10081  
10069 10082                  case SCF_ERROR_NO_MEMORY:
10070 10083                          uu_die(gettext("Out of memory.\n"));
10071 10084                          /* NOTREACHED */
10072 10085  
10073 10086                  case SCF_ERROR_INVALID_ARGUMENT:
10074 10087                          if (g_verbose) {
10075 10088                                  if (scf_property_to_fmri(exp_prop, fmri,
10076 10089                                      max_scf_fmri_len + 2) < 0)
10077 10090                                          scfdie();
10078 10091  
10079 10092                                  warn(gettext("The value of %s is not a valid "
10080 10093                                      "FMRI.\n"), fmri);
10081 10094                          }
10082 10095  
10083 10096                          export_property(exp_prop, exp_str, &pgelts,
10084 10097                              SCE_ALL_VALUES);
10085 10098                          continue;
10086 10099  
10087 10100                  case SCF_ERROR_CONSTRAINT_VIOLATED:
10088 10101                          if (g_verbose) {
10089 10102                                  if (scf_property_to_fmri(exp_prop, fmri,
10090 10103                                      max_scf_fmri_len + 2) < 0)
10091 10104                                          scfdie();
10092 10105  
10093 10106                                  warn(gettext("The value of %s does not specify "
10094 10107                                      "a service or an instance.\n"), fmri);
10095 10108                          }
10096 10109  
10097 10110                          export_property(exp_prop, exp_str, &pgelts,
10098 10111                              SCE_ALL_VALUES);
10099 10112                          continue;
10100 10113  
10101 10114                  case SCF_ERROR_NOT_FOUND:
10102 10115                          if (g_verbose) {
10103 10116                                  if (scf_property_to_fmri(exp_prop, fmri,
10104 10117                                      max_scf_fmri_len + 2) < 0)
10105 10118                                          scfdie();
10106 10119  
10107 10120                                  warn(gettext("The entity specified by %s does "
10108 10121                                      "not exist.\n"), fmri);
10109 10122                          }
10110 10123  
10111 10124                          export_property(exp_prop, exp_str, &pgelts,
10112 10125                              SCE_ALL_VALUES);
10113 10126                          continue;
10114 10127  
10115 10128                  default:
10116 10129  #ifndef NDEBUG
10117 10130                          (void) fprintf(stderr, "%s:%d: %s() failed with "
10118 10131                              "unexpected error %d.\n", __FILE__, __LINE__,
10119 10132                              "fmri_to_entity", serr);
10120 10133  #endif
10121 10134                          abort();
10122 10135                  }
10123 10136  
10124 10137                  if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10125 10138                          if (scf_error() != SCF_ERROR_NOT_FOUND)
10126 10139                                  scfdie();
10127 10140  
10128 10141                          warn(gettext("Entity %s is missing dependency property "
10129 10142                              "group %s.\n"), fmri, exp_str);
10130 10143  
10131 10144                          export_property(exp_prop, NULL, &pgelts,
10132 10145                              SCE_ALL_VALUES);
10133 10146                          continue;
10134 10147                  }
10135 10148  
10136 10149                  if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10137 10150                          scfdie();
10138 10151  
10139 10152                  if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10140 10153                          if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10141 10154                                  scfdie();
10142 10155  
10143 10156                          warn(gettext("Property group %s is not of "
10144 10157                              "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10145 10158  
10146 10159                          export_property(exp_prop, NULL, &pgelts,
10147 10160                              SCE_ALL_VALUES);
10148 10161                          continue;
10149 10162                  }
10150 10163  
10151 10164                  n = export_dependent(opg, exp_str, fmri);
10152 10165                  if (n == NULL) {
10153 10166                          export_property(exp_prop, exp_str, &pgelts,
10154 10167                              SCE_ALL_VALUES);
10155 10168                  } else {
10156 10169                          if (eelts->dependents == NULL)
10157 10170                                  eelts->dependents = n;
10158 10171                          else
10159 10172                                  (void) xmlAddSibling(eelts->dependents,
10160 10173                                      n);
10161 10174                  }
10162 10175          }
10163 10176          if (ret == -1)
10164 10177                  scfdie();
10165 10178  
10166 10179          free(fmri);
10167 10180          free(type);
10168 10181  
10169 10182          scf_iter_destroy(iter);
10170 10183          scf_pg_destroy(opg);
10171 10184  
10172 10185          if (pgelts.propvals != NULL || pgelts.properties != NULL)
10173 10186                  export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10174 10187                      eelts);
10175 10188  }
10176 10189  
10177 10190  static void
10178 10191  make_node(xmlNodePtr *nodep, const char *name)
10179 10192  {
10180 10193          if (*nodep == NULL) {
10181 10194                  *nodep = xmlNewNode(NULL, (xmlChar *)name);
10182 10195                  if (*nodep == NULL)
10183 10196                          uu_die(emsg_create_xml);
10184 10197          }
10185 10198  }
10186 10199  
10187 10200  static xmlNodePtr
10188 10201  export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10189 10202  {
10190 10203          int ret;
10191 10204          xmlNodePtr parent = NULL;
10192 10205          xmlNodePtr loctext = NULL;
10193 10206  
10194 10207          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10195 10208                  scfdie();
10196 10209  
10197 10210          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10198 10211                  if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10199 10212                      prop_get_val(exp_prop, exp_val) != 0)
10200 10213                          continue;
10201 10214  
10202 10215                  if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10203 10216                          scfdie();
10204 10217  
10205 10218                  make_node(&parent, parname);
10206 10219                  loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10207 10220                      (xmlChar *)exp_str);
10208 10221                  if (loctext == NULL)
10209 10222                          uu_die(emsg_create_xml);
10210 10223  
10211 10224                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10212 10225                          scfdie();
10213 10226  
10214 10227                  safe_setprop(loctext, "xml:lang", exp_str);
10215 10228          }
10216 10229  
10217 10230          if (ret == -1)
10218 10231                  scfdie();
10219 10232  
10220 10233          return (parent);
10221 10234  }
10222 10235  
10223 10236  static xmlNodePtr
10224 10237  export_tm_manpage(scf_propertygroup_t *pg)
10225 10238  {
10226 10239          xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10227 10240          if (manpage == NULL)
10228 10241                  uu_die(emsg_create_xml);
10229 10242  
10230 10243          if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10231 10244              set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10232 10245              pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10233 10246              set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10234 10247                  xmlFreeNode(manpage);
10235 10248                  return (NULL);
10236 10249          }
10237 10250  
10238 10251          if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10239 10252                  (void) set_attr_from_prop_default(exp_prop,
10240 10253                      manpage, "manpath", ":default");
10241 10254  
10242 10255          return (manpage);
10243 10256  }
10244 10257  
10245 10258  static xmlNodePtr
10246 10259  export_tm_doc_link(scf_propertygroup_t *pg)
10247 10260  {
10248 10261          xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10249 10262          if (doc_link == NULL)
10250 10263                  uu_die(emsg_create_xml);
10251 10264  
10252 10265          if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10253 10266              set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10254 10267              pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10255 10268              set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10256 10269                  xmlFreeNode(doc_link);
10257 10270                  return (NULL);
10258 10271          }
10259 10272          return (doc_link);
10260 10273  }
10261 10274  
10262 10275  /*
10263 10276   * Process template information for a service or instances.
10264 10277   */
10265 10278  static void
10266 10279  export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10267 10280      struct template_elts *telts)
10268 10281  {
10269 10282          size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10270 10283          size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10271 10284          xmlNodePtr child = NULL;
10272 10285  
10273 10286          if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10274 10287                  scfdie();
10275 10288  
10276 10289          if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10277 10290                  telts->common_name = export_tm_loctext(pg, "common_name");
10278 10291                  if (telts->common_name == NULL)
10279 10292                          export_pg(pg, elts, SCE_ALL_VALUES);
10280 10293                  return;
10281 10294          } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10282 10295                  telts->description = export_tm_loctext(pg, "description");
10283 10296                  if (telts->description == NULL)
10284 10297                          export_pg(pg, elts, SCE_ALL_VALUES);
10285 10298                  return;
10286 10299          }
10287 10300  
10288 10301          if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10289 10302                  child = export_tm_manpage(pg);
10290 10303          } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10291 10304                  child = export_tm_doc_link(pg);
10292 10305          }
10293 10306  
10294 10307          if (child != NULL) {
10295 10308                  make_node(&telts->documentation, "documentation");
10296 10309                  (void) xmlAddChild(telts->documentation, child);
10297 10310          } else {
10298 10311                  export_pg(pg, elts, SCE_ALL_VALUES);
10299 10312          }
10300 10313  }
10301 10314  
10302 10315  /*
10303 10316   * Process parameter and paramval elements
10304 10317   */
10305 10318  static void
10306 10319  export_parameter(scf_property_t *prop, const char *name,
10307 10320      struct params_elts *elts)
10308 10321  {
10309 10322          xmlNodePtr param;
10310 10323          scf_error_t err = 0;
10311 10324          int ret;
10312 10325  
10313 10326          if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10314 10327                  if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10315 10328                          uu_die(emsg_create_xml);
10316 10329  
10317 10330                  safe_setprop(param, name_attr, name);
10318 10331  
10319 10332                  if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10320 10333                          scfdie();
10321 10334                  safe_setprop(param, value_attr, exp_str);
10322 10335  
10323 10336                  if (elts->paramval == NULL)
10324 10337                          elts->paramval = param;
10325 10338                  else
10326 10339                          (void) xmlAddSibling(elts->paramval, param);
10327 10340  
10328 10341                  return;
10329 10342          }
10330 10343  
10331 10344          err = scf_error();
10332 10345  
10333 10346          if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10334 10347              err != SCF_ERROR_NOT_FOUND)
10335 10348                  scfdie();
10336 10349  
10337 10350          if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10338 10351                  uu_die(emsg_create_xml);
10339 10352  
10340 10353          safe_setprop(param, name_attr, name);
10341 10354  
10342 10355          if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10343 10356                  if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10344 10357                          scfdie();
10345 10358  
10346 10359                  while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10347 10360                      1) {
10348 10361                          xmlNodePtr vn;
10349 10362  
10350 10363                          if ((vn = xmlNewChild(param, NULL,
10351 10364                              (xmlChar *)"value_node", NULL)) == NULL)
10352 10365                                  uu_die(emsg_create_xml);
10353 10366  
10354 10367                          if (scf_value_get_as_string(exp_val, exp_str,
10355 10368                              exp_str_sz) < 0)
10356 10369                                  scfdie();
10357 10370  
10358 10371                          safe_setprop(vn, value_attr, exp_str);
10359 10372                  }
10360 10373                  if (ret != 0)
10361 10374                          scfdie();
10362 10375          }
10363 10376  
10364 10377          if (elts->parameter == NULL)
10365 10378                  elts->parameter = param;
10366 10379          else
10367 10380                  (void) xmlAddSibling(elts->parameter, param);
10368 10381  }
10369 10382  
10370 10383  /*
10371 10384   * Process notification parameters for a service or instance
10372 10385   */
10373 10386  static void
10374 10387  export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10375 10388  {
10376 10389          xmlNodePtr n, event, *type;
10377 10390          struct params_elts *eelts;
10378 10391          int ret, err, i;
10379 10392  
10380 10393          n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10381 10394          event = xmlNewNode(NULL, (xmlChar *)"event");
10382 10395          if (n == NULL || event == NULL)
10383 10396                  uu_die(emsg_create_xml);
10384 10397  
10385 10398          /* event value */
10386 10399          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10387 10400                  scfdie();
10388 10401          safe_setprop(event, value_attr, exp_str);
10389 10402  
10390 10403          (void) xmlAddChild(n, event);
10391 10404  
10392 10405          if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10393 10406              (eelts = calloc(URI_SCHEME_NUM,
10394 10407              sizeof (struct params_elts))) == NULL)
10395 10408                  uu_die(gettext("Out of memory.\n"));
10396 10409  
10397 10410          err = 0;
10398 10411  
10399 10412          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10400 10413                  scfdie();
10401 10414  
10402 10415          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10403 10416                  char *t, *p;
10404 10417  
10405 10418                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10406 10419                          scfdie();
10407 10420  
10408 10421                  if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10409 10422                          /*
10410 10423                           * this is not a well formed notification parameters
10411 10424                           * element, we should export as regular pg
10412 10425                           */
10413 10426                          err = 1;
10414 10427                          break;
10415 10428                  }
10416 10429  
10417 10430                  if ((i = check_uri_protocol(t)) < 0) {
10418 10431                          err = 1;
10419 10432                          break;
10420 10433                  }
10421 10434  
10422 10435                  if (type[i] == NULL) {
10423 10436                          if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10424 10437                              NULL)
10425 10438                                  uu_die(emsg_create_xml);
10426 10439  
10427 10440                          safe_setprop(type[i], name_attr, t);
10428 10441                  }
10429 10442                  if (strcmp(p, active_attr) == 0) {
10430 10443                          if (set_attr_from_prop(exp_prop, type[i],
10431 10444                              active_attr) != 0) {
10432 10445                                  err = 1;
10433 10446                                  break;
10434 10447                          }
10435 10448                          continue;
10436 10449                  }
10437 10450                  /*
10438 10451                   * We export the parameter
10439 10452                   */
10440 10453                  export_parameter(exp_prop, p, &eelts[i]);
10441 10454          }
10442 10455  
10443 10456          if (ret == -1)
10444 10457                  scfdie();
10445 10458  
10446 10459          if (err == 1) {
10447 10460                  for (i = 0; i < URI_SCHEME_NUM; ++i)
10448 10461                          xmlFree(type[i]);
10449 10462                  free(type);
10450 10463  
10451 10464                  export_pg(pg, elts, SCE_ALL_VALUES);
10452 10465  
10453 10466                  return;
10454 10467          } else {
10455 10468                  for (i = 0; i < URI_SCHEME_NUM; ++i)
10456 10469                          if (type[i] != NULL) {
10457 10470                                  (void) xmlAddChildList(type[i],
10458 10471                                      eelts[i].paramval);
10459 10472                                  (void) xmlAddChildList(type[i],
10460 10473                                      eelts[i].parameter);
10461 10474                                  (void) xmlAddSibling(event, type[i]);
10462 10475                          }
10463 10476          }
10464 10477          free(type);
10465 10478  
10466 10479          if (elts->notify_params == NULL)
10467 10480                  elts->notify_params = n;
10468 10481          else
10469 10482                  (void) xmlAddSibling(elts->notify_params, n);
10470 10483  }
10471 10484  
10472 10485  /*
10473 10486   * Process the general property group for an instance.
10474 10487   */
10475 10488  static void
10476 10489  export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10477 10490      struct entity_elts *elts)
10478 10491  {
10479 10492          uint8_t enabled;
10480 10493          struct pg_elts pgelts;
10481 10494          int ret;
10482 10495  
10483 10496          /* enabled */
10484 10497          if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10485 10498              prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10486 10499              prop_get_val(exp_prop, exp_val) == 0) {
10487 10500                  if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10488 10501                          scfdie();
10489 10502          } else {
10490 10503                  enabled = 0;
10491 10504          }
10492 10505  
10493 10506          safe_setprop(inode, enabled_attr, enabled ? true : false);
10494 10507  
10495 10508          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10496 10509                  scfdie();
10497 10510  
10498 10511          (void) memset(&pgelts, 0, sizeof (pgelts));
10499 10512  
10500 10513          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10501 10514                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10502 10515                          scfdie();
10503 10516  
10504 10517                  if (strcmp(exp_str, scf_property_enabled) == 0) {
10505 10518                          continue;
10506 10519                  } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10507 10520                          xmlNodePtr rnode, sfnode;
10508 10521  
10509 10522                          rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10510 10523                          if (rnode == NULL)
10511 10524                                  uu_die(emsg_create_xml);
10512 10525  
10513 10526                          sfnode = xmlNewChild(rnode, NULL,
10514 10527                              (xmlChar *)"service_fmri", NULL);
10515 10528                          if (sfnode == NULL)
10516 10529                                  uu_die(emsg_create_xml);
10517 10530  
10518 10531                          if (set_attr_from_prop(exp_prop, sfnode,
10519 10532                              value_attr) == 0) {
10520 10533                                  elts->restarter = rnode;
10521 10534                                  continue;
10522 10535                          }
10523 10536  
10524 10537                          xmlFreeNode(rnode);
10525 10538                  }
10526 10539  
10527 10540                  export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10528 10541          }
10529 10542          if (ret == -1)
10530 10543                  scfdie();
10531 10544  
10532 10545          if (pgelts.propvals != NULL || pgelts.properties != NULL)
10533 10546                  export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10534 10547                      elts);
10535 10548  }
10536 10549  
10537 10550  /*
10538 10551   * Put an instance element for the given instance into selts.
10539 10552   */
10540 10553  static void
10541 10554  export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10542 10555  {
10543 10556          xmlNodePtr n;
10544 10557          boolean_t isdefault;
10545 10558          struct entity_elts elts;
10546 10559          struct template_elts template_elts;
10547 10560          int ret;
10548 10561  
10549 10562          n = xmlNewNode(NULL, (xmlChar *)"instance");
10550 10563          if (n == NULL)
10551 10564                  uu_die(emsg_create_xml);
10552 10565  
10553 10566          /* name */
10554 10567          if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10555 10568                  scfdie();
10556 10569          safe_setprop(n, name_attr, exp_str);
10557 10570          isdefault = strcmp(exp_str, "default") == 0;
10558 10571  
10559 10572          /* check existance of general pg (since general/enabled is required) */
10560 10573          if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10561 10574                  if (scf_error() != SCF_ERROR_NOT_FOUND)
10562 10575                          scfdie();
10563 10576  
10564 10577                  if (g_verbose) {
10565 10578                          if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10566 10579                                  scfdie();
10567 10580  
10568 10581                          warn(gettext("Instance %s has no general property "
10569 10582                              "group; it will be marked disabled.\n"), exp_str);
10570 10583                  }
10571 10584  
10572 10585                  safe_setprop(n, enabled_attr, false);
10573 10586          } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10574 10587              strcmp(exp_str, scf_group_framework) != 0) {
10575 10588                  if (g_verbose) {
10576 10589                          if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10577 10590                                  scfdie();
10578 10591  
10579 10592                          warn(gettext("Property group %s is not of type "
10580 10593                              "framework; the instance will be marked "
10581 10594                              "disabled.\n"), exp_str);
10582 10595                  }
10583 10596  
10584 10597                  safe_setprop(n, enabled_attr, false);
10585 10598          }
10586 10599  
10587 10600          /* property groups */
10588 10601          if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10589 10602                  scfdie();
10590 10603  
10591 10604          (void) memset(&elts, 0, sizeof (elts));
10592 10605          (void) memset(&template_elts, 0, sizeof (template_elts));
10593 10606  
10594 10607          while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10595 10608                  uint32_t pgflags;
10596 10609  
10597 10610                  if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10598 10611                          scfdie();
10599 10612  
10600 10613                  if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10601 10614                          continue;
10602 10615  
10603 10616                  if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10604 10617                          scfdie();
10605 10618  
10606 10619                  if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10607 10620                          export_dependency(exp_pg, &elts);
10608 10621                          continue;
10609 10622                  } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10610 10623                          export_method(exp_pg, &elts);
10611 10624                          continue;
10612 10625                  } else if (strcmp(exp_str, scf_group_framework) == 0) {
10613 10626                          if (scf_pg_get_name(exp_pg, exp_str,
10614 10627                              max_scf_name_len + 1) < 0)
10615 10628                                  scfdie();
10616 10629  
10617 10630                          if (strcmp(exp_str, scf_pg_general) == 0) {
10618 10631                                  export_inst_general(exp_pg, n, &elts);
10619 10632                                  continue;
10620 10633                          } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10621 10634                              0) {
10622 10635                                  export_method_context(exp_pg, &elts);
10623 10636                                  continue;
10624 10637                          } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10625 10638                                  export_dependents(exp_pg, &elts);
10626 10639                                  continue;
10627 10640                          }
10628 10641                  } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10629 10642                          export_template(exp_pg, &elts, &template_elts);
10630 10643                          continue;
10631 10644                  } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10632 10645                          export_notify_params(exp_pg, &elts);
10633 10646                          continue;
10634 10647                  }
10635 10648  
10636 10649                  /* Ordinary pg. */
10637 10650                  export_pg(exp_pg, &elts, flags);
10638 10651          }
10639 10652          if (ret == -1)
10640 10653                  scfdie();
10641 10654  
10642 10655          if (template_elts.common_name != NULL) {
10643 10656                  elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10644 10657                  (void) xmlAddChild(elts.template, template_elts.common_name);
10645 10658                  (void) xmlAddChild(elts.template, template_elts.description);
10646 10659                  (void) xmlAddChild(elts.template, template_elts.documentation);
10647 10660          } else {
10648 10661                  xmlFreeNode(template_elts.description);
10649 10662                  xmlFreeNode(template_elts.documentation);
10650 10663          }
10651 10664  
10652 10665          if (isdefault && elts.restarter == NULL &&
10653 10666              elts.dependencies == NULL && elts.method_context == NULL &&
10654 10667              elts.exec_methods == NULL && elts.notify_params == NULL &&
10655 10668              elts.property_groups == NULL && elts.template == NULL) {
10656 10669                  xmlChar *eval;
10657 10670  
10658 10671                  /* This is a default instance */
10659 10672                  eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10660 10673  
10661 10674                  xmlFreeNode(n);
10662 10675  
10663 10676                  n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10664 10677                  if (n == NULL)
10665 10678                          uu_die(emsg_create_xml);
10666 10679  
10667 10680                  safe_setprop(n, enabled_attr, (char *)eval);
10668 10681                  xmlFree(eval);
10669 10682  
10670 10683                  selts->create_default_instance = n;
10671 10684          } else {
10672 10685                  /* Assemble the children in order. */
10673 10686                  (void) xmlAddChild(n, elts.restarter);
10674 10687                  (void) xmlAddChildList(n, elts.dependencies);
10675 10688                  (void) xmlAddChildList(n, elts.dependents);
10676 10689                  (void) xmlAddChild(n, elts.method_context);
10677 10690                  (void) xmlAddChildList(n, elts.exec_methods);
10678 10691                  (void) xmlAddChildList(n, elts.notify_params);
10679 10692                  (void) xmlAddChildList(n, elts.property_groups);
10680 10693                  (void) xmlAddChild(n, elts.template);
10681 10694  
10682 10695                  if (selts->instances == NULL)
10683 10696                          selts->instances = n;
10684 10697                  else
10685 10698                          (void) xmlAddSibling(selts->instances, n);
10686 10699          }
10687 10700  }
10688 10701  
10689 10702  /*
10690 10703   * Return a service element for the given service.
10691 10704   */
10692 10705  static xmlNodePtr
10693 10706  export_service(scf_service_t *svc, int flags)
10694 10707  {
10695 10708          xmlNodePtr snode;
10696 10709          struct entity_elts elts;
10697 10710          struct template_elts template_elts;
10698 10711          int ret;
10699 10712  
10700 10713          snode = xmlNewNode(NULL, (xmlChar *)"service");
10701 10714          if (snode == NULL)
10702 10715                  uu_die(emsg_create_xml);
10703 10716  
10704 10717          /* Get & set name attribute */
10705 10718          if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10706 10719                  scfdie();
10707 10720          safe_setprop(snode, name_attr, exp_str);
10708 10721  
10709 10722          safe_setprop(snode, type_attr, "service");
10710 10723          safe_setprop(snode, "version", "0");
10711 10724  
10712 10725          /* Acquire child elements. */
10713 10726          if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10714 10727                  scfdie();
10715 10728  
10716 10729          (void) memset(&elts, 0, sizeof (elts));
10717 10730          (void) memset(&template_elts, 0, sizeof (template_elts));
10718 10731  
10719 10732          while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10720 10733                  uint32_t pgflags;
10721 10734  
10722 10735                  if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10723 10736                          scfdie();
10724 10737  
10725 10738                  if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10726 10739                          continue;
10727 10740  
10728 10741                  if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10729 10742                          scfdie();
10730 10743  
10731 10744                  if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10732 10745                          export_dependency(exp_pg, &elts);
10733 10746                          continue;
10734 10747                  } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10735 10748                          export_method(exp_pg, &elts);
10736 10749                          continue;
10737 10750                  } else if (strcmp(exp_str, scf_group_framework) == 0) {
10738 10751                          if (scf_pg_get_name(exp_pg, exp_str,
10739 10752                              max_scf_name_len + 1) < 0)
10740 10753                                  scfdie();
10741 10754  
10742 10755                          if (strcmp(exp_str, scf_pg_general) == 0) {
10743 10756                                  export_svc_general(exp_pg, &elts);
10744 10757                                  continue;
10745 10758                          } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10746 10759                              0) {
10747 10760                                  export_method_context(exp_pg, &elts);
10748 10761                                  continue;
10749 10762                          } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10750 10763                                  export_dependents(exp_pg, &elts);
10751 10764                                  continue;
10752 10765                          } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10753 10766                                  continue;
10754 10767                          }
10755 10768                  } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10756 10769                          export_template(exp_pg, &elts, &template_elts);
10757 10770                          continue;
10758 10771                  } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10759 10772                          export_notify_params(exp_pg, &elts);
10760 10773                          continue;
10761 10774                  }
10762 10775  
10763 10776                  export_pg(exp_pg, &elts, flags);
10764 10777          }
10765 10778          if (ret == -1)
10766 10779                  scfdie();
10767 10780  
10768 10781          if (template_elts.common_name != NULL) {
10769 10782                  elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10770 10783                  (void) xmlAddChild(elts.template, template_elts.common_name);
10771 10784                  (void) xmlAddChild(elts.template, template_elts.description);
10772 10785                  (void) xmlAddChild(elts.template, template_elts.documentation);
10773 10786          } else {
10774 10787                  xmlFreeNode(template_elts.description);
10775 10788                  xmlFreeNode(template_elts.documentation);
10776 10789          }
10777 10790  
10778 10791          /* Iterate instances */
10779 10792          if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10780 10793                  scfdie();
10781 10794  
10782 10795          while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10783 10796                  export_instance(exp_inst, &elts, flags);
10784 10797          if (ret == -1)
10785 10798                  scfdie();
10786 10799  
10787 10800          /* Now add all of the accumulated elements in order. */
10788 10801          (void) xmlAddChild(snode, elts.create_default_instance);
10789 10802          (void) xmlAddChild(snode, elts.single_instance);
10790 10803          (void) xmlAddChild(snode, elts.restarter);
10791 10804          (void) xmlAddChildList(snode, elts.dependencies);
10792 10805          (void) xmlAddChildList(snode, elts.dependents);
10793 10806          (void) xmlAddChild(snode, elts.method_context);
10794 10807          (void) xmlAddChildList(snode, elts.exec_methods);
10795 10808          (void) xmlAddChildList(snode, elts.notify_params);
10796 10809          (void) xmlAddChildList(snode, elts.property_groups);
10797 10810          (void) xmlAddChildList(snode, elts.instances);
10798 10811          (void) xmlAddChild(snode, elts.stability);
10799 10812          (void) xmlAddChild(snode, elts.template);
10800 10813  
10801 10814          return (snode);
10802 10815  }
10803 10816  
10804 10817  static int
10805 10818  export_callback(void *data, scf_walkinfo_t *wip)
10806 10819  {
10807 10820          FILE *f;
10808 10821          xmlDocPtr doc;
10809 10822          xmlNodePtr sb;
10810 10823          int result;
10811 10824          struct export_args *argsp = (struct export_args *)data;
10812 10825  
10813 10826          if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10814 10827              (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10815 10828              (exp_prop = scf_property_create(g_hndl)) == NULL ||
10816 10829              (exp_val = scf_value_create(g_hndl)) == NULL ||
10817 10830              (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10818 10831              (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10819 10832              (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10820 10833              (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10821 10834                  scfdie();
10822 10835  
10823 10836          exp_str_sz = max_scf_len + 1;
10824 10837          exp_str = safe_malloc(exp_str_sz);
10825 10838  
10826 10839          if (argsp->filename != NULL) {
10827 10840                  errno = 0;
10828 10841                  f = fopen(argsp->filename, "wb");
10829 10842                  if (f == NULL) {
10830 10843                          if (errno == 0)
10831 10844                                  uu_die(gettext("Could not open \"%s\": no free "
10832 10845                                      "stdio streams.\n"), argsp->filename);
10833 10846                          else
10834 10847                                  uu_die(gettext("Could not open \"%s\""),
10835 10848                                      argsp->filename);
10836 10849                  }
10837 10850          } else
10838 10851                  f = stdout;
10839 10852  
10840 10853          doc = xmlNewDoc((xmlChar *)"1.0");
10841 10854          if (doc == NULL)
10842 10855                  uu_die(gettext("Could not create XML document.\n"));
10843 10856  
10844 10857          if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10845 10858              (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10846 10859                  uu_die(emsg_create_xml);
10847 10860  
10848 10861          sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10849 10862          if (sb == NULL)
10850 10863                  uu_die(emsg_create_xml);
10851 10864          safe_setprop(sb, type_attr, "manifest");
10852 10865          safe_setprop(sb, name_attr, "export");
10853 10866          (void) xmlAddSibling(doc->children, sb);
10854 10867  
10855 10868          (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10856 10869  
10857 10870          result = write_service_bundle(doc, f);
10858 10871  
10859 10872          free(exp_str);
10860 10873          scf_iter_destroy(exp_val_iter);
10861 10874          scf_iter_destroy(exp_prop_iter);
10862 10875          scf_iter_destroy(exp_pg_iter);
10863 10876          scf_iter_destroy(exp_inst_iter);
10864 10877          scf_value_destroy(exp_val);
10865 10878          scf_property_destroy(exp_prop);
10866 10879          scf_pg_destroy(exp_pg);
10867 10880          scf_instance_destroy(exp_inst);
10868 10881  
10869 10882          xmlFreeDoc(doc);
10870 10883  
10871 10884          if (f != stdout)
10872 10885                  (void) fclose(f);
10873 10886  
10874 10887          return (result);
10875 10888  }
10876 10889  
10877 10890  /*
10878 10891   * Get the service named by fmri, build an XML tree which represents it, and
10879 10892   * dump it into filename (or stdout if filename is NULL).
10880 10893   */
10881 10894  int
10882 10895  lscf_service_export(char *fmri, const char *filename, int flags)
10883 10896  {
10884 10897          struct export_args args;
10885 10898          char *fmridup;
10886 10899          const char *scope, *svc, *inst;
10887 10900          size_t cblen = 3 * max_scf_name_len;
10888 10901          char *canonbuf = alloca(cblen);
10889 10902          int ret, err;
10890 10903  
10891 10904          lscf_prep_hndl();
10892 10905  
10893 10906          bzero(&args, sizeof (args));
10894 10907          args.filename = filename;
10895 10908          args.flags = flags;
10896 10909  
10897 10910          /*
10898 10911           * If some poor user has passed an exact instance FMRI, of the sort
10899 10912           * one might cut and paste from svcs(1) or an error message, warn
10900 10913           * and chop off the instance instead of failing.
10901 10914           */
10902 10915          fmridup = alloca(strlen(fmri) + 1);
10903 10916          (void) strcpy(fmridup, fmri);
10904 10917          if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10905 10918              sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10906 10919              scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10907 10920              inst != NULL) {
10908 10921                  (void) strlcpy(canonbuf, "svc:/", cblen);
10909 10922                  if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10910 10923                          (void) strlcat(canonbuf, "/", cblen);
10911 10924                          (void) strlcat(canonbuf, scope, cblen);
10912 10925                  }
10913 10926                  (void) strlcat(canonbuf, svc, cblen);
10914 10927                  fmri = canonbuf;
10915 10928  
10916 10929                  warn(gettext("Only services may be exported; ignoring "
10917 10930                      "instance portion of argument.\n"));
10918 10931          }
10919 10932  
10920 10933          err = 0;
10921 10934          if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10922 10935              SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10923 10936              &args, &err, semerr)) != 0) {
10924 10937                  if (ret != -1)
10925 10938                          semerr(gettext("Failed to walk instances: %s\n"),
10926 10939                              scf_strerror(ret));
10927 10940                  return (-1);
10928 10941          }
10929 10942  
10930 10943          /*
10931 10944           * Error message has already been printed.
10932 10945           */
10933 10946          if (err != 0)
10934 10947                  return (-1);
10935 10948  
10936 10949          return (0);
10937 10950  }
10938 10951  
10939 10952  
10940 10953  /*
10941 10954   * Archive
10942 10955   */
10943 10956  
10944 10957  static xmlNodePtr
10945 10958  make_archive(int flags)
10946 10959  {
10947 10960          xmlNodePtr sb;
10948 10961          scf_scope_t *scope;
10949 10962          scf_service_t *svc;
10950 10963          scf_iter_t *iter;
10951 10964          int r;
10952 10965  
10953 10966          if ((scope = scf_scope_create(g_hndl)) == NULL ||
10954 10967              (svc = scf_service_create(g_hndl)) == NULL ||
10955 10968              (iter = scf_iter_create(g_hndl)) == NULL ||
10956 10969              (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10957 10970              (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10958 10971              (exp_prop = scf_property_create(g_hndl)) == NULL ||
10959 10972              (exp_val = scf_value_create(g_hndl)) == NULL ||
10960 10973              (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10961 10974              (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10962 10975              (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10963 10976              (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10964 10977                  scfdie();
10965 10978  
10966 10979          exp_str_sz = max_scf_len + 1;
10967 10980          exp_str = safe_malloc(exp_str_sz);
10968 10981  
10969 10982          sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10970 10983          if (sb == NULL)
10971 10984                  uu_die(emsg_create_xml);
10972 10985          safe_setprop(sb, type_attr, "archive");
10973 10986          safe_setprop(sb, name_attr, "none");
10974 10987  
10975 10988          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10976 10989                  scfdie();
10977 10990          if (scf_iter_scope_services(iter, scope) != 0)
10978 10991                  scfdie();
10979 10992  
10980 10993          for (;;) {
10981 10994                  r = scf_iter_next_service(iter, svc);
10982 10995                  if (r == 0)
10983 10996                          break;
10984 10997                  if (r != 1)
10985 10998                          scfdie();
10986 10999  
10987 11000                  if (scf_service_get_name(svc, exp_str,
10988 11001                      max_scf_name_len + 1) < 0)
10989 11002                          scfdie();
10990 11003  
10991 11004                  if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10992 11005                          continue;
10993 11006  
10994 11007                  (void) xmlAddChild(sb, export_service(svc, flags));
10995 11008          }
10996 11009  
10997 11010          free(exp_str);
10998 11011  
10999 11012          scf_iter_destroy(exp_val_iter);
11000 11013          scf_iter_destroy(exp_prop_iter);
11001 11014          scf_iter_destroy(exp_pg_iter);
11002 11015          scf_iter_destroy(exp_inst_iter);
11003 11016          scf_value_destroy(exp_val);
11004 11017          scf_property_destroy(exp_prop);
11005 11018          scf_pg_destroy(exp_pg);
11006 11019          scf_instance_destroy(exp_inst);
11007 11020          scf_iter_destroy(iter);
11008 11021          scf_service_destroy(svc);
11009 11022          scf_scope_destroy(scope);
11010 11023  
11011 11024          return (sb);
11012 11025  }
11013 11026  
11014 11027  int
11015 11028  lscf_archive(const char *filename, int flags)
11016 11029  {
11017 11030          FILE *f;
11018 11031          xmlDocPtr doc;
11019 11032          int result;
11020 11033  
11021 11034          lscf_prep_hndl();
11022 11035  
11023 11036          if (filename != NULL) {
11024 11037                  errno = 0;
11025 11038                  f = fopen(filename, "wb");
11026 11039                  if (f == NULL) {
11027 11040                          if (errno == 0)
11028 11041                                  uu_die(gettext("Could not open \"%s\": no free "
11029 11042                                      "stdio streams.\n"), filename);
11030 11043                          else
11031 11044                                  uu_die(gettext("Could not open \"%s\""),
11032 11045                                      filename);
11033 11046                  }
11034 11047          } else
11035 11048                  f = stdout;
11036 11049  
11037 11050          doc = xmlNewDoc((xmlChar *)"1.0");
11038 11051          if (doc == NULL)
11039 11052                  uu_die(gettext("Could not create XML document.\n"));
11040 11053  
11041 11054          if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11042 11055              (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11043 11056                  uu_die(emsg_create_xml);
11044 11057  
11045 11058          (void) xmlAddSibling(doc->children, make_archive(flags));
11046 11059  
11047 11060          result = write_service_bundle(doc, f);
11048 11061  
11049 11062          xmlFreeDoc(doc);
11050 11063  
11051 11064          if (f != stdout)
11052 11065                  (void) fclose(f);
11053 11066  
11054 11067          return (result);
11055 11068  }
11056 11069  
11057 11070  
11058 11071  /*
11059 11072   * "Extract" a profile.
11060 11073   */
11061 11074  int
11062 11075  lscf_profile_extract(const char *filename)
11063 11076  {
11064 11077          FILE *f;
11065 11078          xmlDocPtr doc;
11066 11079          xmlNodePtr sb, snode, inode;
11067 11080          scf_scope_t *scope;
11068 11081          scf_service_t *svc;
11069 11082          scf_instance_t *inst;
11070 11083          scf_propertygroup_t *pg;
11071 11084          scf_property_t *prop;
11072 11085          scf_value_t *val;
11073 11086          scf_iter_t *siter, *iiter;
11074 11087          int r, s;
11075 11088          char *namebuf;
11076 11089          uint8_t b;
11077 11090          int result;
11078 11091  
11079 11092          lscf_prep_hndl();
11080 11093  
11081 11094          if (filename != NULL) {
11082 11095                  errno = 0;
11083 11096                  f = fopen(filename, "wb");
11084 11097                  if (f == NULL) {
11085 11098                          if (errno == 0)
11086 11099                                  uu_die(gettext("Could not open \"%s\": no "
11087 11100                                      "free stdio streams.\n"), filename);
11088 11101                          else
11089 11102                                  uu_die(gettext("Could not open \"%s\""),
11090 11103                                      filename);
11091 11104                  }
11092 11105          } else
11093 11106                  f = stdout;
11094 11107  
11095 11108          doc = xmlNewDoc((xmlChar *)"1.0");
11096 11109          if (doc == NULL)
11097 11110                  uu_die(gettext("Could not create XML document.\n"));
11098 11111  
11099 11112          if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11100 11113              (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11101 11114                  uu_die(emsg_create_xml);
11102 11115  
11103 11116          sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11104 11117          if (sb == NULL)
11105 11118                  uu_die(emsg_create_xml);
11106 11119          safe_setprop(sb, type_attr, "profile");
11107 11120          safe_setprop(sb, name_attr, "extract");
11108 11121          (void) xmlAddSibling(doc->children, sb);
11109 11122  
11110 11123          if ((scope = scf_scope_create(g_hndl)) == NULL ||
11111 11124              (svc = scf_service_create(g_hndl)) == NULL ||
11112 11125              (inst = scf_instance_create(g_hndl)) == NULL ||
11113 11126              (pg = scf_pg_create(g_hndl)) == NULL ||
11114 11127              (prop = scf_property_create(g_hndl)) == NULL ||
11115 11128              (val = scf_value_create(g_hndl)) == NULL ||
11116 11129              (siter = scf_iter_create(g_hndl)) == NULL ||
11117 11130              (iiter = scf_iter_create(g_hndl)) == NULL)
11118 11131                  scfdie();
11119 11132  
11120 11133          if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11121 11134                  scfdie();
11122 11135  
11123 11136          if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11124 11137                  scfdie();
11125 11138  
11126 11139          namebuf = safe_malloc(max_scf_name_len + 1);
11127 11140  
11128 11141          while ((r = scf_iter_next_service(siter, svc)) == 1) {
11129 11142                  if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11130 11143                          scfdie();
11131 11144  
11132 11145                  snode = xmlNewNode(NULL, (xmlChar *)"service");
11133 11146                  if (snode == NULL)
11134 11147                          uu_die(emsg_create_xml);
11135 11148  
11136 11149                  if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11137 11150                      0)
11138 11151                          scfdie();
11139 11152  
11140 11153                  safe_setprop(snode, name_attr, namebuf);
11141 11154  
11142 11155                  safe_setprop(snode, type_attr, "service");
11143 11156                  safe_setprop(snode, "version", "0");
11144 11157  
11145 11158                  while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11146 11159                          if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11147 11160                              SCF_SUCCESS) {
11148 11161                                  if (scf_error() != SCF_ERROR_NOT_FOUND)
11149 11162                                          scfdie();
11150 11163  
11151 11164                                  if (g_verbose) {
11152 11165                                          ssize_t len;
11153 11166                                          char *fmri;
11154 11167  
11155 11168                                          len =
11156 11169                                              scf_instance_to_fmri(inst, NULL, 0);
11157 11170                                          if (len < 0)
11158 11171                                                  scfdie();
11159 11172  
11160 11173                                          fmri = safe_malloc(len + 1);
11161 11174  
11162 11175                                          if (scf_instance_to_fmri(inst, fmri,
11163 11176                                              len + 1) < 0)
11164 11177                                                  scfdie();
11165 11178  
11166 11179                                          warn("Instance %s has no \"%s\" "
11167 11180                                              "property group.\n", fmri,
11168 11181                                              scf_pg_general);
11169 11182  
11170 11183                                          free(fmri);
11171 11184                                  }
11172 11185  
11173 11186                                  continue;
11174 11187                          }
11175 11188  
11176 11189                          if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11177 11190                              prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11178 11191                              prop_get_val(prop, val) != 0)
11179 11192                                  continue;
11180 11193  
11181 11194                          inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11182 11195                              NULL);
11183 11196                          if (inode == NULL)
11184 11197                                  uu_die(emsg_create_xml);
11185 11198  
11186 11199                          if (scf_instance_get_name(inst, namebuf,
11187 11200                              max_scf_name_len + 1) < 0)
11188 11201                                  scfdie();
11189 11202  
11190 11203                          safe_setprop(inode, name_attr, namebuf);
11191 11204  
11192 11205                          if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11193 11206                                  scfdie();
11194 11207  
11195 11208                          safe_setprop(inode, enabled_attr, b ? true : false);
11196 11209                  }
11197 11210                  if (s < 0)
11198 11211                          scfdie();
11199 11212  
11200 11213                  if (snode->children != NULL)
11201 11214                          (void) xmlAddChild(sb, snode);
11202 11215                  else
11203 11216                          xmlFreeNode(snode);
11204 11217          }
11205 11218          if (r < 0)
11206 11219                  scfdie();
11207 11220  
11208 11221          free(namebuf);
11209 11222  
11210 11223          result = write_service_bundle(doc, f);
11211 11224  
11212 11225          xmlFreeDoc(doc);
11213 11226  
11214 11227          if (f != stdout)
11215 11228                  (void) fclose(f);
11216 11229  
11217 11230          return (result);
11218 11231  }
11219 11232  
11220 11233  
11221 11234  /*
11222 11235   * Entity manipulation commands
11223 11236   */
11224 11237  
11225 11238  /*
11226 11239   * Entity selection.  If no entity is selected, then the current scope is in
11227 11240   * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11228 11241   * only cur_inst is NULL, and when an instance is selected, none are NULL.
11229 11242   * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11230 11243   * cur_inst will be non-NULL.
11231 11244   */
11232 11245  
11233 11246  /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11234 11247  static int
11235 11248  select_inst(const char *name)
11236 11249  {
11237 11250          scf_instance_t *inst;
11238 11251          scf_error_t err;
11239 11252  
11240 11253          assert(cur_svc != NULL);
11241 11254  
11242 11255          inst = scf_instance_create(g_hndl);
11243 11256          if (inst == NULL)
11244 11257                  scfdie();
11245 11258  
11246 11259          if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11247 11260                  cur_inst = inst;
11248 11261                  return (0);
11249 11262          }
11250 11263  
11251 11264          err = scf_error();
11252 11265          if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11253 11266                  scfdie();
11254 11267  
11255 11268          scf_instance_destroy(inst);
11256 11269          return (1);
11257 11270  }
11258 11271  
11259 11272  /* Returns as above. */
11260 11273  static int
11261 11274  select_svc(const char *name)
11262 11275  {
11263 11276          scf_service_t *svc;
11264 11277          scf_error_t err;
11265 11278  
11266 11279          assert(cur_scope != NULL);
11267 11280  
11268 11281          svc = scf_service_create(g_hndl);
11269 11282          if (svc == NULL)
11270 11283                  scfdie();
11271 11284  
11272 11285          if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11273 11286                  cur_svc = svc;
11274 11287                  return (0);
11275 11288          }
11276 11289  
11277 11290          err = scf_error();
11278 11291          if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11279 11292                  scfdie();
11280 11293  
11281 11294          scf_service_destroy(svc);
11282 11295          return (1);
11283 11296  }
11284 11297  
11285 11298  /* ARGSUSED */
11286 11299  static int
11287 11300  select_callback(void *unused, scf_walkinfo_t *wip)
11288 11301  {
11289 11302          scf_instance_t *inst;
11290 11303          scf_service_t *svc;
11291 11304          scf_scope_t *scope;
11292 11305  
11293 11306          if (wip->inst != NULL) {
11294 11307                  if ((scope = scf_scope_create(g_hndl)) == NULL ||
11295 11308                      (svc = scf_service_create(g_hndl)) == NULL ||
11296 11309                      (inst = scf_instance_create(g_hndl)) == NULL)
11297 11310                          scfdie();
11298 11311  
11299 11312                  if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11300 11313                      inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11301 11314                          scfdie();
11302 11315          } else {
11303 11316                  assert(wip->svc != NULL);
11304 11317  
11305 11318                  if ((scope = scf_scope_create(g_hndl)) == NULL ||
11306 11319                      (svc = scf_service_create(g_hndl)) == NULL)
11307 11320                          scfdie();
11308 11321  
11309 11322                  if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 11323                      NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 11324                          scfdie();
11312 11325  
11313 11326                  inst = NULL;
11314 11327          }
11315 11328  
11316 11329          /* Clear out the current selection */
11317 11330          assert(cur_scope != NULL);
11318 11331          scf_scope_destroy(cur_scope);
11319 11332          scf_service_destroy(cur_svc);
11320 11333          scf_instance_destroy(cur_inst);
11321 11334  
11322 11335          cur_scope = scope;
11323 11336          cur_svc = svc;
11324 11337          cur_inst = inst;
11325 11338  
11326 11339          return (0);
11327 11340  }
11328 11341  
11329 11342  static int
11330 11343  validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11331 11344  {
11332 11345          char **fmri = fmri_p;
11333 11346  
11334 11347          *fmri = strdup(wip->fmri);
11335 11348          if (*fmri == NULL)
11336 11349                  uu_die(gettext("Out of memory.\n"));
11337 11350  
11338 11351          return (0);
11339 11352  }
11340 11353  
11341 11354  /*
11342 11355   * validate [fmri]
11343 11356   * Perform the validation of an FMRI instance.
11344 11357   */
11345 11358  void
11346 11359  lscf_validate_fmri(const char *fmri)
11347 11360  {
11348 11361          int ret = 0;
11349 11362          size_t inst_sz;
11350 11363          char *inst_fmri = NULL;
11351 11364          scf_tmpl_errors_t *errs = NULL;
11352 11365          char *snapbuf = NULL;
11353 11366  
11354 11367          lscf_prep_hndl();
11355 11368  
11356 11369          if (fmri == NULL) {
11357 11370                  inst_sz = max_scf_fmri_len + 1;
11358 11371                  inst_fmri = safe_malloc(inst_sz);
11359 11372  
11360 11373                  if (cur_snap != NULL) {
11361 11374                          snapbuf = safe_malloc(max_scf_name_len + 1);
11362 11375                          if (scf_snapshot_get_name(cur_snap, snapbuf,
11363 11376                              max_scf_name_len + 1) < 0)
11364 11377                                  scfdie();
11365 11378                  }
11366 11379                  if (cur_inst == NULL) {
11367 11380                          semerr(gettext("No instance selected\n"));
11368 11381                          goto cleanup;
11369 11382                  } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11370 11383                      inst_sz) >= inst_sz) {
11371 11384                          /* sanity check. Should never get here */
11372 11385                          uu_die(gettext("Unexpected error! file %s, line %d\n"),
11373 11386                              __FILE__, __LINE__);
11374 11387                  }
11375 11388          } else {
11376 11389                  scf_error_t scf_err;
11377 11390                  int err = 0;
11378 11391  
11379 11392                  if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11380 11393                      validate_callback, &inst_fmri, &err, semerr)) != 0) {
11381 11394                          uu_warn("Failed to walk instances: %s\n",
11382 11395                              scf_strerror(scf_err));
11383 11396                          goto cleanup;
11384 11397                  }
11385 11398                  if (err != 0) {
11386 11399                          /* error message displayed by scf_walk_fmri */
11387 11400                          goto cleanup;
11388 11401                  }
11389 11402          }
11390 11403  
11391 11404          ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11392 11405              SCF_TMPL_VALIDATE_FLAG_CURRENT);
11393 11406          if (ret == -1) {
11394 11407                  if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11395 11408                          warn(gettext("Template data for %s is invalid. "
11396 11409                              "Consider reverting to a previous snapshot or "
11397 11410                              "restoring original configuration.\n"), inst_fmri);
11398 11411                  } else {
11399 11412                          uu_warn("%s: %s\n",
11400 11413                              gettext("Error validating the instance"),
11401 11414                              scf_strerror(scf_error()));
11402 11415                  }
11403 11416          } else if (ret == 1 && errs != NULL) {
11404 11417                  scf_tmpl_error_t *err = NULL;
11405 11418                  char *msg;
11406 11419                  size_t len = 256;       /* initial error buffer size */
11407 11420                  int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11408 11421                      SCF_TMPL_STRERROR_HUMAN : 0;
11409 11422  
11410 11423                  msg = safe_malloc(len);
11411 11424  
11412 11425                  while ((err = scf_tmpl_next_error(errs)) != NULL) {
11413 11426                          int ret;
11414 11427  
11415 11428                          if ((ret = scf_tmpl_strerror(err, msg, len,
11416 11429                              flag)) >= len) {
11417 11430                                  len = ret + 1;
11418 11431                                  msg = realloc(msg, len);
11419 11432                                  if (msg == NULL)
11420 11433                                          uu_die(gettext(
11421 11434                                              "Out of memory.\n"));
11422 11435                                  (void) scf_tmpl_strerror(err, msg, len,
11423 11436                                      flag);
11424 11437                          }
11425 11438                          (void) fprintf(stderr, "%s\n", msg);
11426 11439                  }
11427 11440                  if (msg != NULL)
11428 11441                          free(msg);
11429 11442          }
11430 11443          if (errs != NULL)
11431 11444                  scf_tmpl_errors_destroy(errs);
11432 11445  
11433 11446  cleanup:
11434 11447          free(inst_fmri);
11435 11448          free(snapbuf);
11436 11449  }
11437 11450  
11438 11451  static void
11439 11452  lscf_validate_file(const char *filename)
11440 11453  {
11441 11454          tmpl_errors_t *errs;
11442 11455  
11443 11456          bundle_t *b = internal_bundle_new();
11444 11457          if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11445 11458                  if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11446 11459                          tmpl_errors_print(stderr, errs, "");
11447 11460                          semerr(gettext("Validation failed.\n"));
11448 11461                  }
11449 11462                  tmpl_errors_destroy(errs);
11450 11463          }
11451 11464          (void) internal_bundle_free(b);
11452 11465  }
11453 11466  
11454 11467  /*
11455 11468   * validate [fmri|file]
11456 11469   */
11457 11470  void
11458 11471  lscf_validate(const char *arg)
11459 11472  {
11460 11473          const char *str;
11461 11474  
11462 11475          if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11463 11476              sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11464 11477                  str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11465 11478                  lscf_validate_file(str);
11466 11479          } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11467 11480              sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11468 11481                  str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11469 11482                  lscf_validate_fmri(str);
11470 11483          } else if (access(arg, R_OK | F_OK) == 0) {
11471 11484                  lscf_validate_file(arg);
11472 11485          } else {
11473 11486                  lscf_validate_fmri(arg);
11474 11487          }
11475 11488  }
11476 11489  
11477 11490  void
11478 11491  lscf_select(const char *fmri)
11479 11492  {
11480 11493          int ret, err;
11481 11494  
11482 11495          lscf_prep_hndl();
11483 11496  
11484 11497          if (cur_snap != NULL) {
11485 11498                  struct snaplevel *elt;
11486 11499                  char *buf;
11487 11500  
11488 11501                  /* Error unless name is that of the next level. */
11489 11502                  elt = uu_list_next(cur_levels, cur_elt);
11490 11503                  if (elt == NULL) {
11491 11504                          semerr(gettext("No children.\n"));
11492 11505                          return;
11493 11506                  }
11494 11507  
11495 11508                  buf = safe_malloc(max_scf_name_len + 1);
11496 11509  
11497 11510                  if (scf_snaplevel_get_instance_name(elt->sl, buf,
11498 11511                      max_scf_name_len + 1) < 0)
11499 11512                          scfdie();
11500 11513  
11501 11514                  if (strcmp(buf, fmri) != 0) {
11502 11515                          semerr(gettext("No such child.\n"));
11503 11516                          free(buf);
11504 11517                          return;
11505 11518                  }
11506 11519  
11507 11520                  free(buf);
11508 11521  
11509 11522                  cur_elt = elt;
11510 11523                  cur_level = elt->sl;
11511 11524                  return;
11512 11525          }
11513 11526  
11514 11527          /*
11515 11528           * Special case for 'svc:', which takes the user to the scope level.
11516 11529           */
11517 11530          if (strcmp(fmri, "svc:") == 0) {
11518 11531                  scf_instance_destroy(cur_inst);
11519 11532                  scf_service_destroy(cur_svc);
11520 11533                  cur_inst = NULL;
11521 11534                  cur_svc = NULL;
11522 11535                  return;
11523 11536          }
11524 11537  
11525 11538          /*
11526 11539           * Special case for ':properties'.  This appears as part of 'list' but
11527 11540           * can't be selected.  Give a more helpful error message in this case.
11528 11541           */
11529 11542          if (strcmp(fmri, ":properties") == 0) {
11530 11543                  semerr(gettext(":properties is not an entity.  Try 'listprop' "
11531 11544                      "to list properties.\n"));
11532 11545                  return;
11533 11546          }
11534 11547  
11535 11548          /*
11536 11549           * First try the argument as relative to the current selection.
11537 11550           */
11538 11551          if (cur_inst != NULL) {
11539 11552                  /* EMPTY */;
11540 11553          } else if (cur_svc != NULL) {
11541 11554                  if (select_inst(fmri) != 1)
11542 11555                          return;
11543 11556          } else {
11544 11557                  if (select_svc(fmri) != 1)
11545 11558                          return;
11546 11559          }
11547 11560  
11548 11561          err = 0;
11549 11562          if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11550 11563              select_callback, NULL, &err, semerr)) != 0) {
11551 11564                  semerr(gettext("Failed to walk instances: %s\n"),
11552 11565                      scf_strerror(ret));
11553 11566          }
11554 11567  }
11555 11568  
11556 11569  void
11557 11570  lscf_unselect(void)
11558 11571  {
11559 11572          lscf_prep_hndl();
11560 11573  
11561 11574          if (cur_snap != NULL) {
11562 11575                  struct snaplevel *elt;
11563 11576  
11564 11577                  elt = uu_list_prev(cur_levels, cur_elt);
11565 11578                  if (elt == NULL) {
11566 11579                          semerr(gettext("No parent levels.\n"));
11567 11580                  } else {
11568 11581                          cur_elt = elt;
11569 11582                          cur_level = elt->sl;
11570 11583                  }
11571 11584          } else if (cur_inst != NULL) {
11572 11585                  scf_instance_destroy(cur_inst);
11573 11586                  cur_inst = NULL;
11574 11587          } else if (cur_svc != NULL) {
11575 11588                  scf_service_destroy(cur_svc);
11576 11589                  cur_svc = NULL;
11577 11590          } else {
11578 11591                  semerr(gettext("Cannot unselect at scope level.\n"));
11579 11592          }
11580 11593  }
11581 11594  
11582 11595  /*
11583 11596   * Return the FMRI of the current selection, for the prompt.
11584 11597   */
11585 11598  void
11586 11599  lscf_get_selection_str(char *buf, size_t bufsz)
11587 11600  {
11588 11601          char *cp;
11589 11602          ssize_t fmrilen, szret;
11590 11603          boolean_t deleted = B_FALSE;
11591 11604  
11592 11605          if (g_hndl == NULL) {
11593 11606                  (void) strlcpy(buf, "svc:", bufsz);
11594 11607                  return;
11595 11608          }
11596 11609  
11597 11610          if (cur_level != NULL) {
11598 11611                  assert(cur_snap != NULL);
11599 11612  
11600 11613                  /* [ snapshot ] FMRI [: instance ] */
11601 11614                  assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11602 11615                      + 2 + max_scf_name_len + 1 + 1);
11603 11616  
11604 11617                  buf[0] = '[';
11605 11618  
11606 11619                  szret = scf_snapshot_get_name(cur_snap, buf + 1,
11607 11620                      max_scf_name_len + 1);
11608 11621                  if (szret < 0) {
11609 11622                          if (scf_error() != SCF_ERROR_DELETED)
11610 11623                                  scfdie();
11611 11624  
11612 11625                          goto snap_deleted;
11613 11626                  }
11614 11627  
11615 11628                  (void) strcat(buf, "]svc:/");
11616 11629  
11617 11630                  cp = strchr(buf, '\0');
11618 11631  
11619 11632                  szret = scf_snaplevel_get_service_name(cur_level, cp,
11620 11633                      max_scf_name_len + 1);
11621 11634                  if (szret < 0) {
11622 11635                          if (scf_error() != SCF_ERROR_DELETED)
11623 11636                                  scfdie();
11624 11637  
11625 11638                          goto snap_deleted;
11626 11639                  }
11627 11640  
11628 11641                  cp = strchr(cp, '\0');
11629 11642  
11630 11643                  if (snaplevel_is_instance(cur_level)) {
11631 11644                          *cp++ = ':';
11632 11645  
11633 11646                          if (scf_snaplevel_get_instance_name(cur_level, cp,
11634 11647                              max_scf_name_len + 1) < 0) {
11635 11648                                  if (scf_error() != SCF_ERROR_DELETED)
11636 11649                                          scfdie();
11637 11650  
11638 11651                                  goto snap_deleted;
11639 11652                          }
11640 11653                  } else {
11641 11654                          *cp++ = '[';
11642 11655                          *cp++ = ':';
11643 11656  
11644 11657                          if (scf_instance_get_name(cur_inst, cp,
11645 11658                              max_scf_name_len + 1) < 0) {
11646 11659                                  if (scf_error() != SCF_ERROR_DELETED)
11647 11660                                          scfdie();
11648 11661  
11649 11662                                  goto snap_deleted;
11650 11663                          }
11651 11664  
11652 11665                          (void) strcat(buf, "]");
11653 11666                  }
11654 11667  
11655 11668                  return;
11656 11669  
11657 11670  snap_deleted:
11658 11671                  deleted = B_TRUE;
11659 11672                  free(buf);
11660 11673                  unselect_cursnap();
11661 11674          }
11662 11675  
11663 11676          assert(cur_snap == NULL);
11664 11677  
11665 11678          if (cur_inst != NULL) {
11666 11679                  assert(cur_svc != NULL);
11667 11680                  assert(cur_scope != NULL);
11668 11681  
11669 11682                  fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11670 11683                  if (fmrilen >= 0) {
11671 11684                          assert(fmrilen < bufsz);
11672 11685                          if (deleted)
11673 11686                                  warn(emsg_deleted);
11674 11687                          return;
11675 11688                  }
11676 11689  
11677 11690                  if (scf_error() != SCF_ERROR_DELETED)
11678 11691                          scfdie();
11679 11692  
11680 11693                  deleted = B_TRUE;
11681 11694  
11682 11695                  scf_instance_destroy(cur_inst);
11683 11696                  cur_inst = NULL;
11684 11697          }
11685 11698  
11686 11699          if (cur_svc != NULL) {
11687 11700                  assert(cur_scope != NULL);
11688 11701  
11689 11702                  szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11690 11703                  if (szret >= 0) {
11691 11704                          assert(szret < bufsz);
11692 11705                          if (deleted)
11693 11706                                  warn(emsg_deleted);
11694 11707                          return;
11695 11708                  }
11696 11709  
11697 11710                  if (scf_error() != SCF_ERROR_DELETED)
11698 11711                          scfdie();
11699 11712  
11700 11713                  deleted = B_TRUE;
11701 11714                  scf_service_destroy(cur_svc);
11702 11715                  cur_svc = NULL;
11703 11716          }
11704 11717  
11705 11718          assert(cur_scope != NULL);
11706 11719          fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11707 11720  
11708 11721          if (fmrilen < 0)
11709 11722                  scfdie();
11710 11723  
11711 11724          assert(fmrilen < bufsz);
11712 11725          if (deleted)
11713 11726                  warn(emsg_deleted);
11714 11727  }
11715 11728  
11716 11729  /*
11717 11730   * Entity listing.  Entities and colon namespaces (e.g., :properties and
11718 11731   * :statistics) are listed for the current selection.
11719 11732   */
11720 11733  void
11721 11734  lscf_list(const char *pattern)
11722 11735  {
11723 11736          scf_iter_t *iter;
11724 11737          char *buf;
11725 11738          int ret;
11726 11739  
11727 11740          lscf_prep_hndl();
11728 11741  
11729 11742          if (cur_level != NULL) {
11730 11743                  struct snaplevel *elt;
11731 11744  
11732 11745                  (void) fputs(COLON_NAMESPACES, stdout);
11733 11746  
11734 11747                  elt = uu_list_next(cur_levels, cur_elt);
11735 11748                  if (elt == NULL)
11736 11749                          return;
11737 11750  
11738 11751                  /*
11739 11752                   * For now, we know that the next level is an instance.  But
11740 11753                   * if we ever have multiple scopes, this could be complicated.
11741 11754                   */
11742 11755                  buf = safe_malloc(max_scf_name_len + 1);
11743 11756                  if (scf_snaplevel_get_instance_name(elt->sl, buf,
11744 11757                      max_scf_name_len + 1) >= 0) {
11745 11758                          (void) puts(buf);
11746 11759                  } else {
11747 11760                          if (scf_error() != SCF_ERROR_DELETED)
11748 11761                                  scfdie();
11749 11762                  }
11750 11763  
11751 11764                  free(buf);
11752 11765  
11753 11766                  return;
11754 11767          }
11755 11768  
11756 11769          if (cur_inst != NULL) {
11757 11770                  (void) fputs(COLON_NAMESPACES, stdout);
11758 11771                  return;
11759 11772          }
11760 11773  
11761 11774          iter = scf_iter_create(g_hndl);
11762 11775          if (iter == NULL)
11763 11776                  scfdie();
11764 11777  
11765 11778          buf = safe_malloc(max_scf_name_len + 1);
11766 11779  
11767 11780          if (cur_svc != NULL) {
11768 11781                  /* List the instances in this service. */
11769 11782                  scf_instance_t *inst;
11770 11783  
11771 11784                  inst = scf_instance_create(g_hndl);
11772 11785                  if (inst == NULL)
11773 11786                          scfdie();
11774 11787  
11775 11788                  if (scf_iter_service_instances(iter, cur_svc) == 0) {
11776 11789                          safe_printf(COLON_NAMESPACES);
11777 11790  
11778 11791                          for (;;) {
11779 11792                                  ret = scf_iter_next_instance(iter, inst);
11780 11793                                  if (ret == 0)
11781 11794                                          break;
11782 11795                                  if (ret != 1) {
11783 11796                                          if (scf_error() != SCF_ERROR_DELETED)
11784 11797                                                  scfdie();
11785 11798  
11786 11799                                          break;
11787 11800                                  }
11788 11801  
11789 11802                                  if (scf_instance_get_name(inst, buf,
11790 11803                                      max_scf_name_len + 1) >= 0) {
11791 11804                                          if (pattern == NULL ||
11792 11805                                              fnmatch(pattern, buf, 0) == 0)
11793 11806                                                  (void) puts(buf);
11794 11807                                  } else {
11795 11808                                          if (scf_error() != SCF_ERROR_DELETED)
11796 11809                                                  scfdie();
11797 11810                                  }
11798 11811                          }
11799 11812                  } else {
11800 11813                          if (scf_error() != SCF_ERROR_DELETED)
11801 11814                                  scfdie();
11802 11815                  }
11803 11816  
11804 11817                  scf_instance_destroy(inst);
11805 11818          } else {
11806 11819                  /* List the services in this scope. */
11807 11820                  scf_service_t *svc;
11808 11821  
11809 11822                  assert(cur_scope != NULL);
11810 11823  
11811 11824                  svc = scf_service_create(g_hndl);
11812 11825                  if (svc == NULL)
11813 11826                          scfdie();
11814 11827  
11815 11828                  if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11816 11829                          scfdie();
11817 11830  
11818 11831                  for (;;) {
11819 11832                          ret = scf_iter_next_service(iter, svc);
11820 11833                          if (ret == 0)
11821 11834                                  break;
11822 11835                          if (ret != 1)
11823 11836                                  scfdie();
11824 11837  
11825 11838                          if (scf_service_get_name(svc, buf,
11826 11839                              max_scf_name_len + 1) >= 0) {
11827 11840                                  if (pattern == NULL ||
11828 11841                                      fnmatch(pattern, buf, 0) == 0)
11829 11842                                          safe_printf("%s\n", buf);
11830 11843                          } else {
11831 11844                                  if (scf_error() != SCF_ERROR_DELETED)
11832 11845                                          scfdie();
11833 11846                          }
11834 11847                  }
11835 11848  
11836 11849                  scf_service_destroy(svc);
11837 11850          }
11838 11851  
11839 11852          free(buf);
11840 11853          scf_iter_destroy(iter);
11841 11854  }
11842 11855  
11843 11856  /*
11844 11857   * Entity addition.  Creates an empty entity in the current selection.
11845 11858   */
11846 11859  void
11847 11860  lscf_add(const char *name)
11848 11861  {
11849 11862          lscf_prep_hndl();
11850 11863  
11851 11864          if (cur_snap != NULL) {
11852 11865                  semerr(emsg_cant_modify_snapshots);
11853 11866          } else if (cur_inst != NULL) {
11854 11867                  semerr(gettext("Cannot add entities to an instance.\n"));
11855 11868          } else if (cur_svc != NULL) {
11856 11869  
11857 11870                  if (scf_service_add_instance(cur_svc, name, NULL) !=
11858 11871                      SCF_SUCCESS) {
11859 11872                          switch (scf_error()) {
11860 11873                          case SCF_ERROR_INVALID_ARGUMENT:
11861 11874                                  semerr(gettext("Invalid name.\n"));
11862 11875                                  break;
11863 11876  
11864 11877                          case SCF_ERROR_EXISTS:
11865 11878                                  semerr(gettext("Instance already exists.\n"));
11866 11879                                  break;
11867 11880  
11868 11881                          case SCF_ERROR_PERMISSION_DENIED:
11869 11882                                  semerr(emsg_permission_denied);
11870 11883                                  break;
11871 11884  
11872 11885                          default:
11873 11886                                  scfdie();
11874 11887                          }
11875 11888                  }
11876 11889          } else {
11877 11890                  assert(cur_scope != NULL);
11878 11891  
11879 11892                  if (scf_scope_add_service(cur_scope, name, NULL) !=
11880 11893                      SCF_SUCCESS) {
11881 11894                          switch (scf_error()) {
11882 11895                          case SCF_ERROR_INVALID_ARGUMENT:
11883 11896                                  semerr(gettext("Invalid name.\n"));
11884 11897                                  break;
11885 11898  
11886 11899                          case SCF_ERROR_EXISTS:
11887 11900                                  semerr(gettext("Service already exists.\n"));
11888 11901                                  break;
11889 11902  
11890 11903                          case SCF_ERROR_PERMISSION_DENIED:
11891 11904                                  semerr(emsg_permission_denied);
11892 11905                                  break;
11893 11906  
11894 11907                          case SCF_ERROR_BACKEND_READONLY:
11895 11908                                  semerr(emsg_read_only);
11896 11909                                  break;
11897 11910  
11898 11911                          default:
11899 11912                                  scfdie();
11900 11913                          }
11901 11914                  }
11902 11915          }
11903 11916  }
11904 11917  
11905 11918  /* return 1 if the entity has no persistent pgs, else return 0 */
11906 11919  static int
11907 11920  entity_has_no_pgs(void *ent, int isservice)
11908 11921  {
11909 11922          scf_iter_t *iter = NULL;
11910 11923          scf_propertygroup_t *pg = NULL;
11911 11924          uint32_t flags;
11912 11925          int err;
11913 11926          int ret = 1;
11914 11927  
11915 11928          if ((iter = scf_iter_create(g_hndl)) == NULL ||
11916 11929              (pg = scf_pg_create(g_hndl)) == NULL)
11917 11930                  scfdie();
11918 11931  
11919 11932          if (isservice) {
11920 11933                  if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11921 11934                          scfdie();
11922 11935          } else {
11923 11936                  if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11924 11937                          scfdie();
11925 11938          }
11926 11939  
11927 11940          while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11928 11941                  if (scf_pg_get_flags(pg, &flags) != 0)
11929 11942                          scfdie();
11930 11943  
11931 11944                  /* skip nonpersistent pgs */
11932 11945                  if (flags & SCF_PG_FLAG_NONPERSISTENT)
11933 11946                          continue;
11934 11947  
11935 11948                  ret = 0;
11936 11949                  break;
11937 11950          }
11938 11951  
11939 11952          if (err == -1)
11940 11953                  scfdie();
11941 11954  
11942 11955          scf_pg_destroy(pg);
11943 11956          scf_iter_destroy(iter);
11944 11957  
11945 11958          return (ret);
11946 11959  }
11947 11960  
11948 11961  /* return 1 if the service has no instances, else return 0 */
11949 11962  static int
11950 11963  svc_has_no_insts(scf_service_t *svc)
11951 11964  {
11952 11965          scf_instance_t *inst;
11953 11966          scf_iter_t *iter;
11954 11967          int r;
11955 11968          int ret = 1;
11956 11969  
11957 11970          if ((inst = scf_instance_create(g_hndl)) == NULL ||
11958 11971              (iter = scf_iter_create(g_hndl)) == NULL)
11959 11972                  scfdie();
11960 11973  
11961 11974          if (scf_iter_service_instances(iter, svc) != 0)
11962 11975                  scfdie();
11963 11976  
11964 11977          r = scf_iter_next_instance(iter, inst);
11965 11978          if (r == 1) {
11966 11979                  ret = 0;
11967 11980          } else if (r == 0) {
11968 11981                  ret = 1;
11969 11982          } else if (r == -1) {
11970 11983                  scfdie();
11971 11984          } else {
11972 11985                  bad_error("scf_iter_next_instance", r);
11973 11986          }
11974 11987  
11975 11988          scf_iter_destroy(iter);
11976 11989          scf_instance_destroy(inst);
11977 11990  
11978 11991          return (ret);
11979 11992  }
11980 11993  
11981 11994  /*
11982 11995   * Entity deletion.
11983 11996   */
11984 11997  
11985 11998  /*
11986 11999   * Delete the property group <fmri>/:properties/<name>.  Returns
11987 12000   * SCF_ERROR_NONE on success (or if the entity is not found),
11988 12001   * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11989 12002   * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11990 12003   * denied.
11991 12004   */
11992 12005  static scf_error_t
11993 12006  delete_dependency_pg(const char *fmri, const char *name)
11994 12007  {
11995 12008          void *entity = NULL;
11996 12009          int isservice;
11997 12010          scf_propertygroup_t *pg = NULL;
11998 12011          scf_error_t result;
11999 12012          char *pgty;
12000 12013          scf_service_t *svc = NULL;
12001 12014          scf_instance_t *inst = NULL;
12002 12015          scf_iter_t *iter = NULL;
12003 12016          char *name_buf = NULL;
12004 12017  
12005 12018          result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12006 12019          switch (result) {
12007 12020          case SCF_ERROR_NONE:
12008 12021                  break;
12009 12022  
12010 12023          case SCF_ERROR_NO_MEMORY:
12011 12024                  uu_die(gettext("Out of memory.\n"));
12012 12025                  /* NOTREACHED */
12013 12026  
12014 12027          case SCF_ERROR_INVALID_ARGUMENT:
12015 12028          case SCF_ERROR_CONSTRAINT_VIOLATED:
12016 12029                  return (SCF_ERROR_INVALID_ARGUMENT);
12017 12030  
12018 12031          case SCF_ERROR_NOT_FOUND:
12019 12032                  result = SCF_ERROR_NONE;
12020 12033                  goto out;
12021 12034  
12022 12035          default:
12023 12036                  bad_error("fmri_to_entity", result);
12024 12037          }
12025 12038  
12026 12039          pg = scf_pg_create(g_hndl);
12027 12040          if (pg == NULL)
12028 12041                  scfdie();
12029 12042  
12030 12043          if (entity_get_pg(entity, isservice, name, pg) != 0) {
12031 12044                  if (scf_error() != SCF_ERROR_NOT_FOUND)
12032 12045                          scfdie();
12033 12046  
12034 12047                  result = SCF_ERROR_NONE;
12035 12048                  goto out;
12036 12049          }
12037 12050  
12038 12051          pgty = safe_malloc(max_scf_pg_type_len + 1);
12039 12052  
12040 12053          if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12041 12054                  scfdie();
12042 12055  
12043 12056          if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12044 12057                  result = SCF_ERROR_TYPE_MISMATCH;
12045 12058                  free(pgty);
12046 12059                  goto out;
12047 12060          }
12048 12061  
12049 12062          free(pgty);
12050 12063  
12051 12064          if (scf_pg_delete(pg) != 0) {
12052 12065                  result = scf_error();
12053 12066                  if (result != SCF_ERROR_PERMISSION_DENIED)
12054 12067                          scfdie();
12055 12068                  goto out;
12056 12069          }
12057 12070  
12058 12071          /*
12059 12072           * We have to handle the case where we've just deleted the last
12060 12073           * property group of a "dummy" entity (instance or service).
12061 12074           * A "dummy" entity is an entity only present to hold an
12062 12075           * external dependency.
12063 12076           * So, in the case we deleted the last property group then we
12064 12077           * can also delete the entity. If the entity is an instance then
12065 12078           * we must verify if this was the last instance for the service
12066 12079           * and if it is, we can also delete the service if it doesn't
12067 12080           * have any property group either.
12068 12081           */
12069 12082  
12070 12083          result = SCF_ERROR_NONE;
12071 12084  
12072 12085          if (isservice) {
12073 12086                  svc = (scf_service_t *)entity;
12074 12087  
12075 12088                  if ((inst = scf_instance_create(g_hndl)) == NULL ||
12076 12089                      (iter = scf_iter_create(g_hndl)) == NULL)
12077 12090                          scfdie();
12078 12091  
12079 12092                  name_buf = safe_malloc(max_scf_name_len + 1);
12080 12093          } else {
12081 12094                  inst = (scf_instance_t *)entity;
12082 12095          }
12083 12096  
12084 12097          /*
12085 12098           * If the entity is an instance and we've just deleted its last
12086 12099           * property group then we should delete it.
12087 12100           */
12088 12101          if (!isservice && entity_has_no_pgs(entity, isservice)) {
12089 12102                  /* find the service before deleting the inst. - needed later */
12090 12103                  if ((svc = scf_service_create(g_hndl)) == NULL)
12091 12104                          scfdie();
12092 12105  
12093 12106                  if (scf_instance_get_parent(inst, svc) != 0)
12094 12107                          scfdie();
12095 12108  
12096 12109                  /* delete the instance */
12097 12110                  if (scf_instance_delete(inst) != 0) {
12098 12111                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12099 12112                                  scfdie();
12100 12113  
12101 12114                          result = SCF_ERROR_PERMISSION_DENIED;
12102 12115                          goto out;
12103 12116                  }
12104 12117                  /* no need to refresh the instance */
12105 12118                  inst = NULL;
12106 12119          }
12107 12120  
12108 12121          /*
12109 12122           * If the service has no more instances and pgs or we just deleted the
12110 12123           * last instance and the service doesn't have anymore propery groups
12111 12124           * then the service should be deleted.
12112 12125           */
12113 12126          if (svc != NULL &&
12114 12127              svc_has_no_insts(svc) &&
12115 12128              entity_has_no_pgs((void *)svc, 1)) {
12116 12129                  if (scf_service_delete(svc) == 0) {
12117 12130                          if (isservice) {
12118 12131                                  /* no need to refresh the service */
12119 12132                                  svc = NULL;
12120 12133                          }
12121 12134  
12122 12135                          goto out;
12123 12136                  }
12124 12137  
12125 12138                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12126 12139                          scfdie();
12127 12140  
12128 12141                  result = SCF_ERROR_PERMISSION_DENIED;
12129 12142          }
12130 12143  
12131 12144          /* if the entity has not been deleted, refresh it */
12132 12145          if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12133 12146                  (void) refresh_entity(isservice, entity, fmri, inst, iter,
12134 12147                      name_buf);
12135 12148          }
12136 12149  
12137 12150  out:
12138 12151          if (isservice && (inst != NULL && iter != NULL)) {
12139 12152                  free(name_buf);
12140 12153                  scf_iter_destroy(iter);
12141 12154                  scf_instance_destroy(inst);
12142 12155          }
12143 12156  
12144 12157          if (!isservice && svc != NULL) {
12145 12158                  scf_service_destroy(svc);
12146 12159          }
12147 12160  
12148 12161          scf_pg_destroy(pg);
12149 12162          if (entity != NULL)
12150 12163                  entity_destroy(entity, isservice);
12151 12164  
12152 12165          return (result);
12153 12166  }
12154 12167  
12155 12168  static int
12156 12169  delete_dependents(scf_propertygroup_t *pg)
12157 12170  {
12158 12171          char *pgty, *name, *fmri;
12159 12172          scf_property_t *prop;
12160 12173          scf_value_t *val;
12161 12174          scf_iter_t *iter;
12162 12175          int r;
12163 12176          scf_error_t err;
12164 12177  
12165 12178          /* Verify that the pg has the correct type. */
12166 12179          pgty = safe_malloc(max_scf_pg_type_len + 1);
12167 12180          if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12168 12181                  scfdie();
12169 12182  
12170 12183          if (strcmp(pgty, scf_group_framework) != 0) {
12171 12184                  if (g_verbose) {
12172 12185                          fmri = safe_malloc(max_scf_fmri_len + 1);
12173 12186                          if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12174 12187                                  scfdie();
12175 12188  
12176 12189                          warn(gettext("Property group %s is not of expected "
12177 12190                              "type %s.\n"), fmri, scf_group_framework);
12178 12191  
12179 12192                          free(fmri);
12180 12193                  }
12181 12194  
12182 12195                  free(pgty);
12183 12196                  return (-1);
12184 12197          }
12185 12198  
12186 12199          free(pgty);
12187 12200  
12188 12201          /* map delete_dependency_pg onto the properties. */
12189 12202          if ((prop = scf_property_create(g_hndl)) == NULL ||
12190 12203              (val = scf_value_create(g_hndl)) == NULL ||
12191 12204              (iter = scf_iter_create(g_hndl)) == NULL)
12192 12205                  scfdie();
12193 12206  
12194 12207          if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12195 12208                  scfdie();
12196 12209  
12197 12210          name = safe_malloc(max_scf_name_len + 1);
12198 12211          fmri = safe_malloc(max_scf_fmri_len + 2);
12199 12212  
12200 12213          while ((r = scf_iter_next_property(iter, prop)) == 1) {
12201 12214                  scf_type_t ty;
12202 12215  
12203 12216                  if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12204 12217                          scfdie();
12205 12218  
12206 12219                  if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12207 12220                          scfdie();
12208 12221  
12209 12222                  if ((ty != SCF_TYPE_ASTRING &&
12210 12223                      prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12211 12224                      prop_get_val(prop, val) != 0)
12212 12225                          continue;
12213 12226  
12214 12227                  if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12215 12228                          scfdie();
12216 12229  
12217 12230                  err = delete_dependency_pg(fmri, name);
12218 12231                  if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12219 12232                          if (scf_property_to_fmri(prop, fmri,
12220 12233                              max_scf_fmri_len + 2) < 0)
12221 12234                                  scfdie();
12222 12235  
12223 12236                          warn(gettext("Value of %s is not a valid FMRI.\n"),
12224 12237                              fmri);
12225 12238                  } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12226 12239                          warn(gettext("Property group \"%s\" of entity \"%s\" "
12227 12240                              "does not have dependency type.\n"), name, fmri);
12228 12241                  } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12229 12242                          warn(gettext("Could not delete property group \"%s\" "
12230 12243                              "of entity \"%s\" (permission denied).\n"), name,
12231 12244                              fmri);
12232 12245                  }
12233 12246          }
12234 12247          if (r == -1)
12235 12248                  scfdie();
12236 12249  
12237 12250          scf_value_destroy(val);
12238 12251          scf_property_destroy(prop);
12239 12252  
12240 12253          return (0);
12241 12254  }
12242 12255  
12243 12256  /*
12244 12257   * Returns 1 if the instance may be running, and 0 otherwise.
12245 12258   */
12246 12259  static int
12247 12260  inst_is_running(scf_instance_t *inst)
12248 12261  {
12249 12262          scf_propertygroup_t *pg;
12250 12263          scf_property_t *prop;
12251 12264          scf_value_t *val;
12252 12265          char buf[MAX_SCF_STATE_STRING_SZ];
12253 12266          int ret = 0;
12254 12267          ssize_t szret;
12255 12268  
12256 12269          if ((pg = scf_pg_create(g_hndl)) == NULL ||
12257 12270              (prop = scf_property_create(g_hndl)) == NULL ||
12258 12271              (val = scf_value_create(g_hndl)) == NULL)
12259 12272                  scfdie();
12260 12273  
12261 12274          if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12262 12275                  if (scf_error() != SCF_ERROR_NOT_FOUND)
12263 12276                          scfdie();
12264 12277                  goto out;
12265 12278          }
12266 12279  
12267 12280          if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12268 12281              prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12269 12282              prop_get_val(prop, val) != 0)
12270 12283                  goto out;
12271 12284  
12272 12285          szret = scf_value_get_astring(val, buf, sizeof (buf));
12273 12286          assert(szret >= 0);
12274 12287  
12275 12288          ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12276 12289              strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12277 12290  
12278 12291  out:
12279 12292          scf_value_destroy(val);
12280 12293          scf_property_destroy(prop);
12281 12294          scf_pg_destroy(pg);
12282 12295          return (ret);
12283 12296  }
12284 12297  
12285 12298  static uint8_t
12286 12299  pg_is_external_dependency(scf_propertygroup_t *pg)
12287 12300  {
12288 12301          char *type;
12289 12302          scf_value_t *val;
12290 12303          scf_property_t *prop;
12291 12304          uint8_t b = B_FALSE;
12292 12305  
12293 12306          type = safe_malloc(max_scf_pg_type_len + 1);
12294 12307  
12295 12308          if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12296 12309                  scfdie();
12297 12310  
12298 12311          if ((prop = scf_property_create(g_hndl)) == NULL ||
12299 12312              (val = scf_value_create(g_hndl)) == NULL)
12300 12313                  scfdie();
12301 12314  
12302 12315          if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12303 12316                  if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12304 12317                          if (scf_property_get_value(prop, val) != 0)
12305 12318                                  scfdie();
12306 12319                          if (scf_value_get_boolean(val, &b) != 0)
12307 12320                                  scfdie();
12308 12321                  }
12309 12322          }
12310 12323  
12311 12324          free(type);
12312 12325          (void) scf_value_destroy(val);
12313 12326          (void) scf_property_destroy(prop);
12314 12327  
12315 12328          return (b);
12316 12329  }
12317 12330  
12318 12331  #define DELETE_FAILURE                  -1
12319 12332  #define DELETE_SUCCESS_NOEXTDEPS        0
12320 12333  #define DELETE_SUCCESS_EXTDEPS          1
12321 12334  
12322 12335  /*
12323 12336   * lscf_instance_delete() deletes an instance.  Before calling
12324 12337   * scf_instance_delete(), though, we make sure the instance isn't
12325 12338   * running and delete dependencies in other entities which the instance
12326 12339   * declared as "dependents".  If there are dependencies which were
12327 12340   * created for other entities, then instead of deleting the instance we
12328 12341   * make it "empty" by deleting all other property groups and all
12329 12342   * snapshots.
12330 12343   *
12331 12344   * lscf_instance_delete() verifies that there is no external dependency pgs
12332 12345   * before suppressing the instance. If there is, then we must not remove them
12333 12346   * now in case the instance is re-created otherwise the dependencies would be
12334 12347   * lost. The external dependency pgs will be removed if the dependencies are
12335 12348   * removed.
12336 12349   *
12337 12350   * Returns:
12338 12351   *  DELETE_FAILURE              on failure
12339 12352   *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12340 12353   *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12341 12354   */
12342 12355  static int
12343 12356  lscf_instance_delete(scf_instance_t *inst, int force)
12344 12357  {
12345 12358          scf_propertygroup_t *pg;
12346 12359          scf_snapshot_t *snap;
12347 12360          scf_iter_t *iter;
12348 12361          int err;
12349 12362          int external = 0;
12350 12363  
12351 12364          /* If we're not forcing and the instance is running, refuse. */
12352 12365          if (!force && inst_is_running(inst)) {
12353 12366                  char *fmri;
12354 12367  
12355 12368                  fmri = safe_malloc(max_scf_fmri_len + 1);
12356 12369  
12357 12370                  if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12358 12371                          scfdie();
12359 12372  
12360 12373                  semerr(gettext("Instance %s may be running.  "
12361 12374                      "Use delete -f if it is not.\n"), fmri);
12362 12375  
12363 12376                  free(fmri);
12364 12377                  return (DELETE_FAILURE);
12365 12378          }
12366 12379  
12367 12380          pg = scf_pg_create(g_hndl);
12368 12381          if (pg == NULL)
12369 12382                  scfdie();
12370 12383  
12371 12384          if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12372 12385                  (void) delete_dependents(pg);
12373 12386          else if (scf_error() != SCF_ERROR_NOT_FOUND)
12374 12387                  scfdie();
12375 12388  
12376 12389          scf_pg_destroy(pg);
12377 12390  
12378 12391          /*
12379 12392           * If the instance has some external dependencies then we must
12380 12393           * keep them in case the instance is reimported otherwise the
12381 12394           * dependencies would be lost on reimport.
12382 12395           */
12383 12396          if ((iter = scf_iter_create(g_hndl)) == NULL ||
12384 12397              (pg = scf_pg_create(g_hndl)) == NULL)
12385 12398                  scfdie();
12386 12399  
12387 12400          if (scf_iter_instance_pgs(iter, inst) < 0)
12388 12401                  scfdie();
12389 12402  
12390 12403          while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12391 12404                  if (pg_is_external_dependency(pg)) {
12392 12405                          external = 1;
12393 12406                          continue;
12394 12407                  }
12395 12408  
12396 12409                  if (scf_pg_delete(pg) != 0) {
12397 12410                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12398 12411                                  scfdie();
12399 12412                          else {
12400 12413                                  semerr(emsg_permission_denied);
12401 12414  
12402 12415                                  (void) scf_iter_destroy(iter);
12403 12416                                  (void) scf_pg_destroy(pg);
12404 12417                                  return (DELETE_FAILURE);
12405 12418                          }
12406 12419                  }
12407 12420          }
12408 12421  
12409 12422          if (err == -1)
12410 12423                  scfdie();
12411 12424  
12412 12425          (void) scf_iter_destroy(iter);
12413 12426          (void) scf_pg_destroy(pg);
12414 12427  
12415 12428          if (external) {
12416 12429                  /*
12417 12430                   * All the pgs have been deleted for the instance except
12418 12431                   * the ones holding the external dependencies.
12419 12432                   * For the job to be complete, we must also delete the
12420 12433                   * snapshots associated with the instance.
12421 12434                   */
12422 12435                  if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12423 12436                      NULL)
12424 12437                          scfdie();
12425 12438                  if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12426 12439                          scfdie();
12427 12440  
12428 12441                  if (scf_iter_instance_snapshots(iter, inst) == -1)
12429 12442                          scfdie();
12430 12443  
12431 12444                  while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12432 12445                          if (_scf_snapshot_delete(snap) != 0) {
12433 12446                                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12434 12447                                          scfdie();
12435 12448  
12436 12449                                  semerr(emsg_permission_denied);
12437 12450  
12438 12451                                  (void) scf_iter_destroy(iter);
12439 12452                                  (void) scf_snapshot_destroy(snap);
12440 12453                                  return (DELETE_FAILURE);
12441 12454                          }
12442 12455                  }
12443 12456  
12444 12457                  if (err == -1)
12445 12458                          scfdie();
12446 12459  
12447 12460                  (void) scf_iter_destroy(iter);
12448 12461                  (void) scf_snapshot_destroy(snap);
12449 12462                  return (DELETE_SUCCESS_EXTDEPS);
12450 12463          }
12451 12464  
12452 12465          if (scf_instance_delete(inst) != 0) {
12453 12466                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12454 12467                          scfdie();
12455 12468  
12456 12469                  semerr(emsg_permission_denied);
12457 12470  
12458 12471                  return (DELETE_FAILURE);
12459 12472          }
12460 12473  
12461 12474          return (DELETE_SUCCESS_NOEXTDEPS);
12462 12475  }
12463 12476  
12464 12477  /*
12465 12478   * lscf_service_delete() deletes a service.  Before calling
12466 12479   * scf_service_delete(), though, we call lscf_instance_delete() for
12467 12480   * each of the instances and delete dependencies in other entities
12468 12481   * which were created as "dependents" of this service.  If there are
12469 12482   * dependencies which were created for other entities, then we delete
12470 12483   * all other property groups in the service and leave it as "empty".
12471 12484   *
12472 12485   * lscf_service_delete() verifies that there is no external dependency
12473 12486   * pgs at the instance & service level before suppressing the service.
12474 12487   * If there is, then we must not remove them now in case the service
12475 12488   * is re-imported otherwise the dependencies would be lost. The external
12476 12489   * dependency pgs will be removed if the dependencies are removed.
12477 12490   *
12478 12491   * Returns:
12479 12492   *   DELETE_FAILURE             on failure
12480 12493   *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12481 12494   *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12482 12495   */
12483 12496  static int
12484 12497  lscf_service_delete(scf_service_t *svc, int force)
12485 12498  {
12486 12499          int r;
12487 12500          scf_instance_t *inst;
12488 12501          scf_propertygroup_t *pg;
12489 12502          scf_iter_t *iter;
12490 12503          int ret;
12491 12504          int external = 0;
12492 12505  
12493 12506          if ((inst = scf_instance_create(g_hndl)) == NULL ||
12494 12507              (pg = scf_pg_create(g_hndl)) == NULL ||
12495 12508              (iter = scf_iter_create(g_hndl)) == NULL)
12496 12509                  scfdie();
12497 12510  
12498 12511          if (scf_iter_service_instances(iter, svc) != 0)
12499 12512                  scfdie();
12500 12513  
12501 12514          for (r = scf_iter_next_instance(iter, inst);
12502 12515              r == 1;
12503 12516              r = scf_iter_next_instance(iter, inst)) {
12504 12517  
12505 12518                  ret = lscf_instance_delete(inst, force);
12506 12519                  if (ret == DELETE_FAILURE) {
12507 12520                          scf_iter_destroy(iter);
12508 12521                          scf_pg_destroy(pg);
12509 12522                          scf_instance_destroy(inst);
12510 12523                          return (DELETE_FAILURE);
12511 12524                  }
12512 12525  
12513 12526                  /*
12514 12527                   * Record the fact that there is some external dependencies
12515 12528                   * at the instance level.
12516 12529                   */
12517 12530                  if (ret == DELETE_SUCCESS_EXTDEPS)
12518 12531                          external |= 1;
12519 12532          }
12520 12533  
12521 12534          if (r != 0)
12522 12535                  scfdie();
12523 12536  
12524 12537          /* Delete dependency property groups in dependent services. */
12525 12538          if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12526 12539                  (void) delete_dependents(pg);
12527 12540          else if (scf_error() != SCF_ERROR_NOT_FOUND)
12528 12541                  scfdie();
12529 12542  
12530 12543          scf_iter_destroy(iter);
12531 12544          scf_pg_destroy(pg);
12532 12545          scf_instance_destroy(inst);
12533 12546  
12534 12547          /*
12535 12548           * If the service has some external dependencies then we don't
12536 12549           * want to remove them in case the service is re-imported.
12537 12550           */
12538 12551          if ((pg = scf_pg_create(g_hndl)) == NULL ||
12539 12552              (iter = scf_iter_create(g_hndl)) == NULL)
12540 12553                  scfdie();
12541 12554  
12542 12555          if (scf_iter_service_pgs(iter, svc) < 0)
12543 12556                  scfdie();
12544 12557  
12545 12558          while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12546 12559                  if (pg_is_external_dependency(pg)) {
12547 12560                          external |= 2;
12548 12561                          continue;
12549 12562                  }
12550 12563  
12551 12564                  if (scf_pg_delete(pg) != 0) {
12552 12565                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12553 12566                                  scfdie();
12554 12567                          else {
12555 12568                                  semerr(emsg_permission_denied);
12556 12569  
12557 12570                                  (void) scf_iter_destroy(iter);
12558 12571                                  (void) scf_pg_destroy(pg);
12559 12572                                  return (DELETE_FAILURE);
12560 12573                          }
12561 12574                  }
12562 12575          }
12563 12576  
12564 12577          if (r == -1)
12565 12578                  scfdie();
12566 12579  
12567 12580          (void) scf_iter_destroy(iter);
12568 12581          (void) scf_pg_destroy(pg);
12569 12582  
12570 12583          if (external != 0)
12571 12584                  return (DELETE_SUCCESS_EXTDEPS);
12572 12585  
12573 12586          if (scf_service_delete(svc) == 0)
12574 12587                  return (DELETE_SUCCESS_NOEXTDEPS);
12575 12588  
12576 12589          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12577 12590                  scfdie();
12578 12591  
12579 12592          semerr(emsg_permission_denied);
12580 12593          return (DELETE_FAILURE);
12581 12594  }
12582 12595  
12583 12596  static int
12584 12597  delete_callback(void *data, scf_walkinfo_t *wip)
12585 12598  {
12586 12599          int force = (int)data;
12587 12600  
12588 12601          if (wip->inst != NULL)
12589 12602                  (void) lscf_instance_delete(wip->inst, force);
12590 12603          else
12591 12604                  (void) lscf_service_delete(wip->svc, force);
12592 12605  
12593 12606          return (0);
12594 12607  }
12595 12608  
12596 12609  void
12597 12610  lscf_delete(const char *fmri, int force)
12598 12611  {
12599 12612          scf_service_t *svc;
12600 12613          scf_instance_t *inst;
12601 12614          int ret;
12602 12615  
12603 12616          lscf_prep_hndl();
12604 12617  
12605 12618          if (cur_snap != NULL) {
12606 12619                  if (!snaplevel_is_instance(cur_level)) {
12607 12620                          char *buf;
12608 12621  
12609 12622                          buf = safe_malloc(max_scf_name_len + 1);
12610 12623                          if (scf_instance_get_name(cur_inst, buf,
12611 12624                              max_scf_name_len + 1) >= 0) {
12612 12625                                  if (strcmp(buf, fmri) == 0) {
12613 12626                                          semerr(emsg_cant_modify_snapshots);
12614 12627                                          free(buf);
12615 12628                                          return;
12616 12629                                  }
12617 12630                          } else if (scf_error() != SCF_ERROR_DELETED) {
12618 12631                                  scfdie();
12619 12632                          }
12620 12633                          free(buf);
12621 12634                  }
12622 12635          } else if (cur_inst != NULL) {
12623 12636                  /* EMPTY */;
12624 12637          } else if (cur_svc != NULL) {
12625 12638                  inst = scf_instance_create(g_hndl);
12626 12639                  if (inst == NULL)
12627 12640                          scfdie();
12628 12641  
12629 12642                  if (scf_service_get_instance(cur_svc, fmri, inst) ==
12630 12643                      SCF_SUCCESS) {
12631 12644                          (void) lscf_instance_delete(inst, force);
12632 12645                          scf_instance_destroy(inst);
12633 12646                          return;
12634 12647                  }
12635 12648  
12636 12649                  if (scf_error() != SCF_ERROR_NOT_FOUND &&
12637 12650                      scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12638 12651                          scfdie();
12639 12652  
12640 12653                  scf_instance_destroy(inst);
12641 12654          } else {
12642 12655                  assert(cur_scope != NULL);
12643 12656  
12644 12657                  svc = scf_service_create(g_hndl);
12645 12658                  if (svc == NULL)
12646 12659                          scfdie();
12647 12660  
12648 12661                  if (scf_scope_get_service(cur_scope, fmri, svc) ==
12649 12662                      SCF_SUCCESS) {
12650 12663                          (void) lscf_service_delete(svc, force);
12651 12664                          scf_service_destroy(svc);
12652 12665                          return;
12653 12666                  }
12654 12667  
12655 12668                  if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 12669                      scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 12670                          scfdie();
12658 12671  
12659 12672                  scf_service_destroy(svc);
12660 12673          }
12661 12674  
12662 12675          /*
12663 12676           * Match FMRI to entity.
12664 12677           */
12665 12678          if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12666 12679              delete_callback, (void *)force, NULL, semerr)) != 0) {
12667 12680                  semerr(gettext("Failed to walk instances: %s\n"),
12668 12681                      scf_strerror(ret));
12669 12682          }
12670 12683  }
12671 12684  
12672 12685  
12673 12686  
12674 12687  /*
12675 12688   * :properties commands.  These all end with "pg" or "prop" and generally
12676 12689   * operate on the currently selected entity.
12677 12690   */
12678 12691  
12679 12692  /*
12680 12693   * Property listing.  List the property groups, properties, their types and
12681 12694   * their values for the currently selected entity.
12682 12695   */
12683 12696  static void
12684 12697  list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12685 12698  {
12686 12699          char *buf;
12687 12700          uint32_t flags;
12688 12701  
12689 12702          buf = safe_malloc(max_scf_pg_type_len + 1);
12690 12703  
12691 12704          if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12692 12705                  scfdie();
12693 12706  
12694 12707          if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12695 12708                  scfdie();
12696 12709  
12697 12710          safe_printf("%-*s  %s", namewidth, name, buf);
12698 12711  
12699 12712          if (flags & SCF_PG_FLAG_NONPERSISTENT)
12700 12713                  safe_printf("\tNONPERSISTENT");
12701 12714  
12702 12715          safe_printf("\n");
12703 12716  
12704 12717          free(buf);
12705 12718  }
12706 12719  
12707 12720  static boolean_t
12708 12721  prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12709 12722  {
12710 12723          if (scf_property_get_value(prop, val) == 0) {
12711 12724                  return (B_FALSE);
12712 12725          } else {
12713 12726                  switch (scf_error()) {
12714 12727                  case SCF_ERROR_NOT_FOUND:
12715 12728                          return (B_FALSE);
12716 12729                  case SCF_ERROR_PERMISSION_DENIED:
12717 12730                  case SCF_ERROR_CONSTRAINT_VIOLATED:
12718 12731                          return (B_TRUE);
12719 12732                  default:
12720 12733                          scfdie();
12721 12734                          /*NOTREACHED*/
12722 12735                  }
12723 12736          }
12724 12737  }
12725 12738  
12726 12739  static void
12727 12740  list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12728 12741  {
12729 12742          scf_iter_t *iter;
12730 12743          scf_value_t *val;
12731 12744          const char *type;
12732 12745          int multiple_strings = 0;
12733 12746          int ret;
12734 12747  
12735 12748          if ((iter = scf_iter_create(g_hndl)) == NULL ||
12736 12749              (val = scf_value_create(g_hndl)) == NULL)
12737 12750                  scfdie();
12738 12751  
12739 12752          type = prop_to_typestr(prop);
12740 12753          assert(type != NULL);
12741 12754  
12742 12755          safe_printf("%-*s  %-7s ", len, name, type);
12743 12756  
12744 12757          if (prop_has_multiple_values(prop, val) &&
12745 12758              (scf_value_type(val) == SCF_TYPE_ASTRING ||
12746 12759              scf_value_type(val) == SCF_TYPE_USTRING))
12747 12760                  multiple_strings = 1;
12748 12761  
12749 12762          if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12750 12763                  scfdie();
12751 12764  
12752 12765          while ((ret = scf_iter_next_value(iter, val)) == 1) {
12753 12766                  char *buf;
12754 12767                  ssize_t vlen, szret;
12755 12768  
12756 12769                  vlen = scf_value_get_as_string(val, NULL, 0);
12757 12770                  if (vlen < 0)
12758 12771                          scfdie();
12759 12772  
12760 12773                  buf = safe_malloc(vlen + 1);
12761 12774  
12762 12775                  szret = scf_value_get_as_string(val, buf, vlen + 1);
12763 12776                  if (szret < 0)
12764 12777                          scfdie();
12765 12778                  assert(szret <= vlen);
12766 12779  
12767 12780                  /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12768 12781                  if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12769 12782                          safe_printf(" \"");
12770 12783                          (void) quote_and_print(buf, stdout, 0);
12771 12784                          (void) putchar('"');
12772 12785                          if (ferror(stdout)) {
12773 12786                                  (void) putchar('\n');
12774 12787                                  uu_die(gettext("Error writing to stdout.\n"));
12775 12788                          }
12776 12789                  } else {
12777 12790                          safe_printf(" %s", buf);
12778 12791                  }
12779 12792  
12780 12793                  free(buf);
12781 12794          }
12782 12795          if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12783 12796                  scfdie();
12784 12797  
12785 12798          if (putchar('\n') != '\n')
12786 12799                  uu_die(gettext("Could not output newline"));
12787 12800  }
12788 12801  
12789 12802  /*
12790 12803   * Outputs template property group info for the describe subcommand.
12791 12804   * If 'templates' == 2, verbose output is printed in the format expected
12792 12805   * for describe -v, which includes all templates fields.  If pg is
12793 12806   * not NULL, we're describing the template data, not an existing property
12794 12807   * group, and formatting should be appropriate for describe -t.
12795 12808   */
12796 12809  static void
12797 12810  list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12798 12811  {
12799 12812          char *buf;
12800 12813          uint8_t required;
12801 12814          scf_property_t *stability_prop;
12802 12815          scf_value_t *stability_val;
12803 12816  
12804 12817          if (templates == 0)
12805 12818                  return;
12806 12819  
12807 12820          if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12808 12821              (stability_val = scf_value_create(g_hndl)) == NULL)
12809 12822                  scfdie();
12810 12823  
12811 12824          if (templates == 2 && pg != NULL) {
12812 12825                  if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12813 12826                      stability_prop) == 0) {
12814 12827                          if (prop_check_type(stability_prop,
12815 12828                              SCF_TYPE_ASTRING) == 0 &&
12816 12829                              prop_get_val(stability_prop, stability_val) == 0) {
12817 12830                                  char *stability;
12818 12831  
12819 12832                                  stability = safe_malloc(max_scf_value_len + 1);
12820 12833  
12821 12834                                  if (scf_value_get_astring(stability_val,
12822 12835                                      stability, max_scf_value_len + 1) == -1 &&
12823 12836                                      scf_error() != SCF_ERROR_NOT_FOUND)
12824 12837                                          scfdie();
12825 12838  
12826 12839                                  safe_printf("%s%s: %s\n", TMPL_INDENT,
12827 12840                                      gettext("stability"), stability);
12828 12841  
12829 12842                                  free(stability);
12830 12843                          }
12831 12844                  } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12832 12845                          scfdie();
12833 12846          }
12834 12847  
12835 12848          scf_property_destroy(stability_prop);
12836 12849          scf_value_destroy(stability_val);
12837 12850  
12838 12851          if (pgt == NULL)
12839 12852                  return;
12840 12853  
12841 12854          if (pg == NULL || templates == 2) {
12842 12855                  /* print type info only if scf_tmpl_pg_name succeeds */
12843 12856                  if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12844 12857                          if (pg != NULL)
12845 12858                                  safe_printf("%s", TMPL_INDENT);
12846 12859                          safe_printf("%s: ", gettext("name"));
12847 12860                          safe_printf("%s\n", buf);
12848 12861                          free(buf);
12849 12862                  }
12850 12863  
12851 12864                  /* print type info only if scf_tmpl_pg_type succeeds */
12852 12865                  if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12853 12866                          if (pg != NULL)
12854 12867                                  safe_printf("%s", TMPL_INDENT);
12855 12868                          safe_printf("%s: ", gettext("type"));
12856 12869                          safe_printf("%s\n", buf);
12857 12870                          free(buf);
12858 12871                  }
12859 12872          }
12860 12873  
12861 12874          if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12862 12875                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12863 12876                      required ? "true" : "false");
12864 12877  
12865 12878          if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12866 12879                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12867 12880                      buf);
12868 12881                  free(buf);
12869 12882          }
12870 12883  
12871 12884          if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12872 12885                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12873 12886                      buf);
12874 12887                  free(buf);
12875 12888          }
12876 12889  
12877 12890          if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12878 12891                  if (templates == 2)
12879 12892                          safe_printf("%s%s: %s\n", TMPL_INDENT,
12880 12893                              gettext("description"), buf);
12881 12894                  else
12882 12895                          safe_printf("%s%s\n", TMPL_INDENT, buf);
12883 12896                  free(buf);
12884 12897          }
12885 12898  
12886 12899  }
12887 12900  
12888 12901  /*
12889 12902   * With as_value set to true, indent as appropriate for the value level.
12890 12903   * If false, indent to appropriate level for inclusion in constraint
12891 12904   * or choice printout.
12892 12905   */
12893 12906  static void
12894 12907  print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12895 12908      int as_value)
12896 12909  {
12897 12910          char *buf;
12898 12911  
12899 12912          if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12900 12913                  if (as_value == 0)
12901 12914                          safe_printf("%s", TMPL_CHOICE_INDENT);
12902 12915                  else
12903 12916                          safe_printf("%s", TMPL_INDENT);
12904 12917                  safe_printf("%s: %s\n", gettext("value common name"), buf);
12905 12918                  free(buf);
12906 12919          }
12907 12920  
12908 12921          if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12909 12922                  if (as_value == 0)
12910 12923                          safe_printf("%s", TMPL_CHOICE_INDENT);
12911 12924                  else
12912 12925                          safe_printf("%s", TMPL_INDENT);
12913 12926                  safe_printf("%s: %s\n", gettext("value description"), buf);
12914 12927                  free(buf);
12915 12928          }
12916 12929  }
12917 12930  
12918 12931  static void
12919 12932  print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12920 12933  {
12921 12934          safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12922 12935          /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12923 12936          safe_printf("%s\n", val_buf);
12924 12937  
12925 12938          print_template_value_details(prt, val_buf, 1);
12926 12939  }
12927 12940  
12928 12941  static void
12929 12942  print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12930 12943  {
12931 12944          int i, printed = 0;
12932 12945          scf_values_t values;
12933 12946          scf_count_ranges_t c_ranges;
12934 12947          scf_int_ranges_t i_ranges;
12935 12948  
12936 12949          printed = 0;
12937 12950          i = 0;
12938 12951          if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12939 12952                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12940 12953                      gettext("value constraints"));
12941 12954                  printed++;
12942 12955                  for (i = 0; i < values.value_count; ++i) {
12943 12956                          safe_printf("%s%s: %s\n", TMPL_INDENT,
12944 12957                              gettext("value name"), values.values_as_strings[i]);
12945 12958                          if (verbose == 1)
12946 12959                                  print_template_value_details(prt,
12947 12960                                      values.values_as_strings[i], 0);
12948 12961                  }
12949 12962  
12950 12963                  scf_values_destroy(&values);
12951 12964          }
12952 12965  
12953 12966          if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12954 12967                  if (printed++ == 0)
12955 12968                          safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12956 12969                              gettext("value constraints"));
12957 12970                  for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12958 12971                          safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12959 12972                              gettext("range"), c_ranges.scr_min[i],
12960 12973                              c_ranges.scr_max[i]);
12961 12974                  }
12962 12975                  scf_count_ranges_destroy(&c_ranges);
12963 12976          } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12964 12977              scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12965 12978                  if (printed++ == 0)
12966 12979                          safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12967 12980                              gettext("value constraints"));
12968 12981                  for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12969 12982                          safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12970 12983                              gettext("range"), i_ranges.sir_min[i],
12971 12984                              i_ranges.sir_max[i]);
12972 12985                  }
12973 12986                  scf_int_ranges_destroy(&i_ranges);
12974 12987          }
12975 12988  }
12976 12989  
12977 12990  static void
12978 12991  print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12979 12992  {
12980 12993          int i = 0, printed = 0;
12981 12994          scf_values_t values;
12982 12995          scf_count_ranges_t c_ranges;
12983 12996          scf_int_ranges_t i_ranges;
12984 12997  
12985 12998          printed = 0;
12986 12999          if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12987 13000                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988 13001                      gettext("value constraints"));
12989 13002                  printed++;
12990 13003                  for (i = 0; i < values.value_count; i++) {
12991 13004                          safe_printf("%s%s: %s\n", TMPL_INDENT,
12992 13005                              gettext("value name"), values.values_as_strings[i]);
12993 13006                          if (verbose == 1)
12994 13007                                  print_template_value_details(prt,
12995 13008                                      values.values_as_strings[i], 0);
12996 13009                  }
12997 13010  
12998 13011                  scf_values_destroy(&values);
12999 13012          }
13000 13013  
13001 13014          if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13002 13015                  for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13003 13016                          if (printed++ == 0)
13004 13017                                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13005 13018                                      gettext("value choices"));
13006 13019                          safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13007 13020                              gettext("range"), c_ranges.scr_min[i],
13008 13021                              c_ranges.scr_max[i]);
13009 13022                  }
13010 13023                  scf_count_ranges_destroy(&c_ranges);
13011 13024          } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13012 13025              scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13013 13026                  for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13014 13027                          if (printed++ == 0)
13015 13028                                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13016 13029                                      gettext("value choices"));
13017 13030                          safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13018 13031                              gettext("range"), i_ranges.sir_min[i],
13019 13032                              i_ranges.sir_max[i]);
13020 13033                  }
13021 13034                  scf_int_ranges_destroy(&i_ranges);
13022 13035          }
13023 13036  }
13024 13037  
13025 13038  static void
13026 13039  list_values_by_template(scf_prop_tmpl_t *prt)
13027 13040  {
13028 13041          print_template_constraints(prt, 1);
13029 13042          print_template_choices(prt, 1);
13030 13043  }
13031 13044  
13032 13045  static void
13033 13046  list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13034 13047  {
13035 13048          char *val_buf;
13036 13049          scf_iter_t *iter;
13037 13050          scf_value_t *val;
13038 13051          int ret;
13039 13052  
13040 13053          if ((iter = scf_iter_create(g_hndl)) == NULL ||
13041 13054              (val = scf_value_create(g_hndl)) == NULL)
13042 13055                  scfdie();
13043 13056  
13044 13057          if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13045 13058                  scfdie();
13046 13059  
13047 13060          val_buf = safe_malloc(max_scf_value_len + 1);
13048 13061  
13049 13062          while ((ret = scf_iter_next_value(iter, val)) == 1) {
13050 13063                  if (scf_value_get_as_string(val, val_buf,
13051 13064                      max_scf_value_len + 1) < 0)
13052 13065                          scfdie();
13053 13066  
13054 13067                  print_template_value(prt, val_buf);
13055 13068          }
13056 13069          if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13057 13070                  scfdie();
13058 13071          free(val_buf);
13059 13072  
13060 13073          print_template_constraints(prt, 0);
13061 13074          print_template_choices(prt, 0);
13062 13075  
13063 13076  }
13064 13077  
13065 13078  /*
13066 13079   * Outputs property info for the describe subcommand
13067 13080   * Verbose output if templates == 2, -v option of svccfg describe
13068 13081   * Displays template data if prop is not NULL, -t option of svccfg describe
13069 13082   */
13070 13083  static void
13071 13084  list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13072 13085  {
13073 13086          char *buf;
13074 13087          uint8_t u_buf;
13075 13088          int i;
13076 13089          uint64_t min, max;
13077 13090          scf_values_t values;
13078 13091  
13079 13092          if (prt == NULL || templates == 0)
13080 13093                  return;
13081 13094  
13082 13095          if (prop == NULL) {
13083 13096                  safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13084 13097                  if (scf_tmpl_prop_name(prt, &buf) > 0) {
13085 13098                          safe_printf("%s\n", buf);
13086 13099                          free(buf);
13087 13100                  } else
13088 13101                          safe_printf("(%s)\n", gettext("any"));
13089 13102          }
13090 13103  
13091 13104          if (prop == NULL || templates == 2) {
13092 13105                  if (prop != NULL)
13093 13106                          safe_printf("%s", TMPL_INDENT);
13094 13107                  else
13095 13108                          safe_printf("%s", TMPL_VALUE_INDENT);
13096 13109                  safe_printf("%s: ", gettext("type"));
13097 13110                  if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13098 13111                          safe_printf("%s\n", buf);
13099 13112                          free(buf);
13100 13113                  } else
13101 13114                          safe_printf("(%s)\n", gettext("any"));
13102 13115          }
13103 13116  
13104 13117          if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13105 13118                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13106 13119                      u_buf ? "true" : "false");
13107 13120  
13108 13121          if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13109 13122                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13110 13123                      buf);
13111 13124                  free(buf);
13112 13125          }
13113 13126  
13114 13127          if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13115 13128                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13116 13129                      buf);
13117 13130                  free(buf);
13118 13131          }
13119 13132  
13120 13133          if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13121 13134                  safe_printf("%s%s\n", TMPL_INDENT, buf);
13122 13135                  free(buf);
13123 13136          }
13124 13137  
13125 13138          if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13126 13139                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13127 13140                      scf_tmpl_visibility_to_string(u_buf));
13128 13141  
13129 13142          if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13130 13143                  safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13131 13144                      gettext("minimum number of values"), min);
13132 13145                  if (max == ULLONG_MAX) {
13133 13146                          safe_printf("%s%s: %s\n", TMPL_INDENT,
13134 13147                              gettext("maximum number of values"),
13135 13148                              gettext("unlimited"));
13136 13149                  } else {
13137 13150                          safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13138 13151                              gettext("maximum number of values"), max);
13139 13152                  }
13140 13153          }
13141 13154  
13142 13155          if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13143 13156                  for (i = 0; i < values.value_count; i++) {
13144 13157                          if (i == 0) {
13145 13158                                  safe_printf("%s%s:", TMPL_INDENT,
13146 13159                                      gettext("internal separators"));
13147 13160                          }
13148 13161                          safe_printf(" \"%s\"", values.values_as_strings[i]);
13149 13162                  }
13150 13163                  safe_printf("\n");
13151 13164          }
13152 13165  
13153 13166          if (templates != 2)
13154 13167                  return;
13155 13168  
13156 13169          if (prop != NULL)
13157 13170                  list_values_tmpl(prt, prop);
13158 13171          else
13159 13172                  list_values_by_template(prt);
13160 13173  }
13161 13174  
13162 13175  static char *
13163 13176  read_astring(scf_propertygroup_t *pg, const char *prop_name)
13164 13177  {
13165 13178          char *rv;
13166 13179  
13167 13180          rv = _scf_read_single_astring_from_pg(pg, prop_name);
13168 13181          if (rv == NULL) {
13169 13182                  switch (scf_error()) {
13170 13183                  case SCF_ERROR_NOT_FOUND:
13171 13184                          break;
13172 13185                  default:
13173 13186                          scfdie();
13174 13187                  }
13175 13188          }
13176 13189          return (rv);
13177 13190  }
13178 13191  
13179 13192  static void
13180 13193  display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13181 13194  {
13182 13195          size_t doc_len;
13183 13196          size_t man_len;
13184 13197          char *pg_name;
13185 13198          char *text = NULL;
13186 13199          int rv;
13187 13200  
13188 13201          doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13189 13202          man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13190 13203          pg_name = safe_malloc(max_scf_name_len + 1);
13191 13204          while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13192 13205                  if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13193 13206                          scfdie();
13194 13207                  }
13195 13208                  if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13196 13209                          /* Display doc_link and and uri */
13197 13210                          safe_printf("%s%s:\n", TMPL_INDENT,
13198 13211                              gettext("doc_link"));
13199 13212                          text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13200 13213                          if (text != NULL) {
13201 13214                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13202 13215                                      TMPL_INDENT, gettext("name"), text);
13203 13216                                  uu_free(text);
13204 13217                          }
13205 13218                          text = read_astring(pg, SCF_PROPERTY_TM_URI);
13206 13219                          if (text != NULL) {
13207 13220                                  safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13208 13221                                      gettext("uri"), text);
13209 13222                                  uu_free(text);
13210 13223                          }
13211 13224                  } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13212 13225                      man_len) == 0) {
13213 13226                          /* Display manpage title, section and path */
13214 13227                          safe_printf("%s%s:\n", TMPL_INDENT,
13215 13228                              gettext("manpage"));
13216 13229                          text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13217 13230                          if (text != NULL) {
13218 13231                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13219 13232                                      TMPL_INDENT, gettext("title"), text);
13220 13233                                  uu_free(text);
13221 13234                          }
13222 13235                          text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13223 13236                          if (text != NULL) {
13224 13237                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13225 13238                                      TMPL_INDENT, gettext("section"), text);
13226 13239                                  uu_free(text);
13227 13240                          }
13228 13241                          text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13229 13242                          if (text != NULL) {
13230 13243                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13231 13244                                      TMPL_INDENT, gettext("manpath"), text);
13232 13245                                  uu_free(text);
13233 13246                          }
13234 13247                  }
13235 13248          }
13236 13249          if (rv == -1)
13237 13250                  scfdie();
13238 13251  
13239 13252  done:
13240 13253          free(pg_name);
13241 13254  }
13242 13255  
13243 13256  static void
13244 13257  list_entity_tmpl(int templates)
13245 13258  {
13246 13259          char *common_name = NULL;
13247 13260          char *description = NULL;
13248 13261          char *locale = NULL;
13249 13262          scf_iter_t *iter;
13250 13263          scf_propertygroup_t *pg;
13251 13264          scf_property_t *prop;
13252 13265          int r;
13253 13266          scf_value_t *val;
13254 13267  
13255 13268          if ((pg = scf_pg_create(g_hndl)) == NULL ||
13256 13269              (prop = scf_property_create(g_hndl)) == NULL ||
13257 13270              (val = scf_value_create(g_hndl)) == NULL ||
13258 13271              (iter = scf_iter_create(g_hndl)) == NULL)
13259 13272                  scfdie();
13260 13273  
13261 13274          locale = setlocale(LC_MESSAGES, NULL);
13262 13275  
13263 13276          if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13264 13277                  common_name = safe_malloc(max_scf_value_len + 1);
13265 13278  
13266 13279                  /* Try both the current locale and the "C" locale. */
13267 13280                  if (scf_pg_get_property(pg, locale, prop) == 0 ||
13268 13281                      (scf_error() == SCF_ERROR_NOT_FOUND &&
13269 13282                      scf_pg_get_property(pg, "C", prop) == 0)) {
13270 13283                          if (prop_get_val(prop, val) == 0 &&
13271 13284                              scf_value_get_ustring(val, common_name,
13272 13285                              max_scf_value_len + 1) != -1) {
13273 13286                                  safe_printf("%s%s: %s\n", TMPL_INDENT,
13274 13287                                      gettext("common name"), common_name);
13275 13288                          }
13276 13289                  }
13277 13290          }
13278 13291  
13279 13292          /*
13280 13293           * Do description, manpages, and doc links if templates == 2.
13281 13294           */
13282 13295          if (templates == 2) {
13283 13296                  /* Get the description. */
13284 13297                  if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13285 13298                          description = safe_malloc(max_scf_value_len + 1);
13286 13299  
13287 13300                          /* Try both the current locale and the "C" locale. */
13288 13301                          if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289 13302                              (scf_error() == SCF_ERROR_NOT_FOUND &&
13290 13303                              scf_pg_get_property(pg, "C", prop) == 0)) {
13291 13304                                  if (prop_get_val(prop, val) == 0 &&
13292 13305                                      scf_value_get_ustring(val, description,
13293 13306                                      max_scf_value_len + 1) != -1) {
13294 13307                                          safe_printf("%s%s: %s\n", TMPL_INDENT,
13295 13308                                              gettext("description"),
13296 13309                                              description);
13297 13310                                  }
13298 13311                          }
13299 13312                  }
13300 13313  
13301 13314                  /* Process doc_link & manpage elements. */
13302 13315                  if (cur_level != NULL) {
13303 13316                          r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13304 13317                              SCF_GROUP_TEMPLATE);
13305 13318                  } else if (cur_inst != NULL) {
13306 13319                          r = scf_iter_instance_pgs_typed(iter, cur_inst,
13307 13320                              SCF_GROUP_TEMPLATE);
13308 13321                  } else {
13309 13322                          r = scf_iter_service_pgs_typed(iter, cur_svc,
13310 13323                              SCF_GROUP_TEMPLATE);
13311 13324                  }
13312 13325                  if (r == 0) {
13313 13326                          display_documentation(iter, pg);
13314 13327                  }
13315 13328          }
13316 13329  
13317 13330          free(common_name);
13318 13331          free(description);
13319 13332          scf_pg_destroy(pg);
13320 13333          scf_property_destroy(prop);
13321 13334          scf_value_destroy(val);
13322 13335          scf_iter_destroy(iter);
13323 13336  }
13324 13337  
13325 13338  static void
13326 13339  listtmpl(const char *pattern, int templates)
13327 13340  {
13328 13341          scf_pg_tmpl_t *pgt;
13329 13342          scf_prop_tmpl_t *prt;
13330 13343          char *snapbuf = NULL;
13331 13344          char *fmribuf;
13332 13345          char *pg_name = NULL, *prop_name = NULL;
13333 13346          ssize_t prop_name_size;
13334 13347          char *qual_prop_name;
13335 13348          char *search_name;
13336 13349          int listed = 0;
13337 13350  
13338 13351          if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13339 13352              (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13340 13353                  scfdie();
13341 13354  
13342 13355          fmribuf = safe_malloc(max_scf_name_len + 1);
13343 13356          qual_prop_name = safe_malloc(max_scf_name_len + 1);
13344 13357  
13345 13358          if (cur_snap != NULL) {
13346 13359                  snapbuf = safe_malloc(max_scf_name_len + 1);
13347 13360                  if (scf_snapshot_get_name(cur_snap, snapbuf,
13348 13361                      max_scf_name_len + 1) < 0)
13349 13362                          scfdie();
13350 13363          }
13351 13364  
13352 13365          if (cur_inst != NULL) {
13353 13366                  if (scf_instance_to_fmri(cur_inst, fmribuf,
13354 13367                      max_scf_name_len + 1) < 0)
13355 13368                          scfdie();
13356 13369          } else if (cur_svc != NULL) {
13357 13370                  if (scf_service_to_fmri(cur_svc, fmribuf,
13358 13371                      max_scf_name_len + 1) < 0)
13359 13372                          scfdie();
13360 13373          } else
13361 13374                  abort();
13362 13375  
13363 13376          /* If pattern is specified, we want to list only those items. */
13364 13377          while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13365 13378                  listed = 0;
13366 13379                  if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13367 13380                      fnmatch(pattern, pg_name, 0) == 0)) {
13368 13381                          list_pg_tmpl(pgt, NULL, templates);
13369 13382                          listed++;
13370 13383                  }
13371 13384  
13372 13385                  scf_tmpl_prop_reset(prt);
13373 13386  
13374 13387                  while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13375 13388                          search_name = NULL;
13376 13389                          prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13377 13390                          if ((prop_name_size > 0) && (pg_name != NULL)) {
13378 13391                                  if (snprintf(qual_prop_name,
13379 13392                                      max_scf_name_len + 1, "%s/%s",
13380 13393                                      pg_name, prop_name) >=
13381 13394                                      max_scf_name_len + 1) {
13382 13395                                          prop_name_size = -1;
13383 13396                                  } else {
13384 13397                                          search_name = qual_prop_name;
13385 13398                                  }
13386 13399                          }
13387 13400                          if (listed > 0 || pattern == NULL ||
13388 13401                              (prop_name_size > 0 &&
13389 13402                              fnmatch(pattern, search_name,
13390 13403                              FNM_PATHNAME) == 0))
13391 13404                                  list_prop_tmpl(prt, NULL, templates);
13392 13405                          if (prop_name != NULL) {
13393 13406                                  free(prop_name);
13394 13407                                  prop_name = NULL;
13395 13408                          }
13396 13409                  }
13397 13410                  if (pg_name != NULL) {
13398 13411                          free(pg_name);
13399 13412                          pg_name = NULL;
13400 13413                  }
13401 13414          }
13402 13415  
13403 13416          scf_tmpl_prop_destroy(prt);
13404 13417          scf_tmpl_pg_destroy(pgt);
13405 13418          free(snapbuf);
13406 13419          free(fmribuf);
13407 13420          free(qual_prop_name);
13408 13421  }
13409 13422  
13410 13423  static void
13411 13424  listprop(const char *pattern, int only_pgs, int templates)
13412 13425  {
13413 13426          scf_propertygroup_t *pg;
13414 13427          scf_property_t *prop;
13415 13428          scf_iter_t *iter, *piter;
13416 13429          char *pgnbuf, *prnbuf, *ppnbuf;
13417 13430          scf_pg_tmpl_t *pgt, *pgtp;
13418 13431          scf_prop_tmpl_t *prt;
13419 13432  
13420 13433          void **objects;
13421 13434          char **names;
13422 13435          void **tmpls;
13423 13436          int allocd, i;
13424 13437  
13425 13438          int ret;
13426 13439          ssize_t pgnlen, prnlen, szret;
13427 13440          size_t max_len = 0;
13428 13441  
13429 13442          if (cur_svc == NULL && cur_inst == NULL) {
13430 13443                  semerr(emsg_entity_not_selected);
13431 13444                  return;
13432 13445          }
13433 13446  
13434 13447          if ((pg = scf_pg_create(g_hndl)) == NULL ||
13435 13448              (prop = scf_property_create(g_hndl)) == NULL ||
13436 13449              (iter = scf_iter_create(g_hndl)) == NULL ||
13437 13450              (piter = scf_iter_create(g_hndl)) == NULL ||
13438 13451              (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13439 13452              (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13440 13453                  scfdie();
13441 13454  
13442 13455          prnbuf = safe_malloc(max_scf_name_len + 1);
13443 13456  
13444 13457          if (cur_level != NULL)
13445 13458                  ret = scf_iter_snaplevel_pgs(iter, cur_level);
13446 13459          else if (cur_inst != NULL)
13447 13460                  ret = scf_iter_instance_pgs(iter, cur_inst);
13448 13461          else
13449 13462                  ret = scf_iter_service_pgs(iter, cur_svc);
13450 13463          if (ret != 0) {
13451 13464                  return;
13452 13465          }
13453 13466  
13454 13467          /*
13455 13468           * We want to only list items which match pattern, and we want the
13456 13469           * second column to line up, so during the first pass we'll save
13457 13470           * matching items, their names, and their templates in objects,
13458 13471           * names, and tmpls, computing the maximum name length as we go,
13459 13472           * and then we'll print them out.
13460 13473           *
13461 13474           * Note: We always keep an extra slot available so the array can be
13462 13475           * NULL-terminated.
13463 13476           */
13464 13477          i = 0;
13465 13478          allocd = 1;
13466 13479          objects = safe_malloc(sizeof (*objects));
13467 13480          names = safe_malloc(sizeof (*names));
13468 13481          tmpls = safe_malloc(sizeof (*tmpls));
13469 13482  
13470 13483          while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13471 13484                  int new_pg = 0;
13472 13485                  int print_props = 0;
13473 13486                  pgtp = NULL;
13474 13487  
13475 13488                  pgnlen = scf_pg_get_name(pg, NULL, 0);
13476 13489                  if (pgnlen < 0)
13477 13490                          scfdie();
13478 13491  
13479 13492                  pgnbuf = safe_malloc(pgnlen + 1);
13480 13493  
13481 13494                  szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13482 13495                  if (szret < 0)
13483 13496                          scfdie();
13484 13497                  assert(szret <= pgnlen);
13485 13498  
13486 13499                  if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13487 13500                          if (scf_error() != SCF_ERROR_NOT_FOUND)
13488 13501                                  scfdie();
13489 13502                          pgtp = NULL;
13490 13503                  } else {
13491 13504                          pgtp = pgt;
13492 13505                  }
13493 13506  
13494 13507                  if (pattern == NULL ||
13495 13508                      fnmatch(pattern, pgnbuf, 0) == 0) {
13496 13509                          if (i+1 >= allocd) {
13497 13510                                  allocd *= 2;
13498 13511                                  objects = realloc(objects,
13499 13512                                      sizeof (*objects) * allocd);
13500 13513                                  names =
13501 13514                                      realloc(names, sizeof (*names) * allocd);
13502 13515                                  tmpls = realloc(tmpls,
13503 13516                                      sizeof (*tmpls) * allocd);
13504 13517                                  if (objects == NULL || names == NULL ||
13505 13518                                      tmpls == NULL)
13506 13519                                          uu_die(gettext("Out of memory"));
13507 13520                          }
13508 13521                          objects[i] = pg;
13509 13522                          names[i] = pgnbuf;
13510 13523  
13511 13524                          if (pgtp == NULL)
13512 13525                                  tmpls[i] = NULL;
13513 13526                          else
13514 13527                                  tmpls[i] = pgt;
13515 13528  
13516 13529                          ++i;
13517 13530  
13518 13531                          if (pgnlen > max_len)
13519 13532                                  max_len = pgnlen;
13520 13533  
13521 13534                          new_pg = 1;
13522 13535                          print_props = 1;
13523 13536                  }
13524 13537  
13525 13538                  if (only_pgs) {
13526 13539                          if (new_pg) {
13527 13540                                  pg = scf_pg_create(g_hndl);
13528 13541                                  if (pg == NULL)
13529 13542                                          scfdie();
13530 13543                                  pgt = scf_tmpl_pg_create(g_hndl);
13531 13544                                  if (pgt == NULL)
13532 13545                                          scfdie();
13533 13546                          } else
13534 13547                                  free(pgnbuf);
13535 13548  
13536 13549                          continue;
13537 13550                  }
13538 13551  
13539 13552                  if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13540 13553                          scfdie();
13541 13554  
13542 13555                  while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13543 13556                          prnlen = scf_property_get_name(prop, prnbuf,
13544 13557                              max_scf_name_len + 1);
13545 13558                          if (prnlen < 0)
13546 13559                                  scfdie();
13547 13560  
13548 13561                          /* Will prepend the property group name and a slash. */
13549 13562                          prnlen += pgnlen + 1;
13550 13563  
13551 13564                          ppnbuf = safe_malloc(prnlen + 1);
13552 13565  
13553 13566                          if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13554 13567                              prnbuf) < 0)
13555 13568                                  uu_die("snprintf");
13556 13569  
13557 13570                          if (pattern == NULL || print_props == 1 ||
13558 13571                              fnmatch(pattern, ppnbuf, 0) == 0) {
13559 13572                                  if (i+1 >= allocd) {
13560 13573                                          allocd *= 2;
13561 13574                                          objects = realloc(objects,
13562 13575                                              sizeof (*objects) * allocd);
13563 13576                                          names = realloc(names,
13564 13577                                              sizeof (*names) * allocd);
13565 13578                                          tmpls = realloc(tmpls,
13566 13579                                              sizeof (*tmpls) * allocd);
13567 13580                                          if (objects == NULL || names == NULL ||
13568 13581                                              tmpls == NULL)
13569 13582                                                  uu_die(gettext(
13570 13583                                                      "Out of memory"));
13571 13584                                  }
13572 13585  
13573 13586                                  objects[i] = prop;
13574 13587                                  names[i] = ppnbuf;
13575 13588  
13576 13589                                  if (pgtp != NULL) {
13577 13590                                          if (scf_tmpl_get_by_prop(pgt, prnbuf,
13578 13591                                              prt, 0) < 0) {
13579 13592                                                  if (scf_error() !=
13580 13593                                                      SCF_ERROR_NOT_FOUND)
13581 13594                                                          scfdie();
13582 13595                                                  tmpls[i] = NULL;
13583 13596                                          } else {
13584 13597                                                  tmpls[i] = prt;
13585 13598                                          }
13586 13599                                  } else {
13587 13600                                          tmpls[i] = NULL;
13588 13601                                  }
13589 13602  
13590 13603                                  ++i;
13591 13604  
13592 13605                                  if (prnlen > max_len)
13593 13606                                          max_len = prnlen;
13594 13607  
13595 13608                                  prop = scf_property_create(g_hndl);
13596 13609                                  prt = scf_tmpl_prop_create(g_hndl);
13597 13610                          } else {
13598 13611                                  free(ppnbuf);
13599 13612                          }
13600 13613                  }
13601 13614  
13602 13615                  if (new_pg) {
13603 13616                          pg = scf_pg_create(g_hndl);
13604 13617                          if (pg == NULL)
13605 13618                                  scfdie();
13606 13619                          pgt = scf_tmpl_pg_create(g_hndl);
13607 13620                          if (pgt == NULL)
13608 13621                                  scfdie();
13609 13622                  } else
13610 13623                          free(pgnbuf);
13611 13624          }
13612 13625          if (ret != 0)
13613 13626                  scfdie();
13614 13627  
13615 13628          objects[i] = NULL;
13616 13629  
13617 13630          scf_pg_destroy(pg);
13618 13631          scf_tmpl_pg_destroy(pgt);
13619 13632          scf_property_destroy(prop);
13620 13633          scf_tmpl_prop_destroy(prt);
13621 13634  
13622 13635          for (i = 0; objects[i] != NULL; ++i) {
13623 13636                  if (strchr(names[i], '/') == NULL) {
13624 13637                          /* property group */
13625 13638                          pg = (scf_propertygroup_t *)objects[i];
13626 13639                          pgt = (scf_pg_tmpl_t *)tmpls[i];
13627 13640                          list_pg_info(pg, names[i], max_len);
13628 13641                          list_pg_tmpl(pgt, pg, templates);
13629 13642                          free(names[i]);
13630 13643                          scf_pg_destroy(pg);
13631 13644                          if (pgt != NULL)
13632 13645                                  scf_tmpl_pg_destroy(pgt);
13633 13646                  } else {
13634 13647                          /* property */
13635 13648                          prop = (scf_property_t *)objects[i];
13636 13649                          prt = (scf_prop_tmpl_t *)tmpls[i];
13637 13650                          list_prop_info(prop, names[i], max_len);
13638 13651                          list_prop_tmpl(prt, prop, templates);
13639 13652                          free(names[i]);
13640 13653                          scf_property_destroy(prop);
13641 13654                          if (prt != NULL)
13642 13655                                  scf_tmpl_prop_destroy(prt);
13643 13656                  }
13644 13657          }
13645 13658  
13646 13659          free(names);
13647 13660          free(objects);
13648 13661          free(tmpls);
13649 13662  }
13650 13663  
13651 13664  void
13652 13665  lscf_listpg(const char *pattern)
13653 13666  {
13654 13667          lscf_prep_hndl();
13655 13668  
13656 13669          listprop(pattern, 1, 0);
13657 13670  }
13658 13671  
13659 13672  /*
13660 13673   * Property group and property creation, setting, and deletion.  setprop (and
13661 13674   * its alias, addprop) can either create a property group of a given type, or
13662 13675   * it can create or set a property to a given type and list of values.
13663 13676   */
13664 13677  void
13665 13678  lscf_addpg(const char *name, const char *type, const char *flags)
13666 13679  {
13667 13680          scf_propertygroup_t *pg;
13668 13681          int ret;
13669 13682          uint32_t flgs = 0;
13670 13683          const char *cp;
13671 13684  
13672 13685  
13673 13686          lscf_prep_hndl();
13674 13687  
13675 13688          if (cur_snap != NULL) {
13676 13689                  semerr(emsg_cant_modify_snapshots);
13677 13690                  return;
13678 13691          }
13679 13692  
13680 13693          if (cur_inst == NULL && cur_svc == NULL) {
13681 13694                  semerr(emsg_entity_not_selected);
13682 13695                  return;
13683 13696          }
13684 13697  
13685 13698          if (flags != NULL) {
13686 13699                  for (cp = flags; *cp != '\0'; ++cp) {
13687 13700                          switch (*cp) {
13688 13701                          case 'P':
13689 13702                                  flgs |= SCF_PG_FLAG_NONPERSISTENT;
13690 13703                                  break;
13691 13704  
13692 13705                          case 'p':
13693 13706                                  flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13694 13707                                  break;
13695 13708  
13696 13709                          default:
13697 13710                                  semerr(gettext("Invalid property group flag "
13698 13711                                      "%c."), *cp);
13699 13712                                  return;
13700 13713                          }
13701 13714                  }
13702 13715          }
13703 13716  
13704 13717          pg = scf_pg_create(g_hndl);
13705 13718          if (pg == NULL)
13706 13719                  scfdie();
13707 13720  
13708 13721          if (cur_inst != NULL)
13709 13722                  ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13710 13723          else
13711 13724                  ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13712 13725  
13713 13726          if (ret != SCF_SUCCESS) {
13714 13727                  switch (scf_error()) {
13715 13728                  case SCF_ERROR_INVALID_ARGUMENT:
13716 13729                          semerr(gettext("Name, type, or flags are invalid.\n"));
13717 13730                          break;
13718 13731  
13719 13732                  case SCF_ERROR_EXISTS:
13720 13733                          semerr(gettext("Property group already exists.\n"));
13721 13734                          break;
13722 13735  
13723 13736                  case SCF_ERROR_PERMISSION_DENIED:
13724 13737                          semerr(emsg_permission_denied);
13725 13738                          break;
13726 13739  
13727 13740                  case SCF_ERROR_BACKEND_ACCESS:
13728 13741                          semerr(gettext("Backend refused access.\n"));
13729 13742                          break;
13730 13743  
13731 13744                  default:
13732 13745                          scfdie();
13733 13746                  }
13734 13747          }
13735 13748  
13736 13749          scf_pg_destroy(pg);
13737 13750  
13738 13751          private_refresh();
13739 13752  }
13740 13753  
13741 13754  void
13742 13755  lscf_delpg(char *name)
13743 13756  {
13744 13757          lscf_prep_hndl();
13745 13758  
13746 13759          if (cur_snap != NULL) {
13747 13760                  semerr(emsg_cant_modify_snapshots);
13748 13761                  return;
13749 13762          }
13750 13763  
13751 13764          if (cur_inst == NULL && cur_svc == NULL) {
13752 13765                  semerr(emsg_entity_not_selected);
13753 13766                  return;
13754 13767          }
13755 13768  
13756 13769          if (strchr(name, '/') != NULL) {
13757 13770                  semerr(emsg_invalid_pg_name, name);
13758 13771                  return;
13759 13772          }
13760 13773  
13761 13774          lscf_delprop(name);
13762 13775  }
13763 13776  
13764 13777  /*
13765 13778   * scf_delhash() is used to remove the property group related to the
13766 13779   * hash entry for a specific manifest in the repository. pgname will be
13767 13780   * constructed from the location of the manifest file. If deathrow isn't 0,
13768 13781   * manifest file doesn't need to exist (manifest string will be used as
13769 13782   * an absolute path).
13770 13783   */
13771 13784  void
13772 13785  lscf_delhash(char *manifest, int deathrow)
13773 13786  {
13774 13787          char *pgname;
13775 13788  
13776 13789          if (cur_snap != NULL ||
13777 13790              cur_inst != NULL || cur_svc != NULL) {
13778 13791                  warn(gettext("error, an entity is selected\n"));
13779 13792                  return;
13780 13793          }
13781 13794  
13782 13795          /* select smf/manifest */
13783 13796          lscf_select(HASH_SVC);
13784 13797          /*
13785 13798           * Translate the manifest file name to property name. In the deathrow
13786 13799           * case, the manifest file does not need to exist.
13787 13800           */
13788 13801          pgname = mhash_filename_to_propname(manifest,
13789 13802              deathrow ? B_TRUE : B_FALSE);
13790 13803          if (pgname == NULL) {
13791 13804                  warn(gettext("cannot resolve pathname for %s\n"), manifest);
13792 13805                  return;
13793 13806          }
13794 13807          /* delete the hash property name */
13795 13808          lscf_delpg(pgname);
13796 13809  }
13797 13810  
13798 13811  void
13799 13812  lscf_listprop(const char *pattern)
13800 13813  {
13801 13814          lscf_prep_hndl();
13802 13815  
13803 13816          listprop(pattern, 0, 0);
13804 13817  }
13805 13818  
13806 13819  int
13807 13820  lscf_setprop(const char *pgname, const char *type, const char *value,
13808 13821      const uu_list_t *values)
13809 13822  {
13810 13823          scf_type_t ty, current_ty;
13811 13824          scf_service_t *svc;
13812 13825          scf_propertygroup_t *pg, *parent_pg;
13813 13826          scf_property_t *prop, *parent_prop;
13814 13827          scf_pg_tmpl_t *pgt;
13815 13828          scf_prop_tmpl_t *prt;
13816 13829          int ret, result = 0;
13817 13830          scf_transaction_t *tx;
13818 13831          scf_transaction_entry_t *e;
13819 13832          scf_value_t *v;
13820 13833          uu_list_walk_t *walk;
13821 13834          string_list_t *sp;
13822 13835          char *propname;
13823 13836          int req_quotes = 0;
13824 13837  
13825 13838          lscf_prep_hndl();
13826 13839  
13827 13840          if ((e = scf_entry_create(g_hndl)) == NULL ||
13828 13841              (svc = scf_service_create(g_hndl)) == NULL ||
13829 13842              (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13830 13843              (pg = scf_pg_create(g_hndl)) == NULL ||
13831 13844              (parent_prop = scf_property_create(g_hndl)) == NULL ||
13832 13845              (prop = scf_property_create(g_hndl)) == NULL ||
13833 13846              (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13834 13847              (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13835 13848              (tx = scf_transaction_create(g_hndl)) == NULL)
13836 13849                  scfdie();
13837 13850  
13838 13851          if (cur_snap != NULL) {
13839 13852                  semerr(emsg_cant_modify_snapshots);
13840 13853                  goto fail;
13841 13854          }
13842 13855  
13843 13856          if (cur_inst == NULL && cur_svc == NULL) {
13844 13857                  semerr(emsg_entity_not_selected);
13845 13858                  goto fail;
13846 13859          }
13847 13860  
13848 13861          propname = strchr(pgname, '/');
13849 13862          if (propname == NULL) {
13850 13863                  semerr(gettext("Property names must contain a `/'.\n"));
13851 13864                  goto fail;
13852 13865          }
13853 13866  
13854 13867          *propname = '\0';
13855 13868          ++propname;
13856 13869  
13857 13870          if (type != NULL) {
13858 13871                  ty = string_to_type(type);
13859 13872                  if (ty == SCF_TYPE_INVALID) {
13860 13873                          semerr(gettext("Unknown type \"%s\".\n"), type);
13861 13874                          goto fail;
13862 13875                  }
13863 13876          }
13864 13877  
13865 13878          if (cur_inst != NULL)
13866 13879                  ret = scf_instance_get_pg(cur_inst, pgname, pg);
13867 13880          else
13868 13881                  ret = scf_service_get_pg(cur_svc, pgname, pg);
13869 13882          if (ret != SCF_SUCCESS) {
13870 13883                  switch (scf_error()) {
13871 13884                  case SCF_ERROR_NOT_FOUND:
13872 13885                          semerr(emsg_no_such_pg, pgname);
13873 13886                          goto fail;
13874 13887  
13875 13888                  case SCF_ERROR_INVALID_ARGUMENT:
13876 13889                          semerr(emsg_invalid_pg_name, pgname);
13877 13890                          goto fail;
13878 13891  
13879 13892                  default:
13880 13893                          scfdie();
13881 13894                          break;
13882 13895                  }
13883 13896          }
13884 13897  
13885 13898          do {
13886 13899                  if (scf_pg_update(pg) == -1)
13887 13900                          scfdie();
13888 13901                  if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13889 13902                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13890 13903                                  scfdie();
13891 13904  
13892 13905                          semerr(emsg_permission_denied);
13893 13906                          goto fail;
13894 13907                  }
13895 13908  
13896 13909                  ret = scf_pg_get_property(pg, propname, prop);
13897 13910                  if (ret == SCF_SUCCESS) {
13898 13911                          if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13899 13912                                  scfdie();
13900 13913  
13901 13914                          if (type == NULL)
13902 13915                                  ty = current_ty;
13903 13916                          if (scf_transaction_property_change_type(tx, e,
13904 13917                              propname, ty) == -1)
13905 13918                                  scfdie();
13906 13919  
13907 13920                  } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13908 13921                          /* Infer the type, if possible. */
13909 13922                          if (type == NULL) {
13910 13923                                  /*
13911 13924                                   * First check if we're an instance and the
13912 13925                                   * property is set on the service.
13913 13926                                   */
13914 13927                                  if (cur_inst != NULL &&
13915 13928                                      scf_instance_get_parent(cur_inst,
13916 13929                                      svc) == 0 &&
13917 13930                                      scf_service_get_pg(cur_svc, pgname,
13918 13931                                      parent_pg) == 0 &&
13919 13932                                      scf_pg_get_property(parent_pg, propname,
13920 13933                                      parent_prop) == 0 &&
13921 13934                                      scf_property_type(parent_prop,
13922 13935                                      ¤t_ty) == 0) {
13923 13936                                          ty = current_ty;
13924 13937  
13925 13938                                  /* Then check for a type set in a template. */
13926 13939                                  } else if (scf_tmpl_get_by_pg(pg, pgt,
13927 13940                                      0) == 0 &&
13928 13941                                      scf_tmpl_get_by_prop(pgt, propname, prt,
13929 13942                                      0) == 0 &&
13930 13943                                      scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13931 13944                                          ty = current_ty;
13932 13945  
13933 13946                                  /* If type can't be inferred, fail. */
13934 13947                                  } else {
13935 13948                                          semerr(gettext("Type required for new "
13936 13949                                              "properties.\n"));
13937 13950                                          goto fail;
13938 13951                                  }
13939 13952                          }
13940 13953                          if (scf_transaction_property_new(tx, e, propname,
13941 13954                              ty) == -1)
13942 13955                                  scfdie();
13943 13956                  } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13944 13957                          semerr(emsg_invalid_prop_name, propname);
13945 13958                          goto fail;
13946 13959                  } else {
13947 13960                          scfdie();
13948 13961                  }
13949 13962  
13950 13963                  if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13951 13964                          req_quotes = 1;
13952 13965  
13953 13966                  if (value != NULL) {
13954 13967                          v = string_to_value(value, ty, 0);
13955 13968  
13956 13969                          if (v == NULL)
13957 13970                                  goto fail;
13958 13971  
13959 13972                          ret = scf_entry_add_value(e, v);
13960 13973                          assert(ret == SCF_SUCCESS);
13961 13974                  } else {
13962 13975                          assert(values != NULL);
13963 13976  
13964 13977                          walk = uu_list_walk_start((uu_list_t *)values,
13965 13978                              UU_DEFAULT);
13966 13979                          if (walk == NULL)
13967 13980                                  uu_die(gettext("Could not walk list"));
13968 13981  
13969 13982                          for (sp = uu_list_walk_next(walk); sp != NULL;
13970 13983                              sp = uu_list_walk_next(walk)) {
13971 13984                                  v = string_to_value(sp->str, ty, req_quotes);
13972 13985  
13973 13986                                  if (v == NULL) {
13974 13987                                          scf_entry_destroy_children(e);
13975 13988                                          goto fail;
13976 13989                                  }
13977 13990  
13978 13991                                  ret = scf_entry_add_value(e, v);
13979 13992                                  assert(ret == SCF_SUCCESS);
13980 13993                          }
13981 13994                          uu_list_walk_end(walk);
13982 13995                  }
13983 13996                  result = scf_transaction_commit(tx);
13984 13997  
13985 13998                  scf_transaction_reset(tx);
13986 13999                  scf_entry_destroy_children(e);
13987 14000          } while (result == 0);
13988 14001  
13989 14002          if (result < 0) {
13990 14003                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13991 14004                          scfdie();
13992 14005  
13993 14006                  semerr(emsg_permission_denied);
13994 14007                  goto fail;
13995 14008          }
13996 14009  
13997 14010          ret = 0;
13998 14011  
13999 14012          private_refresh();
14000 14013  
14001 14014          goto cleanup;
14002 14015  
14003 14016  fail:
14004 14017          ret = -1;
14005 14018  
14006 14019  cleanup:
14007 14020          scf_transaction_destroy(tx);
14008 14021          scf_entry_destroy(e);
14009 14022          scf_service_destroy(svc);
14010 14023          scf_pg_destroy(parent_pg);
14011 14024          scf_pg_destroy(pg);
14012 14025          scf_property_destroy(parent_prop);
14013 14026          scf_property_destroy(prop);
14014 14027          scf_tmpl_pg_destroy(pgt);
14015 14028          scf_tmpl_prop_destroy(prt);
14016 14029  
14017 14030          return (ret);
14018 14031  }
14019 14032  
14020 14033  void
14021 14034  lscf_delprop(char *pgn)
14022 14035  {
14023 14036          char *slash, *pn;
14024 14037          scf_propertygroup_t *pg;
14025 14038          scf_transaction_t *tx;
14026 14039          scf_transaction_entry_t *e;
14027 14040          int ret;
14028 14041  
14029 14042  
14030 14043          lscf_prep_hndl();
14031 14044  
14032 14045          if (cur_snap != NULL) {
14033 14046                  semerr(emsg_cant_modify_snapshots);
14034 14047                  return;
14035 14048          }
14036 14049  
14037 14050          if (cur_inst == NULL && cur_svc == NULL) {
14038 14051                  semerr(emsg_entity_not_selected);
14039 14052                  return;
14040 14053          }
14041 14054  
14042 14055          pg = scf_pg_create(g_hndl);
14043 14056          if (pg == NULL)
14044 14057                  scfdie();
14045 14058  
14046 14059          slash = strchr(pgn, '/');
14047 14060          if (slash == NULL) {
14048 14061                  pn = NULL;
14049 14062          } else {
14050 14063                  *slash = '\0';
14051 14064                  pn = slash + 1;
14052 14065          }
14053 14066  
14054 14067          if (cur_inst != NULL)
14055 14068                  ret = scf_instance_get_pg(cur_inst, pgn, pg);
14056 14069          else
14057 14070                  ret = scf_service_get_pg(cur_svc, pgn, pg);
14058 14071          if (ret != SCF_SUCCESS) {
14059 14072                  switch (scf_error()) {
14060 14073                  case SCF_ERROR_NOT_FOUND:
14061 14074                          semerr(emsg_no_such_pg, pgn);
14062 14075                          break;
14063 14076  
14064 14077                  case SCF_ERROR_INVALID_ARGUMENT:
14065 14078                          semerr(emsg_invalid_pg_name, pgn);
14066 14079                          break;
14067 14080  
14068 14081                  default:
14069 14082                          scfdie();
14070 14083                  }
14071 14084  
14072 14085                  scf_pg_destroy(pg);
14073 14086  
14074 14087                  return;
14075 14088          }
14076 14089  
14077 14090          if (pn == NULL) {
14078 14091                  /* Try to delete the property group. */
14079 14092                  if (scf_pg_delete(pg) != SCF_SUCCESS) {
14080 14093                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14081 14094                                  scfdie();
14082 14095  
14083 14096                          semerr(emsg_permission_denied);
14084 14097                  } else {
14085 14098                          private_refresh();
14086 14099                  }
14087 14100  
14088 14101                  scf_pg_destroy(pg);
14089 14102                  return;
14090 14103          }
14091 14104  
14092 14105          e = scf_entry_create(g_hndl);
14093 14106          tx = scf_transaction_create(g_hndl);
14094 14107  
14095 14108          do {
14096 14109                  if (scf_pg_update(pg) == -1)
14097 14110                          scfdie();
14098 14111                  if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14099 14112                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100 14113                                  scfdie();
14101 14114  
14102 14115                          semerr(emsg_permission_denied);
14103 14116                          break;
14104 14117                  }
14105 14118  
14106 14119                  if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14107 14120                          if (scf_error() == SCF_ERROR_NOT_FOUND) {
14108 14121                                  semerr(gettext("No such property %s/%s.\n"),
14109 14122                                      pgn, pn);
14110 14123                                  break;
14111 14124                          } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14112 14125                                  semerr(emsg_invalid_prop_name, pn);
14113 14126                                  break;
14114 14127                          } else {
14115 14128                                  scfdie();
14116 14129                          }
14117 14130                  }
14118 14131  
14119 14132                  ret = scf_transaction_commit(tx);
14120 14133  
14121 14134                  if (ret == 0)
14122 14135                          scf_transaction_reset(tx);
14123 14136          } while (ret == 0);
14124 14137  
14125 14138          if (ret < 0) {
14126 14139                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14127 14140                          scfdie();
14128 14141  
14129 14142                  semerr(emsg_permission_denied);
14130 14143          } else {
14131 14144                  private_refresh();
14132 14145          }
14133 14146  
14134 14147          scf_transaction_destroy(tx);
14135 14148          scf_entry_destroy(e);
14136 14149          scf_pg_destroy(pg);
14137 14150  }
14138 14151  
14139 14152  /*
14140 14153   * Property editing.
14141 14154   */
14142 14155  
14143 14156  static int
14144 14157  write_edit_script(FILE *strm)
14145 14158  {
14146 14159          char *fmribuf;
14147 14160          ssize_t fmrilen;
14148 14161  
14149 14162          scf_propertygroup_t *pg;
14150 14163          scf_property_t *prop;
14151 14164          scf_value_t *val;
14152 14165          scf_type_t ty;
14153 14166          int ret, result = 0;
14154 14167          scf_iter_t *iter, *piter, *viter;
14155 14168          char *buf, *tybuf, *pname;
14156 14169          const char *emsg_write_error;
14157 14170  
14158 14171  
14159 14172          emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14160 14173  
14161 14174  
14162 14175          /* select fmri */
14163 14176          if (cur_inst != NULL) {
14164 14177                  fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14165 14178                  if (fmrilen < 0)
14166 14179                          scfdie();
14167 14180                  fmribuf = safe_malloc(fmrilen + 1);
14168 14181                  if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14169 14182                          scfdie();
14170 14183          } else {
14171 14184                  assert(cur_svc != NULL);
14172 14185                  fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14173 14186                  if (fmrilen < 0)
14174 14187                          scfdie();
14175 14188                  fmribuf = safe_malloc(fmrilen + 1);
14176 14189                  if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14177 14190                          scfdie();
14178 14191          }
14179 14192  
14180 14193          if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14181 14194                  warn(emsg_write_error, strerror(errno));
14182 14195                  free(fmribuf);
14183 14196                  return (-1);
14184 14197          }
14185 14198  
14186 14199          free(fmribuf);
14187 14200  
14188 14201  
14189 14202          if ((pg = scf_pg_create(g_hndl)) == NULL ||
14190 14203              (prop = scf_property_create(g_hndl)) == NULL ||
14191 14204              (val = scf_value_create(g_hndl)) == NULL ||
14192 14205              (iter = scf_iter_create(g_hndl)) == NULL ||
14193 14206              (piter = scf_iter_create(g_hndl)) == NULL ||
14194 14207              (viter = scf_iter_create(g_hndl)) == NULL)
14195 14208                  scfdie();
14196 14209  
14197 14210          buf = safe_malloc(max_scf_name_len + 1);
14198 14211          tybuf = safe_malloc(max_scf_pg_type_len + 1);
14199 14212          pname = safe_malloc(max_scf_name_len + 1);
14200 14213  
14201 14214          if (cur_inst != NULL)
14202 14215                  ret = scf_iter_instance_pgs(iter, cur_inst);
14203 14216          else
14204 14217                  ret = scf_iter_service_pgs(iter, cur_svc);
14205 14218          if (ret != SCF_SUCCESS)
14206 14219                  scfdie();
14207 14220  
14208 14221          while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14209 14222                  int ret2;
14210 14223  
14211 14224                  /*
14212 14225                   * # delprop pg
14213 14226                   * # addpg pg type
14214 14227                   */
14215 14228                  if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14216 14229                          scfdie();
14217 14230  
14218 14231                  if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14219 14232                          scfdie();
14220 14233  
14221 14234                  if (fprintf(strm, "# Property group \"%s\"\n"
14222 14235                      "# delprop %s\n"
14223 14236                      "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14224 14237                          warn(emsg_write_error, strerror(errno));
14225 14238                          result = -1;
14226 14239                          goto out;
14227 14240                  }
14228 14241  
14229 14242                  /* # setprop pg/prop = (values) */
14230 14243  
14231 14244                  if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14232 14245                          scfdie();
14233 14246  
14234 14247                  while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14235 14248                          int first = 1;
14236 14249                          int ret3;
14237 14250                          int multiple;
14238 14251                          int is_str;
14239 14252                          scf_type_t bty;
14240 14253  
14241 14254                          if (scf_property_get_name(prop, pname,
14242 14255                              max_scf_name_len + 1) < 0)
14243 14256                                  scfdie();
14244 14257  
14245 14258                          if (scf_property_type(prop, &ty) != 0)
14246 14259                                  scfdie();
14247 14260  
14248 14261                          multiple = prop_has_multiple_values(prop, val);
14249 14262  
14250 14263                          if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14251 14264                              pname, scf_type_to_string(ty), multiple ? "(" : "")
14252 14265                              < 0) {
14253 14266                                  warn(emsg_write_error, strerror(errno));
14254 14267                                  result = -1;
14255 14268                                  goto out;
14256 14269                          }
14257 14270  
14258 14271                          (void) scf_type_base_type(ty, &bty);
14259 14272                          is_str = (bty == SCF_TYPE_ASTRING);
14260 14273  
14261 14274                          if (scf_iter_property_values(viter, prop) !=
14262 14275                              SCF_SUCCESS)
14263 14276                                  scfdie();
14264 14277  
14265 14278                          while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14266 14279                                  char *buf;
14267 14280                                  ssize_t buflen;
14268 14281  
14269 14282                                  buflen = scf_value_get_as_string(val, NULL, 0);
14270 14283                                  if (buflen < 0)
14271 14284                                          scfdie();
14272 14285  
14273 14286                                  buf = safe_malloc(buflen + 1);
14274 14287  
14275 14288                                  if (scf_value_get_as_string(val, buf,
14276 14289                                      buflen + 1) < 0)
14277 14290                                          scfdie();
14278 14291  
14279 14292                                  if (first)
14280 14293                                          first = 0;
14281 14294                                  else {
14282 14295                                          if (putc(' ', strm) != ' ') {
14283 14296                                                  warn(emsg_write_error,
14284 14297                                                      strerror(errno));
14285 14298                                                  result = -1;
14286 14299                                                  goto out;
14287 14300                                          }
14288 14301                                  }
14289 14302  
14290 14303                                  if ((is_str && multiple) ||
14291 14304                                      strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14292 14305                                          (void) putc('"', strm);
14293 14306                                          (void) quote_and_print(buf, strm, 1);
14294 14307                                          (void) putc('"', strm);
14295 14308  
14296 14309                                          if (ferror(strm)) {
14297 14310                                                  warn(emsg_write_error,
14298 14311                                                      strerror(errno));
14299 14312                                                  result = -1;
14300 14313                                                  goto out;
14301 14314                                          }
14302 14315                                  } else {
14303 14316                                          if (fprintf(strm, "%s", buf) < 0) {
14304 14317                                                  warn(emsg_write_error,
14305 14318                                                      strerror(errno));
14306 14319                                                  result = -1;
14307 14320                                                  goto out;
14308 14321                                          }
14309 14322                                  }
14310 14323  
14311 14324                                  free(buf);
14312 14325                          }
14313 14326                          if (ret3 < 0 &&
14314 14327                              scf_error() != SCF_ERROR_PERMISSION_DENIED)
14315 14328                                  scfdie();
14316 14329  
14317 14330                          /* Write closing paren if mult-value property */
14318 14331                          if ((multiple && putc(')', strm) == EOF) ||
14319 14332  
14320 14333                              /* Write final newline */
14321 14334                              fputc('\n', strm) == EOF) {
14322 14335                                  warn(emsg_write_error, strerror(errno));
14323 14336                                  result = -1;
14324 14337                                  goto out;
14325 14338                          }
14326 14339                  }
14327 14340                  if (ret2 < 0)
14328 14341                          scfdie();
14329 14342  
14330 14343                  if (fputc('\n', strm) == EOF) {
14331 14344                          warn(emsg_write_error, strerror(errno));
14332 14345                          result = -1;
14333 14346                          goto out;
14334 14347                  }
14335 14348          }
14336 14349          if (ret < 0)
14337 14350                  scfdie();
14338 14351  
14339 14352  out:
14340 14353          free(pname);
14341 14354          free(tybuf);
14342 14355          free(buf);
14343 14356          scf_iter_destroy(viter);
14344 14357          scf_iter_destroy(piter);
14345 14358          scf_iter_destroy(iter);
14346 14359          scf_value_destroy(val);
14347 14360          scf_property_destroy(prop);
14348 14361          scf_pg_destroy(pg);
14349 14362  
14350 14363          if (result == 0) {
14351 14364                  if (fflush(strm) != 0) {
14352 14365                          warn(emsg_write_error, strerror(errno));
14353 14366                          return (-1);
14354 14367                  }
14355 14368          }
14356 14369  
14357 14370          return (result);
14358 14371  }
14359 14372  
14360 14373  int
14361 14374  lscf_editprop()
14362 14375  {
14363 14376          char *buf, *editor;
14364 14377          size_t bufsz;
14365 14378          int tmpfd;
14366 14379          char tempname[] = TEMP_FILE_PATTERN;
14367 14380  
14368 14381          lscf_prep_hndl();
14369 14382  
14370 14383          if (cur_snap != NULL) {
14371 14384                  semerr(emsg_cant_modify_snapshots);
14372 14385                  return (-1);
14373 14386          }
14374 14387  
14375 14388          if (cur_svc == NULL && cur_inst == NULL) {
14376 14389                  semerr(emsg_entity_not_selected);
14377 14390                  return (-1);
14378 14391          }
14379 14392  
14380 14393          tmpfd = mkstemp(tempname);
14381 14394          if (tmpfd == -1) {
14382 14395                  semerr(gettext("Could not create temporary file.\n"));
14383 14396                  return (-1);
14384 14397          }
14385 14398  
14386 14399          (void) strcpy(tempfilename, tempname);
14387 14400  
14388 14401          tempfile = fdopen(tmpfd, "r+");
14389 14402          if (tempfile == NULL) {
14390 14403                  warn(gettext("Could not create temporary file.\n"));
14391 14404                  if (close(tmpfd) == -1)
14392 14405                          warn(gettext("Could not close temporary file: %s.\n"),
14393 14406                              strerror(errno));
14394 14407  
14395 14408                  remove_tempfile();
14396 14409  
14397 14410                  return (-1);
14398 14411          }
14399 14412  
14400 14413          if (write_edit_script(tempfile) == -1) {
14401 14414                  remove_tempfile();
14402 14415                  return (-1);
14403 14416          }
14404 14417  
14405 14418          editor = getenv("EDITOR");
14406 14419          if (editor == NULL)
14407 14420                  editor = "vi";
14408 14421  
14409 14422          bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14410 14423          buf = safe_malloc(bufsz);
14411 14424  
14412 14425          if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14413 14426                  uu_die(gettext("Error creating editor command"));
14414 14427  
14415 14428          if (system(buf) == -1) {
14416 14429                  semerr(gettext("Could not launch editor %s: %s\n"), editor,
14417 14430                      strerror(errno));
14418 14431                  free(buf);
14419 14432                  remove_tempfile();
14420 14433                  return (-1);
14421 14434          }
14422 14435  
14423 14436          free(buf);
14424 14437  
14425 14438          (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14426 14439  
14427 14440          remove_tempfile();
14428 14441  
14429 14442          return (0);
14430 14443  }
14431 14444  
14432 14445  static void
14433 14446  add_string(uu_list_t *strlist, const char *str)
14434 14447  {
14435 14448          string_list_t *elem;
14436 14449          elem = safe_malloc(sizeof (*elem));
14437 14450          uu_list_node_init(elem, &elem->node, string_pool);
14438 14451          elem->str = safe_strdup(str);
14439 14452          if (uu_list_append(strlist, elem) != 0)
14440 14453                  uu_die(gettext("libuutil error: %s\n"),
14441 14454                      uu_strerror(uu_error()));
14442 14455  }
14443 14456  
14444 14457  static int
14445 14458  remove_string(uu_list_t *strlist, const char *str)
14446 14459  {
14447 14460          uu_list_walk_t  *elems;
14448 14461          string_list_t   *sp;
14449 14462  
14450 14463          /*
14451 14464           * Find the element that needs to be removed.
14452 14465           */
14453 14466          elems = uu_list_walk_start(strlist, UU_DEFAULT);
14454 14467          while ((sp = uu_list_walk_next(elems)) != NULL) {
14455 14468                  if (strcmp(sp->str, str) == 0)
14456 14469                          break;
14457 14470          }
14458 14471          uu_list_walk_end(elems);
14459 14472  
14460 14473          /*
14461 14474           * Returning 1 here as the value was not found, this
14462 14475           * might not be an error.  Leave it to the caller to
14463 14476           * decide.
14464 14477           */
14465 14478          if (sp == NULL) {
14466 14479                  return (1);
14467 14480          }
14468 14481  
14469 14482          uu_list_remove(strlist, sp);
14470 14483  
14471 14484          free(sp->str);
14472 14485          free(sp);
14473 14486  
14474 14487          return (0);
14475 14488  }
14476 14489  
14477 14490  /*
14478 14491   * Get all property values that don't match the given glob pattern,
14479 14492   * if a pattern is specified.
14480 14493   */
14481 14494  static void
14482 14495  get_prop_values(scf_property_t *prop, uu_list_t *values,
14483 14496      const char *pattern)
14484 14497  {
14485 14498          scf_iter_t *iter;
14486 14499          scf_value_t *val;
14487 14500          int ret;
14488 14501  
14489 14502          if ((iter = scf_iter_create(g_hndl)) == NULL ||
14490 14503              (val = scf_value_create(g_hndl)) == NULL)
14491 14504                  scfdie();
14492 14505  
14493 14506          if (scf_iter_property_values(iter, prop) != 0)
14494 14507                  scfdie();
14495 14508  
14496 14509          while ((ret = scf_iter_next_value(iter, val)) == 1) {
14497 14510                  char *buf;
14498 14511                  ssize_t vlen, szret;
14499 14512  
14500 14513                  vlen = scf_value_get_as_string(val, NULL, 0);
14501 14514                  if (vlen < 0)
14502 14515                          scfdie();
14503 14516  
14504 14517                  buf = safe_malloc(vlen + 1);
14505 14518  
14506 14519                  szret = scf_value_get_as_string(val, buf, vlen + 1);
14507 14520                  if (szret < 0)
14508 14521                          scfdie();
14509 14522                  assert(szret <= vlen);
14510 14523  
14511 14524                  if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14512 14525                          add_string(values, buf);
14513 14526  
14514 14527                  free(buf);
14515 14528          }
14516 14529  
14517 14530          if (ret == -1)
14518 14531                  scfdie();
14519 14532  
14520 14533          scf_value_destroy(val);
14521 14534          scf_iter_destroy(iter);
14522 14535  }
14523 14536  
14524 14537  static int
14525 14538  lscf_setpropvalue(const char *pgname, const char *type,
14526 14539      const char *arg, int isadd, int isnotfoundok)
14527 14540  {
14528 14541          scf_type_t ty;
14529 14542          scf_propertygroup_t *pg;
14530 14543          scf_property_t *prop;
14531 14544          int ret, result = 0;
14532 14545          scf_transaction_t *tx;
14533 14546          scf_transaction_entry_t *e;
14534 14547          scf_value_t *v;
14535 14548          string_list_t *sp;
14536 14549          char *propname;
14537 14550          uu_list_t *values;
14538 14551          uu_list_walk_t *walk;
14539 14552          void *cookie = NULL;
14540 14553          char *pattern = NULL;
14541 14554  
14542 14555          lscf_prep_hndl();
14543 14556  
14544 14557          if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14545 14558                  uu_die(gettext("Could not create property list: %s\n"),
14546 14559                      uu_strerror(uu_error()));
14547 14560  
14548 14561          if (!isadd)
14549 14562                  pattern = safe_strdup(arg);
14550 14563  
14551 14564          if ((e = scf_entry_create(g_hndl)) == NULL ||
14552 14565              (pg = scf_pg_create(g_hndl)) == NULL ||
14553 14566              (prop = scf_property_create(g_hndl)) == NULL ||
14554 14567              (tx = scf_transaction_create(g_hndl)) == NULL)
14555 14568                  scfdie();
14556 14569  
14557 14570          if (cur_snap != NULL) {
14558 14571                  semerr(emsg_cant_modify_snapshots);
14559 14572                  goto fail;
14560 14573          }
14561 14574  
14562 14575          if (cur_inst == NULL && cur_svc == NULL) {
14563 14576                  semerr(emsg_entity_not_selected);
14564 14577                  goto fail;
14565 14578          }
14566 14579  
14567 14580          propname = strchr(pgname, '/');
14568 14581          if (propname == NULL) {
14569 14582                  semerr(gettext("Property names must contain a `/'.\n"));
14570 14583                  goto fail;
14571 14584          }
14572 14585  
14573 14586          *propname = '\0';
14574 14587          ++propname;
14575 14588  
14576 14589          if (type != NULL) {
14577 14590                  ty = string_to_type(type);
14578 14591                  if (ty == SCF_TYPE_INVALID) {
14579 14592                          semerr(gettext("Unknown type \"%s\".\n"), type);
14580 14593                          goto fail;
14581 14594                  }
14582 14595          }
14583 14596  
14584 14597          if (cur_inst != NULL)
14585 14598                  ret = scf_instance_get_pg(cur_inst, pgname, pg);
14586 14599          else
14587 14600                  ret = scf_service_get_pg(cur_svc, pgname, pg);
14588 14601          if (ret != 0) {
14589 14602                  switch (scf_error()) {
14590 14603                  case SCF_ERROR_NOT_FOUND:
14591 14604                          if (isnotfoundok) {
14592 14605                                  result = 0;
14593 14606                          } else {
14594 14607                                  semerr(emsg_no_such_pg, pgname);
14595 14608                                  result = -1;
14596 14609                          }
14597 14610                          goto out;
14598 14611  
14599 14612                  case SCF_ERROR_INVALID_ARGUMENT:
14600 14613                          semerr(emsg_invalid_pg_name, pgname);
14601 14614                          goto fail;
14602 14615  
14603 14616                  default:
14604 14617                          scfdie();
14605 14618                  }
14606 14619          }
14607 14620  
14608 14621          do {
14609 14622                  if (scf_pg_update(pg) == -1)
14610 14623                          scfdie();
14611 14624                  if (scf_transaction_start(tx, pg) != 0) {
14612 14625                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14613 14626                                  scfdie();
14614 14627  
14615 14628                          semerr(emsg_permission_denied);
14616 14629                          goto fail;
14617 14630                  }
14618 14631  
14619 14632                  ret = scf_pg_get_property(pg, propname, prop);
14620 14633                  if (ret == 0) {
14621 14634                          scf_type_t ptype;
14622 14635                          char *pat = pattern;
14623 14636  
14624 14637                          if (scf_property_type(prop, &ptype) != 0)
14625 14638                                  scfdie();
14626 14639  
14627 14640                          if (isadd) {
14628 14641                                  if (type != NULL && ptype != ty) {
14629 14642                                          semerr(gettext("Property \"%s\" is not "
14630 14643                                              "of type \"%s\".\n"), propname,
14631 14644                                              type);
14632 14645                                          goto fail;
14633 14646                                  }
14634 14647  
14635 14648                                  pat = NULL;
14636 14649                          } else {
14637 14650                                  size_t len = strlen(pat);
14638 14651                                  if (len > 0 && pat[len - 1] == '\"')
14639 14652                                          pat[len - 1] = '\0';
14640 14653                                  if (len > 0 && pat[0] == '\"')
14641 14654                                          pat++;
14642 14655                          }
14643 14656  
14644 14657                          ty = ptype;
14645 14658  
14646 14659                          get_prop_values(prop, values, pat);
14647 14660  
14648 14661                          if (isadd)
14649 14662                                  add_string(values, arg);
14650 14663  
14651 14664                          if (scf_transaction_property_change(tx, e,
14652 14665                              propname, ty) == -1)
14653 14666                                  scfdie();
14654 14667                  } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14655 14668                          if (isadd) {
14656 14669                                  if (type == NULL) {
14657 14670                                          semerr(gettext("Type required "
14658 14671                                              "for new properties.\n"));
14659 14672                                          goto fail;
14660 14673                                  }
14661 14674  
14662 14675                                  add_string(values, arg);
14663 14676  
14664 14677                                  if (scf_transaction_property_new(tx, e,
14665 14678                                      propname, ty) == -1)
14666 14679                                          scfdie();
14667 14680                          } else if (isnotfoundok) {
14668 14681                                  result = 0;
14669 14682                                  goto out;
14670 14683                          } else {
14671 14684                                  semerr(gettext("No such property %s/%s.\n"),
14672 14685                                      pgname, propname);
14673 14686                                  result = -1;
14674 14687                                  goto out;
14675 14688                          }
14676 14689                  } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14677 14690                          semerr(emsg_invalid_prop_name, propname);
14678 14691                          goto fail;
14679 14692                  } else {
14680 14693                          scfdie();
14681 14694                  }
14682 14695  
14683 14696                  walk = uu_list_walk_start(values, UU_DEFAULT);
14684 14697                  if (walk == NULL)
14685 14698                          uu_die(gettext("Could not walk property list.\n"));
14686 14699  
14687 14700                  for (sp = uu_list_walk_next(walk); sp != NULL;
14688 14701                      sp = uu_list_walk_next(walk)) {
14689 14702                          v = string_to_value(sp->str, ty, 0);
14690 14703  
14691 14704                          if (v == NULL) {
14692 14705                                  scf_entry_destroy_children(e);
14693 14706                                  goto fail;
14694 14707                          }
14695 14708                          ret = scf_entry_add_value(e, v);
14696 14709                          assert(ret == 0);
14697 14710                  }
14698 14711                  uu_list_walk_end(walk);
14699 14712  
14700 14713                  result = scf_transaction_commit(tx);
14701 14714  
14702 14715                  scf_transaction_reset(tx);
14703 14716                  scf_entry_destroy_children(e);
14704 14717          } while (result == 0);
14705 14718  
14706 14719          if (result < 0) {
14707 14720                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14708 14721                          scfdie();
14709 14722  
14710 14723                  semerr(emsg_permission_denied);
14711 14724                  goto fail;
14712 14725          }
14713 14726  
14714 14727          result = 0;
14715 14728  
14716 14729          private_refresh();
14717 14730  
14718 14731  out:
14719 14732          scf_transaction_destroy(tx);
14720 14733          scf_entry_destroy(e);
14721 14734          scf_pg_destroy(pg);
14722 14735          scf_property_destroy(prop);
14723 14736          free(pattern);
14724 14737  
14725 14738          while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14726 14739                  free(sp->str);
14727 14740                  free(sp);
14728 14741          }
14729 14742  
14730 14743          uu_list_destroy(values);
14731 14744  
14732 14745          return (result);
14733 14746  
14734 14747  fail:
14735 14748          result = -1;
14736 14749          goto out;
14737 14750  }
14738 14751  
14739 14752  int
14740 14753  lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14741 14754  {
14742 14755          return (lscf_setpropvalue(pgname, type, value, 1, 0));
14743 14756  }
14744 14757  
14745 14758  int
14746 14759  lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14747 14760  {
14748 14761          return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14749 14762  }
14750 14763  
14751 14764  /*
14752 14765   * Look for a standard start method, first in the instance (if any),
14753 14766   * then the service.
14754 14767   */
14755 14768  static const char *
14756 14769  start_method_name(int *in_instance)
14757 14770  {
14758 14771          scf_propertygroup_t *pg;
14759 14772          char **p;
14760 14773          int ret;
14761 14774          scf_instance_t *inst = cur_inst;
14762 14775  
14763 14776          if ((pg = scf_pg_create(g_hndl)) == NULL)
14764 14777                  scfdie();
14765 14778  
14766 14779  again:
14767 14780          for (p = start_method_names; *p != NULL; p++) {
14768 14781                  if (inst != NULL)
14769 14782                          ret = scf_instance_get_pg(inst, *p, pg);
14770 14783                  else
14771 14784                          ret = scf_service_get_pg(cur_svc, *p, pg);
14772 14785  
14773 14786                  if (ret == 0) {
14774 14787                          size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14775 14788                          char *buf = safe_malloc(bufsz);
14776 14789  
14777 14790                          if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14778 14791                                  free(buf);
14779 14792                                  continue;
14780 14793                          }
14781 14794                          if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14782 14795                                  free(buf);
14783 14796                                  continue;
14784 14797                          }
14785 14798  
14786 14799                          free(buf);
14787 14800                          *in_instance = (inst != NULL);
14788 14801                          scf_pg_destroy(pg);
14789 14802                          return (*p);
14790 14803                  }
14791 14804  
14792 14805                  if (scf_error() == SCF_ERROR_NOT_FOUND)
14793 14806                          continue;
14794 14807  
14795 14808                  scfdie();
14796 14809          }
14797 14810  
14798 14811          if (inst != NULL) {
14799 14812                  inst = NULL;
14800 14813                  goto again;
14801 14814          }
14802 14815  
14803 14816          scf_pg_destroy(pg);
14804 14817          return (NULL);
14805 14818  }
14806 14819  
14807 14820  static int
14808 14821  addpg(const char *name, const char *type)
14809 14822  {
14810 14823          scf_propertygroup_t *pg;
14811 14824          int ret;
14812 14825  
14813 14826          pg = scf_pg_create(g_hndl);
14814 14827          if (pg == NULL)
14815 14828                  scfdie();
14816 14829  
14817 14830          if (cur_inst != NULL)
14818 14831                  ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14819 14832          else
14820 14833                  ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14821 14834  
14822 14835          if (ret != 0) {
14823 14836                  switch (scf_error()) {
14824 14837                  case SCF_ERROR_EXISTS:
14825 14838                          ret = 0;
14826 14839                          break;
14827 14840  
14828 14841                  case SCF_ERROR_PERMISSION_DENIED:
14829 14842                          semerr(emsg_permission_denied);
14830 14843                          break;
14831 14844  
14832 14845                  default:
14833 14846                          scfdie();
14834 14847                  }
14835 14848          }
14836 14849  
14837 14850          scf_pg_destroy(pg);
14838 14851          return (ret);
14839 14852  }
14840 14853  
14841 14854  int
14842 14855  lscf_setenv(uu_list_t *args, int isunset)
14843 14856  {
14844 14857          int ret = 0;
14845 14858          size_t i;
14846 14859          int argc;
14847 14860          char **argv = NULL;
14848 14861          string_list_t *slp;
14849 14862          char *pattern;
14850 14863          char *prop;
14851 14864          int do_service = 0;
14852 14865          int do_instance = 0;
14853 14866          const char *method = NULL;
14854 14867          const char *name = NULL;
14855 14868          const char *value = NULL;
14856 14869          scf_instance_t *saved_cur_inst = cur_inst;
14857 14870  
14858 14871          lscf_prep_hndl();
14859 14872  
14860 14873          argc = uu_list_numnodes(args);
14861 14874          if (argc < 1)
14862 14875                  goto usage;
14863 14876  
14864 14877          argv = calloc(argc + 1, sizeof (char *));
14865 14878          if (argv == NULL)
14866 14879                  uu_die(gettext("Out of memory.\n"));
14867 14880  
14868 14881          for (slp = uu_list_first(args), i = 0;
14869 14882              slp != NULL;
14870 14883              slp = uu_list_next(args, slp), ++i)
14871 14884                  argv[i] = slp->str;
14872 14885  
14873 14886          argv[i] = NULL;
14874 14887  
14875 14888          opterr = 0;
14876 14889          optind = 0;
14877 14890          for (;;) {
14878 14891                  ret = getopt(argc, argv, "sim:");
14879 14892                  if (ret == -1)
14880 14893                          break;
14881 14894  
14882 14895                  switch (ret) {
14883 14896                  case 's':
14884 14897                          do_service = 1;
14885 14898                          cur_inst = NULL;
14886 14899                          break;
14887 14900  
14888 14901                  case 'i':
14889 14902                          do_instance = 1;
14890 14903                          break;
14891 14904  
14892 14905                  case 'm':
14893 14906                          method = optarg;
14894 14907                          break;
14895 14908  
14896 14909                  case '?':
14897 14910                          goto usage;
14898 14911  
14899 14912                  default:
14900 14913                          bad_error("getopt", ret);
14901 14914                  }
14902 14915          }
14903 14916  
14904 14917          argc -= optind;
14905 14918          if ((do_service && do_instance) ||
14906 14919              (isunset && argc != 1) ||
14907 14920              (!isunset && argc != 2))
14908 14921                  goto usage;
14909 14922  
14910 14923          name = argv[optind];
14911 14924          if (!isunset)
14912 14925                  value = argv[optind + 1];
14913 14926  
14914 14927          if (cur_snap != NULL) {
14915 14928                  semerr(emsg_cant_modify_snapshots);
14916 14929                  ret = -1;
14917 14930                  goto out;
14918 14931          }
14919 14932  
14920 14933          if (cur_inst == NULL && cur_svc == NULL) {
14921 14934                  semerr(emsg_entity_not_selected);
14922 14935                  ret = -1;
14923 14936                  goto out;
14924 14937          }
14925 14938  
14926 14939          if (do_instance && cur_inst == NULL) {
14927 14940                  semerr(gettext("No instance is selected.\n"));
14928 14941                  ret = -1;
14929 14942                  goto out;
14930 14943          }
14931 14944  
14932 14945          if (do_service && cur_svc == NULL) {
14933 14946                  semerr(gettext("No service is selected.\n"));
14934 14947                  ret = -1;
14935 14948                  goto out;
14936 14949          }
14937 14950  
14938 14951          if (method == NULL) {
14939 14952                  if (do_instance || do_service) {
14940 14953                          method = "method_context";
14941 14954                          if (!isunset) {
14942 14955                                  ret = addpg("method_context",
14943 14956                                      SCF_GROUP_FRAMEWORK);
14944 14957                                  if (ret != 0)
14945 14958                                          goto out;
14946 14959                          }
14947 14960                  } else {
14948 14961                          int in_instance;
14949 14962                          method = start_method_name(&in_instance);
14950 14963                          if (method == NULL) {
14951 14964                                  semerr(gettext(
14952 14965                                      "Couldn't find start method; please "
14953 14966                                      "specify a method with '-m'.\n"));
14954 14967                                  ret = -1;
14955 14968                                  goto out;
14956 14969                          }
14957 14970                          if (!in_instance)
14958 14971                                  cur_inst = NULL;
14959 14972                  }
14960 14973          } else {
14961 14974                  scf_propertygroup_t *pg;
14962 14975                  size_t bufsz;
14963 14976                  char *buf;
14964 14977                  int ret;
14965 14978  
14966 14979                  if ((pg = scf_pg_create(g_hndl)) == NULL)
14967 14980                          scfdie();
14968 14981  
14969 14982                  if (cur_inst != NULL)
14970 14983                          ret = scf_instance_get_pg(cur_inst, method, pg);
14971 14984                  else
14972 14985                          ret = scf_service_get_pg(cur_svc, method, pg);
14973 14986  
14974 14987                  if (ret != 0) {
14975 14988                          scf_pg_destroy(pg);
14976 14989                          switch (scf_error()) {
14977 14990                          case SCF_ERROR_NOT_FOUND:
14978 14991                                  semerr(gettext("Couldn't find the method "
14979 14992                                      "\"%s\".\n"), method);
14980 14993                                  goto out;
14981 14994  
14982 14995                          case SCF_ERROR_INVALID_ARGUMENT:
14983 14996                                  semerr(gettext("Invalid method name \"%s\".\n"),
14984 14997                                      method);
14985 14998                                  goto out;
14986 14999  
14987 15000                          default:
14988 15001                                  scfdie();
14989 15002                          }
14990 15003                  }
14991 15004  
14992 15005                  bufsz = strlen(SCF_GROUP_METHOD) + 1;
14993 15006                  buf = safe_malloc(bufsz);
14994 15007  
14995 15008                  if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14996 15009                      strcmp(buf, SCF_GROUP_METHOD) != 0) {
14997 15010                          semerr(gettext("Property group \"%s\" is not of type "
14998 15011                              "\"method\".\n"), method);
14999 15012                          ret = -1;
15000 15013                          free(buf);
15001 15014                          scf_pg_destroy(pg);
15002 15015                          goto out;
15003 15016                  }
15004 15017  
15005 15018                  free(buf);
15006 15019                  scf_pg_destroy(pg);
15007 15020          }
15008 15021  
15009 15022          prop = uu_msprintf("%s/environment", method);
15010 15023          pattern = uu_msprintf("%s=*", name);
15011 15024  
15012 15025          if (prop == NULL || pattern == NULL)
15013 15026                  uu_die(gettext("Out of memory.\n"));
15014 15027  
15015 15028          ret = lscf_delpropvalue(prop, pattern, !isunset);
15016 15029  
15017 15030          if (ret == 0 && !isunset) {
15018 15031                  uu_free(pattern);
15019 15032                  uu_free(prop);
15020 15033                  prop = uu_msprintf("%s/environment", method);
15021 15034                  pattern = uu_msprintf("%s=%s", name, value);
15022 15035                  if (prop == NULL || pattern == NULL)
15023 15036                          uu_die(gettext("Out of memory.\n"));
15024 15037                  ret = lscf_addpropvalue(prop, "astring:", pattern);
15025 15038          }
15026 15039          uu_free(pattern);
15027 15040          uu_free(prop);
15028 15041  
15029 15042  out:
15030 15043          cur_inst = saved_cur_inst;
15031 15044  
15032 15045          free(argv);
15033 15046          return (ret);
15034 15047  usage:
15035 15048          ret = -2;
15036 15049          goto out;
15037 15050  }
15038 15051  
15039 15052  /*
15040 15053   * Snapshot commands
15041 15054   */
15042 15055  
15043 15056  void
15044 15057  lscf_listsnap()
15045 15058  {
15046 15059          scf_snapshot_t *snap;
15047 15060          scf_iter_t *iter;
15048 15061          char *nb;
15049 15062          int r;
15050 15063  
15051 15064          lscf_prep_hndl();
15052 15065  
15053 15066          if (cur_inst == NULL) {
15054 15067                  semerr(gettext("Instance not selected.\n"));
15055 15068                  return;
15056 15069          }
15057 15070  
15058 15071          if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15059 15072              (iter = scf_iter_create(g_hndl)) == NULL)
15060 15073                  scfdie();
15061 15074  
15062 15075          if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15063 15076                  scfdie();
15064 15077  
15065 15078          nb = safe_malloc(max_scf_name_len + 1);
15066 15079  
15067 15080          while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15068 15081                  if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15069 15082                          scfdie();
15070 15083  
15071 15084                  (void) puts(nb);
15072 15085          }
15073 15086          if (r < 0)
15074 15087                  scfdie();
15075 15088  
15076 15089          free(nb);
15077 15090          scf_iter_destroy(iter);
15078 15091          scf_snapshot_destroy(snap);
15079 15092  }
15080 15093  
15081 15094  void
15082 15095  lscf_selectsnap(const char *name)
15083 15096  {
15084 15097          scf_snapshot_t *snap;
15085 15098          scf_snaplevel_t *level;
15086 15099  
15087 15100          lscf_prep_hndl();
15088 15101  
15089 15102          if (cur_inst == NULL) {
15090 15103                  semerr(gettext("Instance not selected.\n"));
15091 15104                  return;
15092 15105          }
15093 15106  
15094 15107          if (cur_snap != NULL) {
15095 15108                  if (name != NULL) {
15096 15109                          char *cur_snap_name;
15097 15110                          boolean_t nochange;
15098 15111  
15099 15112                          cur_snap_name = safe_malloc(max_scf_name_len + 1);
15100 15113  
15101 15114                          if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15102 15115                              max_scf_name_len + 1) < 0)
15103 15116                                  scfdie();
15104 15117  
15105 15118                          nochange = strcmp(name, cur_snap_name) == 0;
15106 15119  
15107 15120                          free(cur_snap_name);
15108 15121  
15109 15122                          if (nochange)
15110 15123                                  return;
15111 15124                  }
15112 15125  
15113 15126                  unselect_cursnap();
15114 15127          }
15115 15128  
15116 15129          if (name == NULL)
15117 15130                  return;
15118 15131  
15119 15132          if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15120 15133              (level = scf_snaplevel_create(g_hndl)) == NULL)
15121 15134                  scfdie();
15122 15135  
15123 15136          if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15124 15137              SCF_SUCCESS) {
15125 15138                  switch (scf_error()) {
15126 15139                  case SCF_ERROR_INVALID_ARGUMENT:
15127 15140                          semerr(gettext("Invalid name \"%s\".\n"), name);
15128 15141                          break;
15129 15142  
15130 15143                  case SCF_ERROR_NOT_FOUND:
15131 15144                          semerr(gettext("No such snapshot \"%s\".\n"), name);
15132 15145                          break;
15133 15146  
15134 15147                  default:
15135 15148                          scfdie();
15136 15149                  }
15137 15150  
15138 15151                  scf_snaplevel_destroy(level);
15139 15152                  scf_snapshot_destroy(snap);
15140 15153                  return;
15141 15154          }
15142 15155  
15143 15156          /* Load the snaplevels into our list. */
15144 15157          cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15145 15158          if (cur_levels == NULL)
15146 15159                  uu_die(gettext("Could not create list: %s\n"),
15147 15160                      uu_strerror(uu_error()));
15148 15161  
15149 15162          if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15150 15163                  if (scf_error() != SCF_ERROR_NOT_FOUND)
15151 15164                          scfdie();
15152 15165  
15153 15166                  semerr(gettext("Snapshot has no snaplevels.\n"));
15154 15167  
15155 15168                  scf_snaplevel_destroy(level);
15156 15169                  scf_snapshot_destroy(snap);
15157 15170                  return;
15158 15171          }
15159 15172  
15160 15173          cur_snap = snap;
15161 15174  
15162 15175          for (;;) {
15163 15176                  cur_elt = safe_malloc(sizeof (*cur_elt));
15164 15177                  uu_list_node_init(cur_elt, &cur_elt->list_node,
15165 15178                      snaplevel_pool);
15166 15179                  cur_elt->sl = level;
15167 15180                  if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15168 15181                          uu_die(gettext("libuutil error: %s\n"),
15169 15182                              uu_strerror(uu_error()));
15170 15183  
15171 15184                  level = scf_snaplevel_create(g_hndl);
15172 15185                  if (level == NULL)
15173 15186                          scfdie();
15174 15187  
15175 15188                  if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15176 15189                      level) != SCF_SUCCESS) {
15177 15190                          if (scf_error() != SCF_ERROR_NOT_FOUND)
15178 15191                                  scfdie();
15179 15192  
15180 15193                          scf_snaplevel_destroy(level);
15181 15194                          break;
15182 15195                  }
15183 15196          }
15184 15197  
15185 15198          cur_elt = uu_list_last(cur_levels);
15186 15199          cur_level = cur_elt->sl;
15187 15200  }
15188 15201  
15189 15202  /*
15190 15203   * Copies the properties & values in src to dst.  Assumes src won't change.
15191 15204   * Returns -1 if permission is denied, -2 if another transaction interrupts,
15192 15205   * and 0 on success.
15193 15206   *
15194 15207   * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15195 15208   * property, if it is copied and has type boolean.  (See comment in
15196 15209   * lscf_revert()).
15197 15210   */
15198 15211  static int
15199 15212  pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15200 15213      uint8_t enabled)
15201 15214  {
15202 15215          scf_transaction_t *tx;
15203 15216          scf_iter_t *iter, *viter;
15204 15217          scf_property_t *prop;
15205 15218          scf_value_t *v;
15206 15219          char *nbuf;
15207 15220          int r;
15208 15221  
15209 15222          tx = scf_transaction_create(g_hndl);
15210 15223          if (tx == NULL)
15211 15224                  scfdie();
15212 15225  
15213 15226          if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15214 15227                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15215 15228                          scfdie();
15216 15229  
15217 15230                  scf_transaction_destroy(tx);
15218 15231  
15219 15232                  return (-1);
15220 15233          }
15221 15234  
15222 15235          if ((iter = scf_iter_create(g_hndl)) == NULL ||
15223 15236              (prop = scf_property_create(g_hndl)) == NULL ||
15224 15237              (viter = scf_iter_create(g_hndl)) == NULL)
15225 15238                  scfdie();
15226 15239  
15227 15240          nbuf = safe_malloc(max_scf_name_len + 1);
15228 15241  
15229 15242          if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15230 15243                  scfdie();
15231 15244  
15232 15245          for (;;) {
15233 15246                  scf_transaction_entry_t *e;
15234 15247                  scf_type_t ty;
15235 15248  
15236 15249                  r = scf_iter_next_property(iter, prop);
15237 15250                  if (r == -1)
15238 15251                          scfdie();
15239 15252                  if (r == 0)
15240 15253                          break;
15241 15254  
15242 15255                  e = scf_entry_create(g_hndl);
15243 15256                  if (e == NULL)
15244 15257                          scfdie();
15245 15258  
15246 15259                  if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15247 15260                          scfdie();
15248 15261  
15249 15262                  if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15250 15263                          scfdie();
15251 15264  
15252 15265                  if (scf_transaction_property_new(tx, e, nbuf,
15253 15266                      ty) != SCF_SUCCESS)
15254 15267                          scfdie();
15255 15268  
15256 15269                  if ((enabled == 0 || enabled == 1) &&
15257 15270                      strcmp(nbuf, scf_property_enabled) == 0 &&
15258 15271                      ty == SCF_TYPE_BOOLEAN) {
15259 15272                          v = scf_value_create(g_hndl);
15260 15273                          if (v == NULL)
15261 15274                                  scfdie();
15262 15275  
15263 15276                          scf_value_set_boolean(v, enabled);
15264 15277  
15265 15278                          if (scf_entry_add_value(e, v) != 0)
15266 15279                                  scfdie();
15267 15280                  } else {
15268 15281                          if (scf_iter_property_values(viter, prop) != 0)
15269 15282                                  scfdie();
15270 15283  
15271 15284                          for (;;) {
15272 15285                                  v = scf_value_create(g_hndl);
15273 15286                                  if (v == NULL)
15274 15287                                          scfdie();
15275 15288  
15276 15289                                  r = scf_iter_next_value(viter, v);
15277 15290                                  if (r == -1)
15278 15291                                          scfdie();
15279 15292                                  if (r == 0) {
15280 15293                                          scf_value_destroy(v);
15281 15294                                          break;
15282 15295                                  }
15283 15296  
15284 15297                                  if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15285 15298                                          scfdie();
15286 15299                          }
15287 15300                  }
15288 15301          }
15289 15302  
15290 15303          free(nbuf);
15291 15304          scf_iter_destroy(viter);
15292 15305          scf_property_destroy(prop);
15293 15306          scf_iter_destroy(iter);
15294 15307  
15295 15308          r = scf_transaction_commit(tx);
15296 15309          if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15297 15310                  scfdie();
15298 15311  
15299 15312          scf_transaction_destroy_children(tx);
15300 15313          scf_transaction_destroy(tx);
15301 15314  
15302 15315          switch (r) {
15303 15316          case 1:         return (0);
15304 15317          case 0:         return (-2);
15305 15318          case -1:        return (-1);
15306 15319  
15307 15320          default:
15308 15321                  abort();
15309 15322          }
15310 15323  
15311 15324          /* NOTREACHED */
15312 15325  }
15313 15326  
15314 15327  void
15315 15328  lscf_revert(const char *snapname)
15316 15329  {
15317 15330          scf_snapshot_t *snap, *prev;
15318 15331          scf_snaplevel_t *level, *nlevel;
15319 15332          scf_iter_t *iter;
15320 15333          scf_propertygroup_t *pg, *npg;
15321 15334          scf_property_t *prop;
15322 15335          scf_value_t *val;
15323 15336          char *nbuf, *tbuf;
15324 15337          uint8_t enabled;
15325 15338  
15326 15339          lscf_prep_hndl();
15327 15340  
15328 15341          if (cur_inst == NULL) {
15329 15342                  semerr(gettext("Instance not selected.\n"));
15330 15343                  return;
15331 15344          }
15332 15345  
15333 15346          if (snapname != NULL) {
15334 15347                  snap = scf_snapshot_create(g_hndl);
15335 15348                  if (snap == NULL)
15336 15349                          scfdie();
15337 15350  
15338 15351                  if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15339 15352                      SCF_SUCCESS) {
15340 15353                          switch (scf_error()) {
15341 15354                          case SCF_ERROR_INVALID_ARGUMENT:
15342 15355                                  semerr(gettext("Invalid snapshot name "
15343 15356                                      "\"%s\".\n"), snapname);
15344 15357                                  break;
15345 15358  
15346 15359                          case SCF_ERROR_NOT_FOUND:
15347 15360                                  semerr(gettext("No such snapshot.\n"));
15348 15361                                  break;
15349 15362  
15350 15363                          default:
15351 15364                                  scfdie();
15352 15365                          }
15353 15366  
15354 15367                          scf_snapshot_destroy(snap);
15355 15368                          return;
15356 15369                  }
15357 15370          } else {
15358 15371                  if (cur_snap != NULL) {
15359 15372                          snap = cur_snap;
15360 15373                  } else {
15361 15374                          semerr(gettext("No snapshot selected.\n"));
15362 15375                          return;
15363 15376                  }
15364 15377          }
15365 15378  
15366 15379          if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15367 15380              (level = scf_snaplevel_create(g_hndl)) == NULL ||
15368 15381              (iter = scf_iter_create(g_hndl)) == NULL ||
15369 15382              (pg = scf_pg_create(g_hndl)) == NULL ||
15370 15383              (npg = scf_pg_create(g_hndl)) == NULL ||
15371 15384              (prop = scf_property_create(g_hndl)) == NULL ||
15372 15385              (val = scf_value_create(g_hndl)) == NULL)
15373 15386                  scfdie();
15374 15387  
15375 15388          nbuf = safe_malloc(max_scf_name_len + 1);
15376 15389          tbuf = safe_malloc(max_scf_pg_type_len + 1);
15377 15390  
15378 15391          /* Take the "previous" snapshot before we blow away the properties. */
15379 15392          if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15380 15393                  if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15381 15394                          scfdie();
15382 15395          } else {
15383 15396                  if (scf_error() != SCF_ERROR_NOT_FOUND)
15384 15397                          scfdie();
15385 15398  
15386 15399                  if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15387 15400                          scfdie();
15388 15401          }
15389 15402  
15390 15403          /* Save general/enabled, since we're probably going to replace it. */
15391 15404          enabled = 2;
15392 15405          if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15393 15406              scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15394 15407              scf_property_get_value(prop, val) == 0)
15395 15408                  (void) scf_value_get_boolean(val, &enabled);
15396 15409  
15397 15410          if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15398 15411                  if (scf_error() != SCF_ERROR_NOT_FOUND)
15399 15412                          scfdie();
15400 15413  
15401 15414                  goto out;
15402 15415          }
15403 15416  
15404 15417          for (;;) {
15405 15418                  boolean_t isinst;
15406 15419                  uint32_t flags;
15407 15420                  int r;
15408 15421  
15409 15422                  /* Clear the properties from the corresponding entity. */
15410 15423                  isinst = snaplevel_is_instance(level);
15411 15424  
15412 15425                  if (!isinst)
15413 15426                          r = scf_iter_service_pgs(iter, cur_svc);
15414 15427                  else
15415 15428                          r = scf_iter_instance_pgs(iter, cur_inst);
15416 15429                  if (r != SCF_SUCCESS)
15417 15430                          scfdie();
15418 15431  
15419 15432                  while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15420 15433                          if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15421 15434                                  scfdie();
15422 15435  
15423 15436                          /* Skip nonpersistent pgs. */
15424 15437                          if (flags & SCF_PG_FLAG_NONPERSISTENT)
15425 15438                                  continue;
15426 15439  
15427 15440                          if (scf_pg_delete(pg) != SCF_SUCCESS) {
15428 15441                                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15429 15442                                          scfdie();
15430 15443  
15431 15444                                  semerr(emsg_permission_denied);
15432 15445                                  goto out;
15433 15446                          }
15434 15447                  }
15435 15448                  if (r == -1)
15436 15449                          scfdie();
15437 15450  
15438 15451                  /* Copy the properties to the corresponding entity. */
15439 15452                  if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15440 15453                          scfdie();
15441 15454  
15442 15455                  while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15443 15456                          if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15444 15457                                  scfdie();
15445 15458  
15446 15459                          if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15447 15460                              0)
15448 15461                                  scfdie();
15449 15462  
15450 15463                          if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15451 15464                                  scfdie();
15452 15465  
15453 15466                          if (!isinst)
15454 15467                                  r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15455 15468                                      flags, npg);
15456 15469                          else
15457 15470                                  r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15458 15471                                      flags, npg);
15459 15472                          if (r != SCF_SUCCESS) {
15460 15473                                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15461 15474                                          scfdie();
15462 15475  
15463 15476                                  semerr(emsg_permission_denied);
15464 15477                                  goto out;
15465 15478                          }
15466 15479  
15467 15480                          if ((enabled == 0 || enabled == 1) &&
15468 15481                              strcmp(nbuf, scf_pg_general) == 0)
15469 15482                                  r = pg_copy(pg, npg, enabled);
15470 15483                          else
15471 15484                                  r = pg_copy(pg, npg, 2);
15472 15485  
15473 15486                          switch (r) {
15474 15487                          case 0:
15475 15488                                  break;
15476 15489  
15477 15490                          case -1:
15478 15491                                  semerr(emsg_permission_denied);
15479 15492                                  goto out;
15480 15493  
15481 15494                          case -2:
15482 15495                                  semerr(gettext(
15483 15496                                      "Interrupted by another change.\n"));
15484 15497                                  goto out;
15485 15498  
15486 15499                          default:
15487 15500                                  abort();
15488 15501                          }
15489 15502                  }
15490 15503                  if (r == -1)
15491 15504                          scfdie();
15492 15505  
15493 15506                  /* Get next level. */
15494 15507                  nlevel = scf_snaplevel_create(g_hndl);
15495 15508                  if (nlevel == NULL)
15496 15509                          scfdie();
15497 15510  
15498 15511                  if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15499 15512                      SCF_SUCCESS) {
15500 15513                          if (scf_error() != SCF_ERROR_NOT_FOUND)
15501 15514                                  scfdie();
15502 15515  
15503 15516                          scf_snaplevel_destroy(nlevel);
15504 15517                          break;
15505 15518                  }
15506 15519  
15507 15520                  scf_snaplevel_destroy(level);
15508 15521                  level = nlevel;
15509 15522          }
15510 15523  
15511 15524          if (snapname == NULL) {
15512 15525                  lscf_selectsnap(NULL);
15513 15526                  snap = NULL;            /* cur_snap has been destroyed */
15514 15527          }
15515 15528  
15516 15529  out:
15517 15530          free(tbuf);
15518 15531          free(nbuf);
15519 15532          scf_value_destroy(val);
15520 15533          scf_property_destroy(prop);
15521 15534          scf_pg_destroy(npg);
15522 15535          scf_pg_destroy(pg);
15523 15536          scf_iter_destroy(iter);
15524 15537          scf_snaplevel_destroy(level);
15525 15538          scf_snapshot_destroy(prev);
15526 15539          if (snap != cur_snap)
15527 15540                  scf_snapshot_destroy(snap);
15528 15541  }
15529 15542  
15530 15543  void
15531 15544  lscf_refresh(void)
15532 15545  {
15533 15546          ssize_t fmrilen;
15534 15547          size_t bufsz;
15535 15548          char *fmribuf;
15536 15549          int r;
15537 15550  
15538 15551          lscf_prep_hndl();
15539 15552  
15540 15553          if (cur_inst == NULL) {
15541 15554                  semerr(gettext("Instance not selected.\n"));
15542 15555                  return;
15543 15556          }
15544 15557  
15545 15558          bufsz = max_scf_fmri_len + 1;
15546 15559          fmribuf = safe_malloc(bufsz);
15547 15560          fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15548 15561          if (fmrilen < 0) {
15549 15562                  free(fmribuf);
15550 15563                  if (scf_error() != SCF_ERROR_DELETED)
15551 15564                          scfdie();
15552 15565                  scf_instance_destroy(cur_inst);
15553 15566                  cur_inst = NULL;
15554 15567                  warn(emsg_deleted);
15555 15568                  return;
15556 15569          }
15557 15570          assert(fmrilen < bufsz);
15558 15571  
15559 15572          r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15560 15573          switch (r) {
15561 15574          case 0:
15562 15575                  break;
15563 15576  
15564 15577          case ECONNABORTED:
15565 15578                  warn(gettext("Could not refresh %s "
15566 15579                      "(repository connection broken).\n"), fmribuf);
15567 15580                  break;
15568 15581  
15569 15582          case ECANCELED:
15570 15583                  warn(emsg_deleted);
15571 15584                  break;
15572 15585  
15573 15586          case EPERM:
15574 15587                  warn(gettext("Could not refresh %s "
15575 15588                      "(permission denied).\n"), fmribuf);
15576 15589                  break;
15577 15590  
15578 15591          case ENOSPC:
15579 15592                  warn(gettext("Could not refresh %s "
15580 15593                      "(repository server out of resources).\n"),
15581 15594                      fmribuf);
15582 15595                  break;
15583 15596  
15584 15597          case EACCES:
15585 15598          default:
15586 15599                  bad_error("refresh_entity", scf_error());
15587 15600          }
15588 15601  
15589 15602          free(fmribuf);
15590 15603  }
15591 15604  
15592 15605  /*
15593 15606   * describe [-v] [-t] [pg/prop]
15594 15607   */
15595 15608  int
15596 15609  lscf_describe(uu_list_t *args, int hasargs)
15597 15610  {
15598 15611          int ret = 0;
15599 15612          size_t i;
15600 15613          int argc;
15601 15614          char **argv = NULL;
15602 15615          string_list_t *slp;
15603 15616          int do_verbose = 0;
15604 15617          int do_templates = 0;
15605 15618          char *pattern = NULL;
15606 15619  
15607 15620          lscf_prep_hndl();
15608 15621  
15609 15622          if (hasargs != 0)  {
15610 15623                  argc = uu_list_numnodes(args);
15611 15624                  if (argc < 1)
15612 15625                          goto usage;
15613 15626  
15614 15627                  argv = calloc(argc + 1, sizeof (char *));
15615 15628                  if (argv == NULL)
15616 15629                          uu_die(gettext("Out of memory.\n"));
15617 15630  
15618 15631                  for (slp = uu_list_first(args), i = 0;
15619 15632                      slp != NULL;
15620 15633                      slp = uu_list_next(args, slp), ++i)
15621 15634                          argv[i] = slp->str;
15622 15635  
15623 15636                  argv[i] = NULL;
15624 15637  
15625 15638                  /*
15626 15639                   * We start optind = 0 because our list of arguments
15627 15640                   * starts at argv[0]
15628 15641                   */
15629 15642                  optind = 0;
15630 15643                  opterr = 0;
15631 15644                  for (;;) {
15632 15645                          ret = getopt(argc, argv, "vt");
15633 15646                          if (ret == -1)
15634 15647                                  break;
15635 15648  
15636 15649                          switch (ret) {
15637 15650                          case 'v':
15638 15651                                  do_verbose = 1;
15639 15652                                  break;
15640 15653  
15641 15654                          case 't':
15642 15655                                  do_templates = 1;
15643 15656                                  break;
15644 15657  
15645 15658                          case '?':
15646 15659                                  goto usage;
15647 15660  
15648 15661                          default:
15649 15662                                  bad_error("getopt", ret);
15650 15663                          }
15651 15664                  }
15652 15665  
15653 15666                  pattern = argv[optind];
15654 15667          }
15655 15668  
15656 15669          if (cur_inst == NULL && cur_svc == NULL) {
15657 15670                  semerr(emsg_entity_not_selected);
15658 15671                  ret = -1;
15659 15672                  goto out;
15660 15673          }
15661 15674  
15662 15675          /*
15663 15676           * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15664 15677           * output if their last parameter is set to 2.  Less information is
15665 15678           * produced if the parameter is set to 1.
15666 15679           */
15667 15680          if (pattern == NULL) {
15668 15681                  if (do_verbose == 1)
15669 15682                          list_entity_tmpl(2);
15670 15683                  else
15671 15684                          list_entity_tmpl(1);
15672 15685          }
15673 15686  
15674 15687          if (do_templates == 0) {
15675 15688                  if (do_verbose == 1)
15676 15689                          listprop(pattern, 0, 2);
15677 15690                  else
15678 15691                          listprop(pattern, 0, 1);
15679 15692          } else {
15680 15693                  if (do_verbose == 1)
15681 15694                          listtmpl(pattern, 2);
15682 15695                  else
15683 15696                          listtmpl(pattern, 1);
15684 15697          }
15685 15698  
15686 15699          ret = 0;
15687 15700  out:
15688 15701          if (argv != NULL)
15689 15702                  free(argv);
15690 15703          return (ret);
15691 15704  usage:
15692 15705          ret = -2;
15693 15706          goto out;
15694 15707  }
15695 15708  
15696 15709  #define PARAM_ACTIVE    ((const char *) "active")
15697 15710  #define PARAM_INACTIVE  ((const char *) "inactive")
15698 15711  #define PARAM_SMTP_TO   ((const char *) "to")
15699 15712  
15700 15713  /*
15701 15714   * tokenize()
15702 15715   * Breaks down the string according to the tokens passed.
15703 15716   * Caller is responsible for freeing array of pointers returned.
15704 15717   * Returns NULL on failure
15705 15718   */
15706 15719  char **
15707 15720  tokenize(char *str, const char *sep)
15708 15721  {
15709 15722          char *token, *lasts;
15710 15723          char **buf;
15711 15724          int n = 0;      /* number of elements */
15712 15725          int size = 8;   /* size of the array (initial) */
15713 15726  
15714 15727          buf = safe_malloc(size * sizeof (char *));
15715 15728  
15716 15729          for (token = strtok_r(str, sep, &lasts); token != NULL;
15717 15730              token = strtok_r(NULL, sep, &lasts), ++n) {
15718 15731                  if (n + 1 >= size) {
15719 15732                          size *= 2;
15720 15733                          if ((buf = realloc(buf, size * sizeof (char *))) ==
15721 15734                              NULL) {
15722 15735                                  uu_die(gettext("Out of memory"));
15723 15736                          }
15724 15737                  }
15725 15738                  buf[n] = token;
15726 15739          }
15727 15740          /* NULL terminate the pointer array */
15728 15741          buf[n] = NULL;
15729 15742  
15730 15743          return (buf);
15731 15744  }
15732 15745  
15733 15746  int32_t
15734 15747  check_tokens(char **p)
15735 15748  {
15736 15749          int32_t smf = 0;
15737 15750          int32_t fma = 0;
15738 15751  
15739 15752          while (*p) {
15740 15753                  int32_t t = string_to_tset(*p);
15741 15754  
15742 15755                  if (t == 0) {
15743 15756                          if (is_fma_token(*p) == 0)
15744 15757                                  return (INVALID_TOKENS);
15745 15758                          fma = 1; /* this token is an fma event */
15746 15759                  } else {
15747 15760                          smf |= t;
15748 15761                  }
15749 15762  
15750 15763                  if (smf != 0 && fma == 1)
15751 15764                          return (MIXED_TOKENS);
15752 15765                  ++p;
15753 15766          }
15754 15767  
15755 15768          if (smf > 0)
15756 15769                  return (smf);
15757 15770          else if (fma == 1)
15758 15771                  return (FMA_TOKENS);
15759 15772  
15760 15773          return (INVALID_TOKENS);
15761 15774  }
15762 15775  
15763 15776  static int
15764 15777  get_selection_str(char *fmri, size_t sz)
15765 15778  {
15766 15779          if (g_hndl == NULL) {
15767 15780                  semerr(emsg_entity_not_selected);
15768 15781                  return (-1);
15769 15782          } else if (cur_level != NULL) {
15770 15783                  semerr(emsg_invalid_for_snapshot);
15771 15784                  return (-1);
15772 15785          } else {
15773 15786                  lscf_get_selection_str(fmri, sz);
15774 15787          }
15775 15788  
15776 15789          return (0);
15777 15790  }
15778 15791  
15779 15792  void
15780 15793  lscf_delnotify(const char *set, int global)
15781 15794  {
15782 15795          char *str = strdup(set);
15783 15796          char **pgs;
15784 15797          char **p;
15785 15798          int32_t tset;
15786 15799          char *fmri = NULL;
15787 15800  
15788 15801          if (str == NULL)
15789 15802                  uu_die(gettext("Out of memory.\n"));
15790 15803  
15791 15804          pgs = tokenize(str, ",");
15792 15805  
15793 15806          if ((tset = check_tokens(pgs)) > 0) {
15794 15807                  size_t sz = max_scf_fmri_len + 1;
15795 15808  
15796 15809                  fmri = safe_malloc(sz);
15797 15810                  if (global) {
15798 15811                          (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15799 15812                  } else if (get_selection_str(fmri, sz) != 0) {
15800 15813                          goto out;
15801 15814                  }
15802 15815  
15803 15816                  if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15804 15817                      tset) != SCF_SUCCESS) {
15805 15818                          uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15806 15819                              scf_strerror(scf_error()));
15807 15820                  }
15808 15821          } else if (tset == FMA_TOKENS) {
15809 15822                  if (global) {
15810 15823                          semerr(gettext("Can't use option '-g' with FMA event "
15811 15824                              "definitions\n"));
15812 15825                          goto out;
15813 15826                  }
15814 15827  
15815 15828                  for (p = pgs; *p; ++p) {
15816 15829                          if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15817 15830                              SCF_SUCCESS) {
15818 15831                                  uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15819 15832                                      scf_strerror(scf_error()));
15820 15833                                  goto out;
15821 15834                          }
15822 15835                  }
15823 15836          } else if (tset == MIXED_TOKENS) {
15824 15837                  semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15825 15838                  goto out;
15826 15839          } else {
15827 15840                  uu_die(gettext("Invalid input.\n"));
15828 15841          }
15829 15842  
15830 15843  out:
15831 15844          free(fmri);
15832 15845          free(pgs);
15833 15846          free(str);
15834 15847  }
15835 15848  
15836 15849  void
15837 15850  lscf_listnotify(const char *set, int global)
15838 15851  {
15839 15852          char *str = safe_strdup(set);
15840 15853          char **pgs;
15841 15854          char **p;
15842 15855          int32_t tset;
15843 15856          nvlist_t *nvl;
15844 15857          char *fmri = NULL;
15845 15858  
15846 15859          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15847 15860                  uu_die(gettext("Out of memory.\n"));
15848 15861  
15849 15862          pgs = tokenize(str, ",");
15850 15863  
15851 15864          if ((tset = check_tokens(pgs)) > 0) {
15852 15865                  size_t sz = max_scf_fmri_len + 1;
15853 15866  
15854 15867                  fmri = safe_malloc(sz);
15855 15868                  if (global) {
15856 15869                          (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15857 15870                  } else if (get_selection_str(fmri, sz) != 0) {
15858 15871                          goto out;
15859 15872                  }
15860 15873  
15861 15874                  if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15862 15875                      SCF_SUCCESS) {
15863 15876                          if (scf_error() != SCF_ERROR_NOT_FOUND &&
15864 15877                              scf_error() != SCF_ERROR_DELETED)
15865 15878                                  uu_warn(gettext(
15866 15879                                      "Failed listnotify: %s\n"),
15867 15880                                      scf_strerror(scf_error()));
15868 15881                          goto out;
15869 15882                  }
15870 15883  
15871 15884                  listnotify_print(nvl, NULL);
15872 15885          } else if (tset == FMA_TOKENS) {
15873 15886                  if (global) {
15874 15887                          semerr(gettext("Can't use option '-g' with FMA event "
15875 15888                              "definitions\n"));
15876 15889                          goto out;
15877 15890                  }
15878 15891  
15879 15892                  for (p = pgs; *p; ++p) {
15880 15893                          if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15881 15894                              SCF_SUCCESS) {
15882 15895                                  /*
15883 15896                                   * if the preferences have just been deleted
15884 15897                                   * or does not exist, just skip.
15885 15898                                   */
15886 15899                                  if (scf_error() == SCF_ERROR_NOT_FOUND ||
15887 15900                                      scf_error() == SCF_ERROR_DELETED)
15888 15901                                          continue;
15889 15902                                  uu_warn(gettext(
15890 15903                                      "Failed listnotify: %s\n"),
15891 15904                                      scf_strerror(scf_error()));
15892 15905                                  goto out;
15893 15906                          }
15894 15907                          listnotify_print(nvl, re_tag(*p));
15895 15908                  }
15896 15909          } else if (tset == MIXED_TOKENS) {
15897 15910                  semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15898 15911                  goto out;
15899 15912          } else {
15900 15913                  semerr(gettext("Invalid input.\n"));
15901 15914          }
15902 15915  
15903 15916  out:
15904 15917          nvlist_free(nvl);
15905 15918          free(fmri);
15906 15919          free(pgs);
15907 15920          free(str);
15908 15921  }
15909 15922  
15910 15923  static char *
15911 15924  strip_quotes_and_blanks(char *s)
15912 15925  {
15913 15926          char *start = s;
15914 15927          char *end = strrchr(s, '\"');
15915 15928  
15916 15929          if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15917 15930                  start = s + 1;
15918 15931                  while (isblank(*start))
15919 15932                          start++;
15920 15933                  while (isblank(*(end - 1)) && end > start) {
15921 15934                          end--;
15922 15935                  }
15923 15936                  *end = '\0';
15924 15937          }
15925 15938  
15926 15939          return (start);
15927 15940  }
15928 15941  
15929 15942  static int
15930 15943  set_active(nvlist_t *mech, const char *hier_part)
15931 15944  {
15932 15945          boolean_t b;
15933 15946  
15934 15947          if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15935 15948                  b = B_TRUE;
15936 15949          } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15937 15950                  b = B_FALSE;
15938 15951          } else {
15939 15952                  return (-1);
15940 15953          }
15941 15954  
15942 15955          if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15943 15956                  uu_die(gettext("Out of memory.\n"));
15944 15957  
15945 15958          return (0);
15946 15959  }
15947 15960  
15948 15961  static int
15949 15962  add_snmp_params(nvlist_t *mech, char *hier_part)
15950 15963  {
15951 15964          return (set_active(mech, hier_part));
15952 15965  }
15953 15966  
15954 15967  static int
15955 15968  add_syslog_params(nvlist_t *mech, char *hier_part)
15956 15969  {
15957 15970          return (set_active(mech, hier_part));
15958 15971  }
15959 15972  
15960 15973  /*
15961 15974   * add_mailto_paramas()
15962 15975   * parse the hier_part of mailto URI
15963 15976   * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15964 15977   * or mailto:{[active]|inactive}
15965 15978   */
15966 15979  static int
15967 15980  add_mailto_params(nvlist_t *mech, char *hier_part)
15968 15981  {
15969 15982          const char *tok = "?&";
15970 15983          char *p;
15971 15984          char *lasts;
15972 15985          char *param;
15973 15986          char *val;
15974 15987  
15975 15988          /*
15976 15989           * If the notification parametes are in the form of
15977 15990           *
15978 15991           *   malito:{[active]|inactive}
15979 15992           *
15980 15993           * we set the property accordingly and return.
15981 15994           * Otherwise, we make the notification type active and
15982 15995           * process the hier_part.
15983 15996           */
15984 15997          if (set_active(mech, hier_part) == 0)
15985 15998                  return (0);
15986 15999          else if (set_active(mech, PARAM_ACTIVE) != 0)
15987 16000                  return (-1);
15988 16001  
15989 16002          if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15990 16003                  /*
15991 16004                   * sanity check: we only get here if hier_part = "", but
15992 16005                   * that's handled by set_active
15993 16006                   */
15994 16007                  uu_die("strtok_r");
15995 16008          }
15996 16009  
15997 16010          if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15998 16011                  uu_die(gettext("Out of memory.\n"));
15999 16012  
16000 16013          while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16001 16014                  if ((param = strtok_r(p, "=", &val)) != NULL)
16002 16015                          if (nvlist_add_string(mech, param, val) != 0)
16003 16016                                  uu_die(gettext("Out of memory.\n"));
16004 16017  
16005 16018          return (0);
16006 16019  }
16007 16020  
16008 16021  static int
16009 16022  uri_split(char *uri, char **scheme, char **hier_part)
16010 16023  {
16011 16024          int r = -1;
16012 16025  
16013 16026          if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16014 16027              *hier_part == NULL) {
16015 16028                  semerr(gettext("'%s' is not an URI\n"), uri);
16016 16029                  return (r);
16017 16030          }
16018 16031  
16019 16032          if ((r = check_uri_scheme(*scheme)) < 0) {
16020 16033                  semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16021 16034                  return (r);
16022 16035          }
16023 16036  
16024 16037          return (r);
16025 16038  }
16026 16039  
16027 16040  static int
16028 16041  process_uri(nvlist_t *params, char *uri)
16029 16042  {
16030 16043          char *scheme;
16031 16044          char *hier_part;
16032 16045          nvlist_t *mech;
16033 16046          int index;
16034 16047          int r;
16035 16048  
16036 16049          if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16037 16050                  return (-1);
16038 16051  
16039 16052          if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16040 16053                  uu_die(gettext("Out of memory.\n"));
16041 16054  
16042 16055          switch (index) {
16043 16056          case 0:
16044 16057                  /* error messages displayed by called function */
16045 16058                  r = add_mailto_params(mech, hier_part);
16046 16059                  break;
16047 16060  
16048 16061          case 1:
16049 16062                  if ((r = add_snmp_params(mech, hier_part)) != 0)
16050 16063                          semerr(gettext("Not valid parameters: '%s'\n"),
16051 16064                              hier_part);
16052 16065                  break;
16053 16066  
16054 16067          case 2:
16055 16068                  if ((r = add_syslog_params(mech, hier_part)) != 0)
16056 16069                          semerr(gettext("Not valid parameters: '%s'\n"),
16057 16070                              hier_part);
16058 16071                  break;
16059 16072  
16060 16073          default:
16061 16074                  r = -1;
16062 16075          }
16063 16076  
16064 16077          if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16065 16078              mech) != 0)
16066 16079                  uu_die(gettext("Out of memory.\n"));
16067 16080  
16068 16081          nvlist_free(mech);
16069 16082          return (r);
16070 16083  }
16071 16084  
16072 16085  static int
16073 16086  set_params(nvlist_t *params, char **p)
16074 16087  {
16075 16088          char *uri;
16076 16089  
16077 16090          if (p == NULL)
16078 16091                  /* sanity check */
16079 16092                  uu_die("set_params");
16080 16093  
16081 16094          while (*p) {
16082 16095                  uri = strip_quotes_and_blanks(*p);
16083 16096                  if (process_uri(params, uri) != 0)
16084 16097                          return (-1);
16085 16098  
16086 16099                  ++p;
16087 16100          }
16088 16101  
16089 16102          return (0);
16090 16103  }
16091 16104  
16092 16105  static int
16093 16106  setnotify(const char *e, char **p, int global)
16094 16107  {
16095 16108          char *str = safe_strdup(e);
16096 16109          char **events;
16097 16110          int32_t tset;
16098 16111          int r = -1;
16099 16112          nvlist_t *nvl, *params;
16100 16113          char *fmri = NULL;
16101 16114  
16102 16115          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16103 16116              nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16104 16117              nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16105 16118              SCF_NOTIFY_PARAMS_VERSION) != 0)
16106 16119                  uu_die(gettext("Out of memory.\n"));
16107 16120  
16108 16121          events = tokenize(str, ",");
16109 16122  
16110 16123          if ((tset = check_tokens(events)) > 0) {
16111 16124                  /* SMF state transitions parameters */
16112 16125                  size_t sz = max_scf_fmri_len + 1;
16113 16126  
16114 16127                  fmri = safe_malloc(sz);
16115 16128                  if (global) {
16116 16129                          (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16117 16130                  } else if (get_selection_str(fmri, sz) != 0) {
16118 16131                          goto out;
16119 16132                  }
16120 16133  
16121 16134                  if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16122 16135                      nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16123 16136                          uu_die(gettext("Out of memory.\n"));
16124 16137  
16125 16138                  if ((r = set_params(params, p)) == 0) {
16126 16139                          if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16127 16140                              params) != 0)
16128 16141                                  uu_die(gettext("Out of memory.\n"));
16129 16142  
16130 16143                          if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16131 16144                              nvl) != SCF_SUCCESS) {
16132 16145                                  r = -1;
16133 16146                                  uu_warn(gettext(
16134 16147                                      "Failed smf_notify_set_params(3SCF): %s\n"),
16135 16148                                      scf_strerror(scf_error()));
16136 16149                          }
16137 16150                  }
16138 16151          } else if (tset == FMA_TOKENS) {
16139 16152                  /* FMA event parameters */
16140 16153                  if (global) {
16141 16154                          semerr(gettext("Can't use option '-g' with FMA event "
16142 16155                              "definitions\n"));
16143 16156                          goto out;
16144 16157                  }
16145 16158  
16146 16159                  if ((r = set_params(params, p)) != 0)
16147 16160                          goto out;
16148 16161  
16149 16162                  if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16150 16163                          uu_die(gettext("Out of memory.\n"));
16151 16164  
16152 16165                  while (*events) {
16153 16166                          if (smf_notify_set_params(de_tag(*events), nvl) !=
16154 16167                              SCF_SUCCESS)
16155 16168                                  uu_warn(gettext(
16156 16169                                      "Failed smf_notify_set_params(3SCF) for "
16157 16170                                      "event %s: %s\n"), *events,
16158 16171                                      scf_strerror(scf_error()));
16159 16172                          events++;
16160 16173                  }
16161 16174          } else if (tset == MIXED_TOKENS) {
16162 16175                  semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16163 16176          } else {
16164 16177                  /* Sanity check */
16165 16178                  uu_die(gettext("Invalid input.\n"));
16166 16179          }
16167 16180  
16168 16181  out:
16169 16182          nvlist_free(nvl);
16170 16183          nvlist_free(params);
16171 16184          free(fmri);
16172 16185          free(str);
16173 16186  
16174 16187          return (r);
16175 16188  }
16176 16189  
16177 16190  int
16178 16191  lscf_setnotify(uu_list_t *args)
16179 16192  {
16180 16193          int argc;
16181 16194          char **argv = NULL;
16182 16195          string_list_t *slp;
16183 16196          int global;
16184 16197          char *events;
16185 16198          char **p;
16186 16199          int i;
16187 16200          int ret;
16188 16201  
16189 16202          if ((argc = uu_list_numnodes(args)) < 2)
16190 16203                  goto usage;
16191 16204  
16192 16205          argv = calloc(argc + 1, sizeof (char *));
16193 16206          if (argv == NULL)
16194 16207                  uu_die(gettext("Out of memory.\n"));
16195 16208  
16196 16209          for (slp = uu_list_first(args), i = 0;
16197 16210              slp != NULL;
16198 16211              slp = uu_list_next(args, slp), ++i)
16199 16212                  argv[i] = slp->str;
16200 16213  
16201 16214          argv[i] = NULL;
16202 16215  
16203 16216          if (strcmp(argv[0], "-g") == 0) {
16204 16217                  global = 1;
16205 16218                  events = argv[1];
16206 16219                  p = argv + 2;
16207 16220          } else {
16208 16221                  global = 0;
16209 16222                  events = argv[0];
16210 16223                  p = argv + 1;
16211 16224          }
16212 16225  
16213 16226          ret = setnotify(events, p, global);
16214 16227  
16215 16228  out:
16216 16229          free(argv);
16217 16230          return (ret);
16218 16231  
16219 16232  usage:
16220 16233          ret = -2;
16221 16234          goto out;
16222 16235  }
16223 16236  
16224 16237  /*
16225 16238   * Creates a list of instance name strings associated with a service. If
16226 16239   * wohandcrafted flag is set, get only instances that have a last-import
16227 16240   * snapshot, instances that were imported via svccfg.
16228 16241   */
16229 16242  static uu_list_t *
16230 16243  create_instance_list(scf_service_t *svc, int wohandcrafted)
16231 16244  {
16232 16245          scf_snapshot_t  *snap = NULL;
16233 16246          scf_instance_t  *inst;
16234 16247          scf_iter_t      *inst_iter;
16235 16248          uu_list_t       *instances;
16236 16249          char            *instname;
16237 16250          int             r;
16238 16251  
16239 16252          inst_iter = scf_iter_create(g_hndl);
16240 16253          inst = scf_instance_create(g_hndl);
16241 16254          if (inst_iter == NULL || inst == NULL) {
16242 16255                  uu_warn(gettext("Could not create instance or iterator\n"));
16243 16256                  scfdie();
16244 16257          }
16245 16258  
16246 16259          if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16247 16260                  return (instances);
16248 16261  
16249 16262          if (scf_iter_service_instances(inst_iter, svc) != 0) {
16250 16263                  switch (scf_error()) {
16251 16264                  case SCF_ERROR_CONNECTION_BROKEN:
16252 16265                  case SCF_ERROR_DELETED:
16253 16266                          uu_list_destroy(instances);
16254 16267                          instances = NULL;
16255 16268                          goto out;
16256 16269  
16257 16270                  case SCF_ERROR_HANDLE_MISMATCH:
16258 16271                  case SCF_ERROR_NOT_BOUND:
16259 16272                  case SCF_ERROR_NOT_SET:
16260 16273                  default:
16261 16274                          bad_error("scf_iter_service_instances", scf_error());
16262 16275                  }
16263 16276          }
16264 16277  
16265 16278          instname = safe_malloc(max_scf_name_len + 1);
16266 16279          while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16267 16280                  if (r == -1) {
16268 16281                          (void) uu_warn(gettext("Unable to iterate through "
16269 16282                              "instances to create instance list : %s\n"),
16270 16283                              scf_strerror(scf_error()));
16271 16284  
16272 16285                          uu_list_destroy(instances);
16273 16286                          instances = NULL;
16274 16287                          goto out;
16275 16288                  }
16276 16289  
16277 16290                  /*
16278 16291                   * If the instance does not have a last-import snapshot
16279 16292                   * then do not add it to the list as it is a hand-crafted
16280 16293                   * instance that should not be managed.
16281 16294                   */
16282 16295                  if (wohandcrafted) {
16283 16296                          if (snap == NULL &&
16284 16297                              (snap = scf_snapshot_create(g_hndl)) == NULL) {
16285 16298                                  uu_warn(gettext("Unable to create snapshot "
16286 16299                                      "entity\n"));
16287 16300                                  scfdie();
16288 16301                          }
16289 16302  
16290 16303                          if (scf_instance_get_snapshot(inst,
16291 16304                              snap_lastimport, snap) != 0) {
16292 16305                                  switch (scf_error()) {
16293 16306                                  case SCF_ERROR_NOT_FOUND :
16294 16307                                  case SCF_ERROR_DELETED:
16295 16308                                          continue;
16296 16309  
16297 16310                                  case SCF_ERROR_CONNECTION_BROKEN:
16298 16311                                          uu_list_destroy(instances);
16299 16312                                          instances = NULL;
16300 16313                                          goto out;
16301 16314  
16302 16315                                  case SCF_ERROR_HANDLE_MISMATCH:
16303 16316                                  case SCF_ERROR_NOT_BOUND:
16304 16317                                  case SCF_ERROR_NOT_SET:
16305 16318                                  default:
16306 16319                                          bad_error("scf_iter_service_instances",
16307 16320                                              scf_error());
16308 16321                                  }
16309 16322                          }
16310 16323                  }
16311 16324  
16312 16325                  if (scf_instance_get_name(inst, instname,
16313 16326                      max_scf_name_len + 1) < 0) {
16314 16327                          switch (scf_error()) {
16315 16328                          case SCF_ERROR_NOT_FOUND :
16316 16329                                  continue;
16317 16330  
16318 16331                          case SCF_ERROR_CONNECTION_BROKEN:
16319 16332                          case SCF_ERROR_DELETED:
16320 16333                                  uu_list_destroy(instances);
16321 16334                                  instances = NULL;
16322 16335                                  goto out;
16323 16336  
16324 16337                          case SCF_ERROR_HANDLE_MISMATCH:
16325 16338                          case SCF_ERROR_NOT_BOUND:
16326 16339                          case SCF_ERROR_NOT_SET:
16327 16340                          default:
16328 16341                                  bad_error("scf_iter_service_instances",
16329 16342                                      scf_error());
16330 16343                          }
16331 16344                  }
16332 16345  
16333 16346                  add_string(instances, instname);
16334 16347          }
16335 16348  
16336 16349  out:
16337 16350          if (snap)
16338 16351                  scf_snapshot_destroy(snap);
16339 16352  
16340 16353          scf_instance_destroy(inst);
16341 16354          scf_iter_destroy(inst_iter);
16342 16355          free(instname);
16343 16356          return (instances);
16344 16357  }
16345 16358  
16346 16359  /*
16347 16360   * disable an instance but wait for the instance to
16348 16361   * move out of the running state.
16349 16362   *
16350 16363   * Returns 0 : if the instance did not disable
16351 16364   * Returns non-zero : if the instance disabled.
16352 16365   *
16353 16366   */
16354 16367  static int
16355 16368  disable_instance(scf_instance_t *instance)
16356 16369  {
16357 16370          char    *fmribuf;
16358 16371          int     enabled = 10000;
16359 16372  
16360 16373          if (inst_is_running(instance)) {
16361 16374                  fmribuf = safe_malloc(max_scf_name_len + 1);
16362 16375                  if (scf_instance_to_fmri(instance, fmribuf,
16363 16376                      max_scf_name_len + 1) < 0) {
16364 16377                          free(fmribuf);
16365 16378                          return (0);
16366 16379                  }
16367 16380  
16368 16381                  /*
16369 16382                   * If the instance cannot be disabled then return
16370 16383                   * failure to disable and let the caller decide
16371 16384                   * if that is of importance.
16372 16385                   */
16373 16386                  if (smf_disable_instance(fmribuf, 0) != 0) {
16374 16387                          free(fmribuf);
16375 16388                          return (0);
16376 16389                  }
16377 16390  
16378 16391                  while (enabled) {
16379 16392                          if (!inst_is_running(instance))
16380 16393                                  break;
16381 16394  
16382 16395                          (void) poll(NULL, 0, 5);
16383 16396                          enabled = enabled - 5;
16384 16397                  }
16385 16398  
16386 16399                  free(fmribuf);
16387 16400          }
16388 16401  
16389 16402          return (enabled);
16390 16403  }
16391 16404  
16392 16405  /*
16393 16406   * Function to compare two service_manifest structures.
16394 16407   */
16395 16408  /* ARGSUSED2 */
16396 16409  static int
16397 16410  service_manifest_compare(const void *left, const void *right, void *unused)
16398 16411  {
16399 16412          service_manifest_t *l = (service_manifest_t *)left;
16400 16413          service_manifest_t *r = (service_manifest_t *)right;
16401 16414          int rc;
16402 16415  
16403 16416          rc = strcmp(l->servicename, r->servicename);
16404 16417  
16405 16418          return (rc);
16406 16419  }
16407 16420  
16408 16421  /*
16409 16422   * Look for the provided service in the service to manifest
16410 16423   * tree.  If the service exists, and a manifest was provided
16411 16424   * then add the manifest to that service.  If the service
16412 16425   * does not exist, then add the service and manifest to the
16413 16426   * list.
16414 16427   *
16415 16428   * If the manifest is NULL, return the element if found.  If
16416 16429   * the service is not found return NULL.
16417 16430   */
16418 16431  service_manifest_t *
16419 16432  find_add_svc_mfst(const char *svnbuf, const char *mfst)
16420 16433  {
16421 16434          service_manifest_t      elem;
16422 16435          service_manifest_t      *fnelem;
16423 16436          uu_avl_index_t          marker;
16424 16437  
16425 16438          elem.servicename = svnbuf;
16426 16439          fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16427 16440  
16428 16441          if (mfst) {
16429 16442                  if (fnelem) {
16430 16443                          add_string(fnelem->mfstlist, strdup(mfst));
16431 16444                  } else {
16432 16445                          fnelem = safe_malloc(sizeof (*fnelem));
16433 16446                          fnelem->servicename = safe_strdup(svnbuf);
16434 16447                          if ((fnelem->mfstlist =
16435 16448                              uu_list_create(string_pool, NULL, 0)) == NULL)
16436 16449                                  uu_die(gettext("Could not create property "
16437 16450                                      "list: %s\n"), uu_strerror(uu_error()));
16438 16451  
16439 16452                          add_string(fnelem->mfstlist, safe_strdup(mfst));
16440 16453  
16441 16454                          uu_avl_insert(service_manifest_tree, fnelem, marker);
16442 16455                  }
16443 16456          }
16444 16457  
16445 16458          return (fnelem);
16446 16459  }
16447 16460  
16448 16461  /*
16449 16462   * Create the service to manifest avl tree.
16450 16463   *
16451 16464   * Walk each of the manifests currently installed in the supported
16452 16465   * directories, /lib/svc/manifests and /var/svc/manifests.  For
16453 16466   * each of the manifests, inventory the services and add them to
16454 16467   * the tree.
16455 16468   *
16456 16469   * Code that calls this function should make sure fileystem/minimal is online,
16457 16470   * /var is available, since this function walks the /var/svc/manifest directory.
16458 16471   */
16459 16472  static void
16460 16473  create_manifest_tree(void)
16461 16474  {
16462 16475          manifest_info_t **entry;
16463 16476          manifest_info_t **manifests;
16464 16477          uu_list_walk_t  *svcs;
16465 16478          bundle_t        *b;
16466 16479          entity_t        *mfsvc;
16467 16480          char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16468 16481          int             c, status;
16469 16482  
16470 16483          if (service_manifest_pool)
16471 16484                  return;
16472 16485  
16473 16486          /*
16474 16487           * Create the list pool for the service manifest list
16475 16488           */
16476 16489          service_manifest_pool = uu_avl_pool_create("service_manifest",
16477 16490              sizeof (service_manifest_t),
16478 16491              offsetof(service_manifest_t, svcmfst_node),
16479 16492              service_manifest_compare, UU_DEFAULT);
16480 16493          if (service_manifest_pool == NULL)
16481 16494                  uu_die(gettext("service_manifest pool creation failed: %s\n"),
16482 16495                      uu_strerror(uu_error()));
16483 16496  
16484 16497          /*
16485 16498           * Create the list
16486 16499           */
16487 16500          service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16488 16501              UU_DEFAULT);
16489 16502          if (service_manifest_tree == NULL)
16490 16503                  uu_die(gettext("service_manifest tree creation failed: %s\n"),
16491 16504                      uu_strerror(uu_error()));
16492 16505  
16493 16506          /*
16494 16507           * Walk the manifests adding the service(s) from each manifest.
16495 16508           *
16496 16509           * If a service already exists add the manifest to the manifest
16497 16510           * list for that service.  This covers the case of a service that
16498 16511           * is supported by multiple manifest files.
16499 16512           */
16500 16513          for (c = 0; dirs[c]; c++) {
16501 16514                  status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16502 16515                  if (status < 0) {
16503 16516                          uu_warn(gettext("file tree walk of %s encountered "
16504 16517                              "error %s\n"), dirs[c], strerror(errno));
16505 16518  
16506 16519                          uu_avl_destroy(service_manifest_tree);
16507 16520                          service_manifest_tree = NULL;
16508 16521                          return;
16509 16522                  }
16510 16523  
16511 16524                  /*
16512 16525                   * If a manifest that was in the list is not found
16513 16526                   * then skip and go to the next manifest file.
16514 16527                   */
16515 16528                  if (manifests != NULL) {
16516 16529                          for (entry = manifests; *entry != NULL; entry++) {
16517 16530                                  b = internal_bundle_new();
16518 16531                                  if (lxml_get_bundle_file(b, (*entry)->mi_path,
16519 16532                                      SVCCFG_OP_IMPORT) != 0) {
16520 16533                                          internal_bundle_free(b);
16521 16534                                          continue;
16522 16535                                  }
16523 16536  
16524 16537                                  svcs = uu_list_walk_start(b->sc_bundle_services,
16525 16538                                      0);
16526 16539                                  if (svcs == NULL) {
16527 16540                                          internal_bundle_free(b);
16528 16541                                          continue;
16529 16542                                  }
16530 16543  
16531 16544                                  while ((mfsvc = uu_list_walk_next(svcs)) !=
16532 16545                                      NULL) {
16533 16546                                          /* Add manifest to service */
16534 16547                                          (void) find_add_svc_mfst(mfsvc->sc_name,
16535 16548                                              (*entry)->mi_path);
16536 16549                                  }
16537 16550  
16538 16551                                  uu_list_walk_end(svcs);
16539 16552                                  internal_bundle_free(b);
16540 16553                          }
16541 16554  
16542 16555                          free_manifest_array(manifests);
16543 16556                  }
16544 16557          }
16545 16558  }
16546 16559  
16547 16560  /*
16548 16561   * Check the manifest history file to see
16549 16562   * if the service was ever installed from
16550 16563   * one of the supported directories.
16551 16564   *
16552 16565   * Return Values :
16553 16566   *      -1 - if there's error reading manifest history file
16554 16567   *       1 - if the service is not found
16555 16568   *       0 - if the service is found
16556 16569   */
16557 16570  static int
16558 16571  check_mfst_history(const char *svcname)
16559 16572  {
16560 16573          struct stat     st;
16561 16574          caddr_t         mfsthist_start;
16562 16575          char            *svnbuf;
16563 16576          int             fd;
16564 16577          int             r = 1;
16565 16578  
16566 16579          fd = open(MFSTHISTFILE, O_RDONLY);
16567 16580          if (fd == -1) {
16568 16581                  uu_warn(gettext("Unable to open the history file\n"));
16569 16582                  return (-1);
16570 16583          }
16571 16584  
16572 16585          if (fstat(fd, &st) == -1) {
16573 16586                  uu_warn(gettext("Unable to stat the history file\n"));
16574 16587                  return (-1);
16575 16588          }
16576 16589  
16577 16590          mfsthist_start = mmap(0, st.st_size, PROT_READ,
16578 16591              MAP_PRIVATE, fd, 0);
16579 16592  
16580 16593          (void) close(fd);
16581 16594          if (mfsthist_start == MAP_FAILED ||
16582 16595              *(mfsthist_start + st.st_size) != '\0') {
16583 16596                  (void) munmap(mfsthist_start, st.st_size);
16584 16597                  return (-1);
16585 16598          }
16586 16599  
16587 16600          /*
16588 16601           * The manifest history file is a space delimited list
16589 16602           * of service and instance to manifest linkage.  Adding
16590 16603           * a space to the end of the service name so to get only
16591 16604           * the service that is being searched for.
16592 16605           */
16593 16606          svnbuf = uu_msprintf("%s ", svcname);
16594 16607          if (svnbuf == NULL)
16595 16608                  uu_die(gettext("Out of memory"));
16596 16609  
16597 16610          if (strstr(mfsthist_start, svnbuf) != NULL)
16598 16611                  r = 0;
16599 16612  
16600 16613          (void) munmap(mfsthist_start, st.st_size);
16601 16614          uu_free(svnbuf);
16602 16615          return (r);
16603 16616  }
16604 16617  
16605 16618  /*
16606 16619   * Take down each of the instances in the service
16607 16620   * and remove them, then delete the service.
16608 16621   */
16609 16622  static void
16610 16623  teardown_service(scf_service_t *svc, const char *svnbuf)
16611 16624  {
16612 16625          scf_instance_t  *instance;
16613 16626          scf_iter_t      *iter;
16614 16627          int             r;
16615 16628  
16616 16629          safe_printf(gettext("Delete service %s as there are no "
16617 16630              "supporting manifests\n"), svnbuf);
16618 16631  
16619 16632          instance = scf_instance_create(g_hndl);
16620 16633          iter = scf_iter_create(g_hndl);
16621 16634          if (iter == NULL || instance == NULL) {
16622 16635                  uu_warn(gettext("Unable to create supporting entities to "
16623 16636                      "teardown the service\n"));
16624 16637                  uu_warn(gettext("scf error is : %s\n"),
16625 16638                      scf_strerror(scf_error()));
16626 16639                  scfdie();
16627 16640          }
16628 16641  
16629 16642          if (scf_iter_service_instances(iter, svc) != 0) {
16630 16643                  switch (scf_error()) {
16631 16644                  case SCF_ERROR_CONNECTION_BROKEN:
16632 16645                  case SCF_ERROR_DELETED:
16633 16646                          goto out;
16634 16647  
16635 16648                  case SCF_ERROR_HANDLE_MISMATCH:
16636 16649                  case SCF_ERROR_NOT_BOUND:
16637 16650                  case SCF_ERROR_NOT_SET:
16638 16651                  default:
16639 16652                          bad_error("scf_iter_service_instances",
16640 16653                              scf_error());
16641 16654                  }
16642 16655          }
16643 16656  
16644 16657          while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16645 16658                  if (r == -1) {
16646 16659                          uu_warn(gettext("Error - %s\n"),
16647 16660                              scf_strerror(scf_error()));
16648 16661                          goto out;
16649 16662                  }
16650 16663  
16651 16664                  (void) disable_instance(instance);
16652 16665          }
16653 16666  
16654 16667          /*
16655 16668           * Delete the service... forcing the deletion in case
16656 16669           * any of the instances did not disable.
16657 16670           */
16658 16671          (void) lscf_service_delete(svc, 1);
16659 16672  out:
16660 16673          scf_instance_destroy(instance);
16661 16674          scf_iter_destroy(iter);
16662 16675  }
16663 16676  
16664 16677  /*
16665 16678   * Get the list of instances supported by the manifest
16666 16679   * file.
16667 16680   *
16668 16681   * Return 0 if there are no instances.
16669 16682   *
16670 16683   * Return -1 if there are errors attempting to collect instances.
16671 16684   *
16672 16685   * Return the count of instances found if there are no errors.
16673 16686   *
16674 16687   */
16675 16688  static int
16676 16689  check_instance_support(char *mfstfile, const char *svcname,
16677 16690      uu_list_t *instances)
16678 16691  {
16679 16692          uu_list_walk_t  *svcs, *insts;
16680 16693          uu_list_t       *ilist;
16681 16694          bundle_t        *b;
16682 16695          entity_t        *mfsvc, *mfinst;
16683 16696          const char      *svcn;
16684 16697          int             rminstcnt = 0;
16685 16698  
16686 16699  
16687 16700          b = internal_bundle_new();
16688 16701  
16689 16702          if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16690 16703                  /*
16691 16704                   * Unable to process the manifest file for
16692 16705                   * instance support, so just return as
16693 16706                   * don't want to remove instances that could
16694 16707                   * not be accounted for that might exist here.
16695 16708                   */
16696 16709                  internal_bundle_free(b);
16697 16710                  return (0);
16698 16711          }
16699 16712  
16700 16713          svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16701 16714          if (svcs == NULL) {
16702 16715                  internal_bundle_free(b);
16703 16716                  return (0);
16704 16717          }
16705 16718  
16706 16719          svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16707 16720              (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16708 16721  
16709 16722          while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16710 16723                  if (strcmp(mfsvc->sc_name, svcn) == 0)
16711 16724                          break;
16712 16725          }
16713 16726          uu_list_walk_end(svcs);
16714 16727  
16715 16728          if (mfsvc == NULL) {
16716 16729                  internal_bundle_free(b);
16717 16730                  return (-1);
16718 16731          }
16719 16732  
16720 16733          ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16721 16734          if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16722 16735                  internal_bundle_free(b);
16723 16736                  return (0);
16724 16737          }
16725 16738  
16726 16739          while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16727 16740                  /*
16728 16741                   * Remove the instance from the instances list.
16729 16742                   * The unaccounted for instances will be removed
16730 16743                   * from the service once all manifests are
16731 16744                   * processed.
16732 16745                   */
16733 16746                  (void) remove_string(instances,
16734 16747                      mfinst->sc_name);
16735 16748                  rminstcnt++;
16736 16749          }
16737 16750  
16738 16751          uu_list_walk_end(insts);
16739 16752          internal_bundle_free(b);
16740 16753  
16741 16754          return (rminstcnt);
16742 16755  }
16743 16756  
16744 16757  /*
16745 16758   * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16746 16759   * 'false' to indicate there's no manifest file(s) found for the service.
16747 16760   */
16748 16761  static void
16749 16762  svc_add_no_support(scf_service_t *svc)
16750 16763  {
16751 16764          char    *pname;
16752 16765  
16753 16766          /* Add no support */
16754 16767          cur_svc = svc;
16755 16768          if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16756 16769                  return;
16757 16770  
16758 16771          pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16759 16772          if (pname == NULL)
16760 16773                  uu_die(gettext("Out of memory.\n"));
16761 16774  
16762 16775          (void) lscf_addpropvalue(pname, "boolean:", "0");
16763 16776  
16764 16777          uu_free(pname);
16765 16778          cur_svc = NULL;
16766 16779  }
16767 16780  
16768 16781  /*
16769 16782   * This function handles all upgrade scenarios for a service that doesn't have
16770 16783   * SCF_PG_MANIFESTFILES pg. The function creates and populates
16771 16784   * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16772 16785   * manifest(s) mapping. Manifests under supported directories are inventoried
16773 16786   * and a property is added for each file that delivers configuration to the
16774 16787   * service.  A service that has no corresponding manifest files (deleted) are
16775 16788   * removed from repository.
16776 16789   *
16777 16790   * Unsupported services:
16778 16791   *
16779 16792   * A service is considered unsupported if there is no corresponding manifest
16780 16793   * in the supported directories for that service and the service isn't in the
16781 16794   * history file list.  The history file, MFSTHISTFILE, contains a list of all
16782 16795   * services and instances that were delivered by Solaris before the introduction
16783 16796   * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16784 16797   * the path to the manifest file that defined the service or instance.
16785 16798   *
16786 16799   * Another type of unsupported services is 'handcrafted' services,
16787 16800   * programmatically created services or services created by dependent entries
16788 16801   * in other manifests. A handcrafted service is identified by its lack of any
16789 16802   * instance containing last-import snapshot which is created during svccfg
16790 16803   * import.
16791 16804   *
16792 16805   * This function sets a flag for unsupported services by setting services'
16793 16806   * SCF_PG_MANIFESTFILES/support property to false.
16794 16807   */
16795 16808  static void
16796 16809  upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16797 16810  {
16798 16811          service_manifest_t      *elem;
16799 16812          uu_list_walk_t          *mfwalk;
16800 16813          string_list_t           *mfile;
16801 16814          uu_list_t               *instances;
16802 16815          const char              *sname;
16803 16816          char                    *pname;
16804 16817          int                     r;
16805 16818  
16806 16819          /*
16807 16820           * Since there's no guarantee manifests under /var are available during
16808 16821           * early import, don't perform any upgrade during early import.
16809 16822           */
16810 16823          if (IGNORE_VAR)
16811 16824                  return;
16812 16825  
16813 16826          if (service_manifest_tree == NULL) {
16814 16827                  create_manifest_tree();
16815 16828          }
16816 16829  
16817 16830          /*
16818 16831           * Find service's supporting manifest(s) after
16819 16832           * stripping off the svc:/ prefix that is part
16820 16833           * of the fmri that is not used in the service
16821 16834           * manifest bundle list.
16822 16835           */
16823 16836          sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16824 16837              strlen(SCF_FMRI_SERVICE_PREFIX);
16825 16838          elem = find_add_svc_mfst(sname, NULL);
16826 16839          if (elem == NULL) {
16827 16840  
16828 16841                  /*
16829 16842                   * A handcrafted service, one that has no instance containing
16830 16843                   * last-import snapshot, should get unsupported flag.
16831 16844                   */
16832 16845                  instances = create_instance_list(svc, 1);
16833 16846                  if (instances == NULL) {
16834 16847                          uu_warn(gettext("Unable to create instance list %s\n"),
16835 16848                              svcname);
16836 16849                          return;
16837 16850                  }
16838 16851  
16839 16852                  if (uu_list_numnodes(instances) == 0) {
16840 16853                          svc_add_no_support(svc);
16841 16854                          return;
16842 16855                  }
16843 16856  
16844 16857                  /*
16845 16858                   * If the service is in the history file, and its supporting
16846 16859                   * manifests are not found, we can safely delete the service
16847 16860                   * because its manifests are removed from the system.
16848 16861                   *
16849 16862                   * Services not found in the history file are not delivered by
16850 16863                   * Solaris and/or delivered outside supported directories, set
16851 16864                   * unsupported flag for these services.
16852 16865                   */
16853 16866                  r = check_mfst_history(svcname);
16854 16867                  if (r == -1)
16855 16868                          return;
16856 16869  
16857 16870                  if (r) {
16858 16871                          /* Set unsupported flag for service  */
16859 16872                          svc_add_no_support(svc);
16860 16873                  } else {
16861 16874                          /* Delete the service */
16862 16875                          teardown_service(svc, svcname);
16863 16876                  }
16864 16877  
16865 16878                  return;
16866 16879          }
16867 16880  
16868 16881          /*
16869 16882           * Walk through the list of manifests and add them
16870 16883           * to the service.
16871 16884           *
16872 16885           * Create a manifestfiles pg and add the property.
16873 16886           */
16874 16887          mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16875 16888          if (mfwalk == NULL)
16876 16889                  return;
16877 16890  
16878 16891          cur_svc = svc;
16879 16892          r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16880 16893          if (r != 0) {
16881 16894                  cur_svc = NULL;
16882 16895                  return;
16883 16896          }
16884 16897  
16885 16898          while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16886 16899                  pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16887 16900                      mhash_filename_to_propname(mfile->str, 0));
16888 16901                  if (pname == NULL)
16889 16902                          uu_die(gettext("Out of memory.\n"));
16890 16903  
16891 16904                  (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16892 16905                  uu_free(pname);
16893 16906          }
16894 16907          uu_list_walk_end(mfwalk);
16895 16908  
16896 16909          cur_svc = NULL;
16897 16910  }
16898 16911  
16899 16912  /*
16900 16913   * Take a service and process the manifest file entires to see if
16901 16914   * there is continued support for the service and instances.  If
16902 16915   * not cleanup as appropriate.
16903 16916   *
16904 16917   * If a service does not have a manifest files entry flag it for
16905 16918   * upgrade and return.
16906 16919   *
16907 16920   * For each manifestfiles property check if the manifest file is
16908 16921   * under the supported /lib/svc/manifest or /var/svc/manifest path
16909 16922   * and if not then return immediately as this service is not supported
16910 16923   * by the cleanup mechanism and should be ignored.
16911 16924   *
16912 16925   * For each manifest file that is supported, check to see if the
16913 16926   * file exists.  If not then remove the manifest file property
16914 16927   * from the service and the smf/manifest hash table.  If the manifest
16915 16928   * file exists then verify that it supports the instances that are
16916 16929   * part of the service.
16917 16930   *
16918 16931   * Once all manifest files have been accounted for remove any instances
16919 16932   * that are no longer supported in the service.
16920 16933   *
16921 16934   * Return values :
16922 16935   * 0 - Successfully processed the service
16923 16936   * non-zero - failed to process the service
16924 16937   *
16925 16938   * On most errors, will just return to wait and get the next service,
16926 16939   * unless in case of unable to create the needed structures which is
16927 16940   * most likely a fatal error that is not going to be recoverable.
16928 16941   */
16929 16942  int
16930 16943  lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16931 16944  {
16932 16945          struct mpg_mfile        *mpntov;
16933 16946          struct mpg_mfile        **mpvarry = NULL;
16934 16947          scf_service_t           *svc;
16935 16948          scf_propertygroup_t     *mpg;
16936 16949          scf_property_t          *mp;
16937 16950          scf_value_t             *mv;
16938 16951          scf_iter_t              *mi;
16939 16952          scf_instance_t          *instance;
16940 16953          uu_list_walk_t          *insts;
16941 16954          uu_list_t               *instances = NULL;
16942 16955          boolean_t               activity = (boolean_t)act;
16943 16956          char                    *mpnbuf;
16944 16957          char                    *mpvbuf;
16945 16958          char                    *pgpropbuf;
16946 16959          int                     mfstcnt, rminstct, instct, mfstmax;
16947 16960          int                     index;
16948 16961          int                     r = 0;
16949 16962  
16950 16963          assert(g_hndl != NULL);
16951 16964          assert(wip->svc != NULL);
16952 16965          assert(wip->fmri != NULL);
16953 16966  
16954 16967          svc = wip->svc;
16955 16968  
16956 16969          mpg = scf_pg_create(g_hndl);
16957 16970          mp = scf_property_create(g_hndl);
16958 16971          mi = scf_iter_create(g_hndl);
16959 16972          mv = scf_value_create(g_hndl);
16960 16973          instance = scf_instance_create(g_hndl);
16961 16974  
16962 16975          if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16963 16976              instance == NULL) {
16964 16977                  uu_warn(gettext("Unable to create the supporting entities\n"));
16965 16978                  uu_warn(gettext("scf error is : %s\n"),
16966 16979                      scf_strerror(scf_error()));
16967 16980                  scfdie();
16968 16981          }
16969 16982  
16970 16983          /*
16971 16984           * Get the manifestfiles property group to be parsed for
16972 16985           * files existence.
16973 16986           */
16974 16987          if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16975 16988                  switch (scf_error()) {
16976 16989                  case SCF_ERROR_NOT_FOUND:
16977 16990                          upgrade_svc_mfst_connection(svc, wip->fmri);
16978 16991                          break;
16979 16992                  case SCF_ERROR_DELETED:
16980 16993                  case SCF_ERROR_CONNECTION_BROKEN:
16981 16994                          goto out;
16982 16995  
16983 16996                  case SCF_ERROR_HANDLE_MISMATCH:
16984 16997                  case SCF_ERROR_NOT_BOUND:
16985 16998                  case SCF_ERROR_NOT_SET:
16986 16999                  default:
16987 17000                          bad_error("scf_iter_pg_properties",
16988 17001                              scf_error());
16989 17002                  }
16990 17003  
16991 17004                  goto out;
16992 17005          }
16993 17006  
16994 17007          /*
16995 17008           * Iterate through each of the manifestfiles properties
16996 17009           * to determine what manifestfiles are available.
16997 17010           *
16998 17011           * If a manifest file is supported then increment the
16999 17012           * count and therefore the service is safe.
17000 17013           */
17001 17014          if (scf_iter_pg_properties(mi, mpg) != 0) {
17002 17015                  switch (scf_error()) {
17003 17016                  case SCF_ERROR_DELETED:
17004 17017                  case SCF_ERROR_CONNECTION_BROKEN:
17005 17018                          goto out;
17006 17019  
17007 17020                  case SCF_ERROR_HANDLE_MISMATCH:
17008 17021                  case SCF_ERROR_NOT_BOUND:
17009 17022                  case SCF_ERROR_NOT_SET:
17010 17023                  default:
17011 17024                          bad_error("scf_iter_pg_properties",
17012 17025                              scf_error());
17013 17026                  }
17014 17027          }
17015 17028  
17016 17029          mfstcnt = 0;
17017 17030          mfstmax = MFSTFILE_MAX;
17018 17031          mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17019 17032          while ((r = scf_iter_next_property(mi, mp)) != 0) {
17020 17033                  if (r == -1)
17021 17034                          bad_error(gettext("Unable to iterate through "
17022 17035                              "manifestfiles properties : %s"),
17023 17036                              scf_error());
17024 17037  
17025 17038                  mpntov = safe_malloc(sizeof (struct mpg_mfile));
17026 17039                  mpnbuf = safe_malloc(max_scf_name_len + 1);
17027 17040                  mpvbuf = safe_malloc(max_scf_value_len + 1);
17028 17041                  mpntov->mpg = mpnbuf;
17029 17042                  mpntov->mfile = mpvbuf;
17030 17043                  mpntov->access = 1;
17031 17044                  if (scf_property_get_name(mp, mpnbuf,
17032 17045                      max_scf_name_len + 1) < 0) {
17033 17046                          uu_warn(gettext("Unable to get manifest file "
17034 17047                              "property : %s\n"),
17035 17048                              scf_strerror(scf_error()));
17036 17049  
17037 17050                          switch (scf_error()) {
17038 17051                          case SCF_ERROR_DELETED:
17039 17052                          case SCF_ERROR_CONNECTION_BROKEN:
17040 17053                                  r = scferror2errno(scf_error());
17041 17054                                  goto out_free;
17042 17055  
17043 17056                          case SCF_ERROR_HANDLE_MISMATCH:
17044 17057                          case SCF_ERROR_NOT_BOUND:
17045 17058                          case SCF_ERROR_NOT_SET:
17046 17059                          default:
17047 17060                                  bad_error("scf_iter_pg_properties",
17048 17061                                      scf_error());
17049 17062                          }
17050 17063                  }
17051 17064  
17052 17065                  /*
17053 17066                   * The support property is a boolean value that indicates
17054 17067                   * if the service is supported for manifest file deletion.
17055 17068                   * Currently at this time there is no code that sets this
17056 17069                   * value to true.  So while we could just let this be caught
17057 17070                   * by the support check below, in the future this by be set
17058 17071                   * to true and require processing.  So for that, go ahead
17059 17072                   * and check here, and just return if false.  Otherwise,
17060 17073                   * fall through expecting that other support checks will
17061 17074                   * handle the entries.
17062 17075                   */
17063 17076                  if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17064 17077                          uint8_t support;
17065 17078  
17066 17079                          if (scf_property_get_value(mp, mv) != 0 ||
17067 17080                              scf_value_get_boolean(mv, &support) != 0) {
17068 17081                                  uu_warn(gettext("Unable to get the manifest "
17069 17082                                      "support value: %s\n"),
17070 17083                                      scf_strerror(scf_error()));
17071 17084  
17072 17085                                  switch (scf_error()) {
17073 17086                                  case SCF_ERROR_DELETED:
17074 17087                                  case SCF_ERROR_CONNECTION_BROKEN:
17075 17088                                          r = scferror2errno(scf_error());
17076 17089                                          goto out_free;
17077 17090  
17078 17091                                  case SCF_ERROR_HANDLE_MISMATCH:
17079 17092                                  case SCF_ERROR_NOT_BOUND:
17080 17093                                  case SCF_ERROR_NOT_SET:
17081 17094                                  default:
17082 17095                                          bad_error("scf_iter_pg_properties",
17083 17096                                              scf_error());
17084 17097                                  }
17085 17098                          }
17086 17099  
17087 17100                          if (support == B_FALSE)
17088 17101                                  goto out_free;
17089 17102                  }
17090 17103  
17091 17104                  /*
17092 17105                   * Anything with a manifest outside of the supported
17093 17106                   * directories, immediately bail out because that makes
17094 17107                   * this service non-supported.  We don't even want
17095 17108                   * to do instance processing in this case because the
17096 17109                   * instances could be part of the non-supported manifest.
17097 17110                   */
17098 17111                  if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17099 17112                          /*
17100 17113                           * Manifest is not in /lib/svc, so we need to
17101 17114                           * consider the /var/svc case.
17102 17115                           */
17103 17116                          if (strncmp(mpnbuf, VARSVC_PR,
17104 17117                              strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17105 17118                                  /*
17106 17119                                   * Either the manifest is not in /var/svc or
17107 17120                                   * /var is not yet mounted.  We ignore the
17108 17121                                   * manifest either because it is not in a
17109 17122                                   * standard location or because we cannot
17110 17123                                   * currently access the manifest.
17111 17124                                   */
17112 17125                                  goto out_free;
17113 17126                          }
17114 17127                  }
17115 17128  
17116 17129                  /*
17117 17130                   * Get the value to of the manifest file for this entry
17118 17131                   * for access verification and instance support
17119 17132                   * verification if it still exists.
17120 17133                   *
17121 17134                   * During Early Manifest Import if the manifest is in
17122 17135                   * /var/svc then it may not yet be available for checking
17123 17136                   * so we must determine if /var/svc is available.  If not
17124 17137                   * then defer until Late Manifest Import to cleanup.
17125 17138                   */
17126 17139                  if (scf_property_get_value(mp, mv) != 0) {
17127 17140                          uu_warn(gettext("Unable to get the manifest file "
17128 17141                              "value: %s\n"),
17129 17142                              scf_strerror(scf_error()));
17130 17143  
17131 17144                          switch (scf_error()) {
17132 17145                          case SCF_ERROR_DELETED:
17133 17146                          case SCF_ERROR_CONNECTION_BROKEN:
17134 17147                                  r = scferror2errno(scf_error());
17135 17148                                  goto out_free;
17136 17149  
17137 17150                          case SCF_ERROR_HANDLE_MISMATCH:
17138 17151                          case SCF_ERROR_NOT_BOUND:
17139 17152                          case SCF_ERROR_NOT_SET:
17140 17153                          default:
17141 17154                                  bad_error("scf_property_get_value",
17142 17155                                      scf_error());
17143 17156                          }
17144 17157                  }
17145 17158  
17146 17159                  if (scf_value_get_astring(mv, mpvbuf,
17147 17160                      max_scf_value_len + 1) < 0) {
17148 17161                          uu_warn(gettext("Unable to get the manifest "
17149 17162                              "file : %s\n"),
17150 17163                              scf_strerror(scf_error()));
17151 17164  
17152 17165                          switch (scf_error()) {
17153 17166                          case SCF_ERROR_DELETED:
17154 17167                          case SCF_ERROR_CONNECTION_BROKEN:
17155 17168                                  r = scferror2errno(scf_error());
17156 17169                                  goto out_free;
17157 17170  
17158 17171                          case SCF_ERROR_HANDLE_MISMATCH:
17159 17172                          case SCF_ERROR_NOT_BOUND:
17160 17173                          case SCF_ERROR_NOT_SET:
17161 17174                          default:
17162 17175                                  bad_error("scf_value_get_astring",
17163 17176                                      scf_error());
17164 17177                          }
17165 17178                  }
17166 17179  
17167 17180                  mpvarry[mfstcnt] = mpntov;
17168 17181                  mfstcnt++;
17169 17182  
17170 17183                  /*
17171 17184                   * Check for the need to reallocate array
17172 17185                   */
17173 17186                  if (mfstcnt >= (mfstmax - 1)) {
17174 17187                          struct mpg_mfile **newmpvarry;
17175 17188  
17176 17189                          mfstmax = mfstmax * 2;
17177 17190                          newmpvarry = realloc(mpvarry,
17178 17191                              sizeof (struct mpg_mfile *) * mfstmax);
17179 17192  
17180 17193                          if (newmpvarry == NULL)
17181 17194                                  goto out_free;
17182 17195  
17183 17196                          mpvarry = newmpvarry;
17184 17197                  }
17185 17198  
17186 17199                  mpvarry[mfstcnt] = NULL;
17187 17200          }
17188 17201  
17189 17202          for (index = 0; mpvarry[index]; index++) {
17190 17203                  mpntov = mpvarry[index];
17191 17204  
17192 17205                  /*
17193 17206                   * Check to see if the manifestfile is accessable, if so hand
17194 17207                   * this service and manifestfile off to be processed for
17195 17208                   * instance support.
17196 17209                   */
17197 17210                  mpnbuf = mpntov->mpg;
17198 17211                  mpvbuf = mpntov->mfile;
17199 17212                  if (access(mpvbuf, F_OK) != 0) {
17200 17213                          mpntov->access = 0;
17201 17214                          activity++;
17202 17215                          mfstcnt--;
17203 17216                          /* Remove the entry from the service */
17204 17217                          cur_svc = svc;
17205 17218                          pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17206 17219                              mpnbuf);
17207 17220                          if (pgpropbuf == NULL)
17208 17221                                  uu_die(gettext("Out of memory.\n"));
17209 17222  
17210 17223                          lscf_delprop(pgpropbuf);
17211 17224                          cur_svc = NULL;
17212 17225  
17213 17226                          uu_free(pgpropbuf);
17214 17227                  }
17215 17228          }
17216 17229  
17217 17230          /*
17218 17231           * If mfstcnt is 0, none of the manifests that supported the service
17219 17232           * existed so remove the service.
17220 17233           */
17221 17234          if (mfstcnt == 0) {
17222 17235                  teardown_service(svc, wip->fmri);
17223 17236  
17224 17237                  goto out_free;
17225 17238          }
17226 17239  
17227 17240          if (activity) {
17228 17241                  int     nosvcsupport = 0;
17229 17242  
17230 17243                  /*
17231 17244                   * If the list of service instances is NULL then
17232 17245                   * create the list.
17233 17246                   */
17234 17247                  instances = create_instance_list(svc, 1);
17235 17248                  if (instances == NULL) {
17236 17249                          uu_warn(gettext("Unable to create instance list %s\n"),
17237 17250                              wip->fmri);
17238 17251                          goto out_free;
17239 17252                  }
17240 17253  
17241 17254                  rminstct = uu_list_numnodes(instances);
17242 17255                  instct = rminstct;
17243 17256  
17244 17257                  for (index = 0; mpvarry[index]; index++) {
17245 17258                          mpntov = mpvarry[index];
17246 17259                          if (mpntov->access == 0)
17247 17260                                  continue;
17248 17261  
17249 17262                          mpnbuf = mpntov->mpg;
17250 17263                          mpvbuf = mpntov->mfile;
17251 17264                          r = check_instance_support(mpvbuf, wip->fmri,
17252 17265                              instances);
17253 17266                          if (r == -1) {
17254 17267                                  nosvcsupport++;
17255 17268                          } else {
17256 17269                                  rminstct -= r;
17257 17270                          }
17258 17271                  }
17259 17272  
17260 17273                  if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17261 17274                          teardown_service(svc, wip->fmri);
17262 17275  
17263 17276                          goto out_free;
17264 17277                  }
17265 17278          }
17266 17279  
17267 17280          /*
17268 17281           * If there are instances left on the instance list, then
17269 17282           * we must remove them.
17270 17283           */
17271 17284          if (instances != NULL && uu_list_numnodes(instances)) {
17272 17285                  string_list_t *sp;
17273 17286  
17274 17287                  insts = uu_list_walk_start(instances, 0);
17275 17288                  while ((sp = uu_list_walk_next(insts)) != NULL) {
17276 17289                          /*
17277 17290                           * Remove the instance from the instances list.
17278 17291                           */
17279 17292                          safe_printf(gettext("Delete instance %s from "
17280 17293                              "service %s\n"), sp->str, wip->fmri);
17281 17294                          if (scf_service_get_instance(svc, sp->str,
17282 17295                              instance) != SCF_SUCCESS) {
17283 17296                                  (void) uu_warn("scf_error - %s\n",
17284 17297                                      scf_strerror(scf_error()));
17285 17298  
17286 17299                                  continue;
17287 17300                          }
17288 17301  
17289 17302                          (void) disable_instance(instance);
17290 17303  
17291 17304                          (void) lscf_instance_delete(instance, 1);
17292 17305                  }
17293 17306                  scf_instance_destroy(instance);
17294 17307                  uu_list_walk_end(insts);
17295 17308          }
17296 17309  
17297 17310  out_free:
17298 17311          if (mpvarry) {
17299 17312                  struct mpg_mfile *fmpntov;
17300 17313  
17301 17314                  for (index = 0; mpvarry[index]; index++) {
17302 17315                          fmpntov  = mpvarry[index];
17303 17316                          if (fmpntov->mpg == mpnbuf)
17304 17317                                  mpnbuf = NULL;
17305 17318                          free(fmpntov->mpg);
17306 17319  
17307 17320                          if (fmpntov->mfile == mpvbuf)
17308 17321                                  mpvbuf = NULL;
17309 17322                          free(fmpntov->mfile);
17310 17323  
17311 17324                          if (fmpntov == mpntov)
17312 17325                                  mpntov = NULL;
17313 17326                          free(fmpntov);
17314 17327                  }
17315 17328                  if (mpnbuf)
17316 17329                          free(mpnbuf);
17317 17330                  if (mpvbuf)
17318 17331                          free(mpvbuf);
17319 17332                  if (mpntov)
17320 17333                          free(mpntov);
17321 17334  
17322 17335                  free(mpvarry);
17323 17336          }
17324 17337  out:
17325 17338          scf_pg_destroy(mpg);
17326 17339          scf_property_destroy(mp);
17327 17340          scf_iter_destroy(mi);
17328 17341          scf_value_destroy(mv);
17329 17342  
17330 17343          return (0);
17331 17344  }
17332 17345  
17333 17346  /*
17334 17347   * Take the service and search for the manifestfiles property
17335 17348   * in each of the property groups.  If the manifest file
17336 17349   * associated with the property does not exist then remove
17337 17350   * the property group.
17338 17351   */
17339 17352  int
17340 17353  lscf_hash_cleanup()
17341 17354  {
17342 17355          scf_service_t           *svc;
17343 17356          scf_scope_t             *scope;
17344 17357          scf_propertygroup_t     *pg;
17345 17358          scf_property_t          *prop;
17346 17359          scf_value_t             *val;
17347 17360          scf_iter_t              *iter;
17348 17361          char                    *pgname = NULL;
17349 17362          char                    *mfile = NULL;
17350 17363          int                     r;
17351 17364  
17352 17365          svc = scf_service_create(g_hndl);
17353 17366          scope = scf_scope_create(g_hndl);
17354 17367          pg = scf_pg_create(g_hndl);
17355 17368          prop = scf_property_create(g_hndl);
17356 17369          val = scf_value_create(g_hndl);
17357 17370          iter = scf_iter_create(g_hndl);
17358 17371          if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17359 17372              svc == NULL || scope == NULL) {
17360 17373                  uu_warn(gettext("Unable to create a property group, or "
17361 17374                      "property\n"));
17362 17375                  uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17363 17376                      "pg is not NULL");
17364 17377                  uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17365 17378                      "prop is not NULL");
17366 17379                  uu_warn("%s\n", val == NULL ? "val is NULL" :
17367 17380                      "val is not NULL");
17368 17381                  uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17369 17382                      "iter is not NULL");
17370 17383                  uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17371 17384                      "svc is not NULL");
17372 17385                  uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17373 17386                      "scope is not NULL");
17374 17387                  uu_warn(gettext("scf error is : %s\n"),
17375 17388                      scf_strerror(scf_error()));
17376 17389                  scfdie();
17377 17390          }
17378 17391  
17379 17392          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17380 17393                  switch (scf_error()) {
17381 17394                  case SCF_ERROR_CONNECTION_BROKEN:
17382 17395                  case SCF_ERROR_NOT_FOUND:
17383 17396                          goto out;
17384 17397  
17385 17398                  case SCF_ERROR_HANDLE_MISMATCH:
17386 17399                  case SCF_ERROR_NOT_BOUND:
17387 17400                  case SCF_ERROR_INVALID_ARGUMENT:
17388 17401                  default:
17389 17402                          bad_error("scf_handle_get_scope", scf_error());
17390 17403                  }
17391 17404          }
17392 17405  
17393 17406          if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17394 17407                  uu_warn(gettext("Unable to process the hash service, %s\n"),
17395 17408                      HASH_SVC);
17396 17409                  goto out;
17397 17410          }
17398 17411  
17399 17412          pgname = safe_malloc(max_scf_name_len + 1);
17400 17413          mfile = safe_malloc(max_scf_value_len + 1);
17401 17414  
17402 17415          if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17403 17416                  uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17404 17417                      scf_strerror(scf_error()));
17405 17418                  goto out;
17406 17419          }
17407 17420  
17408 17421          while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17409 17422                  if (r == -1)
17410 17423                          goto out;
17411 17424  
17412 17425                  if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17413 17426                          switch (scf_error()) {
17414 17427                          case SCF_ERROR_DELETED:
17415 17428                                  return (ENODEV);
17416 17429  
17417 17430                          case SCF_ERROR_CONNECTION_BROKEN:
17418 17431                                  return (ECONNABORTED);
17419 17432  
17420 17433                          case SCF_ERROR_NOT_SET:
17421 17434                          case SCF_ERROR_NOT_BOUND:
17422 17435                          default:
17423 17436                                  bad_error("scf_pg_get_name", scf_error());
17424 17437                          }
17425 17438                  }
17426 17439                  if (IGNORE_VAR) {
17427 17440                          if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17428 17441                                  continue;
17429 17442                  }
17430 17443  
17431 17444                  /*
17432 17445                   * If unable to get the property continue as this is an
17433 17446                   * entry that has no location to check against.
17434 17447                   */
17435 17448                  if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17436 17449                          continue;
17437 17450                  }
17438 17451  
17439 17452                  if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17440 17453                          uu_warn(gettext("Unable to get value from %s\n"),
17441 17454                              pgname);
17442 17455  
17443 17456                          switch (scf_error()) {
17444 17457                          case SCF_ERROR_DELETED:
17445 17458                          case SCF_ERROR_CONSTRAINT_VIOLATED:
17446 17459                          case SCF_ERROR_NOT_FOUND:
17447 17460                          case SCF_ERROR_NOT_SET:
17448 17461                                  continue;
17449 17462  
17450 17463                          case SCF_ERROR_CONNECTION_BROKEN:
17451 17464                                  r = scferror2errno(scf_error());
17452 17465                                  goto out;
17453 17466  
17454 17467                          case SCF_ERROR_HANDLE_MISMATCH:
17455 17468                          case SCF_ERROR_NOT_BOUND:
17456 17469                          default:
17457 17470                                  bad_error("scf_property_get_value",
17458 17471                                      scf_error());
17459 17472                          }
17460 17473                  }
17461 17474  
17462 17475                  if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17463 17476                      == -1) {
17464 17477                          uu_warn(gettext("Unable to get astring from %s : %s\n"),
17465 17478                              pgname, scf_strerror(scf_error()));
17466 17479  
17467 17480                          switch (scf_error()) {
17468 17481                          case SCF_ERROR_NOT_SET:
17469 17482                          case SCF_ERROR_TYPE_MISMATCH:
17470 17483                                  continue;
17471 17484  
17472 17485                          default:
17473 17486                                  bad_error("scf_value_get_astring", scf_error());
17474 17487                          }
17475 17488                  }
17476 17489  
17477 17490                  if (access(mfile, F_OK) == 0)
17478 17491                          continue;
17479 17492  
17480 17493                  (void) scf_pg_delete(pg);
17481 17494          }
17482 17495  
17483 17496  out:
17484 17497          scf_scope_destroy(scope);
17485 17498          scf_service_destroy(svc);
17486 17499          scf_pg_destroy(pg);
17487 17500          scf_property_destroy(prop);
17488 17501          scf_value_destroy(val);
17489 17502          scf_iter_destroy(iter);
17490 17503          free(pgname);
17491 17504          free(mfile);
17492 17505  
17493 17506          return (0);
17494 17507  }
17495 17508  
17496 17509  #ifndef NATIVE_BUILD
17497 17510  /* ARGSUSED */
17498 17511  CPL_MATCH_FN(complete_select)
17499 17512  {
17500 17513          const char *arg0, *arg1, *arg1end;
17501 17514          int word_start, err = 0, r;
17502 17515          size_t len;
17503 17516          char *buf;
17504 17517  
17505 17518          lscf_prep_hndl();
17506 17519  
17507 17520          arg0 = line + strspn(line, " \t");
17508 17521          assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17509 17522  
17510 17523          arg1 = arg0 + sizeof ("select") - 1;
17511 17524          arg1 += strspn(arg1, " \t");
17512 17525          word_start = arg1 - line;
17513 17526  
17514 17527          arg1end = arg1 + strcspn(arg1, " \t");
17515 17528          if (arg1end < line + word_end)
17516 17529                  return (0);
17517 17530  
17518 17531          len = line + word_end - arg1;
17519 17532  
17520 17533          buf = safe_malloc(max_scf_name_len + 1);
17521 17534  
17522 17535          if (cur_snap != NULL) {
17523 17536                  return (0);
17524 17537          } else if (cur_inst != NULL) {
17525 17538                  return (0);
17526 17539          } else if (cur_svc != NULL) {
17527 17540                  scf_instance_t *inst;
17528 17541                  scf_iter_t *iter;
17529 17542  
17530 17543                  if ((inst = scf_instance_create(g_hndl)) == NULL ||
17531 17544                      (iter = scf_iter_create(g_hndl)) == NULL)
17532 17545                          scfdie();
17533 17546  
17534 17547                  if (scf_iter_service_instances(iter, cur_svc) != 0)
17535 17548                          scfdie();
17536 17549  
17537 17550                  for (;;) {
17538 17551                          r = scf_iter_next_instance(iter, inst);
17539 17552                          if (r == 0)
17540 17553                                  break;
17541 17554                          if (r != 1)
17542 17555                                  scfdie();
17543 17556  
17544 17557                          if (scf_instance_get_name(inst, buf,
17545 17558                              max_scf_name_len + 1) < 0)
17546 17559                                  scfdie();
17547 17560  
17548 17561                          if (strncmp(buf, arg1, len) == 0) {
17549 17562                                  err = cpl_add_completion(cpl, line, word_start,
17550 17563                                      word_end, buf + len, "", " ");
17551 17564                                  if (err != 0)
17552 17565                                          break;
17553 17566                          }
17554 17567                  }
17555 17568  
17556 17569                  scf_iter_destroy(iter);
17557 17570                  scf_instance_destroy(inst);
17558 17571  
17559 17572                  return (err);
17560 17573          } else {
17561 17574                  scf_service_t *svc;
17562 17575                  scf_iter_t *iter;
17563 17576  
17564 17577                  assert(cur_scope != NULL);
17565 17578  
17566 17579                  if ((svc = scf_service_create(g_hndl)) == NULL ||
17567 17580                      (iter = scf_iter_create(g_hndl)) == NULL)
17568 17581                          scfdie();
17569 17582  
17570 17583                  if (scf_iter_scope_services(iter, cur_scope) != 0)
17571 17584                          scfdie();
17572 17585  
17573 17586                  for (;;) {
17574 17587                          r = scf_iter_next_service(iter, svc);
17575 17588                          if (r == 0)
17576 17589                                  break;
17577 17590                          if (r != 1)
17578 17591                                  scfdie();
17579 17592  
17580 17593                          if (scf_service_get_name(svc, buf,
17581 17594                              max_scf_name_len + 1) < 0)
17582 17595                                  scfdie();
17583 17596  
17584 17597                          if (strncmp(buf, arg1, len) == 0) {
17585 17598                                  err = cpl_add_completion(cpl, line, word_start,
17586 17599                                      word_end, buf + len, "", " ");
17587 17600                                  if (err != 0)
17588 17601                                          break;
17589 17602                          }
17590 17603                  }
17591 17604  
17592 17605                  scf_iter_destroy(iter);
17593 17606                  scf_service_destroy(svc);
17594 17607  
17595 17608                  return (err);
17596 17609          }
17597 17610  }
17598 17611  
17599 17612  /* ARGSUSED */
17600 17613  CPL_MATCH_FN(complete_command)
17601 17614  {
17602 17615          uint32_t scope = 0;
17603 17616  
17604 17617          if (cur_snap != NULL)
17605 17618                  scope = CS_SNAP;
17606 17619          else if (cur_inst != NULL)
17607 17620                  scope = CS_INST;
17608 17621          else if (cur_svc != NULL)
17609 17622                  scope = CS_SVC;
17610 17623          else
17611 17624                  scope = CS_SCOPE;
17612 17625  
17613 17626          return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17614 17627  }
17615 17628  #endif  /* NATIVE_BUILD */
  
    | ↓ open down ↓ | 7755 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX