Print this page
    
7806 svccfg restore segfaults in upgrade_manifestfiles
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>
    
      
        | 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
  
    | 
      ↓ open down ↓ | 
    15 lines elided | 
    
      ↑ open up ↑ | 
  
  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 + * Copyright 2017 RackTop Systems.
  26   27   */
  27   28  
  28   29  
  29   30  #include <alloca.h>
  30   31  #include <assert.h>
  31   32  #include <ctype.h>
  32   33  #include <door.h>
  33   34  #include <errno.h>
  34   35  #include <fcntl.h>
  35   36  #include <fnmatch.h>
  36   37  #include <inttypes.h>
  37   38  #include <libintl.h>
  38   39  #include <libnvpair.h>
  39   40  #include <libscf.h>
  40   41  #include <libscf_priv.h>
  41   42  #include <libtecla.h>
  42   43  #include <libuutil.h>
  43   44  #include <limits.h>
  44   45  #include <locale.h>
  45   46  #include <stdarg.h>
  46   47  #include <string.h>
  47   48  #include <strings.h>
  48   49  #include <time.h>
  49   50  #include <unistd.h>
  50   51  #include <wait.h>
  51   52  #include <poll.h>
  52   53  
  53   54  #include <libxml/tree.h>
  54   55  
  55   56  #include <sys/param.h>
  56   57  
  57   58  #include <sys/stat.h>
  58   59  #include <sys/mman.h>
  59   60  
  60   61  #include "svccfg.h"
  61   62  #include "notify_params.h"
  62   63  #include "manifest_hash.h"
  63   64  #include "manifest_find.h"
  64   65  
  65   66  /* The colon namespaces in each entity (each followed by a newline). */
  66   67  #define COLON_NAMESPACES        ":properties\n"
  67   68  
  68   69  #define TEMP_FILE_PATTERN       "/tmp/svccfg-XXXXXX"
  69   70  
  70   71  /* These are characters which the lexer requires to be in double-quotes. */
  71   72  #define CHARS_TO_QUOTE          " \t\n\\>=\"()"
  72   73  
  73   74  #define HASH_SIZE               16
  74   75  #define HASH_PG_TYPE            "framework"
  75   76  #define HASH_PG_FLAGS           0
  76   77  #define HASH_PROP               "md5sum"
  77   78  
  78   79  /*
  79   80   * Indentation used in the output of the describe subcommand.
  80   81   */
  81   82  #define TMPL_VALUE_INDENT       "  "
  82   83  #define TMPL_INDENT             "    "
  83   84  #define TMPL_INDENT_2X          "        "
  84   85  #define TMPL_CHOICE_INDENT      "      "
  85   86  
  86   87  /*
  87   88   * Directory locations for manifests
  88   89   */
  89   90  #define VARSVC_DIR              "/var/svc/manifest"
  90   91  #define LIBSVC_DIR              "/lib/svc/manifest"
  91   92  #define VARSVC_PR               "var_svc_manifest"
  92   93  #define LIBSVC_PR               "lib_svc_manifest"
  93   94  #define MFSTFILEPR              "manifestfile"
  94   95  
  95   96  #define SUPPORTPROP             "support"
  96   97  
  97   98  #define MFSTHISTFILE            "/lib/svc/share/mfsthistory"
  98   99  
  99  100  #define MFSTFILE_MAX            16
 100  101  
 101  102  /*
 102  103   * These are the classes of elements which may appear as children of service
 103  104   * or instance elements in XML manifests.
 104  105   */
 105  106  struct entity_elts {
 106  107          xmlNodePtr      create_default_instance;
 107  108          xmlNodePtr      single_instance;
 108  109          xmlNodePtr      restarter;
 109  110          xmlNodePtr      dependencies;
 110  111          xmlNodePtr      dependents;
 111  112          xmlNodePtr      method_context;
 112  113          xmlNodePtr      exec_methods;
 113  114          xmlNodePtr      notify_params;
 114  115          xmlNodePtr      property_groups;
 115  116          xmlNodePtr      instances;
 116  117          xmlNodePtr      stability;
 117  118          xmlNodePtr      template;
 118  119  };
 119  120  
 120  121  /*
 121  122   * Likewise for property_group elements.
 122  123   */
 123  124  struct pg_elts {
 124  125          xmlNodePtr      stability;
 125  126          xmlNodePtr      propvals;
 126  127          xmlNodePtr      properties;
 127  128  };
 128  129  
 129  130  /*
 130  131   * Likewise for template elements.
 131  132   */
 132  133  struct template_elts {
 133  134          xmlNodePtr      common_name;
 134  135          xmlNodePtr      description;
 135  136          xmlNodePtr      documentation;
 136  137  };
 137  138  
 138  139  /*
 139  140   * Likewise for type (for notification parameters) elements.
 140  141   */
 141  142  struct params_elts {
 142  143          xmlNodePtr      paramval;
 143  144          xmlNodePtr      parameter;
 144  145  };
 145  146  
 146  147  /*
 147  148   * This structure is for snaplevel lists.  They are convenient because libscf
 148  149   * only allows traversing snaplevels in one direction.
 149  150   */
 150  151  struct snaplevel {
 151  152          uu_list_node_t  list_node;
 152  153          scf_snaplevel_t *sl;
 153  154  };
 154  155  
 155  156  /*
 156  157   * This is used for communication between lscf_service_export and
 157  158   * export_callback.
 158  159   */
 159  160  struct export_args {
 160  161          const char      *filename;
 161  162          int             flags;
 162  163  };
 163  164  
 164  165  /*
 165  166   * The service_manifest structure is used by the upgrade process
 166  167   * to create a list of service to manifest linkages from the manifests
 167  168   * in a set of given directories.
 168  169   */
 169  170  typedef struct service_manifest {
 170  171          const char      *servicename;
 171  172          uu_list_t       *mfstlist;
 172  173          size_t  mfstlist_sz;
 173  174  
 174  175          uu_avl_node_t   svcmfst_node;
 175  176  } service_manifest_t;
 176  177  
 177  178  /*
 178  179   * Structure to track the manifest file property group
 179  180   * and the manifest file associated with that property
 180  181   * group.  Also, a flag to keep the access once it has
 181  182   * been checked.
 182  183   */
 183  184  struct mpg_mfile {
 184  185          char    *mpg;
 185  186          char    *mfile;
 186  187          int     access;
 187  188  };
 188  189  
 189  190  const char * const scf_pg_general = SCF_PG_GENERAL;
 190  191  const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
 191  192  const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
 192  193  const char * const scf_property_external = "external";
 193  194  
 194  195  const char * const snap_initial = "initial";
 195  196  const char * const snap_lastimport = "last-import";
 196  197  const char * const snap_previous = "previous";
 197  198  const char * const snap_running = "running";
 198  199  
 199  200  scf_handle_t *g_hndl = NULL;    /* only valid after lscf_prep_hndl() */
 200  201  
 201  202  ssize_t max_scf_fmri_len;
 202  203  ssize_t max_scf_name_len;
 203  204  ssize_t max_scf_pg_type_len;
 204  205  ssize_t max_scf_value_len;
 205  206  static size_t max_scf_len;
 206  207  
 207  208  static scf_scope_t *cur_scope;
 208  209  static scf_service_t *cur_svc = NULL;
 209  210  static scf_instance_t *cur_inst = NULL;
 210  211  static scf_snapshot_t *cur_snap = NULL;
 211  212  static scf_snaplevel_t *cur_level = NULL;
 212  213  
 213  214  static uu_list_pool_t *snaplevel_pool;
 214  215  /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
 215  216  static uu_list_t *cur_levels;
 216  217  static struct snaplevel *cur_elt;               /* cur_elt->sl == cur_level */
 217  218  
 218  219  static FILE *tempfile = NULL;
 219  220  static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
 220  221  
 221  222  static const char *emsg_entity_not_selected;
 222  223  static const char *emsg_permission_denied;
 223  224  static const char *emsg_create_xml;
 224  225  static const char *emsg_cant_modify_snapshots;
 225  226  static const char *emsg_invalid_for_snapshot;
 226  227  static const char *emsg_read_only;
 227  228  static const char *emsg_deleted;
 228  229  static const char *emsg_invalid_pg_name;
 229  230  static const char *emsg_invalid_prop_name;
 230  231  static const char *emsg_no_such_pg;
 231  232  static const char *emsg_fmri_invalid_pg_name;
 232  233  static const char *emsg_fmri_invalid_pg_name_type;
 233  234  static const char *emsg_pg_added;
 234  235  static const char *emsg_pg_changed;
 235  236  static const char *emsg_pg_deleted;
 236  237  static const char *emsg_pg_mod_perm;
 237  238  static const char *emsg_pg_add_perm;
 238  239  static const char *emsg_pg_del_perm;
 239  240  static const char *emsg_snap_perm;
 240  241  static const char *emsg_dpt_dangling;
 241  242  static const char *emsg_dpt_no_dep;
 242  243  
 243  244  static int li_only = 0;
 244  245  static int no_refresh = 0;
 245  246  
 246  247  /* how long in ns we should wait between checks for a pg */
 247  248  static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
 248  249  
 249  250  /* import globals, to minimize allocations */
 250  251  static scf_scope_t *imp_scope = NULL;
 251  252  static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
 252  253  static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
 253  254  static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
 254  255  static scf_snapshot_t *imp_rsnap = NULL;
 255  256  static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
 256  257  static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
 257  258  static scf_property_t *imp_prop = NULL;
 258  259  static scf_iter_t *imp_iter = NULL;
 259  260  static scf_iter_t *imp_rpg_iter = NULL;
 260  261  static scf_iter_t *imp_up_iter = NULL;
 261  262  static scf_transaction_t *imp_tx = NULL;        /* always reset this */
 262  263  static char *imp_str = NULL;
 263  264  static size_t imp_str_sz;
 264  265  static char *imp_tsname = NULL;
 265  266  static char *imp_fe1 = NULL;            /* for fmri_equal() */
 266  267  static char *imp_fe2 = NULL;
 267  268  static uu_list_t *imp_deleted_dpts = NULL;      /* pgroup_t's to refresh */
 268  269  
 269  270  /* upgrade_dependents() globals */
 270  271  static scf_instance_t *ud_inst = NULL;
 271  272  static scf_snaplevel_t *ud_snpl = NULL;
 272  273  static scf_propertygroup_t *ud_pg = NULL;
 273  274  static scf_propertygroup_t *ud_cur_depts_pg = NULL;
 274  275  static scf_propertygroup_t *ud_run_dpts_pg = NULL;
 275  276  static int ud_run_dpts_pg_set = 0;
 276  277  static scf_property_t *ud_prop = NULL;
 277  278  static scf_property_t *ud_dpt_prop = NULL;
 278  279  static scf_value_t *ud_val = NULL;
 279  280  static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
 280  281  static scf_transaction_t *ud_tx = NULL;
 281  282  static char *ud_ctarg = NULL;
 282  283  static char *ud_oldtarg = NULL;
 283  284  static char *ud_name = NULL;
 284  285  
 285  286  /* export globals */
 286  287  static scf_instance_t *exp_inst;
 287  288  static scf_propertygroup_t *exp_pg;
 288  289  static scf_property_t *exp_prop;
 289  290  static scf_value_t *exp_val;
 290  291  static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
 291  292  static char *exp_str;
 292  293  static size_t exp_str_sz;
 293  294  
 294  295  /* cleanup globals */
 295  296  static uu_avl_pool_t *service_manifest_pool = NULL;
 296  297  static uu_avl_t *service_manifest_tree = NULL;
 297  298  
 298  299  static void scfdie_lineno(int lineno) __NORETURN;
 299  300  
 300  301  static char *start_method_names[] = {
 301  302          "start",
 302  303          "inetd_start",
 303  304          NULL
 304  305  };
 305  306  
 306  307  static struct uri_scheme {
 307  308          const char *scheme;
 308  309          const char *protocol;
 309  310  } uri_scheme[] = {
 310  311          { "mailto", "smtp" },
 311  312          { "snmp", "snmp" },
 312  313          { "syslog", "syslog" },
 313  314          { NULL, NULL }
 314  315  };
 315  316  #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
 316  317      sizeof (struct uri_scheme)) - 1)
 317  318  
 318  319  static int
 319  320  check_uri_scheme(const char *scheme)
 320  321  {
 321  322          int i;
 322  323  
 323  324          for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
 324  325                  if (strcmp(scheme, uri_scheme[i].scheme) == 0)
 325  326                          return (i);
 326  327          }
 327  328  
 328  329          return (-1);
 329  330  }
 330  331  
 331  332  static int
 332  333  check_uri_protocol(const char *p)
 333  334  {
 334  335          int i;
 335  336  
 336  337          for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
 337  338                  if (strcmp(p, uri_scheme[i].protocol) == 0)
 338  339                          return (i);
 339  340          }
 340  341  
 341  342          return (-1);
 342  343  }
 343  344  
 344  345  /*
 345  346   * For unexpected libscf errors.
 346  347   */
 347  348  #ifdef NDEBUG
 348  349  
 349  350  static void scfdie(void) __NORETURN;
 350  351  
 351  352  static void
 352  353  scfdie(void)
 353  354  {
 354  355          scf_error_t err = scf_error();
 355  356  
 356  357          if (err == SCF_ERROR_CONNECTION_BROKEN)
 357  358                  uu_die(gettext("Repository connection broken.  Exiting.\n"));
 358  359  
 359  360          uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
 360  361              scf_strerror(err));
 361  362  }
 362  363  
 363  364  #else
 364  365  
 365  366  #define scfdie()        scfdie_lineno(__LINE__)
 366  367  
 367  368  static void
 368  369  scfdie_lineno(int lineno)
 369  370  {
 370  371          scf_error_t err = scf_error();
 371  372  
 372  373          if (err == SCF_ERROR_CONNECTION_BROKEN)
 373  374                  uu_die(gettext("Repository connection broken.  Exiting.\n"));
 374  375  
 375  376          uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
 376  377              ": %s.\n"), lineno, scf_strerror(err));
 377  378  }
 378  379  
 379  380  #endif
 380  381  
 381  382  static void
 382  383  scfwarn(void)
 383  384  {
 384  385          warn(gettext("Unexpected libscf error: %s.\n"),
 385  386              scf_strerror(scf_error()));
 386  387  }
 387  388  
 388  389  /*
 389  390   * Clear a field of a structure.
 390  391   */
 391  392  static int
 392  393  clear_int(void *a, void *b)
 393  394  {
 394  395          /* LINTED */
 395  396          *(int *)((char *)a + (size_t)b) = 0;
 396  397  
 397  398          return (UU_WALK_NEXT);
 398  399  }
 399  400  
 400  401  static int
 401  402  scferror2errno(scf_error_t err)
 402  403  {
 403  404          switch (err) {
 404  405          case SCF_ERROR_BACKEND_ACCESS:
 405  406                  return (EACCES);
 406  407  
 407  408          case SCF_ERROR_BACKEND_READONLY:
 408  409                  return (EROFS);
 409  410  
 410  411          case SCF_ERROR_CONNECTION_BROKEN:
 411  412                  return (ECONNABORTED);
 412  413  
 413  414          case SCF_ERROR_CONSTRAINT_VIOLATED:
 414  415          case SCF_ERROR_INVALID_ARGUMENT:
 415  416                  return (EINVAL);
 416  417  
 417  418          case SCF_ERROR_DELETED:
 418  419                  return (ECANCELED);
 419  420  
 420  421          case SCF_ERROR_EXISTS:
 421  422                  return (EEXIST);
 422  423  
 423  424          case SCF_ERROR_NO_MEMORY:
 424  425                  return (ENOMEM);
 425  426  
 426  427          case SCF_ERROR_NO_RESOURCES:
 427  428                  return (ENOSPC);
 428  429  
 429  430          case SCF_ERROR_NOT_FOUND:
 430  431                  return (ENOENT);
 431  432  
 432  433          case SCF_ERROR_PERMISSION_DENIED:
 433  434                  return (EPERM);
 434  435  
 435  436          default:
 436  437  #ifndef NDEBUG
 437  438                  (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
 438  439                      __FILE__, __LINE__, err);
 439  440  #else
 440  441                  (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
 441  442  #endif
 442  443                  abort();
 443  444                  /* NOTREACHED */
 444  445          }
 445  446  }
 446  447  
 447  448  static int
 448  449  entity_get_pg(void *ent, int issvc, const char *name,
 449  450      scf_propertygroup_t *pg)
 450  451  {
 451  452          if (issvc)
 452  453                  return (scf_service_get_pg(ent, name, pg));
 453  454          else
 454  455                  return (scf_instance_get_pg(ent, name, pg));
 455  456  }
 456  457  
 457  458  static void
 458  459  entity_destroy(void *ent, int issvc)
 459  460  {
 460  461          if (issvc)
 461  462                  scf_service_destroy(ent);
 462  463          else
 463  464                  scf_instance_destroy(ent);
 464  465  }
 465  466  
 466  467  static int
 467  468  get_pg(const char *pg_name, scf_propertygroup_t *pg)
 468  469  {
 469  470          int ret;
 470  471  
 471  472          if (cur_level != NULL)
 472  473                  ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
 473  474          else if (cur_inst != NULL)
 474  475                  ret = scf_instance_get_pg(cur_inst, pg_name, pg);
 475  476          else
 476  477                  ret = scf_service_get_pg(cur_svc, pg_name, pg);
 477  478  
 478  479          return (ret);
 479  480  }
 480  481  
 481  482  /*
 482  483   * Find a snaplevel in a snapshot.  If get_svc is true, find the service
 483  484   * snaplevel.  Otherwise find the instance snaplevel.
 484  485   *
 485  486   * Returns
 486  487   *   0 - success
 487  488   *   ECONNABORTED - repository connection broken
 488  489   *   ECANCELED - instance containing snap was deleted
 489  490   *   ENOENT - snap has no snaplevels
 490  491   *          - requested snaplevel not found
 491  492   */
 492  493  static int
 493  494  get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
 494  495  {
 495  496          if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
 496  497                  switch (scf_error()) {
 497  498                  case SCF_ERROR_CONNECTION_BROKEN:
 498  499                  case SCF_ERROR_DELETED:
 499  500                  case SCF_ERROR_NOT_FOUND:
 500  501                          return (scferror2errno(scf_error()));
 501  502  
 502  503                  case SCF_ERROR_HANDLE_MISMATCH:
 503  504                  case SCF_ERROR_NOT_BOUND:
 504  505                  case SCF_ERROR_NOT_SET:
 505  506                  default:
 506  507                          bad_error("scf_snapshot_get_base_snaplevel",
 507  508                              scf_error());
 508  509                  }
 509  510          }
 510  511  
 511  512          for (;;) {
 512  513                  ssize_t ssz;
 513  514  
 514  515                  ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
 515  516                  if (ssz >= 0) {
 516  517                          if (!get_svc)
 517  518                                  return (0);
 518  519                  } else {
 519  520                          switch (scf_error()) {
 520  521                          case SCF_ERROR_CONSTRAINT_VIOLATED:
 521  522                                  if (get_svc)
 522  523                                          return (0);
 523  524                                  break;
 524  525  
 525  526                          case SCF_ERROR_DELETED:
 526  527                          case SCF_ERROR_CONNECTION_BROKEN:
 527  528                                  return (scferror2errno(scf_error()));
 528  529  
 529  530                          case SCF_ERROR_NOT_SET:
 530  531                          case SCF_ERROR_NOT_BOUND:
 531  532                          default:
 532  533                                  bad_error("scf_snaplevel_get_instance_name",
 533  534                                      scf_error());
 534  535                          }
 535  536                  }
 536  537  
 537  538                  if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
 538  539                          switch (scf_error()) {
 539  540                          case SCF_ERROR_NOT_FOUND:
 540  541                          case SCF_ERROR_CONNECTION_BROKEN:
 541  542                          case SCF_ERROR_DELETED:
 542  543                                  return (scferror2errno(scf_error()));
 543  544  
 544  545                          case SCF_ERROR_HANDLE_MISMATCH:
 545  546                          case SCF_ERROR_NOT_BOUND:
 546  547                          case SCF_ERROR_NOT_SET:
 547  548                          case SCF_ERROR_INVALID_ARGUMENT:
 548  549                          default:
 549  550                                  bad_error("scf_snaplevel_get_next_snaplevel",
 550  551                                      scf_error());
 551  552                          }
 552  553                  }
 553  554          }
 554  555  }
 555  556  
 556  557  /*
 557  558   * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
 558  559   * a running snapshot, and that snapshot has an instance snaplevel, set pg to
 559  560   * the property group named name in it.  If it doesn't have a running
 560  561   * snapshot, set pg to the instance's current property group named name.
 561  562   *
 562  563   * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
 563  564   * its instances.  If one has a running snapshot with a service snaplevel, set
 564  565   * pg to the property group named name in it.  If no such snaplevel could be
 565  566   * found, set pg to the service's current property group named name.
 566  567   *
 567  568   * iter, inst, snap, and snpl are required scratch objects.
 568  569   *
 569  570   * Returns
 570  571   *   0 - success
 571  572   *   ECONNABORTED - repository connection broken
 572  573   *   ECANCELED - ent was deleted
 573  574   *   ENOENT - no such property group
 574  575   *   EINVAL - name is an invalid property group name
 575  576   *   EBADF - found running snapshot is missing a snaplevel
 576  577   */
 577  578  static int
 578  579  entity_get_running_pg(void *ent, int issvc, const char *name,
 579  580      scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
 580  581      scf_snapshot_t *snap, scf_snaplevel_t *snpl)
 581  582  {
 582  583          int r;
 583  584  
 584  585          if (issvc) {
 585  586                  /* Search for an instance with a running snapshot. */
 586  587                  if (scf_iter_service_instances(iter, ent) != 0) {
 587  588                          switch (scf_error()) {
 588  589                          case SCF_ERROR_DELETED:
 589  590                          case SCF_ERROR_CONNECTION_BROKEN:
 590  591                                  return (scferror2errno(scf_error()));
 591  592  
 592  593                          case SCF_ERROR_NOT_SET:
 593  594                          case SCF_ERROR_NOT_BOUND:
 594  595                          case SCF_ERROR_HANDLE_MISMATCH:
 595  596                          default:
 596  597                                  bad_error("scf_iter_service_instances",
 597  598                                      scf_error());
 598  599                          }
 599  600                  }
 600  601  
 601  602                  for (;;) {
 602  603                          r = scf_iter_next_instance(iter, inst);
 603  604                          if (r == 0) {
 604  605                                  if (scf_service_get_pg(ent, name, pg) == 0)
 605  606                                          return (0);
 606  607  
 607  608                                  switch (scf_error()) {
 608  609                                  case SCF_ERROR_DELETED:
 609  610                                  case SCF_ERROR_NOT_FOUND:
 610  611                                  case SCF_ERROR_INVALID_ARGUMENT:
 611  612                                  case SCF_ERROR_CONNECTION_BROKEN:
 612  613                                          return (scferror2errno(scf_error()));
 613  614  
 614  615                                  case SCF_ERROR_NOT_BOUND:
 615  616                                  case SCF_ERROR_HANDLE_MISMATCH:
 616  617                                  case SCF_ERROR_NOT_SET:
 617  618                                  default:
 618  619                                          bad_error("scf_service_get_pg",
 619  620                                              scf_error());
 620  621                                  }
 621  622                          }
 622  623                          if (r != 1) {
 623  624                                  switch (scf_error()) {
 624  625                                  case SCF_ERROR_DELETED:
 625  626                                  case SCF_ERROR_CONNECTION_BROKEN:
 626  627                                          return (scferror2errno(scf_error()));
 627  628  
 628  629                                  case SCF_ERROR_INVALID_ARGUMENT:
 629  630                                  case SCF_ERROR_NOT_SET:
 630  631                                  case SCF_ERROR_NOT_BOUND:
 631  632                                  case SCF_ERROR_HANDLE_MISMATCH:
 632  633                                  default:
 633  634                                          bad_error("scf_iter_next_instance",
 634  635                                              scf_error());
 635  636                                  }
 636  637                          }
 637  638  
 638  639                          if (scf_instance_get_snapshot(inst, snap_running,
 639  640                              snap) == 0)
 640  641                                  break;
 641  642  
 642  643                          switch (scf_error()) {
 643  644                          case SCF_ERROR_NOT_FOUND:
 644  645                          case SCF_ERROR_DELETED:
 645  646                                  continue;
 646  647  
 647  648                          case SCF_ERROR_CONNECTION_BROKEN:
 648  649                                  return (ECONNABORTED);
 649  650  
 650  651                          case SCF_ERROR_HANDLE_MISMATCH:
 651  652                          case SCF_ERROR_INVALID_ARGUMENT:
 652  653                          case SCF_ERROR_NOT_SET:
 653  654                          case SCF_ERROR_NOT_BOUND:
 654  655                          default:
 655  656                                  bad_error("scf_instance_get_snapshot",
 656  657                                      scf_error());
 657  658                          }
 658  659                  }
 659  660          } else {
 660  661                  if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
 661  662                          switch (scf_error()) {
 662  663                          case SCF_ERROR_NOT_FOUND:
 663  664                                  break;
 664  665  
 665  666                          case SCF_ERROR_DELETED:
 666  667                          case SCF_ERROR_CONNECTION_BROKEN:
 667  668                                  return (scferror2errno(scf_error()));
 668  669  
 669  670                          case SCF_ERROR_NOT_BOUND:
 670  671                          case SCF_ERROR_HANDLE_MISMATCH:
 671  672                          case SCF_ERROR_INVALID_ARGUMENT:
 672  673                          case SCF_ERROR_NOT_SET:
 673  674                          default:
 674  675                                  bad_error("scf_instance_get_snapshot",
 675  676                                      scf_error());
 676  677                          }
 677  678  
 678  679                          if (scf_instance_get_pg(ent, name, pg) == 0)
 679  680                                  return (0);
 680  681  
 681  682                          switch (scf_error()) {
 682  683                          case SCF_ERROR_DELETED:
 683  684                          case SCF_ERROR_NOT_FOUND:
 684  685                          case SCF_ERROR_INVALID_ARGUMENT:
 685  686                          case SCF_ERROR_CONNECTION_BROKEN:
 686  687                                  return (scferror2errno(scf_error()));
 687  688  
 688  689                          case SCF_ERROR_NOT_BOUND:
 689  690                          case SCF_ERROR_HANDLE_MISMATCH:
 690  691                          case SCF_ERROR_NOT_SET:
 691  692                          default:
 692  693                                  bad_error("scf_instance_get_pg", scf_error());
 693  694                          }
 694  695                  }
 695  696          }
 696  697  
 697  698          r = get_snaplevel(snap, issvc, snpl);
 698  699          switch (r) {
 699  700          case 0:
 700  701                  break;
 701  702  
 702  703          case ECONNABORTED:
 703  704          case ECANCELED:
 704  705                  return (r);
 705  706  
 706  707          case ENOENT:
 707  708                  return (EBADF);
 708  709  
 709  710          default:
 710  711                  bad_error("get_snaplevel", r);
 711  712          }
 712  713  
 713  714          if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
 714  715                  return (0);
 715  716  
 716  717          switch (scf_error()) {
 717  718          case SCF_ERROR_DELETED:
 718  719          case SCF_ERROR_INVALID_ARGUMENT:
 719  720          case SCF_ERROR_CONNECTION_BROKEN:
 720  721          case SCF_ERROR_NOT_FOUND:
 721  722                  return (scferror2errno(scf_error()));
 722  723  
 723  724          case SCF_ERROR_NOT_BOUND:
 724  725          case SCF_ERROR_HANDLE_MISMATCH:
 725  726          case SCF_ERROR_NOT_SET:
 726  727          default:
 727  728                  bad_error("scf_snaplevel_get_pg", scf_error());
 728  729                  /* NOTREACHED */
 729  730          }
 730  731  }
 731  732  
 732  733  /*
 733  734   * To be registered with atexit().
 734  735   */
 735  736  static void
 736  737  remove_tempfile(void)
 737  738  {
 738  739          int ret;
 739  740  
 740  741          if (tempfile != NULL) {
 741  742                  if (fclose(tempfile) == EOF)
 742  743                          (void) warn(gettext("Could not close temporary file"));
 743  744                  tempfile = NULL;
 744  745          }
 745  746  
 746  747          if (tempfilename[0] != '\0') {
 747  748                  do {
 748  749                          ret = remove(tempfilename);
 749  750                  } while (ret == -1 && errno == EINTR);
 750  751                  if (ret == -1)
 751  752                          warn(gettext("Could not remove temporary file"));
 752  753                  tempfilename[0] = '\0';
 753  754          }
 754  755  }
 755  756  
 756  757  /*
 757  758   * Launch private svc.configd(1M) for manipulating alternate repositories.
 758  759   */
 759  760  static void
 760  761  start_private_repository(engine_state_t *est)
 761  762  {
 762  763          int fd, stat;
 763  764          struct door_info info;
 764  765          pid_t pid;
 765  766  
 766  767          /*
 767  768           * 1.  Create a temporary file for the door.
 768  769           */
 769  770          if (est->sc_repo_doorname != NULL)
 770  771                  free((void *)est->sc_repo_doorname);
 771  772  
 772  773          est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
 773  774          if (est->sc_repo_doorname == NULL)
 774  775                  uu_die(gettext("Could not acquire temporary filename"));
 775  776  
 776  777          fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
 777  778          if (fd < 0)
 778  779                  uu_die(gettext("Could not create temporary file for "
 779  780                      "repository server"));
 780  781  
 781  782          (void) close(fd);
 782  783  
 783  784          /*
 784  785           * 2.  Launch a configd with that door, using the specified
 785  786           * repository.
 786  787           */
 787  788          if ((est->sc_repo_pid = fork()) == 0) {
 788  789                  (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
 789  790                      "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
 790  791                      NULL);
 791  792                  uu_die(gettext("Could not execute %s"), est->sc_repo_server);
 792  793          } else if (est->sc_repo_pid == -1)
 793  794                  uu_die(gettext("Attempt to fork failed"));
 794  795  
 795  796          do {
 796  797                  pid = waitpid(est->sc_repo_pid, &stat, 0);
 797  798          } while (pid == -1 && errno == EINTR);
 798  799  
 799  800          if (pid == -1)
 800  801                  uu_die(gettext("Could not waitpid() for repository server"));
 801  802  
 802  803          if (!WIFEXITED(stat)) {
 803  804                  uu_die(gettext("Repository server failed (status %d).\n"),
 804  805                      stat);
 805  806          } else if (WEXITSTATUS(stat) != 0) {
 806  807                  uu_die(gettext("Repository server failed (exit %d).\n"),
 807  808                      WEXITSTATUS(stat));
 808  809          }
 809  810  
 810  811          /*
 811  812           * See if it was successful by checking if the door is a door.
 812  813           */
 813  814  
 814  815          fd = open(est->sc_repo_doorname, O_RDWR);
 815  816          if (fd < 0)
 816  817                  uu_die(gettext("Could not open door \"%s\""),
 817  818                      est->sc_repo_doorname);
 818  819  
 819  820          if (door_info(fd, &info) < 0)
 820  821                  uu_die(gettext("Unexpected door_info() error"));
 821  822  
 822  823          if (close(fd) == -1)
 823  824                  warn(gettext("Could not close repository door"),
 824  825                      strerror(errno));
 825  826  
 826  827          est->sc_repo_pid = info.di_target;
 827  828  }
 828  829  
 829  830  void
 830  831  lscf_cleanup(void)
 831  832  {
 832  833          /*
 833  834           * In the case where we've launched a private svc.configd(1M)
 834  835           * instance, we must terminate our child and remove the temporary
 835  836           * rendezvous point.
 836  837           */
 837  838          if (est->sc_repo_pid > 0) {
 838  839                  (void) kill(est->sc_repo_pid, SIGTERM);
 839  840                  (void) waitpid(est->sc_repo_pid, NULL, 0);
 840  841                  (void) unlink(est->sc_repo_doorname);
 841  842  
 842  843                  est->sc_repo_pid = 0;
 843  844          }
 844  845  }
 845  846  
 846  847  void
 847  848  unselect_cursnap(void)
 848  849  {
 849  850          void *cookie;
 850  851  
 851  852          cur_level = NULL;
 852  853  
 853  854          cookie = NULL;
 854  855          while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
 855  856                  scf_snaplevel_destroy(cur_elt->sl);
 856  857                  free(cur_elt);
 857  858          }
 858  859  
 859  860          scf_snapshot_destroy(cur_snap);
 860  861          cur_snap = NULL;
 861  862  }
 862  863  
 863  864  void
 864  865  lscf_prep_hndl(void)
 865  866  {
 866  867          if (g_hndl != NULL)
 867  868                  return;
 868  869  
 869  870          g_hndl = scf_handle_create(SCF_VERSION);
 870  871          if (g_hndl == NULL)
 871  872                  scfdie();
 872  873  
 873  874          if (est->sc_repo_filename != NULL)
 874  875                  start_private_repository(est);
 875  876  
 876  877          if (est->sc_repo_doorname != NULL) {
 877  878                  scf_value_t *repo_value;
 878  879                  int ret;
 879  880  
 880  881                  repo_value = scf_value_create(g_hndl);
 881  882                  if (repo_value == NULL)
 882  883                          scfdie();
 883  884  
 884  885                  ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
 885  886                  assert(ret == SCF_SUCCESS);
 886  887  
 887  888                  if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
 888  889                      SCF_SUCCESS)
 889  890                          scfdie();
 890  891  
 891  892                  scf_value_destroy(repo_value);
 892  893          }
 893  894  
 894  895          if (scf_handle_bind(g_hndl) != 0)
 895  896                  uu_die(gettext("Could not connect to repository server: %s.\n"),
 896  897                      scf_strerror(scf_error()));
 897  898  
 898  899          cur_scope = scf_scope_create(g_hndl);
 899  900          if (cur_scope == NULL)
 900  901                  scfdie();
 901  902  
 902  903          if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
 903  904                  scfdie();
 904  905  }
 905  906  
 906  907  static void
 907  908  repository_teardown(void)
 908  909  {
 909  910          if (g_hndl != NULL) {
 910  911                  if (cur_snap != NULL)
 911  912                          unselect_cursnap();
 912  913                  scf_instance_destroy(cur_inst);
 913  914                  scf_service_destroy(cur_svc);
 914  915                  scf_scope_destroy(cur_scope);
 915  916                  scf_handle_destroy(g_hndl);
 916  917                  cur_inst = NULL;
 917  918                  cur_svc = NULL;
 918  919                  cur_scope = NULL;
 919  920                  g_hndl = NULL;
 920  921                  lscf_cleanup();
 921  922          }
 922  923  }
 923  924  
 924  925  void
 925  926  lscf_set_repository(const char *repfile, int force)
 926  927  {
 927  928          repository_teardown();
 928  929  
 929  930          if (est->sc_repo_filename != NULL) {
 930  931                  free((void *)est->sc_repo_filename);
 931  932                  est->sc_repo_filename = NULL;
 932  933          }
 933  934  
 934  935          if ((force == 0) && (access(repfile, R_OK) != 0)) {
 935  936                  /*
 936  937                   * Repository file does not exist
 937  938                   * or has no read permission.
 938  939                   */
 939  940                  warn(gettext("Cannot access \"%s\": %s\n"),
 940  941                      repfile, strerror(errno));
 941  942          } else {
 942  943                  est->sc_repo_filename = safe_strdup(repfile);
 943  944          }
 944  945  
 945  946          lscf_prep_hndl();
 946  947  }
 947  948  
 948  949  void
 949  950  lscf_init()
 950  951  {
 951  952          if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
 952  953              (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
 953  954              (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
 954  955              0 ||
 955  956              (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
 956  957                  scfdie();
 957  958  
 958  959          max_scf_len = max_scf_fmri_len;
 959  960          if (max_scf_name_len > max_scf_len)
 960  961                  max_scf_len = max_scf_name_len;
 961  962          if (max_scf_pg_type_len > max_scf_len)
 962  963                  max_scf_len = max_scf_pg_type_len;
 963  964          /*
 964  965           * When a value of type opaque is represented as a string, the
 965  966           * string contains 2 characters for every byte of data.  That is
 966  967           * because the string contains the hex representation of the opaque
 967  968           * value.
 968  969           */
 969  970          if (2 * max_scf_value_len > max_scf_len)
 970  971                  max_scf_len = 2 * max_scf_value_len;
 971  972  
 972  973          if (atexit(remove_tempfile) != 0)
 973  974                  uu_die(gettext("Could not register atexit() function"));
 974  975  
 975  976          emsg_entity_not_selected = gettext("An entity is not selected.\n");
 976  977          emsg_permission_denied = gettext("Permission denied.\n");
 977  978          emsg_create_xml = gettext("Could not create XML node.\n");
 978  979          emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
 979  980          emsg_invalid_for_snapshot =
 980  981              gettext("Invalid operation on a snapshot.\n");
 981  982          emsg_read_only = gettext("Backend read-only.\n");
 982  983          emsg_deleted = gettext("Current selection has been deleted.\n");
 983  984          emsg_invalid_pg_name =
 984  985              gettext("Invalid property group name \"%s\".\n");
 985  986          emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
 986  987          emsg_no_such_pg = gettext("No such property group \"%s\".\n");
 987  988          emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
 988  989              "with invalid name \"%s\".\n");
 989  990          emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
 990  991              "group with invalid name \"%s\" or type \"%s\".\n");
 991  992          emsg_pg_added = gettext("%s changed unexpectedly "
 992  993              "(property group \"%s\" added).\n");
 993  994          emsg_pg_changed = gettext("%s changed unexpectedly "
 994  995              "(property group \"%s\" changed).\n");
 995  996          emsg_pg_deleted = gettext("%s changed unexpectedly "
 996  997              "(property group \"%s\" or an ancestor was deleted).\n");
 997  998          emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
 998  999              "in %s (permission denied).\n");
 999 1000          emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 1001              "in %s (permission denied).\n");
1001 1002          emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 1003              "in %s (permission denied).\n");
1003 1004          emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 1005              "(permission denied).\n");
1005 1006          emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 1007              "new dependent \"%s\" because it already exists).  Warning: The "
1007 1008              "current dependent's target (%s) does not exist.\n");
1008 1009          emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 1010              "dependent \"%s\" because it already exists).  Warning: The "
1010 1011              "current dependent's target (%s) does not have a dependency named "
1011 1012              "\"%s\" as expected.\n");
1012 1013  
1013 1014          string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 1015              offsetof(string_list_t, node), NULL, 0);
1015 1016          snaplevel_pool = uu_list_pool_create("snaplevels",
1016 1017              sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 1018              NULL, 0);
1018 1019  }
1019 1020  
1020 1021  
1021 1022  static const char *
1022 1023  prop_to_typestr(const scf_property_t *prop)
1023 1024  {
1024 1025          scf_type_t ty;
1025 1026  
1026 1027          if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 1028                  scfdie();
1028 1029  
1029 1030          return (scf_type_to_string(ty));
1030 1031  }
1031 1032  
1032 1033  static scf_type_t
1033 1034  string_to_type(const char *type)
1034 1035  {
1035 1036          size_t len = strlen(type);
1036 1037          char *buf;
1037 1038  
1038 1039          if (len == 0 || type[len - 1] != ':')
1039 1040                  return (SCF_TYPE_INVALID);
1040 1041  
1041 1042          buf = (char *)alloca(len + 1);
1042 1043          (void) strlcpy(buf, type, len + 1);
1043 1044          buf[len - 1] = 0;
1044 1045  
1045 1046          return (scf_string_to_type(buf));
1046 1047  }
1047 1048  
1048 1049  static scf_value_t *
1049 1050  string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 1051  {
1051 1052          scf_value_t *v;
1052 1053          char *dup, *nstr;
1053 1054          size_t len;
1054 1055  
1055 1056          v = scf_value_create(g_hndl);
1056 1057          if (v == NULL)
1057 1058                  scfdie();
1058 1059  
1059 1060          len = strlen(str);
1060 1061          if (require_quotes &&
1061 1062              (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 1063                  semerr(gettext("Multiple string values or string values "
1063 1064                      "with spaces must be quoted with '\"'.\n"));
1064 1065                  scf_value_destroy(v);
1065 1066                  return (NULL);
1066 1067          }
1067 1068  
1068 1069          nstr = dup = safe_strdup(str);
1069 1070          if (dup[0] == '\"') {
1070 1071                  /*
1071 1072                   * Strip out the first and the last quote.
1072 1073                   */
1073 1074                  dup[len - 1] = '\0';
1074 1075                  nstr = dup + 1;
1075 1076          }
1076 1077  
1077 1078          if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 1079                  assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 1080                  semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 1081                      scf_type_to_string(ty), nstr);
1081 1082                  scf_value_destroy(v);
1082 1083                  v = NULL;
1083 1084          }
1084 1085          free(dup);
1085 1086          return (v);
1086 1087  }
1087 1088  
1088 1089  /*
1089 1090   * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 1091   * Optionally append a comment prefix ('#') to newlines ('\n').
1091 1092   */
1092 1093  static int
1093 1094  quote_and_print(const char *str, FILE *strm, int commentnl)
1094 1095  {
1095 1096          const char *cp;
1096 1097  
1097 1098          for (cp = str; *cp != '\0'; ++cp) {
1098 1099                  if (*cp == '"' || *cp == '\\')
1099 1100                          (void) putc('\\', strm);
1100 1101  
1101 1102                  (void) putc(*cp, strm);
1102 1103  
1103 1104                  if (commentnl && *cp == '\n') {
1104 1105                          (void) putc('#', strm);
1105 1106                  }
1106 1107          }
1107 1108  
1108 1109          return (ferror(strm));
1109 1110  }
1110 1111  
1111 1112  /*
1112 1113   * These wrappers around lowlevel functions provide consistent error checking
1113 1114   * and warnings.
1114 1115   */
1115 1116  static int
1116 1117  pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 1118  {
1118 1119          if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 1120                  return (0);
1120 1121  
1121 1122          if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 1123                  scfdie();
1123 1124  
1124 1125          if (g_verbose) {
1125 1126                  ssize_t len;
1126 1127                  char *fmri;
1127 1128  
1128 1129                  len = scf_pg_to_fmri(pg, NULL, 0);
1129 1130                  if (len < 0)
1130 1131                          scfdie();
1131 1132  
1132 1133                  fmri = safe_malloc(len + 1);
1133 1134  
1134 1135                  if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 1136                          scfdie();
1136 1137  
1137 1138                  warn(gettext("Expected property %s of property group %s is "
1138 1139                      "missing.\n"), propname, fmri);
1139 1140  
1140 1141                  free(fmri);
1141 1142          }
1142 1143  
1143 1144          return (-1);
1144 1145  }
1145 1146  
1146 1147  static int
1147 1148  prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 1149  {
1149 1150          scf_type_t pty;
1150 1151  
1151 1152          if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 1153                  scfdie();
1153 1154  
1154 1155          if (ty == pty)
1155 1156                  return (0);
1156 1157  
1157 1158          if (g_verbose) {
1158 1159                  ssize_t len;
1159 1160                  char *fmri;
1160 1161                  const char *tystr;
1161 1162  
1162 1163                  len = scf_property_to_fmri(prop, NULL, 0);
1163 1164                  if (len < 0)
1164 1165                          scfdie();
1165 1166  
1166 1167                  fmri = safe_malloc(len + 1);
1167 1168  
1168 1169                  if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 1170                          scfdie();
1170 1171  
1171 1172                  tystr = scf_type_to_string(ty);
1172 1173                  if (tystr == NULL)
1173 1174                          tystr = "?";
1174 1175  
1175 1176                  warn(gettext("Property %s is not of expected type %s.\n"),
1176 1177                      fmri, tystr);
1177 1178  
1178 1179                  free(fmri);
1179 1180          }
1180 1181  
1181 1182          return (-1);
1182 1183  }
1183 1184  
1184 1185  static int
1185 1186  prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 1187  {
1187 1188          scf_error_t err;
1188 1189  
1189 1190          if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 1191                  return (0);
1191 1192  
1192 1193          err = scf_error();
1193 1194  
1194 1195          if (err != SCF_ERROR_NOT_FOUND &&
1195 1196              err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 1197              err != SCF_ERROR_PERMISSION_DENIED)
1197 1198                  scfdie();
1198 1199  
1199 1200          if (g_verbose) {
1200 1201                  ssize_t len;
1201 1202                  char *fmri, *emsg;
1202 1203  
1203 1204                  len = scf_property_to_fmri(prop, NULL, 0);
1204 1205                  if (len < 0)
1205 1206                          scfdie();
1206 1207  
1207 1208                  fmri = safe_malloc(len + 1);
1208 1209  
1209 1210                  if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 1211                          scfdie();
1211 1212  
1212 1213                  if (err == SCF_ERROR_NOT_FOUND)
1213 1214                          emsg = gettext("Property %s has no values; expected "
1214 1215                              "one.\n");
1215 1216                  else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 1217                          emsg = gettext("Property %s has multiple values; "
1217 1218                              "expected one.\n");
1218 1219                  else
1219 1220                          emsg = gettext("No permission to read property %s.\n");
1220 1221  
1221 1222                  warn(emsg, fmri);
1222 1223  
1223 1224                  free(fmri);
1224 1225          }
1225 1226  
1226 1227          return (-1);
1227 1228  }
1228 1229  
1229 1230  
1230 1231  static boolean_t
1231 1232  snaplevel_is_instance(const scf_snaplevel_t *level)
1232 1233  {
1233 1234          if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 1235                  if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 1236                          scfdie();
1236 1237                  return (0);
1237 1238          } else {
1238 1239                  return (1);
1239 1240          }
1240 1241  }
1241 1242  
1242 1243  /*
1243 1244   * Decode FMRI into a service or instance, and put the result in *ep.  If
1244 1245   * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1245 1246   * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1246 1247   * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1247 1248   * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1248 1249   * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 1250   * whether *ep is a service.
1250 1251   */
1251 1252  static scf_error_t
1252 1253  fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 1254  {
1254 1255          char *fmri_copy;
1255 1256          const char *sstr, *istr, *pgstr;
1256 1257          scf_service_t *svc;
1257 1258          scf_instance_t *inst;
1258 1259  
1259 1260          fmri_copy = strdup(fmri);
1260 1261          if (fmri_copy == NULL)
1261 1262                  return (SCF_ERROR_NO_MEMORY);
1262 1263  
1263 1264          if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 1265              SCF_SUCCESS) {
1265 1266                  free(fmri_copy);
1266 1267                  return (SCF_ERROR_INVALID_ARGUMENT);
1267 1268          }
1268 1269  
1269 1270          free(fmri_copy);
1270 1271  
1271 1272          if (sstr == NULL || pgstr != NULL)
1272 1273                  return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273 1274  
1274 1275          if (istr == NULL) {
1275 1276                  svc = scf_service_create(h);
1276 1277                  if (svc == NULL)
1277 1278                          return (SCF_ERROR_NO_MEMORY);
1278 1279  
1279 1280                  if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 1281                      SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 1282                          if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 1283                                  scfdie();
1283 1284  
1284 1285                          return (SCF_ERROR_NOT_FOUND);
1285 1286                  }
1286 1287  
1287 1288                  *ep = svc;
1288 1289                  *isservice = 1;
1289 1290          } else {
1290 1291                  inst = scf_instance_create(h);
1291 1292                  if (inst == NULL)
1292 1293                          return (SCF_ERROR_NO_MEMORY);
1293 1294  
1294 1295                  if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 1296                      NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 1297                          if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 1298                                  scfdie();
1298 1299  
1299 1300                          return (SCF_ERROR_NOT_FOUND);
1300 1301                  }
1301 1302  
1302 1303                  *ep = inst;
1303 1304                  *isservice = 0;
1304 1305          }
1305 1306  
1306 1307          return (SCF_ERROR_NONE);
1307 1308  }
1308 1309  
1309 1310  /*
1310 1311   * Create the entity named by fmri.  Place a pointer to its libscf handle in
1311 1312   * *ep, and set or clear *isservicep if it is a service or an instance.
1312 1313   * Returns
1313 1314   *   SCF_ERROR_NONE - success
1314 1315   *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 1316   *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 1317   *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 1318   *   SCF_ERROR_NOT_FOUND - no such scope
1318 1319   *   SCF_ERROR_PERMISSION_DENIED
1319 1320   *   SCF_ERROR_BACKEND_READONLY
1320 1321   *   SCF_ERROR_BACKEND_ACCESS
1321 1322   */
1322 1323  static scf_error_t
1323 1324  create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 1325  {
1325 1326          char *fmri_copy;
1326 1327          const char *scstr, *sstr, *istr, *pgstr;
1327 1328          scf_scope_t *scope = NULL;
1328 1329          scf_service_t *svc = NULL;
1329 1330          scf_instance_t *inst = NULL;
1330 1331          scf_error_t scfe;
1331 1332  
1332 1333          fmri_copy = safe_strdup(fmri);
1333 1334  
1334 1335          if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 1336              0) {
1336 1337                  free(fmri_copy);
1337 1338                  return (SCF_ERROR_INVALID_ARGUMENT);
1338 1339          }
1339 1340  
1340 1341          if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 1342                  free(fmri_copy);
1342 1343                  return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343 1344          }
1344 1345  
1345 1346          *ep = NULL;
1346 1347  
1347 1348          if ((scope = scf_scope_create(h)) == NULL ||
1348 1349              (svc = scf_service_create(h)) == NULL ||
1349 1350              (inst = scf_instance_create(h)) == NULL) {
1350 1351                  scfe = SCF_ERROR_NO_MEMORY;
1351 1352                  goto out;
1352 1353          }
1353 1354  
1354 1355  get_scope:
1355 1356          if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 1357                  switch (scf_error()) {
1357 1358                  case SCF_ERROR_CONNECTION_BROKEN:
1358 1359                          scfdie();
1359 1360                          /* NOTREACHED */
1360 1361  
1361 1362                  case SCF_ERROR_NOT_FOUND:
1362 1363                          scfe = SCF_ERROR_NOT_FOUND;
1363 1364                          goto out;
1364 1365  
1365 1366                  case SCF_ERROR_HANDLE_MISMATCH:
1366 1367                  case SCF_ERROR_NOT_BOUND:
1367 1368                  case SCF_ERROR_INVALID_ARGUMENT:
1368 1369                  default:
1369 1370                          bad_error("scf_handle_get_scope", scf_error());
1370 1371                  }
1371 1372          }
1372 1373  
1373 1374  get_svc:
1374 1375          if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 1376                  switch (scf_error()) {
1376 1377                  case SCF_ERROR_CONNECTION_BROKEN:
1377 1378                          scfdie();
1378 1379                          /* NOTREACHED */
1379 1380  
1380 1381                  case SCF_ERROR_DELETED:
1381 1382                          goto get_scope;
1382 1383  
1383 1384                  case SCF_ERROR_NOT_FOUND:
1384 1385                          break;
1385 1386  
1386 1387                  case SCF_ERROR_HANDLE_MISMATCH:
1387 1388                  case SCF_ERROR_INVALID_ARGUMENT:
1388 1389                  case SCF_ERROR_NOT_BOUND:
1389 1390                  case SCF_ERROR_NOT_SET:
1390 1391                  default:
1391 1392                          bad_error("scf_scope_get_service", scf_error());
1392 1393                  }
1393 1394  
1394 1395                  if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 1396                          switch (scf_error()) {
1396 1397                          case SCF_ERROR_CONNECTION_BROKEN:
1397 1398                                  scfdie();
1398 1399                                  /* NOTREACHED */
1399 1400  
1400 1401                          case SCF_ERROR_DELETED:
1401 1402                                  goto get_scope;
1402 1403  
1403 1404                          case SCF_ERROR_PERMISSION_DENIED:
1404 1405                          case SCF_ERROR_BACKEND_READONLY:
1405 1406                          case SCF_ERROR_BACKEND_ACCESS:
1406 1407                                  scfe = scf_error();
1407 1408                                  goto out;
1408 1409  
1409 1410                          case SCF_ERROR_HANDLE_MISMATCH:
1410 1411                          case SCF_ERROR_INVALID_ARGUMENT:
1411 1412                          case SCF_ERROR_NOT_BOUND:
1412 1413                          case SCF_ERROR_NOT_SET:
1413 1414                          default:
1414 1415                                  bad_error("scf_scope_get_service", scf_error());
1415 1416                          }
1416 1417                  }
1417 1418          }
1418 1419  
1419 1420          if (istr == NULL) {
1420 1421                  scfe = SCF_ERROR_NONE;
1421 1422                  *ep = svc;
1422 1423                  *isservicep = 1;
1423 1424                  goto out;
1424 1425          }
1425 1426  
1426 1427  get_inst:
1427 1428          if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 1429                  switch (scf_error()) {
1429 1430                  case SCF_ERROR_CONNECTION_BROKEN:
1430 1431                          scfdie();
1431 1432                          /* NOTREACHED */
1432 1433  
1433 1434                  case SCF_ERROR_DELETED:
1434 1435                          goto get_svc;
1435 1436  
1436 1437                  case SCF_ERROR_NOT_FOUND:
1437 1438                          break;
1438 1439  
1439 1440                  case SCF_ERROR_HANDLE_MISMATCH:
1440 1441                  case SCF_ERROR_INVALID_ARGUMENT:
1441 1442                  case SCF_ERROR_NOT_BOUND:
1442 1443                  case SCF_ERROR_NOT_SET:
1443 1444                  default:
1444 1445                          bad_error("scf_service_get_instance", scf_error());
1445 1446                  }
1446 1447  
1447 1448                  if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 1449                          switch (scf_error()) {
1449 1450                          case SCF_ERROR_CONNECTION_BROKEN:
1450 1451                                  scfdie();
1451 1452                                  /* NOTREACHED */
1452 1453  
1453 1454                          case SCF_ERROR_DELETED:
1454 1455                                  goto get_svc;
1455 1456  
1456 1457                          case SCF_ERROR_PERMISSION_DENIED:
1457 1458                          case SCF_ERROR_BACKEND_READONLY:
1458 1459                          case SCF_ERROR_BACKEND_ACCESS:
1459 1460                                  scfe = scf_error();
1460 1461                                  goto out;
1461 1462  
1462 1463                          case SCF_ERROR_HANDLE_MISMATCH:
1463 1464                          case SCF_ERROR_INVALID_ARGUMENT:
1464 1465                          case SCF_ERROR_NOT_BOUND:
1465 1466                          case SCF_ERROR_NOT_SET:
1466 1467                          default:
1467 1468                                  bad_error("scf_service_add_instance",
1468 1469                                      scf_error());
1469 1470                          }
1470 1471                  }
1471 1472          }
1472 1473  
1473 1474          scfe = SCF_ERROR_NONE;
1474 1475          *ep = inst;
1475 1476          *isservicep = 0;
1476 1477  
1477 1478  out:
1478 1479          if (*ep != inst)
1479 1480                  scf_instance_destroy(inst);
1480 1481          if (*ep != svc)
1481 1482                  scf_service_destroy(svc);
1482 1483          scf_scope_destroy(scope);
1483 1484          free(fmri_copy);
1484 1485          return (scfe);
1485 1486  }
1486 1487  
1487 1488  /*
1488 1489   * Create or update a snapshot of inst.  snap is a required scratch object.
1489 1490   *
1490 1491   * Returns
1491 1492   *   0 - success
1492 1493   *   ECONNABORTED - repository connection broken
1493 1494   *   EPERM - permission denied
1494 1495   *   ENOSPC - configd is out of resources
1495 1496   *   ECANCELED - inst was deleted
1496 1497   *   -1 - unknown libscf error (message printed)
1497 1498   */
1498 1499  static int
1499 1500  take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 1501  {
1501 1502  again:
1502 1503          if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 1504                  if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 1505                          switch (scf_error()) {
1505 1506                          case SCF_ERROR_CONNECTION_BROKEN:
1506 1507                          case SCF_ERROR_PERMISSION_DENIED:
1507 1508                          case SCF_ERROR_NO_RESOURCES:
1508 1509                                  return (scferror2errno(scf_error()));
1509 1510  
1510 1511                          case SCF_ERROR_NOT_SET:
1511 1512                          case SCF_ERROR_INVALID_ARGUMENT:
1512 1513                          default:
1513 1514                                  bad_error("_scf_snapshot_take_attach",
1514 1515                                      scf_error());
1515 1516                          }
1516 1517                  }
1517 1518          } else {
1518 1519                  switch (scf_error()) {
1519 1520                  case SCF_ERROR_NOT_FOUND:
1520 1521                          break;
1521 1522  
1522 1523                  case SCF_ERROR_DELETED:
1523 1524                  case SCF_ERROR_CONNECTION_BROKEN:
1524 1525                          return (scferror2errno(scf_error()));
1525 1526  
1526 1527                  case SCF_ERROR_HANDLE_MISMATCH:
1527 1528                  case SCF_ERROR_NOT_BOUND:
1528 1529                  case SCF_ERROR_INVALID_ARGUMENT:
1529 1530                  case SCF_ERROR_NOT_SET:
1530 1531                  default:
1531 1532                          bad_error("scf_instance_get_snapshot", scf_error());
1532 1533                  }
1533 1534  
1534 1535                  if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 1536                          switch (scf_error()) {
1536 1537                          case SCF_ERROR_EXISTS:
1537 1538                                  goto again;
1538 1539  
1539 1540                          case SCF_ERROR_CONNECTION_BROKEN:
1540 1541                          case SCF_ERROR_NO_RESOURCES:
1541 1542                          case SCF_ERROR_PERMISSION_DENIED:
1542 1543                                  return (scferror2errno(scf_error()));
1543 1544  
1544 1545                          default:
1545 1546                                  scfwarn();
1546 1547                                  return (-1);
1547 1548  
1548 1549                          case SCF_ERROR_NOT_SET:
1549 1550                          case SCF_ERROR_INTERNAL:
1550 1551                          case SCF_ERROR_INVALID_ARGUMENT:
1551 1552                          case SCF_ERROR_HANDLE_MISMATCH:
1552 1553                                  bad_error("_scf_snapshot_take_new",
1553 1554                                      scf_error());
1554 1555                          }
1555 1556                  }
1556 1557          }
1557 1558  
1558 1559          return (0);
1559 1560  }
1560 1561  
1561 1562  static int
1562 1563  refresh_running_snapshot(void *entity)
1563 1564  {
1564 1565          scf_snapshot_t *snap;
1565 1566          int r;
1566 1567  
1567 1568          if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 1569                  scfdie();
1569 1570          r = take_snap(entity, snap_running, snap);
1570 1571          scf_snapshot_destroy(snap);
1571 1572  
1572 1573          return (r);
1573 1574  }
1574 1575  
1575 1576  /*
1576 1577   * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1577 1578   * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 1579   * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1579 1580   * for scratch space.  Returns
1580 1581   *   0 - success
1581 1582   *   ECONNABORTED - repository connection broken
1582 1583   *   ECANCELED - entity was deleted
1583 1584   *   EACCES - backend denied access
1584 1585   *   EPERM - permission denied
1585 1586   *   ENOSPC - repository server out of resources
1586 1587   *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1587 1588   */
1588 1589  static int
1589 1590  refresh_entity(int isservice, void *entity, const char *fmri,
1590 1591      scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 1592  {
1592 1593          scf_error_t scfe;
1593 1594          int r;
1594 1595  
1595 1596          if (!isservice) {
1596 1597                  /*
1597 1598                   * Let restarter handles refreshing and making new running
1598 1599                   * snapshot only if operating on a live repository and not
1599 1600                   * running in early import.
1600 1601                   */
1601 1602                  if (est->sc_repo_filename == NULL &&
1602 1603                      est->sc_repo_doorname == NULL &&
1603 1604                      est->sc_in_emi == 0) {
1604 1605                          if (_smf_refresh_instance_i(entity) == 0) {
1605 1606                                  if (g_verbose)
1606 1607                                          warn(gettext("Refreshed %s.\n"), fmri);
1607 1608                                  return (0);
1608 1609                          }
1609 1610  
1610 1611                          switch (scf_error()) {
1611 1612                          case SCF_ERROR_BACKEND_ACCESS:
1612 1613                                  return (EACCES);
1613 1614  
1614 1615                          case SCF_ERROR_PERMISSION_DENIED:
1615 1616                                  return (EPERM);
1616 1617  
1617 1618                          default:
1618 1619                                  return (-1);
1619 1620                          }
1620 1621                  } else {
1621 1622                          r = refresh_running_snapshot(entity);
1622 1623                          switch (r) {
1623 1624                          case 0:
1624 1625                                  break;
1625 1626  
1626 1627                          case ECONNABORTED:
1627 1628                          case ECANCELED:
1628 1629                          case EPERM:
1629 1630                          case ENOSPC:
1630 1631                                  break;
1631 1632  
1632 1633                          default:
1633 1634                                  bad_error("refresh_running_snapshot",
1634 1635                                      scf_error());
1635 1636                          }
1636 1637  
1637 1638                          return (r);
1638 1639                  }
1639 1640          }
1640 1641  
1641 1642          if (scf_iter_service_instances(iter, entity) != 0) {
1642 1643                  switch (scf_error()) {
1643 1644                  case SCF_ERROR_CONNECTION_BROKEN:
1644 1645                          return (ECONNABORTED);
1645 1646  
1646 1647                  case SCF_ERROR_DELETED:
1647 1648                          return (ECANCELED);
1648 1649  
1649 1650                  case SCF_ERROR_HANDLE_MISMATCH:
1650 1651                  case SCF_ERROR_NOT_BOUND:
1651 1652                  case SCF_ERROR_NOT_SET:
1652 1653                  default:
1653 1654                          bad_error("scf_iter_service_instances", scf_error());
1654 1655                  }
1655 1656          }
1656 1657  
1657 1658          for (;;) {
1658 1659                  r = scf_iter_next_instance(iter, inst);
1659 1660                  if (r == 0)
1660 1661                          break;
1661 1662                  if (r != 1) {
1662 1663                          switch (scf_error()) {
1663 1664                          case SCF_ERROR_CONNECTION_BROKEN:
1664 1665                                  return (ECONNABORTED);
1665 1666  
1666 1667                          case SCF_ERROR_DELETED:
1667 1668                                  return (ECANCELED);
1668 1669  
1669 1670                          case SCF_ERROR_HANDLE_MISMATCH:
1670 1671                          case SCF_ERROR_NOT_BOUND:
1671 1672                          case SCF_ERROR_NOT_SET:
1672 1673                          case SCF_ERROR_INVALID_ARGUMENT:
1673 1674                          default:
1674 1675                                  bad_error("scf_iter_next_instance",
1675 1676                                      scf_error());
1676 1677                          }
1677 1678                  }
1678 1679  
1679 1680                  /*
1680 1681                   * Similarly, just take a new running snapshot if operating on
1681 1682                   * a non-live repository or running during early import.
1682 1683                   */
1683 1684                  if (est->sc_repo_filename != NULL ||
1684 1685                      est->sc_repo_doorname != NULL ||
1685 1686                      est->sc_in_emi == 1) {
1686 1687                          r = refresh_running_snapshot(inst);
1687 1688                          switch (r) {
1688 1689                          case 0:
1689 1690                                  continue;
1690 1691  
1691 1692                          case ECONNABORTED:
1692 1693                          case ECANCELED:
1693 1694                          case EPERM:
1694 1695                          case ENOSPC:
1695 1696                                  break;
1696 1697                          default:
1697 1698                                  bad_error("refresh_running_snapshot",
1698 1699                                      scf_error());
1699 1700                          }
1700 1701  
1701 1702                          return (r);
1702 1703  
1703 1704                  }
1704 1705  
1705 1706                  if (_smf_refresh_instance_i(inst) == 0) {
1706 1707                          if (g_verbose) {
1707 1708                                  if (scf_instance_get_name(inst, name_buf,
1708 1709                                      max_scf_name_len + 1) < 0)
1709 1710                                          (void) strcpy(name_buf, "?");
1710 1711  
1711 1712                                  warn(gettext("Refreshed %s:%s.\n"),
1712 1713                                      fmri, name_buf);
1713 1714                          }
1714 1715                  } else {
1715 1716                          if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 1717                              g_verbose) {
1717 1718                                  scfe = scf_error();
1718 1719  
1719 1720                                  if (scf_instance_to_fmri(inst, name_buf,
1720 1721                                      max_scf_name_len + 1) < 0)
1721 1722                                          (void) strcpy(name_buf, "?");
1722 1723  
1723 1724                                  warn(gettext(
1724 1725                                      "Refresh of %s:%s failed: %s.\n"), fmri,
1725 1726                                      name_buf, scf_strerror(scfe));
1726 1727                          }
1727 1728                  }
1728 1729          }
1729 1730  
1730 1731          return (0);
1731 1732  }
1732 1733  
1733 1734  static void
1734 1735  private_refresh(void)
1735 1736  {
1736 1737          scf_instance_t *pinst = NULL;
1737 1738          scf_iter_t *piter = NULL;
1738 1739          ssize_t fmrilen;
1739 1740          size_t bufsz;
1740 1741          char *fmribuf;
1741 1742          void *ent;
1742 1743          int issvc;
1743 1744          int r;
1744 1745  
1745 1746          if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 1747                  return;
1747 1748  
1748 1749          assert(cur_svc != NULL);
1749 1750  
1750 1751          bufsz = max_scf_fmri_len + 1;
1751 1752          fmribuf = safe_malloc(bufsz);
1752 1753          if (cur_inst) {
1753 1754                  issvc = 0;
1754 1755                  ent = cur_inst;
1755 1756                  fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 1757          } else {
1757 1758                  issvc = 1;
1758 1759                  ent = cur_svc;
1759 1760                  fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 1761                  if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 1762                          scfdie();
1762 1763  
1763 1764                  if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 1765                          scfdie();
1765 1766          }
1766 1767          if (fmrilen < 0) {
1767 1768                  free(fmribuf);
1768 1769                  if (scf_error() != SCF_ERROR_DELETED)
1769 1770                          scfdie();
1770 1771  
1771 1772                  warn(emsg_deleted);
1772 1773                  return;
1773 1774          }
1774 1775          assert(fmrilen < bufsz);
1775 1776  
1776 1777          r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 1778          switch (r) {
1778 1779          case 0:
1779 1780                  break;
1780 1781  
1781 1782          case ECONNABORTED:
1782 1783                  warn(gettext("Could not refresh %s "
1783 1784                      "(repository connection broken).\n"), fmribuf);
1784 1785                  break;
1785 1786  
1786 1787          case ECANCELED:
1787 1788                  warn(emsg_deleted);
1788 1789                  break;
1789 1790  
1790 1791          case EPERM:
1791 1792                  warn(gettext("Could not refresh %s "
1792 1793                      "(permission denied).\n"), fmribuf);
1793 1794                  break;
1794 1795  
1795 1796          case ENOSPC:
1796 1797                  warn(gettext("Could not refresh %s "
1797 1798                      "(repository server out of resources).\n"),
1798 1799                      fmribuf);
1799 1800                  break;
1800 1801  
1801 1802          case EACCES:
1802 1803          default:
1803 1804                  bad_error("refresh_entity", scf_error());
1804 1805          }
1805 1806  
1806 1807          if (issvc) {
1807 1808                  scf_instance_destroy(pinst);
1808 1809                  scf_iter_destroy(piter);
1809 1810          }
1810 1811  
1811 1812          free(fmribuf);
1812 1813  }
1813 1814  
1814 1815  
1815 1816  static int
1816 1817  stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 1818  {
1818 1819          cbp->sc_err = scferror2errno(err);
1819 1820          return (UU_WALK_ERROR);
1820 1821  }
1821 1822  
1822 1823  static int
1823 1824  stash_scferror(scf_callback_t *cbp)
1824 1825  {
1825 1826          return (stash_scferror_err(cbp, scf_error()));
1826 1827  }
1827 1828  
1828 1829  static int select_inst(const char *);
1829 1830  static int select_svc(const char *);
1830 1831  
1831 1832  /*
1832 1833   * Take a property that does not have a type and check to see if a type
1833 1834   * exists or can be gleened from the current data.  Set the type.
1834 1835   *
1835 1836   * Check the current level (instance) and then check the higher level
1836 1837   * (service).  This could be the case for adding a new property to
1837 1838   * the instance that's going to "override" a service level property.
1838 1839   *
1839 1840   * For a property :
1840 1841   * 1. Take the type from an existing property
1841 1842   * 2. Take the type from a template entry
1842 1843   *
1843 1844   * If the type can not be found, then leave the type as is, and let the import
1844 1845   * report the problem of the missing type.
1845 1846   */
1846 1847  static int
1847 1848  find_current_prop_type(void *p, void *g)
1848 1849  {
1849 1850          property_t *prop = p;
1850 1851          scf_callback_t *lcb = g;
1851 1852          pgroup_t *pg = NULL;
1852 1853  
1853 1854          const char *fmri = NULL;
1854 1855          char *lfmri = NULL;
1855 1856          char *cur_selection = NULL;
1856 1857  
1857 1858          scf_propertygroup_t *sc_pg = NULL;
1858 1859          scf_property_t *sc_prop = NULL;
1859 1860          scf_pg_tmpl_t *t_pg = NULL;
1860 1861          scf_prop_tmpl_t *t_prop = NULL;
1861 1862          scf_type_t prop_type;
1862 1863  
1863 1864          value_t *vp;
1864 1865          int issvc = lcb->sc_service;
1865 1866          int r = UU_WALK_ERROR;
1866 1867  
1867 1868          if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 1869                  return (UU_WALK_NEXT);
1869 1870  
1870 1871          t_prop = scf_tmpl_prop_create(g_hndl);
1871 1872          sc_prop = scf_property_create(g_hndl);
1872 1873          if (sc_prop == NULL || t_prop == NULL) {
1873 1874                  warn(gettext("Unable to create the property to attempt and "
1874 1875                      "find a missing type.\n"));
1875 1876  
1876 1877                  scf_property_destroy(sc_prop);
1877 1878                  scf_tmpl_prop_destroy(t_prop);
1878 1879  
1879 1880                  return (UU_WALK_ERROR);
1880 1881          }
1881 1882  
1882 1883          if (lcb->sc_flags == 1) {
1883 1884                  pg = lcb->sc_parent;
1884 1885                  issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 1886                  fmri = pg->sc_parent->sc_fmri;
1886 1887  retry_pg:
1887 1888                  if (cur_svc && cur_selection == NULL) {
1888 1889                          cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 1890                          lscf_get_selection_str(cur_selection,
1890 1891                              max_scf_fmri_len + 1);
1891 1892  
1892 1893                          if (strcmp(cur_selection, fmri) != 0) {
1893 1894                                  lscf_select(fmri);
1894 1895                          } else {
1895 1896                                  free(cur_selection);
1896 1897                                  cur_selection = NULL;
1897 1898                          }
1898 1899                  } else {
1899 1900                          lscf_select(fmri);
1900 1901                  }
1901 1902  
1902 1903                  if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 1904                          warn(gettext("Unable to create property group to "
1904 1905                              "find a missing property type.\n"));
1905 1906  
1906 1907                          goto out;
1907 1908                  }
1908 1909  
1909 1910                  if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910 1911                          /*
1911 1912                           * If this is the sc_pg from the parent
1912 1913                           * let the caller clean up the sc_pg,
1913 1914                           * and just throw it away in this case.
1914 1915                           */
1915 1916                          if (sc_pg != lcb->sc_parent)
1916 1917                                  scf_pg_destroy(sc_pg);
1917 1918  
1918 1919                          sc_pg = NULL;
1919 1920                          if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 1921                                  warn(gettext("Unable to create template "
1921 1922                                      "property group to find a property "
1922 1923                                      "type.\n"));
1923 1924  
1924 1925                                  goto out;
1925 1926                          }
1926 1927  
1927 1928                          if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 1929                              pg->sc_pgroup_name, NULL, t_pg,
1929 1930                              SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930 1931                                  /*
1931 1932                                   * if instance get service and jump back
1932 1933                                   */
1933 1934                                  scf_tmpl_pg_destroy(t_pg);
1934 1935                                  t_pg = NULL;
1935 1936                                  if (issvc == 0) {
1936 1937                                          entity_t *e = pg->sc_parent->sc_parent;
1937 1938  
1938 1939                                          fmri = e->sc_fmri;
1939 1940                                          issvc = 1;
1940 1941                                          goto retry_pg;
1941 1942                                  } else {
1942 1943                                          goto out;
1943 1944                                  }
1944 1945                          }
1945 1946                  }
1946 1947          } else {
1947 1948                  sc_pg = lcb->sc_parent;
1948 1949          }
1949 1950  
1950 1951          /*
1951 1952           * Attempt to get the type from an existing property.  If the property
1952 1953           * cannot be found then attempt to get the type from a template entry
1953 1954           * for the property.
1954 1955           *
1955 1956           * Finally, if at the instance level look at the service level.
1956 1957           */
1957 1958          if (sc_pg != NULL &&
1958 1959              pg_get_prop(sc_pg, prop->sc_property_name,
1959 1960              sc_prop) == SCF_SUCCESS &&
1960 1961              scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 1962                  prop->sc_value_type = prop_type;
1962 1963  
1963 1964                  /*
1964 1965                   * Found a type, update the value types and validate
1965 1966                   * the actual value against this type.
1966 1967                   */
1967 1968                  for (vp = uu_list_first(prop->sc_property_values);
1968 1969                      vp != NULL;
1969 1970                      vp = uu_list_next(prop->sc_property_values, vp)) {
1970 1971                          vp->sc_type = prop->sc_value_type;
1971 1972                          lxml_store_value(vp, 0, NULL);
1972 1973                  }
1973 1974  
1974 1975                  r = UU_WALK_NEXT;
1975 1976                  goto out;
1976 1977          }
1977 1978  
1978 1979          /*
1979 1980           * If we get here with t_pg set to NULL then we had to have
1980 1981           * gotten an sc_pg but that sc_pg did not have the property
1981 1982           * we are looking for.   So if the t_pg is not null look up
1982 1983           * the template entry for the property.
1983 1984           *
1984 1985           * If the t_pg is null then need to attempt to get a matching
1985 1986           * template entry for the sc_pg, and see if there is a property
1986 1987           * entry for that template entry.
1987 1988           */
1988 1989  do_tmpl :
1989 1990          if (t_pg != NULL &&
1990 1991              scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 1992              t_prop, 0) == SCF_SUCCESS) {
1992 1993                  if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 1994                          prop->sc_value_type = prop_type;
1994 1995  
1995 1996                          /*
1996 1997                           * Found a type, update the value types and validate
1997 1998                           * the actual value against this type.
1998 1999                           */
1999 2000                          for (vp = uu_list_first(prop->sc_property_values);
2000 2001                              vp != NULL;
2001 2002                              vp = uu_list_next(prop->sc_property_values, vp)) {
2002 2003                                  vp->sc_type = prop->sc_value_type;
2003 2004                                  lxml_store_value(vp, 0, NULL);
2004 2005                          }
2005 2006  
2006 2007                          r = UU_WALK_NEXT;
2007 2008                          goto out;
2008 2009                  }
2009 2010          } else {
2010 2011                  if (t_pg == NULL && sc_pg) {
2011 2012                          if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 2013                                  warn(gettext("Unable to create template "
2013 2014                                      "property group to find a property "
2014 2015                                      "type.\n"));
2015 2016  
2016 2017                                  goto out;
2017 2018                          }
2018 2019  
2019 2020                          if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 2021                                  scf_tmpl_pg_destroy(t_pg);
2021 2022                                  t_pg = NULL;
2022 2023                          } else {
2023 2024                                  goto do_tmpl;
2024 2025                          }
2025 2026                  }
2026 2027          }
2027 2028  
2028 2029          if (issvc == 0) {
2029 2030                  scf_instance_t *i;
2030 2031                  scf_service_t *s;
2031 2032  
2032 2033                  issvc = 1;
2033 2034                  if (lcb->sc_flags == 1) {
2034 2035                          entity_t *e = pg->sc_parent->sc_parent;
2035 2036  
2036 2037                          fmri = e->sc_fmri;
2037 2038                          goto retry_pg;
2038 2039                  }
2039 2040  
2040 2041                  /*
2041 2042                   * because lcb->sc_flags was not set then this means
2042 2043                   * the pg was not used and can be used here.
2043 2044                   */
2044 2045                  if ((pg = internal_pgroup_new()) == NULL) {
2045 2046                          warn(gettext("Could not create internal property group "
2046 2047                              "to find a missing type."));
2047 2048  
2048 2049                          goto out;
2049 2050                  }
2050 2051  
2051 2052                  pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 2053                  if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 2054                      max_scf_name_len + 1) < 0)
2054 2055                                  goto out;
2055 2056  
2056 2057                  i = scf_instance_create(g_hndl);
2057 2058                  s = scf_service_create(g_hndl);
2058 2059                  if (i == NULL || s == NULL ||
2059 2060                      scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 2061                          warn(gettext("Could not get a service for the instance "
2061 2062                              "to find a missing type."));
2062 2063  
2063 2064                          goto out;
2064 2065                  }
2065 2066  
2066 2067                  /*
2067 2068                   * Check to see truly at the instance level.
2068 2069                   */
2069 2070                  lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 2071                  if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 2072                      scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 2073                          goto out;
2073 2074                  else
2074 2075                          fmri = (const char *)lfmri;
2075 2076  
2076 2077                  goto retry_pg;
2077 2078          }
2078 2079  
2079 2080  out :
2080 2081          if (sc_pg != lcb->sc_parent) {
2081 2082                  scf_pg_destroy(sc_pg);
2082 2083          }
2083 2084  
2084 2085          /*
2085 2086           * If this is true then the pg was allocated
2086 2087           * here, and the name was set so need to free
2087 2088           * the name and the pg.
2088 2089           */
2089 2090          if (pg != NULL && pg != lcb->sc_parent) {
2090 2091                  free((char *)pg->sc_pgroup_name);
2091 2092                  internal_pgroup_free(pg);
2092 2093          }
2093 2094  
2094 2095          if (cur_selection) {
2095 2096                  lscf_select(cur_selection);
2096 2097                  free(cur_selection);
2097 2098          }
2098 2099  
2099 2100          scf_tmpl_pg_destroy(t_pg);
2100 2101          scf_tmpl_prop_destroy(t_prop);
2101 2102          scf_property_destroy(sc_prop);
2102 2103  
2103 2104          if (r != UU_WALK_NEXT)
2104 2105                  warn(gettext("Could not find property type for \"%s\" "
2105 2106                      "from \"%s\"\n"), prop->sc_property_name,
2106 2107                      fmri != NULL ? fmri : lcb->sc_source_fmri);
2107 2108  
2108 2109          free(lfmri);
2109 2110  
2110 2111          return (r);
2111 2112  }
2112 2113  
2113 2114  /*
2114 2115   * Take a property group that does not have a type and check to see if a type
2115 2116   * exists or can be gleened from the current data.  Set the type.
2116 2117   *
2117 2118   * Check the current level (instance) and then check the higher level
2118 2119   * (service).  This could be the case for adding a new property to
2119 2120   * the instance that's going to "override" a service level property.
2120 2121   *
2121 2122   * For a property group
2122 2123   * 1. Take the type from an existing property group
2123 2124   * 2. Take the type from a template entry
2124 2125   *
2125 2126   * If the type can not be found, then leave the type as is, and let the import
2126 2127   * report the problem of the missing type.
2127 2128   */
2128 2129  static int
2129 2130  find_current_pg_type(void *p, void *sori)
2130 2131  {
2131 2132          entity_t *si = sori;
2132 2133          pgroup_t *pg = p;
2133 2134  
2134 2135          const char *ofmri, *fmri;
2135 2136          char *cur_selection = NULL;
2136 2137          char *pg_type = NULL;
2137 2138  
2138 2139          scf_propertygroup_t *sc_pg = NULL;
2139 2140          scf_pg_tmpl_t *t_pg = NULL;
2140 2141  
2141 2142          int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 2143          int r = UU_WALK_ERROR;
2143 2144  
2144 2145          ofmri = fmri = si->sc_fmri;
2145 2146          if (pg->sc_pgroup_type != NULL) {
2146 2147                  r = UU_WALK_NEXT;
2147 2148  
2148 2149                  goto out;
2149 2150          }
2150 2151  
2151 2152          sc_pg = scf_pg_create(g_hndl);
2152 2153          if (sc_pg == NULL) {
2153 2154                  warn(gettext("Unable to create property group to attempt "
2154 2155                      "and find a missing type.\n"));
2155 2156  
2156 2157                  return (UU_WALK_ERROR);
2157 2158          }
2158 2159  
2159 2160          /*
2160 2161           * Using get_pg() requires that the cur_svc/cur_inst be
2161 2162           * via lscf_select.  Need to preserve the current selection
2162 2163           * if going to use lscf_select() to set up the cur_svc/cur_inst
2163 2164           */
2164 2165          if (cur_svc) {
2165 2166                  cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 2167                  lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167 2168          }
2168 2169  
2169 2170          /*
2170 2171           * If the property group exists get the type, and set
2171 2172           * the pgroup_t type of that type.
2172 2173           *
2173 2174           * If not the check for a template pg_pattern entry
2174 2175           * and take the type from that.
2175 2176           */
2176 2177  retry_svc:
2177 2178          lscf_select(fmri);
2178 2179  
2179 2180          if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 2181                  pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 2182                  if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 2183                      max_scf_pg_type_len + 1) != -1) {
2183 2184                          pg->sc_pgroup_type = pg_type;
2184 2185  
2185 2186                          r = UU_WALK_NEXT;
2186 2187                          goto out;
2187 2188                  } else {
2188 2189                          free(pg_type);
2189 2190                  }
2190 2191          } else {
2191 2192                  if ((t_pg == NULL) &&
2192 2193                      (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 2194                          goto out;
2194 2195  
2195 2196                  if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 2197                      NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 2198                      scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 2199                          pg->sc_pgroup_type = pg_type;
2199 2200  
2200 2201                          r = UU_WALK_NEXT;
2201 2202                          goto out;
2202 2203                  }
2203 2204          }
2204 2205  
2205 2206          /*
2206 2207           * If type is not found at the instance level then attempt to
2207 2208           * find the type at the service level.
2208 2209           */
2209 2210          if (!issvc) {
2210 2211                  si = si->sc_parent;
2211 2212                  fmri = si->sc_fmri;
2212 2213                  issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 2214                  goto retry_svc;
2214 2215          }
2215 2216  
2216 2217  out :
2217 2218          if (cur_selection) {
2218 2219                  lscf_select(cur_selection);
2219 2220                  free(cur_selection);
2220 2221          }
2221 2222  
2222 2223          /*
2223 2224           * Now walk the properties of the property group to make sure that
2224 2225           * all properties have the correct type and values are valid for
2225 2226           * those types.
2226 2227           */
2227 2228          if (r == UU_WALK_NEXT) {
2228 2229                  scf_callback_t cb;
2229 2230  
2230 2231                  cb.sc_service = issvc;
2231 2232                  cb.sc_source_fmri = ofmri;
2232 2233                  if (sc_pg != NULL) {
2233 2234                          cb.sc_parent = sc_pg;
2234 2235                          cb.sc_flags = 0;
2235 2236                  } else {
2236 2237                          cb.sc_parent = pg;
2237 2238                          cb.sc_flags = 1;
2238 2239                  }
2239 2240  
2240 2241                  if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 2242                      &cb, UU_DEFAULT) != 0) {
2242 2243                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 2244                                  bad_error("uu_list_walk", uu_error());
2244 2245  
2245 2246                          r = UU_WALK_ERROR;
2246 2247                  }
2247 2248          } else {
2248 2249                  warn(gettext("Could not find property group type for "
2249 2250                      "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250 2251          }
2251 2252  
2252 2253          scf_tmpl_pg_destroy(t_pg);
2253 2254          scf_pg_destroy(sc_pg);
2254 2255  
2255 2256          return (r);
2256 2257  }
2257 2258  
2258 2259  /*
2259 2260   * Import.  These functions import a bundle into the repository.
2260 2261   */
2261 2262  
2262 2263  /*
2263 2264   * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2264 2265   * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2265 2266   * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2266 2267   * lcbdata->sc_err to
2267 2268   *   ENOMEM - out of memory
2268 2269   *   ECONNABORTED - repository connection broken
2269 2270   *   ECANCELED - sc_trans's property group was deleted
2270 2271   *   EINVAL - p's name is invalid (error printed)
2271 2272   *          - p has an invalid value (error printed)
2272 2273   */
2273 2274  static int
2274 2275  lscf_property_import(void *v, void *pvt)
2275 2276  {
2276 2277          property_t *p = v;
2277 2278          scf_callback_t *lcbdata = pvt;
2278 2279          value_t *vp;
2279 2280          scf_transaction_t *trans = lcbdata->sc_trans;
2280 2281          scf_transaction_entry_t *entr;
2281 2282          scf_value_t *val;
2282 2283          scf_type_t tp;
2283 2284  
2284 2285          if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 2286              lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 2287              strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 2288                  lcbdata->sc_enable = p;
2288 2289                  return (UU_WALK_NEXT);
2289 2290          }
2290 2291  
2291 2292          entr = scf_entry_create(lcbdata->sc_handle);
2292 2293          if (entr == NULL) {
2293 2294                  switch (scf_error()) {
2294 2295                  case SCF_ERROR_NO_MEMORY:
2295 2296                          return (stash_scferror(lcbdata));
2296 2297  
2297 2298                  case SCF_ERROR_INVALID_ARGUMENT:
2298 2299                  default:
2299 2300                          bad_error("scf_entry_create", scf_error());
2300 2301                  }
2301 2302          }
2302 2303  
2303 2304          tp = p->sc_value_type;
2304 2305  
2305 2306          if (scf_transaction_property_new(trans, entr,
2306 2307              p->sc_property_name, tp) != 0) {
2307 2308                  switch (scf_error()) {
2308 2309                  case SCF_ERROR_INVALID_ARGUMENT:
2309 2310                          semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 2311                          scf_entry_destroy(entr);
2311 2312                          return (stash_scferror(lcbdata));
2312 2313  
2313 2314                  case SCF_ERROR_EXISTS:
2314 2315                          break;
2315 2316  
2316 2317                  case SCF_ERROR_DELETED:
2317 2318                  case SCF_ERROR_CONNECTION_BROKEN:
2318 2319                          scf_entry_destroy(entr);
2319 2320                          return (stash_scferror(lcbdata));
2320 2321  
2321 2322                  case SCF_ERROR_NOT_BOUND:
2322 2323                  case SCF_ERROR_HANDLE_MISMATCH:
2323 2324                  case SCF_ERROR_NOT_SET:
2324 2325                  default:
2325 2326                          bad_error("scf_transaction_property_new", scf_error());
2326 2327                  }
2327 2328  
2328 2329                  if (scf_transaction_property_change_type(trans, entr,
2329 2330                      p->sc_property_name, tp) != 0) {
2330 2331                          switch (scf_error()) {
2331 2332                          case SCF_ERROR_DELETED:
2332 2333                          case SCF_ERROR_CONNECTION_BROKEN:
2333 2334                                  scf_entry_destroy(entr);
2334 2335                                  return (stash_scferror(lcbdata));
2335 2336  
2336 2337                          case SCF_ERROR_INVALID_ARGUMENT:
2337 2338                                  semerr(emsg_invalid_prop_name,
2338 2339                                      p->sc_property_name);
2339 2340                                  scf_entry_destroy(entr);
2340 2341                                  return (stash_scferror(lcbdata));
2341 2342  
2342 2343                          case SCF_ERROR_NOT_FOUND:
2343 2344                          case SCF_ERROR_NOT_SET:
2344 2345                          case SCF_ERROR_HANDLE_MISMATCH:
2345 2346                          case SCF_ERROR_NOT_BOUND:
2346 2347                          default:
2347 2348                                  bad_error(
2348 2349                                      "scf_transaction_property_change_type",
2349 2350                                      scf_error());
2350 2351                          }
2351 2352                  }
2352 2353          }
2353 2354  
2354 2355          for (vp = uu_list_first(p->sc_property_values);
2355 2356              vp != NULL;
2356 2357              vp = uu_list_next(p->sc_property_values, vp)) {
2357 2358                  val = scf_value_create(g_hndl);
2358 2359                  if (val == NULL) {
2359 2360                          switch (scf_error()) {
2360 2361                          case SCF_ERROR_NO_MEMORY:
2361 2362                                  return (stash_scferror(lcbdata));
2362 2363  
2363 2364                          case SCF_ERROR_INVALID_ARGUMENT:
2364 2365                          default:
2365 2366                                  bad_error("scf_value_create", scf_error());
2366 2367                          }
2367 2368                  }
2368 2369  
2369 2370                  switch (tp) {
2370 2371                  case SCF_TYPE_BOOLEAN:
2371 2372                          scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 2373                          break;
2373 2374                  case SCF_TYPE_COUNT:
2374 2375                          scf_value_set_count(val, vp->sc_u.sc_count);
2375 2376                          break;
2376 2377                  case SCF_TYPE_INTEGER:
2377 2378                          scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 2379                          break;
2379 2380                  default:
2380 2381                          assert(vp->sc_u.sc_string != NULL);
2381 2382                          if (scf_value_set_from_string(val, tp,
2382 2383                              vp->sc_u.sc_string) != 0) {
2383 2384                                  if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 2385                                          bad_error("scf_value_set_from_string",
2385 2386                                              scf_error());
2386 2387  
2387 2388                                  warn(gettext("Value \"%s\" is not a valid "
2388 2389                                      "%s.\n"), vp->sc_u.sc_string,
2389 2390                                      scf_type_to_string(tp));
2390 2391                                  scf_value_destroy(val);
2391 2392                                  return (stash_scferror(lcbdata));
2392 2393                          }
2393 2394                          break;
2394 2395                  }
2395 2396  
2396 2397                  if (scf_entry_add_value(entr, val) != 0)
2397 2398                          bad_error("scf_entry_add_value", scf_error());
2398 2399          }
2399 2400  
2400 2401          return (UU_WALK_NEXT);
2401 2402  }
2402 2403  
2403 2404  /*
2404 2405   * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2405 2406   * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 2407   * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 2408   * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2408 2409   * lcbdata->sc_err to
2409 2410   *   ECONNABORTED - repository connection broken
2410 2411   *   ENOMEM - out of memory
2411 2412   *   ENOSPC - svc.configd is out of resources
2412 2413   *   ECANCELED - sc_parent was deleted
2413 2414   *   EPERM - could not create property group (permission denied) (error printed)
2414 2415   *         - could not modify property group (permission denied) (error printed)
2415 2416   *         - could not delete property group (permission denied) (error printed)
2416 2417   *   EROFS - could not create property group (repository is read-only)
2417 2418   *         - could not delete property group (repository is read-only)
2418 2419   *   EACCES - could not create property group (backend access denied)
2419 2420   *          - could not delete property group (backend access denied)
2420 2421   *   EEXIST - could not create property group (already exists)
2421 2422   *   EINVAL - invalid property group name (error printed)
2422 2423   *          - invalid property name (error printed)
2423 2424   *          - invalid value (error printed)
2424 2425   *   EBUSY - new property group deleted (error printed)
2425 2426   *         - new property group changed (error printed)
2426 2427   *         - property group added (error printed)
2427 2428   *         - property group deleted (error printed)
2428 2429   */
2429 2430  static int
2430 2431  entity_pgroup_import(void *v, void *pvt)
2431 2432  {
2432 2433          pgroup_t *p = v;
2433 2434          scf_callback_t cbdata;
2434 2435          scf_callback_t *lcbdata = pvt;
2435 2436          void *ent = lcbdata->sc_parent;
2436 2437          int issvc = lcbdata->sc_service;
2437 2438          int r;
2438 2439  
2439 2440          const char * const pg_changed = gettext("%s changed unexpectedly "
2440 2441              "(new property group \"%s\" changed).\n");
2441 2442  
2442 2443          /* Never import deleted property groups. */
2443 2444          if (p->sc_pgroup_delete) {
2444 2445                  if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 2446                      entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 2447                          goto delete_pg;
2447 2448                  }
2448 2449                  return (UU_WALK_NEXT);
2449 2450          }
2450 2451  
2451 2452          if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 2453              strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 2454                  lcbdata->sc_general = p;
2454 2455                  return (UU_WALK_NEXT);
2455 2456          }
2456 2457  
2457 2458  add_pg:
2458 2459          if (issvc)
2459 2460                  r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 2461                      p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 2462          else
2462 2463                  r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 2464                      p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 2465          if (r != 0) {
2465 2466                  switch (scf_error()) {
2466 2467                  case SCF_ERROR_DELETED:
2467 2468                  case SCF_ERROR_CONNECTION_BROKEN:
2468 2469                  case SCF_ERROR_BACKEND_READONLY:
2469 2470                  case SCF_ERROR_BACKEND_ACCESS:
2470 2471                  case SCF_ERROR_NO_RESOURCES:
2471 2472                          return (stash_scferror(lcbdata));
2472 2473  
2473 2474                  case SCF_ERROR_EXISTS:
2474 2475                          if (lcbdata->sc_flags & SCI_FORCE)
2475 2476                                  break;
2476 2477                          return (stash_scferror(lcbdata));
2477 2478  
2478 2479                  case SCF_ERROR_INVALID_ARGUMENT:
2479 2480                          warn(emsg_fmri_invalid_pg_name_type,
2480 2481                              lcbdata->sc_source_fmri,
2481 2482                              p->sc_pgroup_name, p->sc_pgroup_type);
2482 2483                          return (stash_scferror(lcbdata));
2483 2484  
2484 2485                  case SCF_ERROR_PERMISSION_DENIED:
2485 2486                          warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 2487                              lcbdata->sc_target_fmri);
2487 2488                          return (stash_scferror(lcbdata));
2488 2489  
2489 2490                  case SCF_ERROR_NOT_BOUND:
2490 2491                  case SCF_ERROR_HANDLE_MISMATCH:
2491 2492                  case SCF_ERROR_NOT_SET:
2492 2493                  default:
2493 2494                          bad_error("scf_service_add_pg", scf_error());
2494 2495                  }
2495 2496  
2496 2497                  if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 2498                          switch (scf_error()) {
2498 2499                          case SCF_ERROR_CONNECTION_BROKEN:
2499 2500                          case SCF_ERROR_DELETED:
2500 2501                                  return (stash_scferror(lcbdata));
2501 2502  
2502 2503                          case SCF_ERROR_INVALID_ARGUMENT:
2503 2504                                  warn(emsg_fmri_invalid_pg_name,
2504 2505                                      lcbdata->sc_source_fmri,
2505 2506                                      p->sc_pgroup_name);
2506 2507                                  return (stash_scferror(lcbdata));
2507 2508  
2508 2509                          case SCF_ERROR_NOT_FOUND:
2509 2510                                  warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 2511                                      p->sc_pgroup_name);
2511 2512                                  lcbdata->sc_err = EBUSY;
2512 2513                                  return (UU_WALK_ERROR);
2513 2514  
2514 2515                          case SCF_ERROR_NOT_BOUND:
2515 2516                          case SCF_ERROR_HANDLE_MISMATCH:
2516 2517                          case SCF_ERROR_NOT_SET:
2517 2518                          default:
2518 2519                                  bad_error("entity_get_pg", scf_error());
2519 2520                          }
2520 2521                  }
2521 2522  
2522 2523                  if (lcbdata->sc_flags & SCI_KEEP)
2523 2524                          goto props;
2524 2525  
2525 2526  delete_pg:
2526 2527                  if (scf_pg_delete(imp_pg) != 0) {
2527 2528                          switch (scf_error()) {
2528 2529                          case SCF_ERROR_DELETED:
2529 2530                                  warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 2531                                      p->sc_pgroup_name);
2531 2532                                  lcbdata->sc_err = EBUSY;
2532 2533                                  return (UU_WALK_ERROR);
2533 2534  
2534 2535                          case SCF_ERROR_PERMISSION_DENIED:
2535 2536                                  warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 2537                                      lcbdata->sc_target_fmri);
2537 2538                                  return (stash_scferror(lcbdata));
2538 2539  
2539 2540                          case SCF_ERROR_BACKEND_READONLY:
2540 2541                          case SCF_ERROR_BACKEND_ACCESS:
2541 2542                          case SCF_ERROR_CONNECTION_BROKEN:
2542 2543                                  return (stash_scferror(lcbdata));
2543 2544  
2544 2545                          case SCF_ERROR_NOT_SET:
2545 2546                          default:
2546 2547                                  bad_error("scf_pg_delete", scf_error());
2547 2548                          }
2548 2549                  }
2549 2550  
2550 2551                  if (p->sc_pgroup_delete)
2551 2552                          return (UU_WALK_NEXT);
2552 2553  
2553 2554                  goto add_pg;
2554 2555          }
2555 2556  
2556 2557  props:
2557 2558  
2558 2559          /*
2559 2560           * Add properties to property group, if any.
2560 2561           */
2561 2562          cbdata.sc_handle = lcbdata->sc_handle;
2562 2563          cbdata.sc_parent = imp_pg;
2563 2564          cbdata.sc_flags = lcbdata->sc_flags;
2564 2565          cbdata.sc_trans = imp_tx;
2565 2566          cbdata.sc_enable = NULL;
2566 2567  
2567 2568          if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 2569                  switch (scf_error()) {
2569 2570                  case SCF_ERROR_BACKEND_ACCESS:
2570 2571                  case SCF_ERROR_BACKEND_READONLY:
2571 2572                  case SCF_ERROR_CONNECTION_BROKEN:
2572 2573                          return (stash_scferror(lcbdata));
2573 2574  
2574 2575                  case SCF_ERROR_DELETED:
2575 2576                          warn(pg_changed, lcbdata->sc_target_fmri,
2576 2577                              p->sc_pgroup_name);
2577 2578                          lcbdata->sc_err = EBUSY;
2578 2579                          return (UU_WALK_ERROR);
2579 2580  
2580 2581                  case SCF_ERROR_PERMISSION_DENIED:
2581 2582                          warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 2583                              lcbdata->sc_target_fmri);
2583 2584                          return (stash_scferror(lcbdata));
2584 2585  
2585 2586                  case SCF_ERROR_NOT_BOUND:
2586 2587                  case SCF_ERROR_NOT_SET:
2587 2588                  case SCF_ERROR_IN_USE:
2588 2589                  case SCF_ERROR_HANDLE_MISMATCH:
2589 2590                  default:
2590 2591                          bad_error("scf_transaction_start", scf_error());
2591 2592                  }
2592 2593          }
2593 2594  
2594 2595          if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 2596              UU_DEFAULT) != 0) {
2596 2597                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 2598                          bad_error("uu_list_walk", uu_error());
2598 2599                  scf_transaction_reset(imp_tx);
2599 2600  
2600 2601                  lcbdata->sc_err = cbdata.sc_err;
2601 2602                  if (cbdata.sc_err == ECANCELED) {
2602 2603                          warn(pg_changed, lcbdata->sc_target_fmri,
2603 2604                              p->sc_pgroup_name);
2604 2605                          lcbdata->sc_err = EBUSY;
2605 2606                  }
2606 2607                  return (UU_WALK_ERROR);
2607 2608          }
2608 2609  
2609 2610          if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 2611                  cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611 2612  
2612 2613                  /*
2613 2614                   * take the snapshot running snapshot then
2614 2615                   * import the stored general/enable property
2615 2616                   */
2616 2617                  r = take_snap(ent, snap_running, imp_rsnap);
2617 2618                  switch (r) {
2618 2619                  case 0:
2619 2620                          break;
2620 2621  
2621 2622                  case ECONNABORTED:
2622 2623                          warn(gettext("Could not take %s snapshot on import "
2623 2624                              "(repository connection broken).\n"),
2624 2625                              snap_running);
2625 2626                          lcbdata->sc_err = r;
2626 2627                          return (UU_WALK_ERROR);
2627 2628                  case ECANCELED:
2628 2629                          warn(emsg_deleted);
2629 2630                          lcbdata->sc_err = r;
2630 2631                          return (UU_WALK_ERROR);
2631 2632  
2632 2633                  case EPERM:
2633 2634                          warn(gettext("Could not take %s snapshot "
2634 2635                              "(permission denied).\n"), snap_running);
2635 2636                          lcbdata->sc_err = r;
2636 2637                          return (UU_WALK_ERROR);
2637 2638  
2638 2639                  case ENOSPC:
2639 2640                          warn(gettext("Could not take %s snapshot"
2640 2641                              "(repository server out of resources).\n"),
2641 2642                              snap_running);
2642 2643                          lcbdata->sc_err = r;
2643 2644                          return (UU_WALK_ERROR);
2644 2645  
2645 2646                  default:
2646 2647                          bad_error("take_snap", r);
2647 2648                  }
2648 2649  
2649 2650                  r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 2651                  if (r != UU_WALK_NEXT) {
2651 2652                          if (r != UU_WALK_ERROR)
2652 2653                                  bad_error("lscf_property_import", r);
2653 2654                          return (EINVAL);
2654 2655                  }
2655 2656          }
2656 2657  
2657 2658          r = scf_transaction_commit(imp_tx);
2658 2659          switch (r) {
2659 2660          case 1:
2660 2661                  r = UU_WALK_NEXT;
2661 2662                  break;
2662 2663  
2663 2664          case 0:
2664 2665                  warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 2666                  lcbdata->sc_err = EBUSY;
2666 2667                  r = UU_WALK_ERROR;
2667 2668                  break;
2668 2669  
2669 2670          case -1:
2670 2671                  switch (scf_error()) {
2671 2672                  case SCF_ERROR_BACKEND_READONLY:
2672 2673                  case SCF_ERROR_BACKEND_ACCESS:
2673 2674                  case SCF_ERROR_CONNECTION_BROKEN:
2674 2675                  case SCF_ERROR_NO_RESOURCES:
2675 2676                          r = stash_scferror(lcbdata);
2676 2677                          break;
2677 2678  
2678 2679                  case SCF_ERROR_DELETED:
2679 2680                          warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 2681                              p->sc_pgroup_name);
2681 2682                          lcbdata->sc_err = EBUSY;
2682 2683                          r = UU_WALK_ERROR;
2683 2684                          break;
2684 2685  
2685 2686                  case SCF_ERROR_PERMISSION_DENIED:
2686 2687                          warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 2688                              lcbdata->sc_target_fmri);
2688 2689                          r = stash_scferror(lcbdata);
2689 2690                          break;
2690 2691  
2691 2692                  case SCF_ERROR_NOT_SET:
2692 2693                  case SCF_ERROR_INVALID_ARGUMENT:
2693 2694                  case SCF_ERROR_NOT_BOUND:
2694 2695                  default:
2695 2696                          bad_error("scf_transaction_commit", scf_error());
2696 2697                  }
2697 2698                  break;
2698 2699  
2699 2700          default:
2700 2701                  bad_error("scf_transaction_commit", r);
2701 2702          }
2702 2703  
2703 2704          scf_transaction_destroy_children(imp_tx);
2704 2705  
2705 2706          return (r);
2706 2707  }
2707 2708  
2708 2709  /*
2709 2710   * Returns
2710 2711   *   0 - success
2711 2712   *   ECONNABORTED - repository connection broken
2712 2713   *   ENOMEM - out of memory
2713 2714   *   ENOSPC - svc.configd is out of resources
2714 2715   *   ECANCELED - inst was deleted
2715 2716   *   EPERM - could not create property group (permission denied) (error printed)
2716 2717   *         - could not modify property group (permission denied) (error printed)
2717 2718   *   EROFS - could not create property group (repository is read-only)
2718 2719   *   EACCES - could not create property group (backend access denied)
2719 2720   *   EEXIST - could not create property group (already exists)
2720 2721   *   EINVAL - invalid property group name (error printed)
2721 2722   *          - invalid property name (error printed)
2722 2723   *          - invalid value (error printed)
2723 2724   *   EBUSY - new property group changed (error printed)
2724 2725   */
2725 2726  static int
2726 2727  lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727 2728      const entity_t *isvc, int flags)
2728 2729  {
2729 2730          scf_callback_t cbdata;
2730 2731  
2731 2732          cbdata.sc_handle = scf_service_handle(svc);
2732 2733          cbdata.sc_parent = svc;
2733 2734          cbdata.sc_service = 1;
2734 2735          cbdata.sc_general = 0;
2735 2736          cbdata.sc_enable = 0;
2736 2737          cbdata.sc_flags = flags;
2737 2738          cbdata.sc_source_fmri = isvc->sc_fmri;
2738 2739          cbdata.sc_target_fmri = target_fmri;
2739 2740  
2740 2741          /*
2741 2742           * If the op is set, then add the flag to the callback
2742 2743           * flags for later use.
2743 2744           */
2744 2745          if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 2746                  switch (isvc->sc_op) {
2746 2747                  case SVCCFG_OP_IMPORT :
2747 2748                          cbdata.sc_flags |= SCI_OP_IMPORT;
2748 2749                          break;
2749 2750                  case SVCCFG_OP_APPLY :
2750 2751                          cbdata.sc_flags |= SCI_OP_APPLY;
2751 2752                          break;
2752 2753                  case SVCCFG_OP_RESTORE :
2753 2754                          cbdata.sc_flags |= SCI_OP_RESTORE;
2754 2755                          break;
2755 2756                  default :
2756 2757                          uu_die(gettext("lscf_import_service_pgs : "
2757 2758                              "Unknown op stored in the service entity\n"));
2758 2759  
2759 2760                  }
2760 2761          }
2761 2762  
2762 2763          if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 2764              UU_DEFAULT) != 0) {
2764 2765                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 2766                          bad_error("uu_list_walk", uu_error());
2766 2767  
2767 2768                  return (cbdata.sc_err);
2768 2769          }
2769 2770  
2770 2771          return (0);
2771 2772  }
2772 2773  
2773 2774  /*
2774 2775   * Returns
2775 2776   *   0 - success
2776 2777   *   ECONNABORTED - repository connection broken
2777 2778   *   ENOMEM - out of memory
2778 2779   *   ENOSPC - svc.configd is out of resources
2779 2780   *   ECANCELED - inst was deleted
2780 2781   *   EPERM - could not create property group (permission denied) (error printed)
2781 2782   *         - could not modify property group (permission denied) (error printed)
2782 2783   *   EROFS - could not create property group (repository is read-only)
2783 2784   *   EACCES - could not create property group (backend access denied)
2784 2785   *   EEXIST - could not create property group (already exists)
2785 2786   *   EINVAL - invalid property group name (error printed)
2786 2787   *          - invalid property name (error printed)
2787 2788   *          - invalid value (error printed)
2788 2789   *   EBUSY - new property group changed (error printed)
2789 2790   */
2790 2791  static int
2791 2792  lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792 2793      const entity_t *iinst, int flags)
2793 2794  {
2794 2795          scf_callback_t cbdata;
2795 2796  
2796 2797          cbdata.sc_handle = scf_instance_handle(inst);
2797 2798          cbdata.sc_parent = inst;
2798 2799          cbdata.sc_service = 0;
2799 2800          cbdata.sc_general = NULL;
2800 2801          cbdata.sc_enable = NULL;
2801 2802          cbdata.sc_flags = flags;
2802 2803          cbdata.sc_source_fmri = iinst->sc_fmri;
2803 2804          cbdata.sc_target_fmri = target_fmri;
2804 2805  
2805 2806          /*
2806 2807           * If the op is set, then add the flag to the callback
2807 2808           * flags for later use.
2808 2809           */
2809 2810          if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 2811                  switch (iinst->sc_op) {
2811 2812                  case SVCCFG_OP_IMPORT :
2812 2813                          cbdata.sc_flags |= SCI_OP_IMPORT;
2813 2814                          break;
2814 2815                  case SVCCFG_OP_APPLY :
2815 2816                          cbdata.sc_flags |= SCI_OP_APPLY;
2816 2817                          break;
2817 2818                  case SVCCFG_OP_RESTORE :
2818 2819                          cbdata.sc_flags |= SCI_OP_RESTORE;
2819 2820                          break;
2820 2821                  default :
2821 2822                          uu_die(gettext("lscf_import_instance_pgs : "
2822 2823                              "Unknown op stored in the instance entity\n"));
2823 2824                  }
2824 2825          }
2825 2826  
2826 2827          if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 2828              UU_DEFAULT) != 0) {
2828 2829                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 2830                          bad_error("uu_list_walk", uu_error());
2830 2831  
2831 2832                  return (cbdata.sc_err);
2832 2833          }
2833 2834  
2834 2835          if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 2836                  cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836 2837                  /*
2837 2838                   * If importing with the SCI_NOENABLED flag then
2838 2839                   * skip the delay, but if not then add the delay
2839 2840                   * of the enable property.
2840 2841                   */
2841 2842                  if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 2843                          cbdata.sc_flags |= SCI_DELAYENABLE;
2843 2844                  }
2844 2845  
2845 2846                  if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 2847                      != UU_WALK_NEXT)
2847 2848                          return (cbdata.sc_err);
2848 2849          }
2849 2850  
2850 2851          return (0);
2851 2852  }
2852 2853  
2853 2854  /*
2854 2855   * Report the reasons why we can't upgrade pg2 to pg1.
2855 2856   */
2856 2857  static void
2857 2858  report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858 2859      int new)
2859 2860  {
2860 2861          property_t *p1, *p2;
2861 2862  
2862 2863          assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863 2864  
2864 2865          if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 2866                  return;
2866 2867  
2867 2868          for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 2869              p1 != NULL;
2869 2870              p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 2871                  p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 2872                  if (p2 != NULL) {
2872 2873                          (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 2874                              new);
2874 2875                          continue;
2875 2876                  }
2876 2877  
2877 2878                  if (new)
2878 2879                          warn(gettext("Conflict upgrading %s (new property "
2879 2880                              "group \"%s\" is missing property \"%s\").\n"),
2880 2881                              fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 2882                  else
2882 2883                          warn(gettext("Conflict upgrading %s (property "
2883 2884                              "\"%s/%s\" is missing).\n"), fmri,
2884 2885                              pg1->sc_pgroup_name, p1->sc_property_name);
2885 2886          }
2886 2887  
2887 2888          /*
2888 2889           * Since pg1 should be from the manifest, any properties in pg2 which
2889 2890           * aren't in pg1 shouldn't be reported as conflicts.
2890 2891           */
2891 2892  }
2892 2893  
2893 2894  /*
2894 2895   * Add transaction entries to tx which will upgrade cur's pg according to old
2895 2896   * & new.
2896 2897   *
2897 2898   * Returns
2898 2899   *   0 - success
2899 2900   *   EINVAL - new has a property with an invalid name or value (message emitted)
2900 2901   *   ENOMEM - out of memory
2901 2902   */
2902 2903  static int
2903 2904  add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904 2905      pgroup_t *cur, int speak, const char *fmri)
2905 2906  {
2906 2907          property_t *p, *new_p, *cur_p;
2907 2908          scf_transaction_entry_t *e;
2908 2909          int r;
2909 2910          int is_general;
2910 2911          int is_protected;
2911 2912  
2912 2913          if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 2914              (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 2915                  bad_error("uu_list_walk", uu_error());
2915 2916  
2916 2917          is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917 2918  
2918 2919          for (p = uu_list_first(old->sc_pgroup_props);
2919 2920              p != NULL;
2920 2921              p = uu_list_next(old->sc_pgroup_props, p)) {
2921 2922                  /* p is a property in the old property group. */
2922 2923  
2923 2924                  /* Protect live properties. */
2924 2925                  is_protected = 0;
2925 2926                  if (is_general) {
2926 2927                          if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 2928                              0 ||
2928 2929                              strcmp(p->sc_property_name,
2929 2930                              SCF_PROPERTY_RESTARTER) == 0)
2930 2931                                  is_protected = 1;
2931 2932                  }
2932 2933  
2933 2934                  /* Look for the same property in the new properties. */
2934 2935                  new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 2936                  if (new_p != NULL) {
2936 2937                          new_p->sc_seen = 1;
2937 2938  
2938 2939                          /*
2939 2940                           * If the new property is the same as the old, don't do
2940 2941                           * anything (leave any user customizations).
2941 2942                           */
2942 2943                          if (prop_equal(p, new_p, NULL, NULL, 0))
2943 2944                                  continue;
2944 2945  
2945 2946                          if (new_p->sc_property_override)
2946 2947                                  goto upgrade;
2947 2948                  }
2948 2949  
2949 2950                  cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 2951                  if (cur_p == NULL) {
2951 2952                          /*
2952 2953                           * p has been deleted from the repository.  If we were
2953 2954                           * going to delete it anyway, do nothing.  Otherwise
2954 2955                           * report a conflict.
2955 2956                           */
2956 2957                          if (new_p == NULL)
2957 2958                                  continue;
2958 2959  
2959 2960                          if (is_protected)
2960 2961                                  continue;
2961 2962  
2962 2963                          warn(gettext("Conflict upgrading %s "
2963 2964                              "(property \"%s/%s\" is missing).\n"), fmri,
2964 2965                              old->sc_pgroup_name, p->sc_property_name);
2965 2966                          continue;
2966 2967                  }
2967 2968  
2968 2969                  if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969 2970                          /*
2970 2971                           * Conflict.  Don't warn if the property is already the
2971 2972                           * way we want it, though.
2972 2973                           */
2973 2974                          if (is_protected)
2974 2975                                  continue;
2975 2976  
2976 2977                          if (new_p == NULL)
2977 2978                                  (void) prop_equal(p, cur_p, fmri,
2978 2979                                      old->sc_pgroup_name, 0);
2979 2980                          else
2980 2981                                  (void) prop_equal(cur_p, new_p, fmri,
2981 2982                                      old->sc_pgroup_name, 0);
2982 2983                          continue;
2983 2984                  }
2984 2985  
2985 2986                  if (is_protected) {
2986 2987                          if (speak)
2987 2988                                  warn(gettext("%s: Refusing to upgrade "
2988 2989                                      "\"%s/%s\" (live property).\n"), fmri,
2989 2990                                      old->sc_pgroup_name, p->sc_property_name);
2990 2991                          continue;
2991 2992                  }
2992 2993  
2993 2994  upgrade:
2994 2995                  /* p hasn't been customized in the repository.  Upgrade it. */
2995 2996                  if (new_p == NULL) {
2996 2997                          /* p was deleted.  Delete from cur if unchanged. */
2997 2998                          if (speak)
2998 2999                                  warn(gettext(
2999 3000                                      "%s: Deleting property \"%s/%s\".\n"),
3000 3001                                      fmri, old->sc_pgroup_name,
3001 3002                                      p->sc_property_name);
3002 3003  
3003 3004                          e = scf_entry_create(g_hndl);
3004 3005                          if (e == NULL)
3005 3006                                  return (ENOMEM);
3006 3007  
3007 3008                          if (scf_transaction_property_delete(tx, e,
3008 3009                              p->sc_property_name) != 0) {
3009 3010                                  switch (scf_error()) {
3010 3011                                  case SCF_ERROR_DELETED:
3011 3012                                          scf_entry_destroy(e);
3012 3013                                          return (ECANCELED);
3013 3014  
3014 3015                                  case SCF_ERROR_CONNECTION_BROKEN:
3015 3016                                          scf_entry_destroy(e);
3016 3017                                          return (ECONNABORTED);
3017 3018  
3018 3019                                  case SCF_ERROR_NOT_FOUND:
3019 3020                                          /*
3020 3021                                           * This can happen if cur is from the
3021 3022                                           * running snapshot (and it differs
3022 3023                                           * from the live properties).
3023 3024                                           */
3024 3025                                          scf_entry_destroy(e);
3025 3026                                          break;
3026 3027  
3027 3028                                  case SCF_ERROR_HANDLE_MISMATCH:
3028 3029                                  case SCF_ERROR_NOT_BOUND:
3029 3030                                  case SCF_ERROR_NOT_SET:
3030 3031                                  case SCF_ERROR_INVALID_ARGUMENT:
3031 3032                                  default:
3032 3033                                          bad_error(
3033 3034                                              "scf_transaction_property_delete",
3034 3035                                              scf_error());
3035 3036                                  }
3036 3037                          }
3037 3038                  } else {
3038 3039                          scf_callback_t ctx;
3039 3040  
3040 3041                          if (speak)
3041 3042                                  warn(gettext(
3042 3043                                      "%s: Upgrading property \"%s/%s\".\n"),
3043 3044                                      fmri, old->sc_pgroup_name,
3044 3045                                      p->sc_property_name);
3045 3046  
3046 3047                          ctx.sc_handle = g_hndl;
3047 3048                          ctx.sc_trans = tx;
3048 3049                          ctx.sc_flags = 0;
3049 3050  
3050 3051                          r = lscf_property_import(new_p, &ctx);
3051 3052                          if (r != UU_WALK_NEXT) {
3052 3053                                  if (r != UU_WALK_ERROR)
3053 3054                                          bad_error("lscf_property_import", r);
3054 3055                                  return (EINVAL);
3055 3056                          }
3056 3057                  }
3057 3058          }
3058 3059  
3059 3060          /* Go over the properties which were added. */
3060 3061          for (new_p = uu_list_first(new->sc_pgroup_props);
3061 3062              new_p != NULL;
3062 3063              new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 3064                  if (new_p->sc_seen)
3064 3065                          continue;
3065 3066  
3066 3067                  /* This is a new property. */
3067 3068                  cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 3069                  if (cur_p == NULL) {
3069 3070                          scf_callback_t ctx;
3070 3071  
3071 3072                          ctx.sc_handle = g_hndl;
3072 3073                          ctx.sc_trans = tx;
3073 3074                          ctx.sc_flags = 0;
3074 3075  
3075 3076                          r = lscf_property_import(new_p, &ctx);
3076 3077                          if (r != UU_WALK_NEXT) {
3077 3078                                  if (r != UU_WALK_ERROR)
3078 3079                                          bad_error("lscf_property_import", r);
3079 3080                                  return (EINVAL);
3080 3081                          }
3081 3082                          continue;
3082 3083                  }
3083 3084  
3084 3085                  /*
3085 3086                   * Report a conflict if the new property differs from the
3086 3087                   * current one.  Unless it's general/enabled, since that's
3087 3088                   * never in the last-import snapshot.
3088 3089                   */
3089 3090                  if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 3091                      0 &&
3091 3092                      strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 3093                          continue;
3093 3094  
3094 3095                  (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095 3096          }
3096 3097  
3097 3098          return (0);
3098 3099  }
3099 3100  
3100 3101  /*
3101 3102   * Upgrade pg according to old & new.
3102 3103   *
3103 3104   * Returns
3104 3105   *   0 - success
3105 3106   *   ECONNABORTED - repository connection broken
3106 3107   *   ENOMEM - out of memory
3107 3108   *   ENOSPC - svc.configd is out of resources
3108 3109   *   ECANCELED - pg was deleted
3109 3110   *   EPERM - couldn't modify pg (permission denied)
3110 3111   *   EROFS - couldn't modify pg (backend read-only)
3111 3112   *   EACCES - couldn't modify pg (backend access denied)
3112 3113   *   EINVAL - new has a property with invalid name or value (error printed)
3113 3114   *   EBUSY - pg changed unexpectedly
3114 3115   */
3115 3116  static int
3116 3117  upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117 3118      pgroup_t *new, int speak, const char *fmri)
3118 3119  {
3119 3120          int r;
3120 3121  
3121 3122          if (scf_transaction_start(imp_tx, pg) != 0) {
3122 3123                  switch (scf_error()) {
3123 3124                  case SCF_ERROR_CONNECTION_BROKEN:
3124 3125                  case SCF_ERROR_DELETED:
3125 3126                  case SCF_ERROR_PERMISSION_DENIED:
3126 3127                  case SCF_ERROR_BACKEND_READONLY:
3127 3128                  case SCF_ERROR_BACKEND_ACCESS:
3128 3129                          return (scferror2errno(scf_error()));
3129 3130  
3130 3131                  case SCF_ERROR_HANDLE_MISMATCH:
3131 3132                  case SCF_ERROR_IN_USE:
3132 3133                  case SCF_ERROR_NOT_BOUND:
3133 3134                  case SCF_ERROR_NOT_SET:
3134 3135                  default:
3135 3136                          bad_error("scf_transaction_start", scf_error());
3136 3137                  }
3137 3138          }
3138 3139  
3139 3140          r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 3141          switch (r) {
3141 3142          case 0:
3142 3143                  break;
3143 3144  
3144 3145          case EINVAL:
3145 3146          case ENOMEM:
3146 3147                  scf_transaction_destroy_children(imp_tx);
3147 3148                  return (r);
3148 3149  
3149 3150          default:
3150 3151                  bad_error("add_upgrade_entries", r);
3151 3152          }
3152 3153  
3153 3154          r = scf_transaction_commit(imp_tx);
3154 3155  
3155 3156          scf_transaction_destroy_children(imp_tx);
3156 3157  
3157 3158          switch (r) {
3158 3159          case 1:
3159 3160                  break;
3160 3161  
3161 3162          case 0:
3162 3163                  return (EBUSY);
3163 3164  
3164 3165          case -1:
3165 3166                  switch (scf_error()) {
3166 3167                  case SCF_ERROR_CONNECTION_BROKEN:
3167 3168                  case SCF_ERROR_NO_RESOURCES:
3168 3169                  case SCF_ERROR_PERMISSION_DENIED:
3169 3170                  case SCF_ERROR_BACKEND_READONLY:
3170 3171                  case SCF_ERROR_BACKEND_ACCESS:
3171 3172                  case SCF_ERROR_DELETED:
3172 3173                          return (scferror2errno(scf_error()));
3173 3174  
3174 3175                  case SCF_ERROR_NOT_BOUND:
3175 3176                  case SCF_ERROR_INVALID_ARGUMENT:
3176 3177                  case SCF_ERROR_NOT_SET:
3177 3178                  default:
3178 3179                          bad_error("scf_transaction_commit", scf_error());
3179 3180                  }
3180 3181  
3181 3182          default:
3182 3183                  bad_error("scf_transaction_commit", r);
3183 3184          }
3184 3185  
3185 3186          return (0);
3186 3187  }
3187 3188  
3188 3189  /*
3189 3190   * Compares two entity FMRIs.  Returns
3190 3191   *
3191 3192   *   1 - equal
3192 3193   *   0 - not equal
3193 3194   *   -1 - f1 is invalid or not an entity
3194 3195   *   -2 - f2 is invalid or not an entity
3195 3196   */
3196 3197  static int
3197 3198  fmri_equal(const char *f1, const char *f2)
3198 3199  {
3199 3200          int r;
3200 3201          const char *s1, *i1, *pg1;
3201 3202          const char *s2, *i2, *pg2;
3202 3203  
3203 3204          if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 3205                  return (-1);
3205 3206          if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 3207                  return (-1);
3207 3208  
3208 3209          if (s1 == NULL || pg1 != NULL)
3209 3210                  return (-1);
3210 3211  
3211 3212          if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 3213                  return (-2);
3213 3214          if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 3215                  return (-2);
3215 3216  
3216 3217          if (s2 == NULL || pg2 != NULL)
3217 3218                  return (-2);
3218 3219  
3219 3220          r = strcmp(s1, s2);
3220 3221          if (r != 0)
3221 3222                  return (0);
3222 3223  
3223 3224          if (i1 == NULL && i2 == NULL)
3224 3225                  return (1);
3225 3226  
3226 3227          if (i1 == NULL || i2 == NULL)
3227 3228                  return (0);
3228 3229  
3229 3230          return (strcmp(i1, i2) == 0);
3230 3231  }
3231 3232  
3232 3233  /*
3233 3234   * Import a dependent by creating a dependency property group in the dependent
3234 3235   * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3235 3236   * dependents pg, and add an entry to create a new property for this
3236 3237   * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237 3238   *
3238 3239   * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3239 3240   * lcbdata->sc_err to
3240 3241   *   ECONNABORTED - repository connection broken
3241 3242   *   ENOMEM - out of memory
3242 3243   *   ENOSPC - configd is out of resources
3243 3244   *   EINVAL - target is invalid (error printed)
3244 3245   *          - target is not an entity (error printed)
3245 3246   *          - dependent has invalid name (error printed)
3246 3247   *          - invalid property name (error printed)
3247 3248   *          - invalid value (error printed)
3248 3249   *          - scope of target does not exist (error printed)
3249 3250   *   EPERM - couldn't create target (permission denied) (error printed)
3250 3251   *         - couldn't create dependency pg (permission denied) (error printed)
3251 3252   *         - couldn't modify dependency pg (permission denied) (error printed)
3252 3253   *   EROFS - couldn't create target (repository read-only)
3253 3254   *         - couldn't create dependency pg (repository read-only)
3254 3255   *   EACCES - couldn't create target (backend access denied)
3255 3256   *          - couldn't create dependency pg (backend access denied)
3256 3257   *   ECANCELED - sc_trans's pg was deleted
3257 3258   *   EALREADY - property for dependent already exists in sc_trans's pg
3258 3259   *   EEXIST - dependency pg already exists in target (error printed)
3259 3260   *   EBUSY - target deleted (error printed)
3260 3261   *         - property group changed during import (error printed)
3261 3262   */
3262 3263  static int
3263 3264  lscf_dependent_import(void *a1, void *pvt)
3264 3265  {
3265 3266          pgroup_t *pgrp = a1;
3266 3267          scf_callback_t *lcbdata = pvt;
3267 3268  
3268 3269          int isservice;
3269 3270          int ret;
3270 3271          scf_transaction_entry_t *e;
3271 3272          scf_value_t *val;
3272 3273          scf_callback_t dependent_cbdata;
3273 3274          scf_error_t scfe;
3274 3275  
3275 3276          /*
3276 3277           * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3277 3278           * it's invalid, we fail before modifying the repository.
3278 3279           */
3279 3280          scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 3281              &dependent_cbdata.sc_parent, &isservice);
3281 3282          switch (scfe) {
3282 3283          case SCF_ERROR_NONE:
3283 3284                  break;
3284 3285  
3285 3286          case SCF_ERROR_NO_MEMORY:
3286 3287                  return (stash_scferror_err(lcbdata, scfe));
3287 3288  
3288 3289          case SCF_ERROR_INVALID_ARGUMENT:
3289 3290                  semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 3291                      "invalid.\n"), pgrp->sc_pgroup_name);
3291 3292                  return (stash_scferror_err(lcbdata, scfe));
3292 3293  
3293 3294          case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 3295                  semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 3296                      "specifies neither a service nor an instance.\n"),
3296 3297                      pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 3298                  return (stash_scferror_err(lcbdata, scfe));
3298 3299  
3299 3300          case SCF_ERROR_NOT_FOUND:
3300 3301                  scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 3302                      &dependent_cbdata.sc_parent, &isservice);
3302 3303                  switch (scfe) {
3303 3304                  case SCF_ERROR_NONE:
3304 3305                          break;
3305 3306  
3306 3307                  case SCF_ERROR_NO_MEMORY:
3307 3308                  case SCF_ERROR_BACKEND_READONLY:
3308 3309                  case SCF_ERROR_BACKEND_ACCESS:
3309 3310                          return (stash_scferror_err(lcbdata, scfe));
3310 3311  
3311 3312                  case SCF_ERROR_NOT_FOUND:
3312 3313                          semerr(gettext("The scope in FMRI \"%s\" for the "
3313 3314                              "\"%s\" dependent does not exist.\n"),
3314 3315                              pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 3316                          lcbdata->sc_err = EINVAL;
3316 3317                          return (UU_WALK_ERROR);
3317 3318  
3318 3319                  case SCF_ERROR_PERMISSION_DENIED:
3319 3320                          warn(gettext(
3320 3321                              "Could not create %s (permission denied).\n"),
3321 3322                              pgrp->sc_pgroup_fmri);
3322 3323                          return (stash_scferror_err(lcbdata, scfe));
3323 3324  
3324 3325                  case SCF_ERROR_INVALID_ARGUMENT:
3325 3326                  case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 3327                  default:
3327 3328                          bad_error("create_entity", scfe);
3328 3329                  }
3329 3330                  break;
3330 3331  
3331 3332          default:
3332 3333                  bad_error("fmri_to_entity", scfe);
3333 3334          }
3334 3335  
3335 3336          if (lcbdata->sc_trans != NULL) {
3336 3337                  e = scf_entry_create(lcbdata->sc_handle);
3337 3338                  if (e == NULL) {
3338 3339                          if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 3340                                  bad_error("scf_entry_create", scf_error());
3340 3341  
3341 3342                          entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 3343                          return (stash_scferror(lcbdata));
3343 3344                  }
3344 3345  
3345 3346                  if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 3347                      pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 3348                          switch (scf_error()) {
3348 3349                          case SCF_ERROR_INVALID_ARGUMENT:
3349 3350                                  warn(gettext("Dependent of %s has invalid name "
3350 3351                                      "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 3352                                      pgrp->sc_pgroup_name);
3352 3353                                  /* FALLTHROUGH */
3353 3354  
3354 3355                          case SCF_ERROR_DELETED:
3355 3356                          case SCF_ERROR_CONNECTION_BROKEN:
3356 3357                                  scf_entry_destroy(e);
3357 3358                                  entity_destroy(dependent_cbdata.sc_parent,
3358 3359                                      isservice);
3359 3360                                  return (stash_scferror(lcbdata));
3360 3361  
3361 3362                          case SCF_ERROR_EXISTS:
3362 3363                                  scf_entry_destroy(e);
3363 3364                                  entity_destroy(dependent_cbdata.sc_parent,
3364 3365                                      isservice);
3365 3366                                  lcbdata->sc_err = EALREADY;
3366 3367                                  return (UU_WALK_ERROR);
3367 3368  
3368 3369                          case SCF_ERROR_NOT_BOUND:
3369 3370                          case SCF_ERROR_HANDLE_MISMATCH:
3370 3371                          case SCF_ERROR_NOT_SET:
3371 3372                          default:
3372 3373                                  bad_error("scf_transaction_property_new",
3373 3374                                      scf_error());
3374 3375                          }
3375 3376                  }
3376 3377  
3377 3378                  val = scf_value_create(lcbdata->sc_handle);
3378 3379                  if (val == NULL) {
3379 3380                          if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 3381                                  bad_error("scf_value_create", scf_error());
3381 3382  
3382 3383                          entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 3384                          return (stash_scferror(lcbdata));
3384 3385                  }
3385 3386  
3386 3387                  if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 3388                      pgrp->sc_pgroup_fmri) != 0)
3388 3389                          /* invalid should have been caught above */
3389 3390                          bad_error("scf_value_set_from_string", scf_error());
3390 3391  
3391 3392                  if (scf_entry_add_value(e, val) != 0)
3392 3393                          bad_error("scf_entry_add_value", scf_error());
3393 3394          }
3394 3395  
3395 3396          /* Add the property group to the target entity. */
3396 3397  
3397 3398          dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 3399          dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 3400          dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 3401          dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401 3402  
3402 3403          ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403 3404  
3404 3405          entity_destroy(dependent_cbdata.sc_parent, isservice);
3405 3406  
3406 3407          if (ret == UU_WALK_NEXT)
3407 3408                  return (ret);
3408 3409  
3409 3410          if (ret != UU_WALK_ERROR)
3410 3411                  bad_error("entity_pgroup_import", ret);
3411 3412  
3412 3413          switch (dependent_cbdata.sc_err) {
3413 3414          case ECANCELED:
3414 3415                  warn(gettext("%s deleted unexpectedly.\n"),
3415 3416                      pgrp->sc_pgroup_fmri);
3416 3417                  lcbdata->sc_err = EBUSY;
3417 3418                  break;
3418 3419  
3419 3420          case EEXIST:
3420 3421                  warn(gettext("Could not create \"%s\" dependency in %s "
3421 3422                      "(already exists).\n"), pgrp->sc_pgroup_name,
3422 3423                      pgrp->sc_pgroup_fmri);
3423 3424                  /* FALLTHROUGH */
3424 3425  
3425 3426          default:
3426 3427                  lcbdata->sc_err = dependent_cbdata.sc_err;
3427 3428          }
3428 3429  
3429 3430          return (UU_WALK_ERROR);
3430 3431  }
3431 3432  
3432 3433  static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433 3434      const scf_snaplevel_t *, scf_transaction_t *);
3434 3435  static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435 3436      const pgroup_t *);
3436 3437  
3437 3438  /*
3438 3439   * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3439 3440   * the current dependent targets from running (the snaplevel of a running
3440 3441   * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 3442   * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3442 3443   * dependent targets and dependency properties from li_dpts_pg (the
3443 3444   * "dependents" property group in snpl) and snpl (the snaplevel which
3444 3445   * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3445 3446   * snpl doesn't have a "dependents" property group, and any dependents in ient
3446 3447   * are new.
3447 3448   *
3448 3449   * Returns
3449 3450   *   0 - success
3450 3451   *   ECONNABORTED - repository connection broken
3451 3452   *   ENOMEM - out of memory
3452 3453   *   ENOSPC - configd is out of resources
3453 3454   *   ECANCELED - ent was deleted
3454 3455   *   ENODEV - the entity containing li_dpts_pg was deleted
3455 3456   *   EPERM - could not modify dependents pg (permission denied) (error printed)
3456 3457   *         - couldn't upgrade dependent (permission denied) (error printed)
3457 3458   *         - couldn't create dependent (permission denied) (error printed)
3458 3459   *   EROFS - could not modify dependents pg (repository read-only)
3459 3460   *         - couldn't upgrade dependent (repository read-only)
3460 3461   *         - couldn't create dependent (repository read-only)
3461 3462   *   EACCES - could not modify dependents pg (backend access denied)
3462 3463   *          - could not upgrade dependent (backend access denied)
3463 3464   *          - could not create dependent (backend access denied)
3464 3465   *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 3466   *         - dependent target deleted (error printed)
3466 3467   *         - dependent pg changed (error printed)
3467 3468   *   EINVAL - new dependent is invalid (error printed)
3468 3469   *   EBADF - snpl is corrupt (error printed)
3469 3470   *         - snpl has corrupt pg (error printed)
3470 3471   *         - dependency pg in target is corrupt (error printed)
3471 3472   *         - target has corrupt snapshot (error printed)
3472 3473   *   EEXIST - dependency pg already existed in target service (error printed)
3473 3474   */
3474 3475  static int
3475 3476  upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476 3477      const scf_snaplevel_t *snpl, const entity_t *ient,
3477 3478      const scf_snaplevel_t *running, void *ent)
3478 3479  {
3479 3480          pgroup_t *new_dpt_pgroup;
3480 3481          scf_callback_t cbdata;
3481 3482          int r, unseen, tx_started = 0;
3482 3483          int have_cur_depts;
3483 3484  
3484 3485          const char * const dependents = "dependents";
3485 3486  
3486 3487          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487 3488  
3488 3489          if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 3490                  /* Nothing to do. */
3490 3491                  return (0);
3491 3492  
3492 3493          /* Fetch the current version of the "dependents" property group. */
3493 3494          have_cur_depts = 1;
3494 3495          if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 3496                  switch (scf_error()) {
3496 3497                  case SCF_ERROR_NOT_FOUND:
3497 3498                          break;
3498 3499  
3499 3500                  case SCF_ERROR_DELETED:
3500 3501                  case SCF_ERROR_CONNECTION_BROKEN:
3501 3502                          return (scferror2errno(scf_error()));
3502 3503  
3503 3504                  case SCF_ERROR_NOT_SET:
3504 3505                  case SCF_ERROR_INVALID_ARGUMENT:
3505 3506                  case SCF_ERROR_HANDLE_MISMATCH:
3506 3507                  case SCF_ERROR_NOT_BOUND:
3507 3508                  default:
3508 3509                          bad_error("entity_get_pg", scf_error());
3509 3510                  }
3510 3511  
3511 3512                  have_cur_depts = 0;
3512 3513          }
3513 3514  
3514 3515          /* Fetch the running version of the "dependents" property group. */
3515 3516          ud_run_dpts_pg_set = 0;
3516 3517          if (running != NULL)
3517 3518                  r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 3519          else
3519 3520                  r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 3521          if (r == 0) {
3521 3522                  ud_run_dpts_pg_set = 1;
3522 3523          } else {
3523 3524                  switch (scf_error()) {
3524 3525                  case SCF_ERROR_NOT_FOUND:
3525 3526                          break;
3526 3527  
3527 3528                  case SCF_ERROR_DELETED:
3528 3529                  case SCF_ERROR_CONNECTION_BROKEN:
3529 3530                          return (scferror2errno(scf_error()));
3530 3531  
3531 3532                  case SCF_ERROR_NOT_SET:
3532 3533                  case SCF_ERROR_INVALID_ARGUMENT:
3533 3534                  case SCF_ERROR_HANDLE_MISMATCH:
3534 3535                  case SCF_ERROR_NOT_BOUND:
3535 3536                  default:
3536 3537                          bad_error(running ? "scf_snaplevel_get_pg" :
3537 3538                              "entity_get_pg", scf_error());
3538 3539                  }
3539 3540          }
3540 3541  
3541 3542          /*
3542 3543           * Clear the seen fields of the dependents, so we can tell which ones
3543 3544           * are new.
3544 3545           */
3545 3546          if (uu_list_walk(ient->sc_dependents, clear_int,
3546 3547              (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 3548                  bad_error("uu_list_walk", uu_error());
3548 3549  
3549 3550          if (li_dpts_pg != NULL) {
3550 3551                  /*
3551 3552                   * Each property in li_dpts_pg represents a dependent tag in
3552 3553                   * the old manifest.  For each, call upgrade_dependent(),
3553 3554                   * which will change ud_cur_depts_pg or dependencies in other
3554 3555                   * services as appropriate.  Note (a) that changes to
3555 3556                   * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 3557                   * made en masse, and (b) it's ok if the entity doesn't have
3557 3558                   * a current version of the "dependents" property group,
3558 3559                   * because we'll just consider all dependents as customized
3559 3560                   * (by being deleted).
3560 3561                   */
3561 3562  
3562 3563                  if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 3564                          switch (scf_error()) {
3564 3565                          case SCF_ERROR_DELETED:
3565 3566                                  return (ENODEV);
3566 3567  
3567 3568                          case SCF_ERROR_CONNECTION_BROKEN:
3568 3569                                  return (ECONNABORTED);
3569 3570  
3570 3571                          case SCF_ERROR_HANDLE_MISMATCH:
3571 3572                          case SCF_ERROR_NOT_BOUND:
3572 3573                          case SCF_ERROR_NOT_SET:
3573 3574                          default:
3574 3575                                  bad_error("scf_iter_pg_properties",
3575 3576                                      scf_error());
3576 3577                          }
3577 3578                  }
3578 3579  
3579 3580                  if (have_cur_depts &&
3580 3581                      scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 3582                          switch (scf_error()) {
3582 3583                          case SCF_ERROR_BACKEND_ACCESS:
3583 3584                          case SCF_ERROR_BACKEND_READONLY:
3584 3585                          case SCF_ERROR_CONNECTION_BROKEN:
3585 3586                                  return (scferror2errno(scf_error()));
3586 3587  
3587 3588                          case SCF_ERROR_DELETED:
3588 3589                                  warn(emsg_pg_deleted, ient->sc_fmri,
3589 3590                                      dependents);
3590 3591                                  return (EBUSY);
3591 3592  
3592 3593                          case SCF_ERROR_PERMISSION_DENIED:
3593 3594                                  warn(emsg_pg_mod_perm, dependents,
3594 3595                                      ient->sc_fmri);
3595 3596                                  return (scferror2errno(scf_error()));
3596 3597  
3597 3598                          case SCF_ERROR_HANDLE_MISMATCH:
3598 3599                          case SCF_ERROR_IN_USE:
3599 3600                          case SCF_ERROR_NOT_BOUND:
3600 3601                          case SCF_ERROR_NOT_SET:
3601 3602                          default:
3602 3603                                  bad_error("scf_transaction_start", scf_error());
3603 3604                          }
3604 3605                  }
3605 3606                  tx_started = have_cur_depts;
3606 3607  
3607 3608                  for (;;) {
3608 3609                          r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 3610                          if (r == 0)
3610 3611                                  break;
3611 3612                          if (r == 1) {
3612 3613                                  r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 3614                                      tx_started ? ud_tx : NULL);
3614 3615                                  switch (r) {
3615 3616                                  case 0:
3616 3617                                          continue;
3617 3618  
3618 3619                                  case ECONNABORTED:
3619 3620                                  case ENOMEM:
3620 3621                                  case ENOSPC:
3621 3622                                  case EBADF:
3622 3623                                  case EBUSY:
3623 3624                                  case EINVAL:
3624 3625                                  case EPERM:
3625 3626                                  case EROFS:
3626 3627                                  case EACCES:
3627 3628                                  case EEXIST:
3628 3629                                          break;
3629 3630  
3630 3631                                  case ECANCELED:
3631 3632                                          r = ENODEV;
3632 3633                                          break;
3633 3634  
3634 3635                                  default:
3635 3636                                          bad_error("upgrade_dependent", r);
3636 3637                                  }
3637 3638  
3638 3639                                  if (tx_started)
3639 3640                                          scf_transaction_destroy_children(ud_tx);
3640 3641                                  return (r);
3641 3642                          }
3642 3643                          if (r != -1)
3643 3644                                  bad_error("scf_iter_next_property", r);
3644 3645  
3645 3646                          switch (scf_error()) {
3646 3647                          case SCF_ERROR_DELETED:
3647 3648                                  r = ENODEV;
3648 3649                                  break;
3649 3650  
3650 3651                          case SCF_ERROR_CONNECTION_BROKEN:
3651 3652                                  r = ECONNABORTED;
3652 3653                                  break;
3653 3654  
3654 3655                          case SCF_ERROR_NOT_SET:
3655 3656                          case SCF_ERROR_INVALID_ARGUMENT:
3656 3657                          case SCF_ERROR_NOT_BOUND:
3657 3658                          case SCF_ERROR_HANDLE_MISMATCH:
3658 3659                          default:
3659 3660                                  bad_error("scf_iter_next_property",
3660 3661                                      scf_error());
3661 3662                          }
3662 3663  
3663 3664                          if (tx_started)
3664 3665                                  scf_transaction_destroy_children(ud_tx);
3665 3666                          return (r);
3666 3667                  }
3667 3668          }
3668 3669  
3669 3670          /* import unseen dependents */
3670 3671          unseen = 0;
3671 3672          for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 3673              new_dpt_pgroup != NULL;
3673 3674              new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 3675              new_dpt_pgroup)) {
3675 3676                  if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 3677                          unseen = 1;
3677 3678                          break;
3678 3679                  }
3679 3680          }
3680 3681  
3681 3682          /* If there are none, exit early. */
3682 3683          if (unseen == 0)
3683 3684                  goto commit;
3684 3685  
3685 3686          /* Set up for lscf_dependent_import() */
3686 3687          cbdata.sc_handle = g_hndl;
3687 3688          cbdata.sc_parent = ent;
3688 3689          cbdata.sc_service = issvc;
3689 3690          cbdata.sc_flags = 0;
3690 3691  
3691 3692          if (!have_cur_depts) {
3692 3693                  /*
3693 3694                   * We have new dependents to import, so we need a "dependents"
3694 3695                   * property group.
3695 3696                   */
3696 3697                  if (issvc)
3697 3698                          r = scf_service_add_pg(ent, dependents,
3698 3699                              SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 3700                  else
3700 3701                          r = scf_instance_add_pg(ent, dependents,
3701 3702                              SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 3703                  if (r != 0) {
3703 3704                          switch (scf_error()) {
3704 3705                          case SCF_ERROR_DELETED:
3705 3706                          case SCF_ERROR_CONNECTION_BROKEN:
3706 3707                          case SCF_ERROR_BACKEND_READONLY:
3707 3708                          case SCF_ERROR_BACKEND_ACCESS:
3708 3709                          case SCF_ERROR_NO_RESOURCES:
3709 3710                                  return (scferror2errno(scf_error()));
3710 3711  
3711 3712                          case SCF_ERROR_EXISTS:
3712 3713                                  warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 3714                                  return (EBUSY);
3714 3715  
3715 3716                          case SCF_ERROR_PERMISSION_DENIED:
3716 3717                                  warn(emsg_pg_add_perm, dependents,
3717 3718                                      ient->sc_fmri);
3718 3719                                  return (scferror2errno(scf_error()));
3719 3720  
3720 3721                          case SCF_ERROR_NOT_BOUND:
3721 3722                          case SCF_ERROR_HANDLE_MISMATCH:
3722 3723                          case SCF_ERROR_INVALID_ARGUMENT:
3723 3724                          case SCF_ERROR_NOT_SET:
3724 3725                          default:
3725 3726                                  bad_error("scf_service_add_pg", scf_error());
3726 3727                          }
3727 3728                  }
3728 3729          }
3729 3730  
3730 3731          cbdata.sc_trans = ud_tx;
3731 3732  
3732 3733          if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 3734                  switch (scf_error()) {
3734 3735                  case SCF_ERROR_CONNECTION_BROKEN:
3735 3736                  case SCF_ERROR_BACKEND_ACCESS:
3736 3737                  case SCF_ERROR_BACKEND_READONLY:
3737 3738                          return (scferror2errno(scf_error()));
3738 3739  
3739 3740                  case SCF_ERROR_DELETED:
3740 3741                          warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 3742                          return (EBUSY);
3742 3743  
3743 3744                  case SCF_ERROR_PERMISSION_DENIED:
3744 3745                          warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 3746                          return (scferror2errno(scf_error()));
3746 3747  
3747 3748                  case SCF_ERROR_HANDLE_MISMATCH:
3748 3749                  case SCF_ERROR_IN_USE:
3749 3750                  case SCF_ERROR_NOT_BOUND:
3750 3751                  case SCF_ERROR_NOT_SET:
3751 3752                  default:
3752 3753                          bad_error("scf_transaction_start", scf_error());
3753 3754                  }
3754 3755          }
3755 3756          tx_started = 1;
3756 3757  
3757 3758          for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 3759              new_dpt_pgroup != NULL;
3759 3760              new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 3761              new_dpt_pgroup)) {
3761 3762                  if (new_dpt_pgroup->sc_pgroup_seen)
3762 3763                          continue;
3763 3764  
3764 3765                  if (ud_run_dpts_pg_set) {
3765 3766                          /*
3766 3767                           * If the dependent is already there, then we have
3767 3768                           * a conflict.
3768 3769                           */
3769 3770                          if (scf_pg_get_property(ud_run_dpts_pg,
3770 3771                              new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 3772                                  r = handle_dependent_conflict(ient, ud_prop,
3772 3773                                      new_dpt_pgroup);
3773 3774                                  switch (r) {
3774 3775                                  case 0:
3775 3776                                          continue;
3776 3777  
3777 3778                                  case ECONNABORTED:
3778 3779                                  case ENOMEM:
3779 3780                                  case EBUSY:
3780 3781                                  case EBADF:
3781 3782                                  case EINVAL:
3782 3783                                          scf_transaction_destroy_children(ud_tx);
3783 3784                                          return (r);
3784 3785  
3785 3786                                  default:
3786 3787                                          bad_error("handle_dependent_conflict",
3787 3788                                              r);
3788 3789                                  }
3789 3790                          } else {
3790 3791                                  switch (scf_error()) {
3791 3792                                  case SCF_ERROR_NOT_FOUND:
3792 3793                                          break;
3793 3794  
3794 3795                                  case SCF_ERROR_INVALID_ARGUMENT:
3795 3796                                          warn(emsg_fmri_invalid_pg_name,
3796 3797                                              ient->sc_fmri,
3797 3798                                              new_dpt_pgroup->sc_pgroup_name);
3798 3799                                          scf_transaction_destroy_children(ud_tx);
3799 3800                                          return (EINVAL);
3800 3801  
3801 3802                                  case SCF_ERROR_DELETED:
3802 3803                                          warn(emsg_pg_deleted, ient->sc_fmri,
3803 3804                                              new_dpt_pgroup->sc_pgroup_name);
3804 3805                                          scf_transaction_destroy_children(ud_tx);
3805 3806                                          return (EBUSY);
3806 3807  
3807 3808                                  case SCF_ERROR_CONNECTION_BROKEN:
3808 3809                                          scf_transaction_destroy_children(ud_tx);
3809 3810                                          return (ECONNABORTED);
3810 3811  
3811 3812                                  case SCF_ERROR_NOT_BOUND:
3812 3813                                  case SCF_ERROR_HANDLE_MISMATCH:
3813 3814                                  case SCF_ERROR_NOT_SET:
3814 3815                                  default:
3815 3816                                          bad_error("scf_pg_get_property",
3816 3817                                              scf_error());
3817 3818                                  }
3818 3819                          }
3819 3820                  }
3820 3821  
3821 3822                  r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 3823                  if (r != UU_WALK_NEXT) {
3823 3824                          if (r != UU_WALK_ERROR)
3824 3825                                  bad_error("lscf_dependent_import", r);
3825 3826  
3826 3827                          if (cbdata.sc_err == EALREADY) {
3827 3828                                  /* Collisions were handled preemptively. */
3828 3829                                  bad_error("lscf_dependent_import",
3829 3830                                      cbdata.sc_err);
3830 3831                          }
3831 3832  
3832 3833                          scf_transaction_destroy_children(ud_tx);
3833 3834                          return (cbdata.sc_err);
3834 3835                  }
3835 3836          }
3836 3837  
3837 3838  commit:
3838 3839          if (!tx_started)
3839 3840                  return (0);
3840 3841  
3841 3842          r = scf_transaction_commit(ud_tx);
3842 3843  
3843 3844          scf_transaction_destroy_children(ud_tx);
3844 3845  
3845 3846          switch (r) {
3846 3847          case 1:
3847 3848                  return (0);
3848 3849  
3849 3850          case 0:
3850 3851                  warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 3852                  return (EBUSY);
3852 3853  
3853 3854          case -1:
3854 3855                  break;
3855 3856  
3856 3857          default:
3857 3858                  bad_error("scf_transaction_commit", r);
3858 3859          }
3859 3860  
3860 3861          switch (scf_error()) {
3861 3862          case SCF_ERROR_CONNECTION_BROKEN:
3862 3863          case SCF_ERROR_BACKEND_READONLY:
3863 3864          case SCF_ERROR_BACKEND_ACCESS:
3864 3865          case SCF_ERROR_NO_RESOURCES:
3865 3866                  return (scferror2errno(scf_error()));
3866 3867  
3867 3868          case SCF_ERROR_DELETED:
3868 3869                  warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 3870                  return (EBUSY);
3870 3871  
3871 3872          case SCF_ERROR_PERMISSION_DENIED:
3872 3873                  warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 3874                  return (scferror2errno(scf_error()));
3874 3875  
3875 3876          case SCF_ERROR_NOT_BOUND:
3876 3877          case SCF_ERROR_INVALID_ARGUMENT:
3877 3878          case SCF_ERROR_NOT_SET:
3878 3879          default:
3879 3880                  bad_error("scf_transaction_destroy", scf_error());
3880 3881                  /* NOTREACHED */
3881 3882          }
3882 3883  }
3883 3884  
3884 3885  /*
3885 3886   * Used to add the manifests to the list of currently supported manifests.
3886 3887   * We can modify the existing manifest list removing entries if the files
3887 3888   * don't exist.
  
    | 
      ↓ open down ↓ | 
    3852 lines elided | 
    
      ↑ open up ↑ | 
  
3888 3889   *
3889 3890   * Get the old list and the new file name
3890 3891   * If the new file name is in the list return
3891 3892   * If not then add the file to the list.
3892 3893   * As we process the list check to see if the files in the old list exist
3893 3894   *      if not then remove the file from the list.
3894 3895   * Commit the list of manifest file names.
3895 3896   *
3896 3897   */
3897 3898  static int
3898      -upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
     3899 +upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3899 3900      const scf_snaplevel_t *running, void *ent)
3900 3901  {
3901 3902          scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 3903          scf_property_t *ud_prop = NULL;
3903 3904          scf_iter_t *ud_prop_iter;
3904 3905          scf_value_t *fname_value;
3905 3906          scf_callback_t cbdata;
3906 3907          pgroup_t *mfst_pgroup;
3907 3908          property_t *mfst_prop;
3908 3909          property_t *old_prop;
3909 3910          char *pname;
3910 3911          char *fval;
3911 3912          char *old_pname;
3912 3913          char *old_fval;
3913 3914          int no_upgrade_pg;
3914 3915          int mfst_seen;
3915 3916          int r;
3916 3917  
3917 3918          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918 3919  
3919 3920          /*
3920 3921           * This should always be the service base on the code
3921 3922           * path, and the fact that the manifests pg is a service
3922 3923           * level property group only.
3923 3924           */
3924 3925          ud_mfsts_pg = scf_pg_create(g_hndl);
3925 3926          ud_prop = scf_property_create(g_hndl);
3926 3927          ud_prop_iter = scf_iter_create(g_hndl);
3927 3928          fname_value = scf_value_create(g_hndl);
3928 3929  
3929 3930          /* Fetch the "manifests" property group */
3930 3931          no_upgrade_pg = 0;
3931 3932          r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 3933              ud_mfsts_pg);
3933 3934          if (r != 0) {
3934 3935                  switch (scf_error()) {
3935 3936                  case SCF_ERROR_NOT_FOUND:
3936 3937                          no_upgrade_pg = 1;
3937 3938                          break;
3938 3939  
3939 3940                  case SCF_ERROR_DELETED:
3940 3941                  case SCF_ERROR_CONNECTION_BROKEN:
3941 3942                          return (scferror2errno(scf_error()));
3942 3943  
3943 3944                  case SCF_ERROR_NOT_SET:
3944 3945                  case SCF_ERROR_INVALID_ARGUMENT:
3945 3946                  case SCF_ERROR_HANDLE_MISMATCH:
3946 3947                  case SCF_ERROR_NOT_BOUND:
3947 3948                  default:
3948 3949                          bad_error(running ? "scf_snaplevel_get_pg" :
3949 3950                              "entity_get_pg", scf_error());
3950 3951                  }
3951 3952          }
3952 3953  
3953 3954          if (no_upgrade_pg) {
3954 3955                  cbdata.sc_handle = g_hndl;
3955 3956                  cbdata.sc_parent = ent;
3956 3957                  cbdata.sc_service = issvc;
3957 3958                  cbdata.sc_flags = SCI_FORCE;
  
    | 
      ↓ open down ↓ | 
    49 lines elided | 
    
      ↑ open up ↑ | 
  
3958 3959                  cbdata.sc_source_fmri = ient->sc_fmri;
3959 3960                  cbdata.sc_target_fmri = ient->sc_fmri;
3960 3961  
3961 3962                  if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 3963                          return (cbdata.sc_err);
3963 3964  
3964 3965                  return (0);
3965 3966          }
3966 3967  
3967 3968          /* Fetch the new manifests property group */
3968      -        for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969      -            mfst_pgroup != NULL;
3970      -            mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971      -                if (strcmp(mfst_pgroup->sc_pgroup_name,
3972      -                    SCF_PG_MANIFESTFILES) == 0)
3973      -                        break;
3974      -        }
     3969 +        mfst_pgroup = internal_pgroup_find_or_create(ient,
     3970 +            SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
     3971 +        assert(mfst_pgroup != NULL);
3975 3972  
3976 3973          if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 3974              SCF_SUCCESS)
3978 3975                  return (-1);
3979 3976  
3980 3977          if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 3978                  return (ENOMEM);
3982 3979          if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 3980                  free(pname);
3984 3981                  return (ENOMEM);
3985 3982          }
3986 3983  
3987 3984          while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 3985                  mfst_seen = 0;
3989 3986                  if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 3987                          continue;
3991 3988  
3992 3989                  for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 3990                      mfst_prop != NULL;
3994 3991                      mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 3992                      mfst_prop)) {
3996 3993                          if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 3994                                  mfst_seen = 1;
3998 3995                          }
3999 3996                  }
4000 3997  
4001 3998                  /*
4002 3999                   * If the manifest is not seen then add it to the new mfst
4003 4000                   * property list to get proccessed into the repo.
4004 4001                   */
4005 4002                  if (mfst_seen == 0) {
4006 4003                          /*
4007 4004                           * If we cannot get the value then there is no
4008 4005                           * reason to attempt to attach the value to
4009 4006                           * the property group
4010 4007                           */
4011 4008                          if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 4009                              scf_value_get_astring(fname_value, fval,
4013 4010                              MAXPATHLEN) != -1)  {
4014 4011                                  old_pname = safe_strdup(pname);
4015 4012                                  old_fval = safe_strdup(fval);
4016 4013                                  old_prop = internal_property_create(old_pname,
4017 4014                                      SCF_TYPE_ASTRING, 1, old_fval);
4018 4015  
4019 4016                                  /*
4020 4017                                   * Already checked to see if the property exists
4021 4018                                   * in the group, and it does not.
4022 4019                                   */
4023 4020                                  (void) internal_attach_property(mfst_pgroup,
4024 4021                                      old_prop);
4025 4022                          }
4026 4023                  }
4027 4024          }
4028 4025          free(pname);
4029 4026          free(fval);
4030 4027  
4031 4028          cbdata.sc_handle = g_hndl;
4032 4029          cbdata.sc_parent = ent;
4033 4030          cbdata.sc_service = issvc;
4034 4031          cbdata.sc_flags = SCI_FORCE;
4035 4032          cbdata.sc_source_fmri = ient->sc_fmri;
4036 4033          cbdata.sc_target_fmri = ient->sc_fmri;
4037 4034  
4038 4035          if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 4036                  return (cbdata.sc_err);
4040 4037  
4041 4038          return (r);
4042 4039  }
4043 4040  
4044 4041  /*
4045 4042   * prop is taken to be a property in the "dependents" property group of snpl,
4046 4043   * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 4044   * to ient.  If prop is a valid dependents property, upgrade the dependent it
4048 4045   * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4049 4046   * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 4047   * of the entity ient represents (possibly in the running snapshot).  If it
4051 4048   * needs to be changed, an entry will be added to tx, if not NULL.
4052 4049   *
4053 4050   * Returns
4054 4051   *   0 - success
4055 4052   *   ECONNABORTED - repository connection broken
4056 4053   *   ENOMEM - out of memory
4057 4054   *   ENOSPC - configd was out of resources
4058 4055   *   ECANCELED - snpl's entity was deleted
4059 4056   *   EINVAL - dependent target is invalid (error printed)
4060 4057   *          - dependent is invalid (error printed)
4061 4058   *   EBADF - snpl is corrupt (error printed)
4062 4059   *         - snpl has corrupt pg (error printed)
4063 4060   *         - dependency pg in target is corrupt (error printed)
4064 4061   *         - running snapshot in dependent is missing snaplevel (error printed)
4065 4062   *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 4063   *         - couldn't create dependent (permission denied) (error printed)
4067 4064   *         - couldn't modify dependent pg (permission denied) (error printed)
4068 4065   *   EROFS - couldn't delete dependency pg (repository read-only)
4069 4066   *         - couldn't create dependent (repository read-only)
4070 4067   *   EACCES - couldn't delete dependency pg (backend access denied)
4071 4068   *          - couldn't create dependent (backend access denied)
4072 4069   *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 4070   *         - tx's pg was deleted (error printed)
4074 4071   *         - dependent pg was changed or deleted (error printed)
4075 4072   *   EEXIST - dependency pg already exists in new target (error printed)
4076 4073   */
4077 4074  static int
4078 4075  upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079 4076      const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 4077  {
4081 4078          pgroup_t pgrp;
4082 4079          scf_type_t ty;
4083 4080          pgroup_t *new_dpt_pgroup;
4084 4081          pgroup_t *old_dpt_pgroup = NULL;
4085 4082          pgroup_t *current_pg;
4086 4083          pgroup_t *dpt;
4087 4084          scf_callback_t cbdata;
4088 4085          int tissvc;
4089 4086          void *target_ent;
4090 4087          scf_error_t serr;
4091 4088          int r;
4092 4089          scf_transaction_entry_t *ent;
4093 4090  
4094 4091          const char * const cf_inval = gettext("Conflict upgrading %s "
4095 4092              "(dependent \"%s\" has invalid dependents property).\n");
4096 4093          const char * const cf_missing = gettext("Conflict upgrading %s "
4097 4094              "(dependent \"%s\" is missing).\n");
4098 4095          const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 4096              "(dependent \"%s\" has new dependency property group).\n");
4100 4097          const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 4098              "(dependent \"%s\" has new target).\n");
4102 4099          const char * const li_corrupt =
4103 4100              gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 4101          const char * const upgrading =
4105 4102              gettext("%s: Upgrading dependent \"%s\".\n");
4106 4103          const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 4104              "corrupt (missing snaplevel).\n");
4108 4105  
4109 4106          if (scf_property_type(prop, &ty) != 0) {
4110 4107                  switch (scf_error()) {
4111 4108                  case SCF_ERROR_DELETED:
4112 4109                  case SCF_ERROR_CONNECTION_BROKEN:
4113 4110                          return (scferror2errno(scf_error()));
4114 4111  
4115 4112                  case SCF_ERROR_NOT_BOUND:
4116 4113                  case SCF_ERROR_NOT_SET:
4117 4114                  default:
4118 4115                          bad_error("scf_property_type", scf_error());
4119 4116                  }
4120 4117          }
4121 4118  
4122 4119          if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 4120                  warn(li_corrupt, ient->sc_fmri);
4124 4121                  return (EBADF);
4125 4122          }
4126 4123  
4127 4124          /*
4128 4125           * prop represents a dependent in the old manifest.  It is named after
4129 4126           * the dependent.
4130 4127           */
4131 4128          if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 4129                  switch (scf_error()) {
4133 4130                  case SCF_ERROR_DELETED:
4134 4131                  case SCF_ERROR_CONNECTION_BROKEN:
4135 4132                          return (scferror2errno(scf_error()));
4136 4133  
4137 4134                  case SCF_ERROR_NOT_BOUND:
4138 4135                  case SCF_ERROR_NOT_SET:
4139 4136                  default:
4140 4137                          bad_error("scf_property_get_name", scf_error());
4141 4138                  }
4142 4139          }
4143 4140  
4144 4141          /* See if it's in the new manifest. */
4145 4142          pgrp.sc_pgroup_name = ud_name;
4146 4143          new_dpt_pgroup =
4147 4144              uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148 4145  
4149 4146          /* If it's not, delete it... if it hasn't been customized. */
4150 4147          if (new_dpt_pgroup == NULL) {
4151 4148                  if (!ud_run_dpts_pg_set)
4152 4149                          return (0);
4153 4150  
4154 4151                  if (scf_property_get_value(prop, ud_val) != 0) {
4155 4152                          switch (scf_error()) {
4156 4153                          case SCF_ERROR_NOT_FOUND:
4157 4154                          case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 4155                                  warn(li_corrupt, ient->sc_fmri);
4159 4156                                  return (EBADF);
4160 4157  
4161 4158                          case SCF_ERROR_DELETED:
4162 4159                          case SCF_ERROR_CONNECTION_BROKEN:
4163 4160                                  return (scferror2errno(scf_error()));
4164 4161  
4165 4162                          case SCF_ERROR_HANDLE_MISMATCH:
4166 4163                          case SCF_ERROR_NOT_BOUND:
4167 4164                          case SCF_ERROR_NOT_SET:
4168 4165                          case SCF_ERROR_PERMISSION_DENIED:
4169 4166                          default:
4170 4167                                  bad_error("scf_property_get_value",
4171 4168                                      scf_error());
4172 4169                          }
4173 4170                  }
4174 4171  
4175 4172                  if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 4173                      max_scf_value_len + 1) < 0)
4177 4174                          bad_error("scf_value_get_as_string", scf_error());
4178 4175  
4179 4176                  if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 4177                      0) {
4181 4178                          switch (scf_error()) {
4182 4179                          case SCF_ERROR_NOT_FOUND:
4183 4180                                  return (0);
4184 4181  
4185 4182                          case SCF_ERROR_CONNECTION_BROKEN:
4186 4183                                  return (scferror2errno(scf_error()));
4187 4184  
4188 4185                          case SCF_ERROR_DELETED:
4189 4186                                  warn(emsg_pg_deleted, ient->sc_fmri,
4190 4187                                      "dependents");
4191 4188                                  return (EBUSY);
4192 4189  
4193 4190                          case SCF_ERROR_INVALID_ARGUMENT:
4194 4191                          case SCF_ERROR_NOT_BOUND:
4195 4192                          case SCF_ERROR_HANDLE_MISMATCH:
4196 4193                          case SCF_ERROR_NOT_SET:
4197 4194                          default:
4198 4195                                  bad_error("scf_pg_get_property", scf_error());
4199 4196                          }
4200 4197                  }
4201 4198                  if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 4199                          switch (scf_error()) {
4203 4200                          case SCF_ERROR_NOT_FOUND:
4204 4201                          case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 4202                                  warn(cf_inval, ient->sc_fmri, ud_name);
4206 4203                                  return (0);
4207 4204  
4208 4205                          case SCF_ERROR_DELETED:
4209 4206                          case SCF_ERROR_CONNECTION_BROKEN:
4210 4207                                  return (scferror2errno(scf_error()));
4211 4208  
4212 4209                          case SCF_ERROR_HANDLE_MISMATCH:
4213 4210                          case SCF_ERROR_NOT_BOUND:
4214 4211                          case SCF_ERROR_NOT_SET:
4215 4212                          case SCF_ERROR_PERMISSION_DENIED:
4216 4213                          default:
4217 4214                                  bad_error("scf_property_get_value",
4218 4215                                      scf_error());
4219 4216                          }
4220 4217                  }
4221 4218  
4222 4219                  ty = scf_value_type(ud_val);
4223 4220                  assert(ty != SCF_TYPE_INVALID);
4224 4221                  if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 4222                          warn(cf_inval, ient->sc_fmri, ud_name);
4226 4223                          return (0);
4227 4224                  }
4228 4225  
4229 4226                  if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 4227                      max_scf_value_len + 1) < 0)
4231 4228                          bad_error("scf_value_get_as_string", scf_error());
4232 4229  
4233 4230                  r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 4231                  switch (r) {
4235 4232                  case 1:
4236 4233                          break;
4237 4234  
4238 4235                  case 0:
4239 4236                  case -1:        /* warn? */
4240 4237                          warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 4238                          return (0);
4242 4239  
4243 4240                  case -2:
4244 4241                          warn(li_corrupt, ient->sc_fmri);
4245 4242                          return (EBADF);
4246 4243  
4247 4244                  default:
4248 4245                          bad_error("fmri_equal", r);
4249 4246                  }
4250 4247  
4251 4248                  if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 4249                          switch (scf_error()) {
4253 4250                          case SCF_ERROR_NOT_FOUND:
4254 4251                                  warn(li_corrupt, ient->sc_fmri);
4255 4252                                  return (EBADF);
4256 4253  
4257 4254                          case SCF_ERROR_DELETED:
4258 4255                          case SCF_ERROR_CONNECTION_BROKEN:
4259 4256                                  return (scferror2errno(scf_error()));
4260 4257  
4261 4258                          case SCF_ERROR_NOT_BOUND:
4262 4259                          case SCF_ERROR_HANDLE_MISMATCH:
4263 4260                          case SCF_ERROR_INVALID_ARGUMENT:
4264 4261                          case SCF_ERROR_NOT_SET:
4265 4262                          default:
4266 4263                                  bad_error("scf_snaplevel_get_pg", scf_error());
4267 4264                          }
4268 4265                  }
4269 4266  
4270 4267                  r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 4268                      snap_lastimport);
4272 4269                  switch (r) {
4273 4270                  case 0:
4274 4271                          break;
4275 4272  
4276 4273                  case ECANCELED:
4277 4274                  case ECONNABORTED:
4278 4275                  case ENOMEM:
4279 4276                  case EBADF:
4280 4277                          return (r);
4281 4278  
4282 4279                  case EACCES:
4283 4280                  default:
4284 4281                          bad_error("load_pg", r);
4285 4282                  }
4286 4283  
4287 4284                  serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 4285                  switch (serr) {
4289 4286                  case SCF_ERROR_NONE:
4290 4287                          break;
4291 4288  
4292 4289                  case SCF_ERROR_NO_MEMORY:
4293 4290                          internal_pgroup_free(old_dpt_pgroup);
4294 4291                          return (ENOMEM);
4295 4292  
4296 4293                  case SCF_ERROR_NOT_FOUND:
4297 4294                          internal_pgroup_free(old_dpt_pgroup);
4298 4295                          goto delprop;
4299 4296  
4300 4297                  case SCF_ERROR_CONSTRAINT_VIOLATED:     /* caught above */
4301 4298                  case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
4302 4299                  default:
4303 4300                          bad_error("fmri_to_entity", serr);
4304 4301                  }
4305 4302  
4306 4303                  r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 4304                      ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 4305                  switch (r) {
4309 4306                  case 0:
4310 4307                          break;
4311 4308  
4312 4309                  case ECONNABORTED:
4313 4310                          internal_pgroup_free(old_dpt_pgroup);
4314 4311                          return (r);
4315 4312  
4316 4313                  case ECANCELED:
4317 4314                  case ENOENT:
4318 4315                          internal_pgroup_free(old_dpt_pgroup);
4319 4316                          goto delprop;
4320 4317  
4321 4318                  case EBADF:
4322 4319                          warn(r_no_lvl, ud_ctarg);
4323 4320                          internal_pgroup_free(old_dpt_pgroup);
4324 4321                          return (r);
4325 4322  
4326 4323                  case EINVAL:
4327 4324                  default:
4328 4325                          bad_error("entity_get_running_pg", r);
4329 4326                  }
4330 4327  
4331 4328                  /* load it */
4332 4329                  r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4333 4330                  switch (r) {
4334 4331                  case 0:
4335 4332                          break;
4336 4333  
4337 4334                  case ECANCELED:
4338 4335                          internal_pgroup_free(old_dpt_pgroup);
4339 4336                          goto delprop;
4340 4337  
4341 4338                  case ECONNABORTED:
4342 4339                  case ENOMEM:
4343 4340                  case EBADF:
4344 4341                          internal_pgroup_free(old_dpt_pgroup);
4345 4342                          return (r);
4346 4343  
4347 4344                  case EACCES:
4348 4345                  default:
4349 4346                          bad_error("load_pg", r);
4350 4347                  }
4351 4348  
4352 4349                  /* compare property groups */
4353 4350                  if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 4351                          warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 4352                          internal_pgroup_free(old_dpt_pgroup);
4356 4353                          internal_pgroup_free(current_pg);
4357 4354                          return (0);
4358 4355                  }
4359 4356  
4360 4357                  internal_pgroup_free(old_dpt_pgroup);
4361 4358                  internal_pgroup_free(current_pg);
4362 4359  
4363 4360                  if (g_verbose)
4364 4361                          warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 4362                              ient->sc_fmri, ud_name);
4366 4363  
4367 4364                  if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 4365                          switch (scf_error()) {
4369 4366                          case SCF_ERROR_NOT_FOUND:
4370 4367                          case SCF_ERROR_DELETED:
4371 4368                                  internal_pgroup_free(old_dpt_pgroup);
4372 4369                                  goto delprop;
4373 4370  
4374 4371                          case SCF_ERROR_CONNECTION_BROKEN:
4375 4372                                  internal_pgroup_free(old_dpt_pgroup);
4376 4373                                  return (ECONNABORTED);
4377 4374  
4378 4375                          case SCF_ERROR_NOT_SET:
4379 4376                          case SCF_ERROR_INVALID_ARGUMENT:
4380 4377                          case SCF_ERROR_HANDLE_MISMATCH:
4381 4378                          case SCF_ERROR_NOT_BOUND:
4382 4379                          default:
4383 4380                                  bad_error("entity_get_pg", scf_error());
4384 4381                          }
4385 4382                  }
4386 4383  
4387 4384                  if (scf_pg_delete(ud_pg) != 0) {
4388 4385                          switch (scf_error()) {
4389 4386                          case SCF_ERROR_DELETED:
4390 4387                                  break;
4391 4388  
4392 4389                          case SCF_ERROR_CONNECTION_BROKEN:
4393 4390                          case SCF_ERROR_BACKEND_READONLY:
4394 4391                          case SCF_ERROR_BACKEND_ACCESS:
4395 4392                                  return (scferror2errno(scf_error()));
4396 4393  
4397 4394                          case SCF_ERROR_PERMISSION_DENIED:
4398 4395                                  warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 4396                                  return (scferror2errno(scf_error()));
4400 4397  
4401 4398                          case SCF_ERROR_NOT_SET:
4402 4399                          default:
4403 4400                                  bad_error("scf_pg_delete", scf_error());
4404 4401                          }
4405 4402                  }
4406 4403  
4407 4404                  /*
4408 4405                   * This service was changed, so it must be refreshed.  But
4409 4406                   * since it's not mentioned in the new manifest, we have to
4410 4407                   * record its FMRI here for use later.  We record the name
4411 4408                   * & the entity (via sc_parent) in case we need to print error
4412 4409                   * messages during the refresh.
4413 4410                   */
4414 4411                  dpt = internal_pgroup_new();
4415 4412                  if (dpt == NULL)
4416 4413                          return (ENOMEM);
4417 4414                  dpt->sc_pgroup_name = strdup(ud_name);
4418 4415                  dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 4416                  if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 4417                          return (ENOMEM);
4421 4418                  dpt->sc_parent = (entity_t *)ient;
4422 4419                  if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 4420                          uu_die(gettext("libuutil error: %s\n"),
4424 4421                              uu_strerror(uu_error()));
4425 4422  
4426 4423  delprop:
4427 4424                  if (tx == NULL)
4428 4425                          return (0);
4429 4426  
4430 4427                  ent = scf_entry_create(g_hndl);
4431 4428                  if (ent == NULL)
4432 4429                          return (ENOMEM);
4433 4430  
4434 4431                  if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 4432                          scf_entry_destroy(ent);
4436 4433                          switch (scf_error()) {
4437 4434                          case SCF_ERROR_DELETED:
4438 4435                                  warn(emsg_pg_deleted, ient->sc_fmri,
4439 4436                                      "dependents");
4440 4437                                  return (EBUSY);
4441 4438  
4442 4439                          case SCF_ERROR_CONNECTION_BROKEN:
4443 4440                                  return (scferror2errno(scf_error()));
4444 4441  
4445 4442                          case SCF_ERROR_NOT_FOUND:
4446 4443                                  break;
4447 4444  
4448 4445                          case SCF_ERROR_HANDLE_MISMATCH:
4449 4446                          case SCF_ERROR_NOT_BOUND:
4450 4447                          case SCF_ERROR_INVALID_ARGUMENT:
4451 4448                          case SCF_ERROR_NOT_SET:
4452 4449                          default:
4453 4450                                  bad_error("scf_transaction_property_delete",
4454 4451                                      scf_error());
4455 4452                          }
4456 4453                  }
4457 4454  
4458 4455                  return (0);
4459 4456          }
4460 4457  
4461 4458          new_dpt_pgroup->sc_pgroup_seen = 1;
4462 4459  
4463 4460          /*
4464 4461           * Decide whether the dependent has changed in the manifest.
4465 4462           */
4466 4463          /* Compare the target. */
4467 4464          if (scf_property_get_value(prop, ud_val) != 0) {
4468 4465                  switch (scf_error()) {
4469 4466                  case SCF_ERROR_NOT_FOUND:
4470 4467                  case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 4468                          warn(li_corrupt, ient->sc_fmri);
4472 4469                          return (EBADF);
4473 4470  
4474 4471                  case SCF_ERROR_DELETED:
4475 4472                  case SCF_ERROR_CONNECTION_BROKEN:
4476 4473                          return (scferror2errno(scf_error()));
4477 4474  
4478 4475                  case SCF_ERROR_HANDLE_MISMATCH:
4479 4476                  case SCF_ERROR_NOT_BOUND:
4480 4477                  case SCF_ERROR_NOT_SET:
4481 4478                  case SCF_ERROR_PERMISSION_DENIED:
4482 4479                  default:
4483 4480                          bad_error("scf_property_get_value", scf_error());
4484 4481                  }
4485 4482          }
4486 4483  
4487 4484          if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488 4485              0)
4489 4486                  bad_error("scf_value_get_as_string", scf_error());
4490 4487  
4491 4488          /*
4492 4489           * If the fmri's are not equal then the old fmri will need to
4493 4490           * be refreshed to ensure that the changes are properly updated
4494 4491           * in that service.
4495 4492           */
4496 4493          r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 4494          switch (r) {
4498 4495          case 0:
4499 4496                  dpt = internal_pgroup_new();
4500 4497                  if (dpt == NULL)
4501 4498                          return (ENOMEM);
4502 4499                  dpt->sc_pgroup_name = strdup(ud_name);
4503 4500                  dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 4501                  if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 4502                          return (ENOMEM);
4506 4503                  dpt->sc_parent = (entity_t *)ient;
4507 4504                  if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 4505                          uu_die(gettext("libuutil error: %s\n"),
4509 4506                              uu_strerror(uu_error()));
4510 4507                  break;
4511 4508  
4512 4509          case 1:
4513 4510                  /* Compare the dependency pgs. */
4514 4511                  if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 4512                          switch (scf_error()) {
4516 4513                          case SCF_ERROR_NOT_FOUND:
4517 4514                                  warn(li_corrupt, ient->sc_fmri);
4518 4515                                  return (EBADF);
4519 4516  
4520 4517                          case SCF_ERROR_DELETED:
4521 4518                          case SCF_ERROR_CONNECTION_BROKEN:
4522 4519                                  return (scferror2errno(scf_error()));
4523 4520  
4524 4521                          case SCF_ERROR_NOT_BOUND:
4525 4522                          case SCF_ERROR_HANDLE_MISMATCH:
4526 4523                          case SCF_ERROR_INVALID_ARGUMENT:
4527 4524                          case SCF_ERROR_NOT_SET:
4528 4525                          default:
4529 4526                                  bad_error("scf_snaplevel_get_pg", scf_error());
4530 4527                          }
4531 4528                  }
4532 4529  
4533 4530                  r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 4531                      snap_lastimport);
4535 4532                  switch (r) {
4536 4533                  case 0:
4537 4534                          break;
4538 4535  
4539 4536                  case ECANCELED:
4540 4537                  case ECONNABORTED:
4541 4538                  case ENOMEM:
4542 4539                  case EBADF:
4543 4540                          return (r);
4544 4541  
4545 4542                  case EACCES:
4546 4543                  default:
4547 4544                          bad_error("load_pg", r);
4548 4545                  }
4549 4546  
4550 4547                  if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 4548                          /* no change, leave customizations */
4552 4549                          internal_pgroup_free(old_dpt_pgroup);
4553 4550                          return (0);
4554 4551                  }
4555 4552                  break;
4556 4553  
4557 4554          case -1:
4558 4555                  warn(li_corrupt, ient->sc_fmri);
4559 4556                  return (EBADF);
4560 4557  
4561 4558          case -2:
4562 4559                  warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 4560                      ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 4561                  return (EINVAL);
4565 4562  
4566 4563          default:
4567 4564                  bad_error("fmri_equal", r);
4568 4565          }
4569 4566  
4570 4567          /*
4571 4568           * The dependent has changed in the manifest.  Upgrade the current
4572 4569           * properties if they haven't been customized.
4573 4570           */
4574 4571  
4575 4572          /*
4576 4573           * If new_dpt_pgroup->sc_override, then act as though the property
4577 4574           * group hasn't been customized.
4578 4575           */
4579 4576          if (new_dpt_pgroup->sc_pgroup_override) {
4580 4577                  (void) strcpy(ud_ctarg, ud_oldtarg);
4581 4578                  goto nocust;
4582 4579          }
4583 4580  
4584 4581          if (!ud_run_dpts_pg_set) {
4585 4582                  warn(cf_missing, ient->sc_fmri, ud_name);
4586 4583                  r = 0;
4587 4584                  goto out;
4588 4585          } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 4586                  switch (scf_error()) {
4590 4587                  case SCF_ERROR_NOT_FOUND:
4591 4588                          warn(cf_missing, ient->sc_fmri, ud_name);
4592 4589                          r = 0;
4593 4590                          goto out;
4594 4591  
4595 4592                  case SCF_ERROR_CONNECTION_BROKEN:
4596 4593                          r = scferror2errno(scf_error());
4597 4594                          goto out;
4598 4595  
4599 4596                  case SCF_ERROR_DELETED:
4600 4597                          warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 4598                          r = EBUSY;
4602 4599                          goto out;
4603 4600  
4604 4601                  case SCF_ERROR_INVALID_ARGUMENT:
4605 4602                  case SCF_ERROR_NOT_BOUND:
4606 4603                  case SCF_ERROR_HANDLE_MISMATCH:
4607 4604                  case SCF_ERROR_NOT_SET:
4608 4605                  default:
4609 4606                          bad_error("scf_pg_get_property", scf_error());
4610 4607                  }
4611 4608          }
4612 4609  
4613 4610          if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 4611                  switch (scf_error()) {
4615 4612                  case SCF_ERROR_NOT_FOUND:
4616 4613                  case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 4614                          warn(cf_inval, ient->sc_fmri, ud_name);
4618 4615                          r = 0;
4619 4616                          goto out;
4620 4617  
4621 4618                  case SCF_ERROR_DELETED:
4622 4619                  case SCF_ERROR_CONNECTION_BROKEN:
4623 4620                          r = scferror2errno(scf_error());
4624 4621                          goto out;
4625 4622  
4626 4623                  case SCF_ERROR_HANDLE_MISMATCH:
4627 4624                  case SCF_ERROR_NOT_BOUND:
4628 4625                  case SCF_ERROR_NOT_SET:
4629 4626                  case SCF_ERROR_PERMISSION_DENIED:
4630 4627                  default:
4631 4628                          bad_error("scf_property_get_value", scf_error());
4632 4629                  }
4633 4630          }
4634 4631  
4635 4632          ty = scf_value_type(ud_val);
4636 4633          assert(ty != SCF_TYPE_INVALID);
4637 4634          if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 4635                  warn(cf_inval, ient->sc_fmri, ud_name);
4639 4636                  r = 0;
4640 4637                  goto out;
4641 4638          }
4642 4639          if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643 4640              0)
4644 4641                  bad_error("scf_value_get_as_string", scf_error());
4645 4642  
4646 4643          r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 4644          if (r == -1) {
4648 4645                  warn(cf_inval, ient->sc_fmri, ud_name);
4649 4646                  r = 0;
4650 4647                  goto out;
4651 4648          } else if (r == -2) {
4652 4649                  warn(li_corrupt, ient->sc_fmri);
4653 4650                  r = EBADF;
4654 4651                  goto out;
4655 4652          } else if (r == 0) {
4656 4653                  /*
4657 4654                   * Target has been changed.  Only abort now if it's been
4658 4655                   * changed to something other than what's in the manifest.
4659 4656                   */
4660 4657                  r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 4658                  if (r == -1) {
4662 4659                          warn(cf_inval, ient->sc_fmri, ud_name);
4663 4660                          r = 0;
4664 4661                          goto out;
4665 4662                  } else if (r == 0) {
4666 4663                          warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 4664                          r = 0;
4668 4665                          goto out;
4669 4666                  } else if (r != 1) {
4670 4667                          /* invalid sc_pgroup_fmri caught above */
4671 4668                          bad_error("fmri_equal", r);
4672 4669                  }
4673 4670  
4674 4671                  /*
4675 4672                   * Fetch the current dependency pg.  If it's what the manifest
4676 4673                   * says, then no problem.
4677 4674                   */
4678 4675                  serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 4676                  switch (serr) {
4680 4677                  case SCF_ERROR_NONE:
4681 4678                          break;
4682 4679  
4683 4680                  case SCF_ERROR_NOT_FOUND:
4684 4681                          warn(cf_missing, ient->sc_fmri, ud_name);
4685 4682                          r = 0;
4686 4683                          goto out;
4687 4684  
4688 4685                  case SCF_ERROR_NO_MEMORY:
4689 4686                          r = ENOMEM;
4690 4687                          goto out;
4691 4688  
4692 4689                  case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 4690                  case SCF_ERROR_INVALID_ARGUMENT:
4694 4691                  default:
4695 4692                          bad_error("fmri_to_entity", serr);
4696 4693                  }
4697 4694  
4698 4695                  r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 4696                      ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 4697                  switch (r) {
4701 4698                  case 0:
4702 4699                          break;
4703 4700  
4704 4701                  case ECONNABORTED:
4705 4702                          goto out;
4706 4703  
4707 4704                  case ECANCELED:
4708 4705                  case ENOENT:
4709 4706                          warn(cf_missing, ient->sc_fmri, ud_name);
4710 4707                          r = 0;
4711 4708                          goto out;
4712 4709  
4713 4710                  case EBADF:
4714 4711                          warn(r_no_lvl, ud_ctarg);
4715 4712                          goto out;
4716 4713  
4717 4714                  case EINVAL:
4718 4715                  default:
4719 4716                          bad_error("entity_get_running_pg", r);
4720 4717                  }
4721 4718  
4722 4719                  r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4723 4720                  switch (r) {
4724 4721                  case 0:
4725 4722                          break;
4726 4723  
4727 4724                  case ECANCELED:
4728 4725                          warn(cf_missing, ient->sc_fmri, ud_name);
4729 4726                          r = 0;
4730 4727                          goto out;
4731 4728  
4732 4729                  case ECONNABORTED:
4733 4730                  case ENOMEM:
4734 4731                  case EBADF:
4735 4732                          goto out;
4736 4733  
4737 4734                  case EACCES:
4738 4735                  default:
4739 4736                          bad_error("load_pg", r);
4740 4737                  }
4741 4738  
4742 4739                  if (!pg_equal(current_pg, new_dpt_pgroup))
4743 4740                          warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 4741                  internal_pgroup_free(current_pg);
4745 4742                  r = 0;
4746 4743                  goto out;
4747 4744          } else if (r != 1) {
4748 4745                  bad_error("fmri_equal", r);
4749 4746          }
4750 4747  
4751 4748  nocust:
4752 4749          /*
4753 4750           * Target has not been customized.  Check the dependency property
4754 4751           * group.
4755 4752           */
4756 4753  
4757 4754          if (old_dpt_pgroup == NULL) {
4758 4755                  if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 4756                      ud_pg) != 0) {
4760 4757                          switch (scf_error()) {
4761 4758                          case SCF_ERROR_NOT_FOUND:
4762 4759                                  warn(li_corrupt, ient->sc_fmri);
4763 4760                                  return (EBADF);
4764 4761  
4765 4762                          case SCF_ERROR_DELETED:
4766 4763                          case SCF_ERROR_CONNECTION_BROKEN:
4767 4764                                  return (scferror2errno(scf_error()));
4768 4765  
4769 4766                          case SCF_ERROR_NOT_BOUND:
4770 4767                          case SCF_ERROR_HANDLE_MISMATCH:
4771 4768                          case SCF_ERROR_INVALID_ARGUMENT:
4772 4769                          case SCF_ERROR_NOT_SET:
4773 4770                          default:
4774 4771                                  bad_error("scf_snaplevel_get_pg", scf_error());
4775 4772                          }
4776 4773                  }
4777 4774  
4778 4775                  r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 4776                      snap_lastimport);
4780 4777                  switch (r) {
4781 4778                  case 0:
4782 4779                          break;
4783 4780  
4784 4781                  case ECANCELED:
4785 4782                  case ECONNABORTED:
4786 4783                  case ENOMEM:
4787 4784                  case EBADF:
4788 4785                          return (r);
4789 4786  
4790 4787                  case EACCES:
4791 4788                  default:
4792 4789                          bad_error("load_pg", r);
4793 4790                  }
4794 4791          }
4795 4792          serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 4793          switch (serr) {
4797 4794          case SCF_ERROR_NONE:
4798 4795                  break;
4799 4796  
4800 4797          case SCF_ERROR_NOT_FOUND:
4801 4798                  warn(cf_missing, ient->sc_fmri, ud_name);
4802 4799                  r = 0;
4803 4800                  goto out;
4804 4801  
4805 4802          case SCF_ERROR_NO_MEMORY:
4806 4803                  r = ENOMEM;
4807 4804                  goto out;
4808 4805  
4809 4806          case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 4807          case SCF_ERROR_INVALID_ARGUMENT:
4811 4808          default:
4812 4809                  bad_error("fmri_to_entity", serr);
4813 4810          }
4814 4811  
4815 4812          r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 4813              ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 4814          switch (r) {
4818 4815          case 0:
4819 4816                  break;
4820 4817  
4821 4818          case ECONNABORTED:
4822 4819                  goto out;
4823 4820  
4824 4821          case ECANCELED:
4825 4822          case ENOENT:
4826 4823                  warn(cf_missing, ient->sc_fmri, ud_name);
4827 4824                  r = 0;
4828 4825                  goto out;
4829 4826  
4830 4827          case EBADF:
4831 4828                  warn(r_no_lvl, ud_ctarg);
4832 4829                  goto out;
4833 4830  
4834 4831          case EINVAL:
4835 4832          default:
4836 4833                  bad_error("entity_get_running_pg", r);
4837 4834          }
4838 4835  
4839 4836          r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4840 4837          switch (r) {
4841 4838          case 0:
4842 4839                  break;
4843 4840  
4844 4841          case ECANCELED:
4845 4842                  warn(cf_missing, ient->sc_fmri, ud_name);
4846 4843                  goto out;
4847 4844  
4848 4845          case ECONNABORTED:
4849 4846          case ENOMEM:
4850 4847          case EBADF:
4851 4848                  goto out;
4852 4849  
4853 4850          case EACCES:
4854 4851          default:
4855 4852                  bad_error("load_pg", r);
4856 4853          }
4857 4854  
4858 4855          if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 4856                  if (!pg_equal(current_pg, new_dpt_pgroup))
4860 4857                          warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 4858                  internal_pgroup_free(current_pg);
4862 4859                  r = 0;
4863 4860                  goto out;
4864 4861          }
4865 4862  
4866 4863          /* Uncustomized.  Upgrade. */
4867 4864  
4868 4865          r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 4866          switch (r) {
4870 4867          case 1:
4871 4868                  if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 4869                          /* Already upgraded. */
4873 4870                          internal_pgroup_free(current_pg);
4874 4871                          r = 0;
4875 4872                          goto out;
4876 4873                  }
4877 4874  
4878 4875                  internal_pgroup_free(current_pg);
4879 4876  
4880 4877                  /* upgrade current_pg */
4881 4878                  if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 4879                          switch (scf_error()) {
4883 4880                          case SCF_ERROR_CONNECTION_BROKEN:
4884 4881                                  r = scferror2errno(scf_error());
4885 4882                                  goto out;
4886 4883  
4887 4884                          case SCF_ERROR_DELETED:
4888 4885                                  warn(cf_missing, ient->sc_fmri, ud_name);
4889 4886                                  r = 0;
4890 4887                                  goto out;
4891 4888  
4892 4889                          case SCF_ERROR_NOT_FOUND:
4893 4890                                  break;
4894 4891  
4895 4892                          case SCF_ERROR_INVALID_ARGUMENT:
4896 4893                          case SCF_ERROR_NOT_BOUND:
4897 4894                          case SCF_ERROR_NOT_SET:
4898 4895                          case SCF_ERROR_HANDLE_MISMATCH:
4899 4896                          default:
4900 4897                                  bad_error("entity_get_pg", scf_error());
4901 4898                          }
4902 4899  
4903 4900                          if (tissvc)
4904 4901                                  r = scf_service_add_pg(target_ent, ud_name,
4905 4902                                      SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 4903                          else
4907 4904                                  r = scf_instance_add_pg(target_ent, ud_name,
4908 4905                                      SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 4906                          if (r != 0) {
4910 4907                                  switch (scf_error()) {
4911 4908                                  case SCF_ERROR_CONNECTION_BROKEN:
4912 4909                                  case SCF_ERROR_NO_RESOURCES:
4913 4910                                  case SCF_ERROR_BACKEND_READONLY:
4914 4911                                  case SCF_ERROR_BACKEND_ACCESS:
4915 4912                                          r = scferror2errno(scf_error());
4916 4913                                          goto out;
4917 4914  
4918 4915                                  case SCF_ERROR_DELETED:
4919 4916                                          warn(cf_missing, ient->sc_fmri,
4920 4917                                              ud_name);
4921 4918                                          r = 0;
4922 4919                                          goto out;
4923 4920  
4924 4921                                  case SCF_ERROR_PERMISSION_DENIED:
4925 4922                                          warn(emsg_pg_deleted, ud_ctarg,
4926 4923                                              ud_name);
4927 4924                                          r = EPERM;
4928 4925                                          goto out;
4929 4926  
4930 4927                                  case SCF_ERROR_EXISTS:
4931 4928                                          warn(emsg_pg_added, ud_ctarg, ud_name);
4932 4929                                          r = EBUSY;
4933 4930                                          goto out;
4934 4931  
4935 4932                                  case SCF_ERROR_NOT_BOUND:
4936 4933                                  case SCF_ERROR_HANDLE_MISMATCH:
4937 4934                                  case SCF_ERROR_INVALID_ARGUMENT:
4938 4935                                  case SCF_ERROR_NOT_SET:
4939 4936                                  default:
4940 4937                                          bad_error("entity_add_pg", scf_error());
4941 4938                                  }
4942 4939                          }
4943 4940                  }
4944 4941  
4945 4942                  r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4946 4943                  switch (r) {
4947 4944                  case 0:
4948 4945                          break;
4949 4946  
4950 4947                  case ECANCELED:
4951 4948                          warn(cf_missing, ient->sc_fmri, ud_name);
4952 4949                          goto out;
4953 4950  
4954 4951                  case ECONNABORTED:
4955 4952                  case ENOMEM:
4956 4953                  case EBADF:
4957 4954                          goto out;
4958 4955  
4959 4956                  case EACCES:
4960 4957                  default:
4961 4958                          bad_error("load_pg", r);
4962 4959                  }
4963 4960  
4964 4961                  if (g_verbose)
4965 4962                          warn(upgrading, ient->sc_fmri, ud_name);
4966 4963  
4967 4964                  r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 4965                      new_dpt_pgroup, 0, ient->sc_fmri);
4969 4966                  switch (r) {
4970 4967                  case 0:
4971 4968                          break;
4972 4969  
4973 4970                  case ECANCELED:
4974 4971                          warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 4972                          r = EBUSY;
4976 4973                          goto out;
4977 4974  
4978 4975                  case EPERM:
4979 4976                          warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 4977                          goto out;
4981 4978  
4982 4979                  case EBUSY:
4983 4980                          warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 4981                          goto out;
4985 4982  
4986 4983                  case ECONNABORTED:
4987 4984                  case ENOMEM:
4988 4985                  case ENOSPC:
4989 4986                  case EROFS:
4990 4987                  case EACCES:
4991 4988                  case EINVAL:
4992 4989                          goto out;
4993 4990  
4994 4991                  default:
4995 4992                          bad_error("upgrade_pg", r);
4996 4993                  }
4997 4994                  break;
4998 4995  
4999 4996          case 0: {
5000 4997                  scf_transaction_entry_t *ent;
5001 4998                  scf_value_t *val;
5002 4999  
5003 5000                  internal_pgroup_free(current_pg);
5004 5001  
5005 5002                  /* delete old pg */
5006 5003                  if (g_verbose)
5007 5004                          warn(upgrading, ient->sc_fmri, ud_name);
5008 5005  
5009 5006                  if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 5007                          switch (scf_error()) {
5011 5008                          case SCF_ERROR_CONNECTION_BROKEN:
5012 5009                                  r = scferror2errno(scf_error());
5013 5010                                  goto out;
5014 5011  
5015 5012                          case SCF_ERROR_DELETED:
5016 5013                                  warn(cf_missing, ient->sc_fmri, ud_name);
5017 5014                                  r = 0;
5018 5015                                  goto out;
5019 5016  
5020 5017                          case SCF_ERROR_NOT_FOUND:
5021 5018                                  break;
5022 5019  
5023 5020                          case SCF_ERROR_INVALID_ARGUMENT:
5024 5021                          case SCF_ERROR_NOT_BOUND:
5025 5022                          case SCF_ERROR_NOT_SET:
5026 5023                          case SCF_ERROR_HANDLE_MISMATCH:
5027 5024                          default:
5028 5025                                  bad_error("entity_get_pg", scf_error());
5029 5026                          }
5030 5027                  } else if (scf_pg_delete(ud_pg) != 0) {
5031 5028                          switch (scf_error()) {
5032 5029                          case SCF_ERROR_DELETED:
5033 5030                                  break;
5034 5031  
5035 5032                          case SCF_ERROR_CONNECTION_BROKEN:
5036 5033                          case SCF_ERROR_BACKEND_READONLY:
5037 5034                          case SCF_ERROR_BACKEND_ACCESS:
5038 5035                                  r = scferror2errno(scf_error());
5039 5036                                  goto out;
5040 5037  
5041 5038                          case SCF_ERROR_PERMISSION_DENIED:
5042 5039                                  warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 5040                                  r = scferror2errno(scf_error());
5044 5041                                  goto out;
5045 5042  
5046 5043                          case SCF_ERROR_NOT_SET:
5047 5044                          default:
5048 5045                                  bad_error("scf_pg_delete", scf_error());
5049 5046                          }
5050 5047                  }
5051 5048  
5052 5049                  /* import new one */
5053 5050                  cbdata.sc_handle = g_hndl;
5054 5051                  cbdata.sc_trans = NULL;         /* handled below */
5055 5052                  cbdata.sc_flags = 0;
5056 5053  
5057 5054                  r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 5055                  if (r != UU_WALK_NEXT) {
5059 5056                          if (r != UU_WALK_ERROR)
5060 5057                                  bad_error("lscf_dependent_import", r);
5061 5058  
5062 5059                          r = cbdata.sc_err;
5063 5060                          goto out;
5064 5061                  }
5065 5062  
5066 5063                  if (tx == NULL)
5067 5064                          break;
5068 5065  
5069 5066                  if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 5067                      (val = scf_value_create(g_hndl)) == NULL) {
5071 5068                          if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 5069                                  return (ENOMEM);
5073 5070  
5074 5071                          bad_error("scf_entry_create", scf_error());
5075 5072                  }
5076 5073  
5077 5074                  if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 5075                      SCF_TYPE_FMRI) != 0) {
5079 5076                          switch (scf_error()) {
5080 5077                          case SCF_ERROR_CONNECTION_BROKEN:
5081 5078                                  r = scferror2errno(scf_error());
5082 5079                                  goto out;
5083 5080  
5084 5081                          case SCF_ERROR_DELETED:
5085 5082                                  warn(emsg_pg_deleted, ient->sc_fmri,
5086 5083                                      "dependents");
5087 5084                                  r = EBUSY;
5088 5085                                  goto out;
5089 5086  
5090 5087                          case SCF_ERROR_NOT_FOUND:
5091 5088                                  break;
5092 5089  
5093 5090                          case SCF_ERROR_NOT_BOUND:
5094 5091                          case SCF_ERROR_HANDLE_MISMATCH:
5095 5092                          case SCF_ERROR_INVALID_ARGUMENT:
5096 5093                          case SCF_ERROR_NOT_SET:
5097 5094                          default:
5098 5095                                  bad_error("scf_transaction_property_"
5099 5096                                      "change_type", scf_error());
5100 5097                          }
5101 5098  
5102 5099                          if (scf_transaction_property_new(tx, ent, ud_name,
5103 5100                              SCF_TYPE_FMRI) != 0) {
5104 5101                                  switch (scf_error()) {
5105 5102                                  case SCF_ERROR_CONNECTION_BROKEN:
5106 5103                                          r = scferror2errno(scf_error());
5107 5104                                          goto out;
5108 5105  
5109 5106                                  case SCF_ERROR_DELETED:
5110 5107                                          warn(emsg_pg_deleted, ient->sc_fmri,
5111 5108                                              "dependents");
5112 5109                                          r = EBUSY;
5113 5110                                          goto out;
5114 5111  
5115 5112                                  case SCF_ERROR_EXISTS:
5116 5113                                          warn(emsg_pg_changed, ient->sc_fmri,
5117 5114                                              "dependents");
5118 5115                                          r = EBUSY;
5119 5116                                          goto out;
5120 5117  
5121 5118                                  case SCF_ERROR_INVALID_ARGUMENT:
5122 5119                                  case SCF_ERROR_HANDLE_MISMATCH:
5123 5120                                  case SCF_ERROR_NOT_BOUND:
5124 5121                                  case SCF_ERROR_NOT_SET:
5125 5122                                  default:
5126 5123                                          bad_error("scf_transaction_property_"
5127 5124                                              "new", scf_error());
5128 5125                                  }
5129 5126                          }
5130 5127                  }
5131 5128  
5132 5129                  if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 5130                      new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 5131                          /* invalid sc_pgroup_fmri caught above */
5135 5132                          bad_error("scf_value_set_from_string",
5136 5133                              scf_error());
5137 5134  
5138 5135                  if (scf_entry_add_value(ent, val) != 0)
5139 5136                          bad_error("scf_entry_add_value", scf_error());
5140 5137                  break;
5141 5138          }
5142 5139  
5143 5140          case -2:
5144 5141                  warn(li_corrupt, ient->sc_fmri);
5145 5142                  internal_pgroup_free(current_pg);
5146 5143                  r = EBADF;
5147 5144                  goto out;
5148 5145  
5149 5146          case -1:
5150 5147          default:
5151 5148                  /* invalid sc_pgroup_fmri caught above */
5152 5149                  bad_error("fmri_equal", r);
5153 5150          }
5154 5151  
5155 5152          r = 0;
5156 5153  
5157 5154  out:
5158 5155          if (old_dpt_pgroup != NULL)
5159 5156                  internal_pgroup_free(old_dpt_pgroup);
5160 5157  
5161 5158          return (r);
5162 5159  }
5163 5160  
5164 5161  /*
5165 5162   * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 5163   * would import it, except it seems to exist in the service anyway.  Compare
5167 5164   * the existent dependent with the one we would import, and report any
5168 5165   * differences (if there are none, be silent).  prop is the property which
5169 5166   * represents the existent dependent (in the dependents property group) in the
5170 5167   * entity corresponding to ient.
5171 5168   *
5172 5169   * Returns
5173 5170   *   0 - success (Sort of.  At least, we can continue importing.)
5174 5171   *   ECONNABORTED - repository connection broken
5175 5172   *   EBUSY - ancestor of prop was deleted (error printed)
5176 5173   *   ENOMEM - out of memory
5177 5174   *   EBADF - corrupt property group (error printed)
5178 5175   *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5179 5176   */
5180 5177  static int
5181 5178  handle_dependent_conflict(const entity_t * const ient,
5182 5179      const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 5180  {
5184 5181          int r;
5185 5182          scf_type_t ty;
5186 5183          scf_error_t scfe;
5187 5184          void *tptr;
5188 5185          int tissvc;
5189 5186          pgroup_t *pgroup;
5190 5187  
5191 5188          if (scf_property_get_value(prop, ud_val) != 0) {
5192 5189                  switch (scf_error()) {
5193 5190                  case SCF_ERROR_CONNECTION_BROKEN:
5194 5191                          return (scferror2errno(scf_error()));
5195 5192  
5196 5193                  case SCF_ERROR_DELETED:
5197 5194                          warn(emsg_pg_deleted, ient->sc_fmri,
5198 5195                              new_dpt_pgroup->sc_pgroup_name);
5199 5196                          return (EBUSY);
5200 5197  
5201 5198                  case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 5199                  case SCF_ERROR_NOT_FOUND:
5203 5200                          warn(gettext("Conflict upgrading %s (not importing "
5204 5201                              "dependent \"%s\" because it already exists.)  "
5205 5202                              "Warning: The \"%s/%2$s\" property has more or "
5206 5203                              "fewer than one value)).\n"), ient->sc_fmri,
5207 5204                              new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 5205                          return (0);
5209 5206  
5210 5207                  case SCF_ERROR_HANDLE_MISMATCH:
5211 5208                  case SCF_ERROR_NOT_BOUND:
5212 5209                  case SCF_ERROR_NOT_SET:
5213 5210                  case SCF_ERROR_PERMISSION_DENIED:
5214 5211                  default:
5215 5212                          bad_error("scf_property_get_value",
5216 5213                              scf_error());
5217 5214                  }
5218 5215          }
5219 5216  
5220 5217          ty = scf_value_type(ud_val);
5221 5218          assert(ty != SCF_TYPE_INVALID);
5222 5219          if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 5220                  warn(gettext("Conflict upgrading %s (not importing dependent "
5224 5221                      "\"%s\" because it already exists).  Warning: The "
5225 5222                      "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 5223                      ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 5224                      scf_type_to_string(ty), "dependents");
5228 5225                  return (0);
5229 5226          }
5230 5227  
5231 5228          if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232 5229              0)
5233 5230                  bad_error("scf_value_get_as_string", scf_error());
5234 5231  
5235 5232          r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 5233          switch (r) {
5237 5234          case 0:
5238 5235                  warn(gettext("Conflict upgrading %s (not importing dependent "
5239 5236                      "\"%s\" (target \"%s\") because it already exists with "
5240 5237                      "target \"%s\").\n"), ient->sc_fmri,
5241 5238                      new_dpt_pgroup->sc_pgroup_name,
5242 5239                      new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 5240                  return (0);
5244 5241  
5245 5242          case 1:
5246 5243                  break;
5247 5244  
5248 5245          case -1:
5249 5246                  warn(gettext("Conflict upgrading %s (not importing dependent "
5250 5247                      "\"%s\" because it already exists).  Warning: The current "
5251 5248                      "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 5249                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 5250                  return (0);
5254 5251  
5255 5252          case -2:
5256 5253                  warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 5254                      "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 5255                      new_dpt_pgroup->sc_pgroup_fmri);
5259 5256                  return (EINVAL);
5260 5257  
5261 5258          default:
5262 5259                  bad_error("fmri_equal", r);
5263 5260          }
5264 5261  
5265 5262          /* compare dependency pgs in target */
5266 5263          scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 5264          switch (scfe) {
5268 5265          case SCF_ERROR_NONE:
5269 5266                  break;
5270 5267  
5271 5268          case SCF_ERROR_NO_MEMORY:
5272 5269                  return (ENOMEM);
5273 5270  
5274 5271          case SCF_ERROR_NOT_FOUND:
5275 5272                  warn(emsg_dpt_dangling, ient->sc_fmri,
5276 5273                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 5274                  return (0);
5278 5275  
5279 5276          case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 5277          case SCF_ERROR_INVALID_ARGUMENT:
5281 5278          default:
5282 5279                  bad_error("fmri_to_entity", scfe);
5283 5280          }
5284 5281  
5285 5282          r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 5283              ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 5284          switch (r) {
5288 5285          case 0:
5289 5286                  break;
5290 5287  
5291 5288          case ECONNABORTED:
5292 5289                  return (r);
5293 5290  
5294 5291          case ECANCELED:
5295 5292                  warn(emsg_dpt_dangling, ient->sc_fmri,
5296 5293                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 5294                  return (0);
5298 5295  
5299 5296          case EBADF:
5300 5297                  if (tissvc)
5301 5298                          warn(gettext("%s has an instance with a \"%s\" "
5302 5299                              "snapshot which is missing a snaplevel.\n"),
5303 5300                              ud_ctarg, "running");
5304 5301                  else
5305 5302                          warn(gettext("%s has a \"%s\" snapshot which is "
5306 5303                              "missing a snaplevel.\n"), ud_ctarg, "running");
5307 5304                  /* FALLTHROUGH */
5308 5305  
5309 5306          case ENOENT:
5310 5307                  warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 5308                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 5309                      new_dpt_pgroup->sc_pgroup_name);
5313 5310                  return (0);
5314 5311  
5315 5312          case EINVAL:
5316 5313          default:
5317 5314                  bad_error("entity_get_running_pg", r);
5318 5315          }
5319 5316  
5320 5317          pgroup = internal_pgroup_new();
5321 5318          if (pgroup == NULL)
5322 5319                  return (ENOMEM);
5323 5320  
5324 5321          r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 5322          switch (r) {
5326 5323          case 0:
5327 5324                  break;
5328 5325  
5329 5326          case ECONNABORTED:
5330 5327          case EBADF:
5331 5328          case ENOMEM:
5332 5329                  internal_pgroup_free(pgroup);
5333 5330                  return (r);
5334 5331  
5335 5332          case ECANCELED:
5336 5333                  warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 5334                      new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 5335                      new_dpt_pgroup->sc_pgroup_name);
5339 5336                  internal_pgroup_free(pgroup);
5340 5337                  return (0);
5341 5338  
5342 5339          case EACCES:
5343 5340          default:
5344 5341                  bad_error("load_pg", r);
5345 5342          }
5346 5343  
5347 5344          /* report differences */
5348 5345          report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 5346          internal_pgroup_free(pgroup);
5350 5347          return (0);
5351 5348  }
5352 5349  
5353 5350  /*
5354 5351   * lipg is a property group in the last-import snapshot of ent, which is an
5355 5352   * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5356 5353   * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5357 5354   * in ents's property groups, compare and upgrade ent appropriately.
5358 5355   *
5359 5356   * Returns
5360 5357   *   0 - success
5361 5358   *   ECONNABORTED - repository connection broken
5362 5359   *   ENOMEM - out of memory
5363 5360   *   ENOSPC - configd is out of resources
5364 5361   *   EINVAL - ient has invalid dependent (error printed)
5365 5362   *          - ient has invalid pgroup_t (error printed)
5366 5363   *   ECANCELED - ent has been deleted
5367 5364   *   ENODEV - entity containing lipg has been deleted
5368 5365   *          - entity containing running has been deleted
5369 5366   *   EPERM - could not delete pg (permission denied) (error printed)
5370 5367   *         - couldn't upgrade dependents (permission denied) (error printed)
5371 5368   *         - couldn't import pg (permission denied) (error printed)
5372 5369   *         - couldn't upgrade pg (permission denied) (error printed)
5373 5370   *   EROFS - could not delete pg (repository read-only)
5374 5371   *         - couldn't upgrade dependents (repository read-only)
5375 5372   *         - couldn't import pg (repository read-only)
5376 5373   *         - couldn't upgrade pg (repository read-only)
5377 5374   *   EACCES - could not delete pg (backend access denied)
5378 5375   *          - couldn't upgrade dependents (backend access denied)
5379 5376   *          - couldn't import pg (backend access denied)
5380 5377   *          - couldn't upgrade pg (backend access denied)
5381 5378   *          - couldn't read property (backend access denied)
5382 5379   *   EBUSY - property group was added (error printed)
5383 5380   *         - property group was deleted (error printed)
5384 5381   *         - property group changed (error printed)
5385 5382   *         - "dependents" pg was added, changed, or deleted (error printed)
5386 5383   *         - dependent target deleted (error printed)
5387 5384   *         - dependent pg changed (error printed)
5388 5385   *   EBADF - imp_snpl is corrupt (error printed)
5389 5386   *         - ent has bad pg (error printed)
5390 5387   *   EEXIST - dependent collision in target service (error printed)
5391 5388   */
5392 5389  static int
5393 5390  process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394 5391      const scf_snaplevel_t *running)
5395 5392  {
5396 5393          int r;
5397 5394          pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 5395          scf_callback_t cbdata;
5399 5396  
5400 5397          const char * const cf_pg_missing =
5401 5398              gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 5399          const char * const deleting =
5403 5400              gettext("%s: Deleting property group \"%s\".\n");
5404 5401  
5405 5402          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406 5403  
5407 5404          /* Skip dependent property groups. */
5408 5405          if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 5406                  switch (scf_error()) {
5410 5407                  case SCF_ERROR_DELETED:
5411 5408                          return (ENODEV);
5412 5409  
5413 5410                  case SCF_ERROR_CONNECTION_BROKEN:
5414 5411                          return (ECONNABORTED);
5415 5412  
5416 5413                  case SCF_ERROR_NOT_SET:
5417 5414                  case SCF_ERROR_NOT_BOUND:
5418 5415                  default:
5419 5416                          bad_error("scf_pg_get_type", scf_error());
5420 5417                  }
5421 5418          }
5422 5419  
5423 5420          if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 5421                  if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 5422                          return (0);
5426 5423  
5427 5424                  switch (scf_error()) {
5428 5425                  case SCF_ERROR_NOT_FOUND:
5429 5426                          break;
5430 5427  
5431 5428                  case SCF_ERROR_CONNECTION_BROKEN:
5432 5429                          return (ECONNABORTED);
5433 5430  
5434 5431                  case SCF_ERROR_DELETED:
5435 5432                          return (ENODEV);
5436 5433  
5437 5434                  case SCF_ERROR_INVALID_ARGUMENT:
5438 5435                  case SCF_ERROR_NOT_BOUND:
5439 5436                  case SCF_ERROR_HANDLE_MISMATCH:
5440 5437                  case SCF_ERROR_NOT_SET:
5441 5438                  default:
5442 5439                          bad_error("scf_pg_get_property", scf_error());
5443 5440                  }
5444 5441          }
5445 5442  
5446 5443          /* lookup pg in new properties */
5447 5444          if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 5445                  switch (scf_error()) {
5449 5446                  case SCF_ERROR_DELETED:
5450 5447                          return (ENODEV);
5451 5448  
5452 5449                  case SCF_ERROR_CONNECTION_BROKEN:
5453 5450                          return (ECONNABORTED);
5454 5451  
5455 5452                  case SCF_ERROR_NOT_SET:
5456 5453                  case SCF_ERROR_NOT_BOUND:
5457 5454                  default:
5458 5455                          bad_error("scf_pg_get_name", scf_error());
5459 5456                  }
5460 5457          }
5461 5458  
5462 5459          pgrp.sc_pgroup_name = imp_str;
5463 5460          mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464 5461  
5465 5462          if (mpg != NULL)
5466 5463                  mpg->sc_pgroup_seen = 1;
5467 5464  
5468 5465          /* Special handling for dependents */
5469 5466          if (strcmp(imp_str, "dependents") == 0)
5470 5467                  return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471 5468  
5472 5469          if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 5470                  return (upgrade_manifestfiles(NULL, ient, running, ent));
5474 5471  
5475 5472          if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 5473                  /* property group was deleted from manifest */
5477 5474                  if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 5475                          switch (scf_error()) {
5479 5476                          case SCF_ERROR_NOT_FOUND:
5480 5477                                  return (0);
5481 5478  
5482 5479                          case SCF_ERROR_DELETED:
5483 5480                          case SCF_ERROR_CONNECTION_BROKEN:
5484 5481                                  return (scferror2errno(scf_error()));
5485 5482  
5486 5483                          case SCF_ERROR_INVALID_ARGUMENT:
5487 5484                          case SCF_ERROR_HANDLE_MISMATCH:
5488 5485                          case SCF_ERROR_NOT_BOUND:
5489 5486                          case SCF_ERROR_NOT_SET:
5490 5487                          default:
5491 5488                                  bad_error("entity_get_pg", scf_error());
5492 5489                          }
5493 5490                  }
5494 5491  
5495 5492                  if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 5493                          if (g_verbose)
5497 5494                                  warn(deleting, ient->sc_fmri, imp_str);
5498 5495                          if (scf_pg_delete(imp_pg2) == 0)
5499 5496                                  return (0);
5500 5497  
5501 5498                          switch (scf_error()) {
5502 5499                          case SCF_ERROR_DELETED:
5503 5500                                  return (0);
5504 5501  
5505 5502                          case SCF_ERROR_CONNECTION_BROKEN:
5506 5503                          case SCF_ERROR_BACKEND_READONLY:
5507 5504                          case SCF_ERROR_BACKEND_ACCESS:
5508 5505                                  return (scferror2errno(scf_error()));
5509 5506  
5510 5507                          case SCF_ERROR_PERMISSION_DENIED:
5511 5508                                  warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 5509                                  return (scferror2errno(scf_error()));
5513 5510  
5514 5511                          case SCF_ERROR_NOT_SET:
5515 5512                          default:
5516 5513                                  bad_error("scf_pg_delete", scf_error());
5517 5514                          }
5518 5515                  }
5519 5516  
5520 5517                  r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 5518                  switch (r) {
5522 5519                  case 0:
5523 5520                          break;
5524 5521  
5525 5522                  case ECANCELED:
5526 5523                          return (ENODEV);
5527 5524  
5528 5525                  case ECONNABORTED:
5529 5526                  case ENOMEM:
5530 5527                  case EBADF:
5531 5528                  case EACCES:
5532 5529                          return (r);
5533 5530  
5534 5531                  default:
5535 5532                          bad_error("load_pg", r);
5536 5533                  }
5537 5534  
5538 5535                  r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 5536                  switch (r) {
5540 5537                  case 0:
5541 5538                          break;
5542 5539  
5543 5540                  case ECANCELED:
5544 5541                  case ECONNABORTED:
5545 5542                  case ENOMEM:
5546 5543                  case EBADF:
5547 5544                  case EACCES:
5548 5545                          internal_pgroup_free(lipg_i);
5549 5546                          return (r);
5550 5547  
5551 5548                  default:
5552 5549                          bad_error("load_pg", r);
5553 5550                  }
5554 5551  
5555 5552                  if (pg_equal(lipg_i, curpg_i)) {
5556 5553                          if (g_verbose)
5557 5554                                  warn(deleting, ient->sc_fmri, imp_str);
5558 5555                          if (scf_pg_delete(imp_pg2) != 0) {
5559 5556                                  switch (scf_error()) {
5560 5557                                  case SCF_ERROR_DELETED:
5561 5558                                          break;
5562 5559  
5563 5560                                  case SCF_ERROR_CONNECTION_BROKEN:
5564 5561                                          internal_pgroup_free(lipg_i);
5565 5562                                          internal_pgroup_free(curpg_i);
5566 5563                                          return (ECONNABORTED);
5567 5564  
5568 5565                                  case SCF_ERROR_NOT_SET:
5569 5566                                  case SCF_ERROR_NOT_BOUND:
5570 5567                                  default:
5571 5568                                          bad_error("scf_pg_delete", scf_error());
5572 5569                                  }
5573 5570                          }
5574 5571                  } else {
5575 5572                          report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 5573                  }
5577 5574  
5578 5575                  internal_pgroup_free(lipg_i);
5579 5576                  internal_pgroup_free(curpg_i);
5580 5577  
5581 5578                  return (0);
5582 5579          }
5583 5580  
5584 5581          /*
5585 5582           * Only dependent pgs can have override set, and we skipped those
5586 5583           * above.
5587 5584           */
5588 5585          assert(!mpg->sc_pgroup_override);
5589 5586  
5590 5587          /* compare */
5591 5588          r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 5589          switch (r) {
5593 5590          case 0:
5594 5591                  break;
5595 5592  
5596 5593          case ECANCELED:
5597 5594                  return (ENODEV);
5598 5595  
5599 5596          case ECONNABORTED:
5600 5597          case EBADF:
5601 5598          case ENOMEM:
5602 5599          case EACCES:
5603 5600                  return (r);
5604 5601  
5605 5602          default:
5606 5603                  bad_error("load_pg", r);
5607 5604          }
5608 5605  
5609 5606          if (pg_equal(mpg, lipg_i)) {
5610 5607                  /* The manifest pg has not changed.  Move on. */
5611 5608                  r = 0;
5612 5609                  goto out;
5613 5610          }
5614 5611  
5615 5612          /* upgrade current properties according to lipg & mpg */
5616 5613          if (running != NULL)
5617 5614                  r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 5615          else
5619 5616                  r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 5617          if (r != 0) {
5621 5618                  switch (scf_error()) {
5622 5619                  case SCF_ERROR_CONNECTION_BROKEN:
5623 5620                          r = scferror2errno(scf_error());
5624 5621                          goto out;
5625 5622  
5626 5623                  case SCF_ERROR_DELETED:
5627 5624                          if (running != NULL)
5628 5625                                  r = ENODEV;
5629 5626                          else
5630 5627                                  r = ECANCELED;
5631 5628                          goto out;
5632 5629  
5633 5630                  case SCF_ERROR_NOT_FOUND:
5634 5631                          break;
5635 5632  
5636 5633                  case SCF_ERROR_INVALID_ARGUMENT:
5637 5634                  case SCF_ERROR_HANDLE_MISMATCH:
5638 5635                  case SCF_ERROR_NOT_BOUND:
5639 5636                  case SCF_ERROR_NOT_SET:
5640 5637                  default:
5641 5638                          bad_error("entity_get_pg", scf_error());
5642 5639                  }
5643 5640  
5644 5641                  warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645 5642  
5646 5643                  r = 0;
5647 5644                  goto out;
5648 5645          }
5649 5646  
5650 5647          r = load_pg_attrs(imp_pg2, &curpg_i);
5651 5648          switch (r) {
5652 5649          case 0:
5653 5650                  break;
5654 5651  
5655 5652          case ECANCELED:
5656 5653                  warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 5654                  r = 0;
5658 5655                  goto out;
5659 5656  
5660 5657          case ECONNABORTED:
5661 5658          case ENOMEM:
5662 5659                  goto out;
5663 5660  
5664 5661          default:
5665 5662                  bad_error("load_pg_attrs", r);
5666 5663          }
5667 5664  
5668 5665          if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 5666                  (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 5667                  internal_pgroup_free(curpg_i);
5671 5668                  r = 0;
5672 5669                  goto out;
5673 5670          }
5674 5671  
5675 5672          internal_pgroup_free(curpg_i);
5676 5673  
5677 5674          r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 5675          switch (r) {
5679 5676          case 0:
5680 5677                  break;
5681 5678  
5682 5679          case ECANCELED:
5683 5680                  warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 5681                  r = 0;
5685 5682                  goto out;
5686 5683  
5687 5684          case ECONNABORTED:
5688 5685          case EBADF:
5689 5686          case ENOMEM:
5690 5687          case EACCES:
5691 5688                  goto out;
5692 5689  
5693 5690          default:
5694 5691                  bad_error("load_pg", r);
5695 5692          }
5696 5693  
5697 5694          if (pg_equal(lipg_i, curpg_i) &&
5698 5695              !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 5696                  int do_delete = 1;
5700 5697  
5701 5698                  if (g_verbose)
5702 5699                          warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 5700                              ient->sc_fmri, mpg->sc_pgroup_name);
5704 5701  
5705 5702                  internal_pgroup_free(curpg_i);
5706 5703  
5707 5704                  if (running != NULL &&
5708 5705                      entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 5706                          switch (scf_error()) {
5710 5707                          case SCF_ERROR_DELETED:
5711 5708                                  r = ECANCELED;
5712 5709                                  goto out;
5713 5710  
5714 5711                          case SCF_ERROR_NOT_FOUND:
5715 5712                                  do_delete = 0;
5716 5713                                  break;
5717 5714  
5718 5715                          case SCF_ERROR_CONNECTION_BROKEN:
5719 5716                                  r = scferror2errno(scf_error());
5720 5717                                  goto out;
5721 5718  
5722 5719                          case SCF_ERROR_HANDLE_MISMATCH:
5723 5720                          case SCF_ERROR_INVALID_ARGUMENT:
5724 5721                          case SCF_ERROR_NOT_SET:
5725 5722                          case SCF_ERROR_NOT_BOUND:
5726 5723                          default:
5727 5724                                  bad_error("entity_get_pg", scf_error());
5728 5725                          }
5729 5726                  }
5730 5727  
5731 5728                  if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 5729                          switch (scf_error()) {
5733 5730                          case SCF_ERROR_DELETED:
5734 5731                                  break;
5735 5732  
5736 5733                          case SCF_ERROR_CONNECTION_BROKEN:
5737 5734                          case SCF_ERROR_BACKEND_READONLY:
5738 5735                          case SCF_ERROR_BACKEND_ACCESS:
5739 5736                                  r = scferror2errno(scf_error());
5740 5737                                  goto out;
5741 5738  
5742 5739                          case SCF_ERROR_PERMISSION_DENIED:
5743 5740                                  warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 5741                                      ient->sc_fmri);
5745 5742                                  r = scferror2errno(scf_error());
5746 5743                                  goto out;
5747 5744  
5748 5745                          case SCF_ERROR_NOT_SET:
5749 5746                          case SCF_ERROR_NOT_BOUND:
5750 5747                          default:
5751 5748                                  bad_error("scf_pg_delete", scf_error());
5752 5749                          }
5753 5750                  }
5754 5751  
5755 5752                  cbdata.sc_handle = g_hndl;
5756 5753                  cbdata.sc_parent = ent;
5757 5754                  cbdata.sc_service = issvc;
5758 5755                  cbdata.sc_flags = 0;
5759 5756                  cbdata.sc_source_fmri = ient->sc_fmri;
5760 5757                  cbdata.sc_target_fmri = ient->sc_fmri;
5761 5758  
5762 5759                  r = entity_pgroup_import(mpg, &cbdata);
5763 5760                  switch (r) {
5764 5761                  case UU_WALK_NEXT:
5765 5762                          r = 0;
5766 5763                          goto out;
5767 5764  
5768 5765                  case UU_WALK_ERROR:
5769 5766                          if (cbdata.sc_err == EEXIST) {
5770 5767                                  warn(emsg_pg_added, ient->sc_fmri,
5771 5768                                      mpg->sc_pgroup_name);
5772 5769                                  r = EBUSY;
5773 5770                          } else {
5774 5771                                  r = cbdata.sc_err;
5775 5772                          }
5776 5773                          goto out;
5777 5774  
5778 5775                  default:
5779 5776                          bad_error("entity_pgroup_import", r);
5780 5777                  }
5781 5778          }
5782 5779  
5783 5780          if (running != NULL &&
5784 5781              entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 5782                  switch (scf_error()) {
5786 5783                  case SCF_ERROR_CONNECTION_BROKEN:
5787 5784                  case SCF_ERROR_DELETED:
5788 5785                          r = scferror2errno(scf_error());
5789 5786                          goto out;
5790 5787  
5791 5788                  case SCF_ERROR_NOT_FOUND:
5792 5789                          break;
5793 5790  
5794 5791                  case SCF_ERROR_HANDLE_MISMATCH:
5795 5792                  case SCF_ERROR_INVALID_ARGUMENT:
5796 5793                  case SCF_ERROR_NOT_SET:
5797 5794                  case SCF_ERROR_NOT_BOUND:
5798 5795                  default:
5799 5796                          bad_error("entity_get_pg", scf_error());
5800 5797                  }
5801 5798  
5802 5799                  cbdata.sc_handle = g_hndl;
5803 5800                  cbdata.sc_parent = ent;
5804 5801                  cbdata.sc_service = issvc;
5805 5802                  cbdata.sc_flags = SCI_FORCE;
5806 5803                  cbdata.sc_source_fmri = ient->sc_fmri;
5807 5804                  cbdata.sc_target_fmri = ient->sc_fmri;
5808 5805  
5809 5806                  r = entity_pgroup_import(mpg, &cbdata);
5810 5807                  switch (r) {
5811 5808                  case UU_WALK_NEXT:
5812 5809                          r = 0;
5813 5810                          goto out;
5814 5811  
5815 5812                  case UU_WALK_ERROR:
5816 5813                          if (cbdata.sc_err == EEXIST) {
5817 5814                                  warn(emsg_pg_added, ient->sc_fmri,
5818 5815                                      mpg->sc_pgroup_name);
5819 5816                                  r = EBUSY;
5820 5817                          } else {
5821 5818                                  r = cbdata.sc_err;
5822 5819                          }
5823 5820                          goto out;
5824 5821  
5825 5822                  default:
5826 5823                          bad_error("entity_pgroup_import", r);
5827 5824                  }
5828 5825          }
5829 5826  
5830 5827          r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 5828          internal_pgroup_free(curpg_i);
5832 5829          switch (r) {
5833 5830          case 0:
5834 5831                  ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 5832                  break;
5836 5833  
5837 5834          case ECANCELED:
5838 5835                  warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 5836                  r = EBUSY;
5840 5837                  break;
5841 5838  
5842 5839          case EPERM:
5843 5840                  warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 5841                  break;
5845 5842  
5846 5843          case EBUSY:
5847 5844                  warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 5845                  break;
5849 5846  
5850 5847          case ECONNABORTED:
5851 5848          case ENOMEM:
5852 5849          case ENOSPC:
5853 5850          case EROFS:
5854 5851          case EACCES:
5855 5852          case EINVAL:
5856 5853                  break;
5857 5854  
5858 5855          default:
5859 5856                  bad_error("upgrade_pg", r);
5860 5857          }
5861 5858  
5862 5859  out:
5863 5860          internal_pgroup_free(lipg_i);
5864 5861          return (r);
5865 5862  }
5866 5863  
5867 5864  /*
5868 5865   * Upgrade the properties of ent according to snpl & ient.
5869 5866   *
5870 5867   * Returns
5871 5868   *   0 - success
5872 5869   *   ECONNABORTED - repository connection broken
5873 5870   *   ENOMEM - out of memory
5874 5871   *   ENOSPC - configd is out of resources
5875 5872   *   ECANCELED - ent was deleted
5876 5873   *   ENODEV - entity containing snpl was deleted
5877 5874   *          - entity containing running was deleted
5878 5875   *   EBADF - imp_snpl is corrupt (error printed)
5879 5876   *         - ent has corrupt pg (error printed)
5880 5877   *         - dependent has corrupt pg (error printed)
5881 5878   *         - dependent target has a corrupt snapshot (error printed)
5882 5879   *   EBUSY - pg was added, changed, or deleted (error printed)
5883 5880   *         - dependent target was deleted (error printed)
5884 5881   *         - dependent pg changed (error printed)
5885 5882   *   EINVAL - invalid property group name (error printed)
5886 5883   *          - invalid property name (error printed)
5887 5884   *          - invalid value (error printed)
5888 5885   *          - ient has invalid pgroup or dependent (error printed)
5889 5886   *   EPERM - could not create property group (permission denied) (error printed)
5890 5887   *         - could not modify property group (permission denied) (error printed)
5891 5888   *         - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 5889   *   EROFS - could not create property group (repository read-only)
5893 5890   *         - couldn't delete, upgrade, or import pg or dependent
5894 5891   *   EACCES - could not create property group (backend access denied)
5895 5892   *          - couldn't delete, upgrade, or import pg or dependent
5896 5893   *   EEXIST - dependent collision in target service (error printed)
5897 5894   */
5898 5895  static int
5899 5896  upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900 5897      entity_t *ient)
5901 5898  {
5902 5899          pgroup_t *pg, *rpg;
5903 5900          int r;
5904 5901          uu_list_t *pgs = ient->sc_pgroups;
5905 5902  
5906 5903          const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907 5904  
5908 5905          /* clear sc_sceen for pgs */
5909 5906          if (uu_list_walk(pgs, clear_int,
5910 5907              (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 5908                  bad_error("uu_list_walk", uu_error());
5912 5909  
5913 5910          if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 5911                  switch (scf_error()) {
5915 5912                  case SCF_ERROR_DELETED:
5916 5913                          return (ENODEV);
5917 5914  
5918 5915                  case SCF_ERROR_CONNECTION_BROKEN:
5919 5916                          return (ECONNABORTED);
5920 5917  
5921 5918                  case SCF_ERROR_NOT_SET:
5922 5919                  case SCF_ERROR_NOT_BOUND:
5923 5920                  case SCF_ERROR_HANDLE_MISMATCH:
5924 5921                  default:
5925 5922                          bad_error("scf_iter_snaplevel_pgs", scf_error());
5926 5923                  }
5927 5924          }
5928 5925  
5929 5926          for (;;) {
5930 5927                  r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 5928                  if (r == 0)
5932 5929                          break;
5933 5930                  if (r == 1) {
5934 5931                          r = process_old_pg(imp_pg, ient, ent, running);
5935 5932                          switch (r) {
5936 5933                          case 0:
5937 5934                                  break;
5938 5935  
5939 5936                          case ECONNABORTED:
5940 5937                          case ENOMEM:
5941 5938                          case ENOSPC:
5942 5939                          case ECANCELED:
5943 5940                          case ENODEV:
5944 5941                          case EPERM:
5945 5942                          case EROFS:
5946 5943                          case EACCES:
5947 5944                          case EBADF:
5948 5945                          case EBUSY:
5949 5946                          case EINVAL:
5950 5947                          case EEXIST:
5951 5948                                  return (r);
5952 5949  
5953 5950                          default:
5954 5951                                  bad_error("process_old_pg", r);
5955 5952                          }
5956 5953                          continue;
5957 5954                  }
5958 5955                  if (r != -1)
5959 5956                          bad_error("scf_iter_next_pg", r);
5960 5957  
5961 5958                  switch (scf_error()) {
5962 5959                  case SCF_ERROR_DELETED:
5963 5960                          return (ENODEV);
5964 5961  
5965 5962                  case SCF_ERROR_CONNECTION_BROKEN:
5966 5963                          return (ECONNABORTED);
5967 5964  
5968 5965                  case SCF_ERROR_HANDLE_MISMATCH:
5969 5966                  case SCF_ERROR_NOT_BOUND:
5970 5967                  case SCF_ERROR_NOT_SET:
5971 5968                  case SCF_ERROR_INVALID_ARGUMENT:
5972 5969                  default:
5973 5970                          bad_error("scf_iter_next_pg", scf_error());
5974 5971                  }
5975 5972          }
5976 5973  
5977 5974          for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 5975                  if (pg->sc_pgroup_seen)
5979 5976                          continue;
5980 5977  
5981 5978                  /* pg is new */
5982 5979  
5983 5980                  if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 5981                          r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 5982                              ent);
5986 5983                          switch (r) {
5987 5984                          case 0:
5988 5985                                  break;
5989 5986  
5990 5987                          case ECONNABORTED:
5991 5988                          case ENOMEM:
5992 5989                          case ENOSPC:
5993 5990                          case ECANCELED:
5994 5991                          case ENODEV:
5995 5992                          case EBADF:
5996 5993                          case EBUSY:
5997 5994                          case EINVAL:
5998 5995                          case EPERM:
5999 5996                          case EROFS:
6000 5997                          case EACCES:
6001 5998                          case EEXIST:
6002 5999                                  return (r);
6003 6000  
6004 6001                          default:
6005 6002                                  bad_error("upgrade_dependents", r);
6006 6003                          }
6007 6004                          continue;
6008 6005                  }
6009 6006  
6010 6007                  if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 6008                          r = upgrade_manifestfiles(pg, ient, running, ent);
6012 6009                          switch (r) {
6013 6010                          case 0:
6014 6011                                  break;
6015 6012  
6016 6013                          case ECONNABORTED:
6017 6014                          case ENOMEM:
6018 6015                          case ENOSPC:
6019 6016                          case ECANCELED:
6020 6017                          case ENODEV:
6021 6018                          case EBADF:
6022 6019                          case EBUSY:
6023 6020                          case EINVAL:
6024 6021                          case EPERM:
6025 6022                          case EROFS:
6026 6023                          case EACCES:
6027 6024                          case EEXIST:
6028 6025                                  return (r);
6029 6026  
6030 6027                          default:
6031 6028                                  bad_error("upgrade_manifestfiles", r);
6032 6029                          }
6033 6030                          continue;
6034 6031                  }
6035 6032  
6036 6033                  if (running != NULL) {
6037 6034                          r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 6035                              imp_pg);
6039 6036                  } else {
6040 6037                          r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 6038                              imp_pg);
6042 6039                  }
6043 6040                  if (r != 0) {
6044 6041                          scf_callback_t cbdata;
6045 6042  
6046 6043                          switch (scf_error()) {
6047 6044                          case SCF_ERROR_NOT_FOUND:
6048 6045                                  break;
6049 6046  
6050 6047                          case SCF_ERROR_CONNECTION_BROKEN:
6051 6048                                  return (scferror2errno(scf_error()));
6052 6049  
6053 6050                          case SCF_ERROR_DELETED:
6054 6051                                  if (running != NULL)
6055 6052                                          return (ENODEV);
6056 6053                                  else
6057 6054                                          return (scferror2errno(scf_error()));
6058 6055  
6059 6056                          case SCF_ERROR_INVALID_ARGUMENT:
6060 6057                                  warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 6058                                      pg->sc_pgroup_name);
6062 6059                                  return (EINVAL);
6063 6060  
6064 6061                          case SCF_ERROR_NOT_SET:
6065 6062                          case SCF_ERROR_HANDLE_MISMATCH:
6066 6063                          case SCF_ERROR_NOT_BOUND:
6067 6064                          default:
6068 6065                                  bad_error("entity_get_pg", scf_error());
6069 6066                          }
6070 6067  
6071 6068                          /* User doesn't have pg, so import it. */
6072 6069  
6073 6070                          cbdata.sc_handle = g_hndl;
6074 6071                          cbdata.sc_parent = ent;
6075 6072                          cbdata.sc_service = issvc;
6076 6073                          cbdata.sc_flags = SCI_FORCE;
6077 6074                          cbdata.sc_source_fmri = ient->sc_fmri;
6078 6075                          cbdata.sc_target_fmri = ient->sc_fmri;
6079 6076  
6080 6077                          r = entity_pgroup_import(pg, &cbdata);
6081 6078                          switch (r) {
6082 6079                          case UU_WALK_NEXT:
6083 6080                                  ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 6081                                  continue;
6085 6082  
6086 6083                          case UU_WALK_ERROR:
6087 6084                                  if (cbdata.sc_err == EEXIST) {
6088 6085                                          warn(emsg_pg_added, ient->sc_fmri,
6089 6086                                              pg->sc_pgroup_name);
6090 6087                                          return (EBUSY);
6091 6088                                  }
6092 6089                                  return (cbdata.sc_err);
6093 6090  
6094 6091                          default:
6095 6092                                  bad_error("entity_pgroup_import", r);
6096 6093                          }
6097 6094                  }
6098 6095  
6099 6096                  /* report differences between pg & current */
6100 6097                  r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 6098                  switch (r) {
6102 6099                  case 0:
6103 6100                          break;
6104 6101  
6105 6102                  case ECANCELED:
6106 6103                          warn(emsg_pg_deleted, ient->sc_fmri,
6107 6104                              pg->sc_pgroup_name);
6108 6105                          return (EBUSY);
6109 6106  
6110 6107                  case ECONNABORTED:
6111 6108                  case EBADF:
6112 6109                  case ENOMEM:
6113 6110                  case EACCES:
6114 6111                          return (r);
6115 6112  
6116 6113                  default:
6117 6114                          bad_error("load_pg", r);
6118 6115                  }
6119 6116                  report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 6117                  internal_pgroup_free(rpg);
6121 6118                  rpg = NULL;
6122 6119          }
6123 6120  
6124 6121          return (0);
6125 6122  }
6126 6123  
6127 6124  /*
6128 6125   * Import an instance.  If it doesn't exist, create it.  If it has
6129 6126   * a last-import snapshot, upgrade its properties.  Finish by updating its
6130 6127   * last-import snapshot.  If it doesn't have a last-import snapshot then it
6131 6128   * could have been created for a dependent tag in another manifest.  Import the
6132 6129   * new properties.  If there's a conflict, don't override, like now?
6133 6130   *
6134 6131   * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6135 6132   * lcbdata->sc_err to
6136 6133   *   ECONNABORTED - repository connection broken
6137 6134   *   ENOMEM - out of memory
6138 6135   *   ENOSPC - svc.configd is out of resources
6139 6136   *   EEXIST - dependency collision in dependent service (error printed)
6140 6137   *   EPERM - couldn't create temporary instance (permission denied)
6141 6138   *         - couldn't import into temporary instance (permission denied)
6142 6139   *         - couldn't take snapshot (permission denied)
6143 6140   *         - couldn't upgrade properties (permission denied)
6144 6141   *         - couldn't import properties (permission denied)
6145 6142   *         - couldn't import dependents (permission denied)
6146 6143   *   EROFS - couldn't create temporary instance (repository read-only)
6147 6144   *         - couldn't import into temporary instance (repository read-only)
6148 6145   *         - couldn't upgrade properties (repository read-only)
6149 6146   *         - couldn't import properties (repository read-only)
6150 6147   *         - couldn't import dependents (repository read-only)
6151 6148   *   EACCES - couldn't create temporary instance (backend access denied)
6152 6149   *          - couldn't import into temporary instance (backend access denied)
6153 6150   *          - couldn't upgrade properties (backend access denied)
6154 6151   *          - couldn't import properties (backend access denied)
6155 6152   *          - couldn't import dependents (backend access denied)
6156 6153   *   EINVAL - invalid instance name (error printed)
6157 6154   *          - invalid pgroup_t's (error printed)
6158 6155   *          - invalid dependents (error printed)
6159 6156   *   EBUSY - temporary service deleted (error printed)
6160 6157   *         - temporary instance deleted (error printed)
6161 6158   *         - temporary instance changed (error printed)
6162 6159   *         - temporary instance already exists (error printed)
6163 6160   *         - instance deleted (error printed)
6164 6161   *   EBADF - instance has corrupt last-import snapshot (error printed)
6165 6162   *         - instance is corrupt (error printed)
6166 6163   *         - dependent has corrupt pg (error printed)
6167 6164   *         - dependent target has a corrupt snapshot (error printed)
6168 6165   *   -1 - unknown libscf error (error printed)
6169 6166   */
6170 6167  static int
6171 6168  lscf_instance_import(void *v, void *pvt)
6172 6169  {
6173 6170          entity_t *inst = v;
6174 6171          scf_callback_t ctx;
6175 6172          scf_callback_t *lcbdata = pvt;
6176 6173          scf_service_t *rsvc = lcbdata->sc_parent;
6177 6174          int r;
6178 6175          scf_snaplevel_t *running;
6179 6176          int flags = lcbdata->sc_flags;
6180 6177  
6181 6178          const char * const emsg_tdel =
6182 6179              gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 6180          const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 6181              "changed unexpectedly.\n");
6185 6182          const char * const emsg_del = gettext("%s changed unexpectedly "
6186 6183              "(instance \"%s\" was deleted.)\n");
6187 6184          const char * const emsg_badsnap = gettext(
6188 6185              "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 6186  
6190 6187          /*
6191 6188           * prepare last-import snapshot:
6192 6189           * create temporary instance (service was precreated)
6193 6190           * populate with properties from bundle
6194 6191           * take snapshot
6195 6192           */
6196 6193          if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 6194                  switch (scf_error()) {
6198 6195                  case SCF_ERROR_CONNECTION_BROKEN:
6199 6196                  case SCF_ERROR_NO_RESOURCES:
6200 6197                  case SCF_ERROR_BACKEND_READONLY:
6201 6198                  case SCF_ERROR_BACKEND_ACCESS:
6202 6199                          return (stash_scferror(lcbdata));
6203 6200  
6204 6201                  case SCF_ERROR_EXISTS:
6205 6202                          warn(gettext("Temporary service svc:/%s "
6206 6203                              "changed unexpectedly (instance \"%s\" added).\n"),
6207 6204                              imp_tsname, inst->sc_name);
6208 6205                          lcbdata->sc_err = EBUSY;
6209 6206                          return (UU_WALK_ERROR);
6210 6207  
6211 6208                  case SCF_ERROR_DELETED:
6212 6209                          warn(gettext("Temporary service svc:/%s "
6213 6210                              "was deleted unexpectedly.\n"), imp_tsname);
6214 6211                          lcbdata->sc_err = EBUSY;
6215 6212                          return (UU_WALK_ERROR);
6216 6213  
6217 6214                  case SCF_ERROR_INVALID_ARGUMENT:
6218 6215                          warn(gettext("Invalid instance name \"%s\".\n"),
6219 6216                              inst->sc_name);
6220 6217                          return (stash_scferror(lcbdata));
6221 6218  
6222 6219                  case SCF_ERROR_PERMISSION_DENIED:
6223 6220                          warn(gettext("Could not create temporary instance "
6224 6221                              "\"%s\" in svc:/%s (permission denied).\n"),
6225 6222                              inst->sc_name, imp_tsname);
6226 6223                          return (stash_scferror(lcbdata));
6227 6224  
6228 6225                  case SCF_ERROR_HANDLE_MISMATCH:
6229 6226                  case SCF_ERROR_NOT_BOUND:
6230 6227                  case SCF_ERROR_NOT_SET:
6231 6228                  default:
6232 6229                          bad_error("scf_service_add_instance", scf_error());
6233 6230                  }
6234 6231          }
6235 6232  
6236 6233          r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 6234              inst->sc_name);
6238 6235          if (r < 0)
6239 6236                  bad_error("snprintf", errno);
6240 6237  
6241 6238          r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 6239              lcbdata->sc_flags | SCI_NOENABLED);
6243 6240          switch (r) {
6244 6241          case 0:
6245 6242                  break;
6246 6243  
6247 6244          case ECANCELED:
6248 6245                  warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 6246                  lcbdata->sc_err = EBUSY;
6250 6247                  r = UU_WALK_ERROR;
6251 6248                  goto deltemp;
6252 6249  
6253 6250          case EEXIST:
6254 6251                  warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 6252                  lcbdata->sc_err = EBUSY;
6256 6253                  r = UU_WALK_ERROR;
6257 6254                  goto deltemp;
6258 6255  
6259 6256          case ECONNABORTED:
6260 6257                  goto connaborted;
6261 6258  
6262 6259          case ENOMEM:
6263 6260          case ENOSPC:
6264 6261          case EPERM:
6265 6262          case EROFS:
6266 6263          case EACCES:
6267 6264          case EINVAL:
6268 6265          case EBUSY:
6269 6266                  lcbdata->sc_err = r;
6270 6267                  r = UU_WALK_ERROR;
6271 6268                  goto deltemp;
6272 6269  
6273 6270          default:
6274 6271                  bad_error("lscf_import_instance_pgs", r);
6275 6272          }
6276 6273  
6277 6274          r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 6275              inst->sc_name);
6279 6276          if (r < 0)
6280 6277                  bad_error("snprintf", errno);
6281 6278  
6282 6279          ctx.sc_handle = lcbdata->sc_handle;
6283 6280          ctx.sc_parent = imp_tinst;
6284 6281          ctx.sc_service = 0;
6285 6282          ctx.sc_source_fmri = inst->sc_fmri;
6286 6283          ctx.sc_target_fmri = imp_str;
6287 6284          if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 6285              UU_DEFAULT) != 0) {
6289 6286                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 6287                          bad_error("uu_list_walk", uu_error());
6291 6288  
6292 6289                  switch (ctx.sc_err) {
6293 6290                  case ECONNABORTED:
6294 6291                          goto connaborted;
6295 6292  
6296 6293                  case ECANCELED:
6297 6294                          warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 6295                          lcbdata->sc_err = EBUSY;
6299 6296                          break;
6300 6297  
6301 6298                  case EEXIST:
6302 6299                          warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 6300                          lcbdata->sc_err = EBUSY;
6304 6301                          break;
6305 6302  
6306 6303                  default:
6307 6304                          lcbdata->sc_err = ctx.sc_err;
6308 6305                  }
6309 6306                  r = UU_WALK_ERROR;
6310 6307                  goto deltemp;
6311 6308          }
6312 6309  
6313 6310          if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 6311              inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 6312                  switch (scf_error()) {
6316 6313                  case SCF_ERROR_CONNECTION_BROKEN:
6317 6314                          goto connaborted;
6318 6315  
6319 6316                  case SCF_ERROR_NO_RESOURCES:
6320 6317                          r = stash_scferror(lcbdata);
6321 6318                          goto deltemp;
6322 6319  
6323 6320                  case SCF_ERROR_EXISTS:
6324 6321                          warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 6322                          lcbdata->sc_err = EBUSY;
6326 6323                          r = UU_WALK_ERROR;
6327 6324                          goto deltemp;
6328 6325  
6329 6326                  case SCF_ERROR_PERMISSION_DENIED:
6330 6327                          warn(gettext("Could not take \"%s\" snapshot of %s "
6331 6328                              "(permission denied).\n"), snap_lastimport,
6332 6329                              imp_str);
6333 6330                          r = stash_scferror(lcbdata);
6334 6331                          goto deltemp;
6335 6332  
6336 6333                  default:
6337 6334                          scfwarn();
6338 6335                          lcbdata->sc_err = -1;
6339 6336                          r = UU_WALK_ERROR;
6340 6337                          goto deltemp;
6341 6338  
6342 6339                  case SCF_ERROR_HANDLE_MISMATCH:
6343 6340                  case SCF_ERROR_INVALID_ARGUMENT:
6344 6341                  case SCF_ERROR_NOT_SET:
6345 6342                          bad_error("_scf_snapshot_take_new_named", scf_error());
6346 6343                  }
6347 6344          }
6348 6345  
6349 6346          if (lcbdata->sc_flags & SCI_FRESH)
6350 6347                  goto fresh;
6351 6348  
6352 6349          if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 6350                  if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 6351                      imp_lisnap) != 0) {
6355 6352                          switch (scf_error()) {
6356 6353                          case SCF_ERROR_DELETED:
6357 6354                                  warn(emsg_del, inst->sc_parent->sc_fmri,
6358 6355                                      inst->sc_name);
6359 6356                                  lcbdata->sc_err = EBUSY;
6360 6357                                  r = UU_WALK_ERROR;
6361 6358                                  goto deltemp;
6362 6359  
6363 6360                          case SCF_ERROR_NOT_FOUND:
6364 6361                                  flags |= SCI_FORCE;
6365 6362                                  goto nosnap;
6366 6363  
6367 6364                          case SCF_ERROR_CONNECTION_BROKEN:
6368 6365                                  goto connaborted;
6369 6366  
6370 6367                          case SCF_ERROR_INVALID_ARGUMENT:
6371 6368                          case SCF_ERROR_HANDLE_MISMATCH:
6372 6369                          case SCF_ERROR_NOT_BOUND:
6373 6370                          case SCF_ERROR_NOT_SET:
6374 6371                          default:
6375 6372                                  bad_error("scf_instance_get_snapshot",
6376 6373                                      scf_error());
6377 6374                          }
6378 6375                  }
6379 6376  
6380 6377                  /* upgrade */
6381 6378  
6382 6379                  /*
6383 6380                   * compare new properties with last-import properties
6384 6381                   * upgrade current properties
6385 6382                   */
6386 6383                  /* clear sc_sceen for pgs */
6387 6384                  if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 6385                      (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389 6386                      0)
6390 6387                          bad_error("uu_list_walk", uu_error());
6391 6388  
6392 6389                  r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 6390                  switch (r) {
6394 6391                  case 0:
6395 6392                          break;
6396 6393  
6397 6394                  case ECONNABORTED:
6398 6395                          goto connaborted;
6399 6396  
6400 6397                  case ECANCELED:
6401 6398                          warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 6399                          lcbdata->sc_err = EBUSY;
6403 6400                          r = UU_WALK_ERROR;
6404 6401                          goto deltemp;
6405 6402  
6406 6403                  case ENOENT:
6407 6404                          warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 6405                          lcbdata->sc_err = EBADF;
6409 6406                          r = UU_WALK_ERROR;
6410 6407                          goto deltemp;
6411 6408  
6412 6409                  default:
6413 6410                          bad_error("get_snaplevel", r);
6414 6411                  }
6415 6412  
6416 6413                  if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 6414                      imp_rsnap) != 0) {
6418 6415                          switch (scf_error()) {
6419 6416                          case SCF_ERROR_DELETED:
6420 6417                                  warn(emsg_del, inst->sc_parent->sc_fmri,
6421 6418                                      inst->sc_name);
6422 6419                                  lcbdata->sc_err = EBUSY;
6423 6420                                  r = UU_WALK_ERROR;
6424 6421                                  goto deltemp;
6425 6422  
6426 6423                          case SCF_ERROR_NOT_FOUND:
6427 6424                                  break;
6428 6425  
6429 6426                          case SCF_ERROR_CONNECTION_BROKEN:
6430 6427                                  goto connaborted;
6431 6428  
6432 6429                          case SCF_ERROR_INVALID_ARGUMENT:
6433 6430                          case SCF_ERROR_HANDLE_MISMATCH:
6434 6431                          case SCF_ERROR_NOT_BOUND:
6435 6432                          case SCF_ERROR_NOT_SET:
6436 6433                          default:
6437 6434                                  bad_error("scf_instance_get_snapshot",
6438 6435                                      scf_error());
6439 6436                          }
6440 6437  
6441 6438                          running = NULL;
6442 6439                  } else {
6443 6440                          r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 6441                          switch (r) {
6445 6442                          case 0:
6446 6443                                  running = imp_rsnpl;
6447 6444                                  break;
6448 6445  
6449 6446                          case ECONNABORTED:
6450 6447                                  goto connaborted;
6451 6448  
6452 6449                          case ECANCELED:
6453 6450                                  warn(emsg_del, inst->sc_parent->sc_fmri,
6454 6451                                      inst->sc_name);
6455 6452                                  lcbdata->sc_err = EBUSY;
6456 6453                                  r = UU_WALK_ERROR;
6457 6454                                  goto deltemp;
6458 6455  
6459 6456                          case ENOENT:
6460 6457                                  warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 6458                                  lcbdata->sc_err = EBADF;
6462 6459                                  r = UU_WALK_ERROR;
6463 6460                                  goto deltemp;
6464 6461  
6465 6462                          default:
6466 6463                                  bad_error("get_snaplevel", r);
6467 6464                          }
6468 6465                  }
6469 6466  
6470 6467                  r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 6468                  switch (r) {
6472 6469                  case 0:
6473 6470                          break;
6474 6471  
6475 6472                  case ECANCELED:
6476 6473                  case ENODEV:
6477 6474                          warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 6475                          lcbdata->sc_err = EBUSY;
6479 6476                          r = UU_WALK_ERROR;
6480 6477                          goto deltemp;
6481 6478  
6482 6479                  case ECONNABORTED:
6483 6480                          goto connaborted;
6484 6481  
6485 6482                  case ENOMEM:
6486 6483                  case ENOSPC:
6487 6484                  case EBADF:
6488 6485                  case EBUSY:
6489 6486                  case EINVAL:
6490 6487                  case EPERM:
6491 6488                  case EROFS:
6492 6489                  case EACCES:
6493 6490                  case EEXIST:
6494 6491                          lcbdata->sc_err = r;
6495 6492                          r = UU_WALK_ERROR;
6496 6493                          goto deltemp;
6497 6494  
6498 6495                  default:
6499 6496                          bad_error("upgrade_props", r);
6500 6497                  }
6501 6498  
6502 6499                  inst->sc_import_state = IMPORT_PROP_DONE;
6503 6500          } else {
6504 6501                  switch (scf_error()) {
6505 6502                  case SCF_ERROR_CONNECTION_BROKEN:
6506 6503                          goto connaborted;
6507 6504  
6508 6505                  case SCF_ERROR_NOT_FOUND:
6509 6506                          break;
6510 6507  
6511 6508                  case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
6512 6509                  case SCF_ERROR_HANDLE_MISMATCH:
6513 6510                  case SCF_ERROR_NOT_BOUND:
6514 6511                  case SCF_ERROR_NOT_SET:
6515 6512                  default:
6516 6513                          bad_error("scf_service_get_instance", scf_error());
6517 6514                  }
6518 6515  
6519 6516  fresh:
6520 6517                  /* create instance */
6521 6518                  if (scf_service_add_instance(rsvc, inst->sc_name,
6522 6519                      imp_inst) != 0) {
6523 6520                          switch (scf_error()) {
6524 6521                          case SCF_ERROR_CONNECTION_BROKEN:
6525 6522                                  goto connaborted;
6526 6523  
6527 6524                          case SCF_ERROR_NO_RESOURCES:
6528 6525                          case SCF_ERROR_BACKEND_READONLY:
6529 6526                          case SCF_ERROR_BACKEND_ACCESS:
6530 6527                                  r = stash_scferror(lcbdata);
6531 6528                                  goto deltemp;
6532 6529  
6533 6530                          case SCF_ERROR_EXISTS:
6534 6531                                  warn(gettext("%s changed unexpectedly "
6535 6532                                      "(instance \"%s\" added).\n"),
6536 6533                                      inst->sc_parent->sc_fmri, inst->sc_name);
6537 6534                                  lcbdata->sc_err = EBUSY;
6538 6535                                  r = UU_WALK_ERROR;
6539 6536                                  goto deltemp;
6540 6537  
6541 6538                          case SCF_ERROR_PERMISSION_DENIED:
6542 6539                                  warn(gettext("Could not create \"%s\" instance "
6543 6540                                      "in %s (permission denied).\n"),
6544 6541                                      inst->sc_name, inst->sc_parent->sc_fmri);
6545 6542                                  r = stash_scferror(lcbdata);
6546 6543                                  goto deltemp;
6547 6544  
6548 6545                          case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6549 6546                          case SCF_ERROR_HANDLE_MISMATCH:
6550 6547                          case SCF_ERROR_NOT_BOUND:
6551 6548                          case SCF_ERROR_NOT_SET:
6552 6549                          default:
6553 6550                                  bad_error("scf_service_add_instance",
6554 6551                                      scf_error());
6555 6552                          }
6556 6553                  }
6557 6554  
6558 6555  nosnap:
6559 6556                  /*
6560 6557                   * Create a last-import snapshot to serve as an attachment
6561 6558                   * point for the real one from the temporary instance.  Since
6562 6559                   * the contents is irrelevant, take it now, while the instance
6563 6560                   * is empty, to minimize svc.configd's work.
6564 6561                   */
6565 6562                  if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 6563                      imp_lisnap) != 0) {
6567 6564                          switch (scf_error()) {
6568 6565                          case SCF_ERROR_CONNECTION_BROKEN:
6569 6566                                  goto connaborted;
6570 6567  
6571 6568                          case SCF_ERROR_NO_RESOURCES:
6572 6569                                  r = stash_scferror(lcbdata);
6573 6570                                  goto deltemp;
6574 6571  
6575 6572                          case SCF_ERROR_EXISTS:
6576 6573                                  warn(gettext("%s changed unexpectedly "
6577 6574                                      "(snapshot \"%s\" added).\n"),
6578 6575                                      inst->sc_fmri, snap_lastimport);
6579 6576                                  lcbdata->sc_err = EBUSY;
6580 6577                                  r = UU_WALK_ERROR;
6581 6578                                  goto deltemp;
6582 6579  
6583 6580                          case SCF_ERROR_PERMISSION_DENIED:
6584 6581                                  warn(gettext("Could not take \"%s\" snapshot "
6585 6582                                      "of %s (permission denied).\n"),
6586 6583                                      snap_lastimport, inst->sc_fmri);
6587 6584                                  r = stash_scferror(lcbdata);
6588 6585                                  goto deltemp;
6589 6586  
6590 6587                          default:
6591 6588                                  scfwarn();
6592 6589                                  lcbdata->sc_err = -1;
6593 6590                                  r = UU_WALK_ERROR;
6594 6591                                  goto deltemp;
6595 6592  
6596 6593                          case SCF_ERROR_NOT_SET:
6597 6594                          case SCF_ERROR_INTERNAL:
6598 6595                          case SCF_ERROR_INVALID_ARGUMENT:
6599 6596                          case SCF_ERROR_HANDLE_MISMATCH:
6600 6597                                  bad_error("_scf_snapshot_take_new",
6601 6598                                      scf_error());
6602 6599                          }
6603 6600                  }
6604 6601  
6605 6602                  if (li_only)
6606 6603                          goto lionly;
6607 6604  
6608 6605                  inst->sc_import_state = IMPORT_PROP_BEGUN;
6609 6606  
6610 6607                  r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 6608                      flags);
6612 6609                  switch (r) {
6613 6610                  case 0:
6614 6611                          break;
6615 6612  
6616 6613                  case ECONNABORTED:
6617 6614                          goto connaborted;
6618 6615  
6619 6616                  case ECANCELED:
6620 6617                          warn(gettext("%s changed unexpectedly "
6621 6618                              "(instance \"%s\" deleted).\n"),
6622 6619                              inst->sc_parent->sc_fmri, inst->sc_name);
6623 6620                          lcbdata->sc_err = EBUSY;
6624 6621                          r = UU_WALK_ERROR;
6625 6622                          goto deltemp;
6626 6623  
6627 6624                  case EEXIST:
6628 6625                          warn(gettext("%s changed unexpectedly "
6629 6626                              "(property group added).\n"), inst->sc_fmri);
6630 6627                          lcbdata->sc_err = EBUSY;
6631 6628                          r = UU_WALK_ERROR;
6632 6629                          goto deltemp;
6633 6630  
6634 6631                  default:
6635 6632                          lcbdata->sc_err = r;
6636 6633                          r = UU_WALK_ERROR;
6637 6634                          goto deltemp;
6638 6635  
6639 6636                  case EINVAL:    /* caught above */
6640 6637                          bad_error("lscf_import_instance_pgs", r);
6641 6638                  }
6642 6639  
6643 6640                  ctx.sc_parent = imp_inst;
6644 6641                  ctx.sc_service = 0;
6645 6642                  ctx.sc_trans = NULL;
6646 6643                  ctx.sc_flags = 0;
6647 6644                  if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 6645                      &ctx, UU_DEFAULT) != 0) {
6649 6646                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 6647                                  bad_error("uu_list_walk", uu_error());
6651 6648  
6652 6649                          if (ctx.sc_err == ECONNABORTED)
6653 6650                                  goto connaborted;
6654 6651                          lcbdata->sc_err = ctx.sc_err;
6655 6652                          r = UU_WALK_ERROR;
6656 6653                          goto deltemp;
6657 6654                  }
6658 6655  
6659 6656                  inst->sc_import_state = IMPORT_PROP_DONE;
6660 6657  
6661 6658                  if (g_verbose)
6662 6659                          warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 6660                              snap_initial, inst->sc_fmri);
6664 6661                  r = take_snap(imp_inst, snap_initial, imp_snap);
6665 6662                  switch (r) {
6666 6663                  case 0:
6667 6664                          break;
6668 6665  
6669 6666                  case ECONNABORTED:
6670 6667                          goto connaborted;
6671 6668  
6672 6669                  case ENOSPC:
6673 6670                  case -1:
6674 6671                          lcbdata->sc_err = r;
6675 6672                          r = UU_WALK_ERROR;
6676 6673                          goto deltemp;
6677 6674  
6678 6675                  case ECANCELED:
6679 6676                          warn(gettext("%s changed unexpectedly "
6680 6677                              "(instance %s deleted).\n"),
6681 6678                              inst->sc_parent->sc_fmri, inst->sc_name);
6682 6679                          lcbdata->sc_err = r;
6683 6680                          r = UU_WALK_ERROR;
6684 6681                          goto deltemp;
6685 6682  
6686 6683                  case EPERM:
6687 6684                          warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 6685                          lcbdata->sc_err = r;
6689 6686                          r = UU_WALK_ERROR;
6690 6687                          goto deltemp;
6691 6688  
6692 6689                  default:
6693 6690                          bad_error("take_snap", r);
6694 6691                  }
6695 6692          }
6696 6693  
6697 6694  lionly:
6698 6695          if (lcbdata->sc_flags & SCI_NOSNAP)
6699 6696                  goto deltemp;
6700 6697  
6701 6698          /* transfer snapshot from temporary instance */
6702 6699          if (g_verbose)
6703 6700                  warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 6701                      snap_lastimport, inst->sc_fmri);
6705 6702          if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 6703                  switch (scf_error()) {
6707 6704                  case SCF_ERROR_CONNECTION_BROKEN:
6708 6705                          goto connaborted;
6709 6706  
6710 6707                  case SCF_ERROR_NO_RESOURCES:
6711 6708                          r = stash_scferror(lcbdata);
6712 6709                          goto deltemp;
6713 6710  
6714 6711                  case SCF_ERROR_PERMISSION_DENIED:
6715 6712                          warn(gettext("Could not take \"%s\" snapshot for %s "
6716 6713                              "(permission denied).\n"), snap_lastimport,
6717 6714                              inst->sc_fmri);
6718 6715                          r = stash_scferror(lcbdata);
6719 6716                          goto deltemp;
6720 6717  
6721 6718                  case SCF_ERROR_NOT_SET:
6722 6719                  case SCF_ERROR_HANDLE_MISMATCH:
6723 6720                  default:
6724 6721                          bad_error("_scf_snapshot_attach", scf_error());
6725 6722                  }
6726 6723          }
6727 6724  
6728 6725          inst->sc_import_state = IMPORT_COMPLETE;
6729 6726  
6730 6727          r = UU_WALK_NEXT;
6731 6728  
6732 6729  deltemp:
6733 6730          /* delete temporary instance */
6734 6731          if (scf_instance_delete(imp_tinst) != 0) {
6735 6732                  switch (scf_error()) {
6736 6733                  case SCF_ERROR_DELETED:
6737 6734                          break;
6738 6735  
6739 6736                  case SCF_ERROR_CONNECTION_BROKEN:
6740 6737                          goto connaborted;
6741 6738  
6742 6739                  case SCF_ERROR_NOT_SET:
6743 6740                  case SCF_ERROR_NOT_BOUND:
6744 6741                  default:
6745 6742                          bad_error("scf_instance_delete", scf_error());
6746 6743                  }
6747 6744          }
6748 6745  
6749 6746          return (r);
6750 6747  
6751 6748  connaborted:
6752 6749          warn(gettext("Could not delete svc:/%s:%s "
6753 6750              "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 6751          lcbdata->sc_err = ECONNABORTED;
6755 6752          return (UU_WALK_ERROR);
6756 6753  }
6757 6754  
6758 6755  /*
6759 6756   * When an instance is imported we end up telling configd about it. Once we tell
6760 6757   * configd about these changes, startd eventually notices. If this is a new
6761 6758   * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 6759   * property group. However, many of the other tools expect that this property
6763 6760   * group exists and has certain values.
6764 6761   *
6765 6762   * These values are added asynchronously by startd. We should not return from
6766 6763   * this routine until we can verify that the property group we need is there.
6767 6764   *
6768 6765   * Before we go ahead and verify this, we have to ask ourselves an important
6769 6766   * question: Is the early manifest service currently running?  Because if it is
6770 6767   * running and it has invoked us, then the service will never get a restarter
6771 6768   * property because svc.startd is blocked on EMI finishing before it lets itself
6772 6769   * fully connect to svc.configd. Of course, this means that this race condition
6773 6770   * is in fact impossible to 100% eliminate.
6774 6771   *
6775 6772   * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 6773   * the state of the EMI instance. If it is online it bails out and makes sure
6777 6774   * that it doesn't run again. In this case, we're going to do something similar,
6778 6775   * only if the state is online, then we're going to actually verify. EMI always
6779 6776   * has to be present, but it can be explicitly disabled to reduce the amount of
6780 6777   * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 6778   * about the implicit race condition and can go ahead and check things. If EMI
6782 6779   * is in some state that isn't online or disabled and isn't runinng, then we
6783 6780   * assume that things are rather bad and we're not going to get in your way,
6784 6781   * even if the rest of SMF does.
6785 6782   *
6786 6783   * Returns 0 on success or returns an errno.
6787 6784   */
6788 6785  #ifndef NATIVE_BUILD
6789 6786  static int
6790 6787  lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 6788  {
6792 6789          int ret, err;
6793 6790          struct timespec ts;
6794 6791          char *emi_state;
6795 6792  
6796 6793          /*
6797 6794           * smf_get_state does not distinguish between its different failure
6798 6795           * modes: memory allocation failures, SMF internal failures, and a lack
6799 6796           * of EMI entirely because it's been removed. In these cases, we're
6800 6797           * going to be conservative and opt to say that if we don't know, better
6801 6798           * to not block import or falsely warn to the user.
6802 6799           */
6803 6800          if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804 6801                  return (0);
6805 6802          }
6806 6803  
6807 6804          /*
6808 6805           * As per the block comment for this function check the state of EMI
6809 6806           */
6810 6807          if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811 6808              strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812 6809                  warn(gettext("Not validating instance %s:%s because EMI's "
6813 6810                      "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814 6811                  free(emi_state);
6815 6812                  return (0);
6816 6813          }
6817 6814  
6818 6815          free(emi_state);
6819 6816  
6820 6817          /*
6821 6818           * First we have to get the property.
6822 6819           */
6823 6820          if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824 6821                  ret = scf_error();
6825 6822                  warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826 6823                  return (ret);
6827 6824          }
6828 6825  
6829 6826          /*
6830 6827           * We should always be able to get the instance. It should already
6831 6828           * exist because we just created it or got it. There probably is a
6832 6829           * slim chance that someone may have come in and deleted it though from
6833 6830           * under us.
6834 6831           */
6835 6832          if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836 6833              != 0) {
6837 6834                  ret = scf_error();
6838 6835                  warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839 6836                  switch (ret) {
6840 6837                  case SCF_ERROR_DELETED:
6841 6838                          err = ENODEV;
6842 6839                          break;
6843 6840                  case SCF_ERROR_CONNECTION_BROKEN:
6844 6841                          warn(gettext("Lost repository connection\n"));
6845 6842                          err = ECONNABORTED;
6846 6843                          break;
6847 6844                  case SCF_ERROR_NOT_FOUND:
6848 6845                          warn(gettext("Instance \"%s\" disappeared out from "
6849 6846                              "under us.\n"), inst->sc_name);
6850 6847                          err = ENOENT;
6851 6848                          break;
6852 6849                  default:
6853 6850                          bad_error("scf_service_get_instance", ret);
6854 6851                  }
6855 6852  
6856 6853                  return (err);
6857 6854          }
6858 6855  
6859 6856          /*
6860 6857           * An astute observer may want to use _scf_wait_pg which would notify us
6861 6858           * of a property group change, unfortunately that does not work if the
6862 6859           * property group in question does not exist. So instead we have to
6863 6860           * manually poll and ask smf the best way to get to it.
6864 6861           */
6865 6862          while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866 6863              != SCF_SUCCESS) {
6867 6864                  ret = scf_error();
6868 6865                  if (ret != SCF_ERROR_NOT_FOUND) {
6869 6866                          warn(gettext("Failed to get restarter property "
6870 6867                              "group for instance: %s\n"), inst->sc_name);
6871 6868                          switch (ret) {
6872 6869                          case SCF_ERROR_DELETED:
6873 6870                                  err = ENODEV;
6874 6871                                  break;
6875 6872                          case SCF_ERROR_CONNECTION_BROKEN:
6876 6873                                  warn(gettext("Lost repository connection\n"));
6877 6874                                  err = ECONNABORTED;
6878 6875                                  break;
6879 6876                          default:
6880 6877                                  bad_error("scf_service_get_instance", ret);
6881 6878                          }
6882 6879  
6883 6880                          return (err);
6884 6881                  }
6885 6882  
6886 6883                  ts.tv_sec = pg_timeout / NANOSEC;
6887 6884                  ts.tv_nsec = pg_timeout % NANOSEC;
6888 6885  
6889 6886                  (void) nanosleep(&ts, NULL);
6890 6887          }
6891 6888  
6892 6889          /*
6893 6890           * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894 6891           * So in addition to the property group being present, we need to wait
6895 6892           * for the property to be there in some form.
6896 6893           *
6897 6894           * Note that a property group is a frozen snapshot in time. To properly
6898 6895           * get beyond this, you have to refresh the property group each time.
6899 6896           */
6900 6897          while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901 6898              imp_prop)) != 0) {
6902 6899  
6903 6900                  ret = scf_error();
6904 6901                  if (ret != SCF_ERROR_NOT_FOUND) {
6905 6902                          warn(gettext("Failed to get property %s from the "
6906 6903                              "restarter property group of instance %s\n"),
6907 6904                              SCF_PROPERTY_STATE, inst->sc_name);
6908 6905                          switch (ret) {
6909 6906                          case SCF_ERROR_CONNECTION_BROKEN:
6910 6907                                  warn(gettext("Lost repository connection\n"));
6911 6908                                  err = ECONNABORTED;
6912 6909                                  break;
6913 6910                          case SCF_ERROR_DELETED:
6914 6911                                  err = ENODEV;
6915 6912                                  break;
6916 6913                          default:
6917 6914                                  bad_error("scf_pg_get_property", ret);
6918 6915                          }
6919 6916  
6920 6917                          return (err);
6921 6918                  }
6922 6919  
6923 6920                  ts.tv_sec = pg_timeout / NANOSEC;
6924 6921                  ts.tv_nsec = pg_timeout % NANOSEC;
6925 6922  
6926 6923                  (void) nanosleep(&ts, NULL);
6927 6924  
6928 6925                  ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929 6926                  if (ret != SCF_SUCCESS) {
6930 6927                          warn(gettext("Failed to get restarter property "
6931 6928                              "group for instance: %s\n"), inst->sc_name);
6932 6929                          switch (ret) {
6933 6930                          case SCF_ERROR_DELETED:
6934 6931                                  err = ENODEV;
6935 6932                                  break;
6936 6933                          case SCF_ERROR_CONNECTION_BROKEN:
6937 6934                                  warn(gettext("Lost repository connection\n"));
6938 6935                                  err = ECONNABORTED;
6939 6936                                  break;
6940 6937                          default:
6941 6938                                  bad_error("scf_service_get_instance", ret);
6942 6939                          }
6943 6940  
6944 6941                          return (err);
6945 6942                  }
6946 6943          }
6947 6944  
6948 6945          /*
6949 6946           * We don't have to free the property groups or other values that we got
6950 6947           * because we stored them in global variables that are allocated and
6951 6948           * freed by the routines that call into these functions. Unless of
6952 6949           * course the rest of the code here that we are basing this on is
6953 6950           * mistaken.
6954 6951           */
6955 6952          return (0);
6956 6953  }
6957 6954  #endif
6958 6955  
6959 6956  /*
6960 6957   * If the service is missing, create it, import its properties, and import the
6961 6958   * instances.  Since the service is brand new, it should be empty, and if we
6962 6959   * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963 6960   *
6964 6961   * If the service exists, we want to upgrade its properties and import the
6965 6962   * instances.  Upgrade requires a last-import snapshot, though, which are
6966 6963   * children of instances, so first we'll have to go through the instances
6967 6964   * looking for a last-import snapshot.  If we don't find one then we'll just
6968 6965   * override-import the service properties (but don't delete existing
6969 6966   * properties: another service might have declared us as a dependent).  Before
6970 6967   * we change anything, though, we want to take the previous snapshots.  We
6971 6968   * also give lscf_instance_import() a leg up on taking last-import snapshots
6972 6969   * by importing the manifest's service properties into a temporary service.
6973 6970   *
6974 6971   * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6975 6972   * sets lcbdata->sc_err to
6976 6973   *   ECONNABORTED - repository connection broken
6977 6974   *   ENOMEM - out of memory
6978 6975   *   ENOSPC - svc.configd is out of resources
6979 6976   *   EPERM - couldn't create temporary service (error printed)
6980 6977   *         - couldn't import into temp service (error printed)
6981 6978   *         - couldn't create service (error printed)
6982 6979   *         - couldn't import dependent (error printed)
6983 6980   *         - couldn't take snapshot (error printed)
6984 6981   *         - couldn't create instance (error printed)
6985 6982   *         - couldn't create, modify, or delete pg (error printed)
6986 6983   *         - couldn't create, modify, or delete dependent (error printed)
6987 6984   *         - couldn't import instance (error printed)
6988 6985   *   EROFS - couldn't create temporary service (repository read-only)
6989 6986   *         - couldn't import into temporary service (repository read-only)
6990 6987   *         - couldn't create service (repository read-only)
6991 6988   *         - couldn't import dependent (repository read-only)
6992 6989   *         - couldn't create instance (repository read-only)
6993 6990   *         - couldn't create, modify, or delete pg or dependent
6994 6991   *         - couldn't import instance (repository read-only)
6995 6992   *   EACCES - couldn't create temporary service (backend access denied)
6996 6993   *          - couldn't import into temporary service (backend access denied)
6997 6994   *          - couldn't create service (backend access denied)
6998 6995   *          - couldn't import dependent (backend access denied)
6999 6996   *          - couldn't create instance (backend access denied)
7000 6997   *          - couldn't create, modify, or delete pg or dependent
7001 6998   *          - couldn't import instance (backend access denied)
7002 6999   *   EINVAL - service name is invalid (error printed)
7003 7000   *          - service name is too long (error printed)
7004 7001   *          - s has invalid pgroup (error printed)
7005 7002   *          - s has invalid dependent (error printed)
7006 7003   *          - instance name is invalid (error printed)
7007 7004   *          - instance entity_t is invalid (error printed)
7008 7005   *   EEXIST - couldn't create temporary service (already exists) (error printed)
7009 7006   *          - couldn't import dependent (dependency pg already exists) (printed)
7010 7007   *          - dependency collision in dependent service (error printed)
7011 7008   *   EBUSY - temporary service deleted (error printed)
7012 7009   *         - property group added to temporary service (error printed)
7013 7010   *         - new property group changed or was deleted (error printed)
7014 7011   *         - service was added unexpectedly (error printed)
7015 7012   *         - service was deleted unexpectedly (error printed)
7016 7013   *         - property group added to new service (error printed)
7017 7014   *         - instance added unexpectedly (error printed)
7018 7015   *         - instance deleted unexpectedly (error printed)
7019 7016   *         - dependent service deleted unexpectedly (error printed)
7020 7017   *         - pg was added, changed, or deleted (error printed)
7021 7018   *         - dependent pg changed (error printed)
7022 7019   *         - temporary instance added, changed, or deleted (error printed)
7023 7020   *   EBADF - a last-import snapshot is corrupt (error printed)
7024 7021   *         - the service is corrupt (error printed)
7025 7022   *         - a dependent is corrupt (error printed)
7026 7023   *         - an instance is corrupt (error printed)
7027 7024   *         - an instance has a corrupt last-import snapshot (error printed)
7028 7025   *         - dependent target has a corrupt snapshot (error printed)
7029 7026   *   -1 - unknown libscf error (error printed)
7030 7027   */
7031 7028  static int
7032 7029  lscf_service_import(void *v, void *pvt)
7033 7030  {
7034 7031          entity_t *s = v;
7035 7032          scf_callback_t cbdata;
7036 7033          scf_callback_t *lcbdata = pvt;
7037 7034          scf_scope_t *scope = lcbdata->sc_parent;
7038 7035          entity_t *inst, linst;
7039 7036          int r;
7040 7037          int fresh = 0;
7041 7038          scf_snaplevel_t *running;
7042 7039          int have_ge = 0;
7043 7040          boolean_t retried = B_FALSE;
7044 7041  
7045 7042          const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046 7043              "was deleted unexpectedly.\n");
7047 7044          const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048 7045              "changed unexpectedly (property group added).\n");
7049 7046          const char * const s_deleted =
7050 7047              gettext("%s was deleted unexpectedly.\n");
7051 7048          const char * const i_deleted =
7052 7049              gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053 7050          const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054 7051              "is corrupt (missing service snaplevel).\n");
7055 7052          const char * const s_mfile_upd =
7056 7053              gettext("Unable to update the manifest file connection "
7057 7054              "for %s\n");
7058 7055  
7059 7056          li_only = 0;
7060 7057          /* Validate the service name */
7061 7058          if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062 7059                  switch (scf_error()) {
7063 7060                  case SCF_ERROR_CONNECTION_BROKEN:
7064 7061                          return (stash_scferror(lcbdata));
7065 7062  
7066 7063                  case SCF_ERROR_INVALID_ARGUMENT:
7067 7064                          warn(gettext("\"%s\" is an invalid service name.  "
7068 7065                              "Cannot import.\n"), s->sc_name);
7069 7066                          return (stash_scferror(lcbdata));
7070 7067  
7071 7068                  case SCF_ERROR_NOT_FOUND:
7072 7069                          break;
7073 7070  
7074 7071                  case SCF_ERROR_HANDLE_MISMATCH:
7075 7072                  case SCF_ERROR_NOT_BOUND:
7076 7073                  case SCF_ERROR_NOT_SET:
7077 7074                  default:
7078 7075                          bad_error("scf_scope_get_service", scf_error());
7079 7076                  }
7080 7077          }
7081 7078  
7082 7079          /* create temporary service */
7083 7080          /*
7084 7081           * the size of the buffer was reduced to max_scf_name_len to prevent
7085 7082           * hitting bug 6681151.  After the bug fix, the size of the buffer
7086 7083           * should be restored to its original value (max_scf_name_len +1)
7087 7084           */
7088 7085          r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089 7086          if (r < 0)
7090 7087                  bad_error("snprintf", errno);
7091 7088          if (r > max_scf_name_len) {
7092 7089                  warn(gettext(
7093 7090                      "Service name \"%s\" is too long.  Cannot import.\n"),
7094 7091                      s->sc_name);
7095 7092                  lcbdata->sc_err = EINVAL;
7096 7093                  return (UU_WALK_ERROR);
7097 7094          }
7098 7095  
7099 7096  retry:
7100 7097          if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101 7098                  switch (scf_error()) {
7102 7099                  case SCF_ERROR_CONNECTION_BROKEN:
7103 7100                  case SCF_ERROR_NO_RESOURCES:
7104 7101                  case SCF_ERROR_BACKEND_READONLY:
7105 7102                  case SCF_ERROR_BACKEND_ACCESS:
7106 7103                          return (stash_scferror(lcbdata));
7107 7104  
7108 7105                  case SCF_ERROR_EXISTS:
7109 7106                          if (!retried) {
7110 7107                                  lscf_delete(imp_tsname, 0);
7111 7108                                  retried = B_TRUE;
7112 7109                                  goto retry;
7113 7110                          }
7114 7111                          warn(gettext(
7115 7112                              "Temporary service \"%s\" must be deleted before "
7116 7113                              "this manifest can be imported.\n"), imp_tsname);
7117 7114                          return (stash_scferror(lcbdata));
7118 7115  
7119 7116                  case SCF_ERROR_PERMISSION_DENIED:
7120 7117                          warn(gettext("Could not create temporary service "
7121 7118                              "\"%s\" (permission denied).\n"), imp_tsname);
7122 7119                          return (stash_scferror(lcbdata));
7123 7120  
7124 7121                  case SCF_ERROR_INVALID_ARGUMENT:
7125 7122                  case SCF_ERROR_HANDLE_MISMATCH:
7126 7123                  case SCF_ERROR_NOT_BOUND:
7127 7124                  case SCF_ERROR_NOT_SET:
7128 7125                  default:
7129 7126                          bad_error("scf_scope_add_service", scf_error());
7130 7127                  }
7131 7128          }
7132 7129  
7133 7130          r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134 7131          if (r < 0)
7135 7132                  bad_error("snprintf", errno);
7136 7133  
7137 7134          cbdata.sc_handle = lcbdata->sc_handle;
7138 7135          cbdata.sc_parent = imp_tsvc;
7139 7136          cbdata.sc_service = 1;
7140 7137          cbdata.sc_source_fmri = s->sc_fmri;
7141 7138          cbdata.sc_target_fmri = imp_str;
7142 7139          cbdata.sc_flags = 0;
7143 7140  
7144 7141          if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145 7142              UU_DEFAULT) != 0) {
7146 7143                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147 7144                          bad_error("uu_list_walk", uu_error());
7148 7145  
7149 7146                  lcbdata->sc_err = cbdata.sc_err;
7150 7147                  switch (cbdata.sc_err) {
7151 7148                  case ECONNABORTED:
7152 7149                          goto connaborted;
7153 7150  
7154 7151                  case ECANCELED:
7155 7152                          warn(ts_deleted, imp_tsname);
7156 7153                          lcbdata->sc_err = EBUSY;
7157 7154                          return (UU_WALK_ERROR);
7158 7155  
7159 7156                  case EEXIST:
7160 7157                          warn(ts_pg_added, imp_tsname);
7161 7158                          lcbdata->sc_err = EBUSY;
7162 7159                          return (UU_WALK_ERROR);
7163 7160                  }
7164 7161  
7165 7162                  r = UU_WALK_ERROR;
7166 7163                  goto deltemp;
7167 7164          }
7168 7165  
7169 7166          if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170 7167              UU_DEFAULT) != 0) {
7171 7168                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172 7169                          bad_error("uu_list_walk", uu_error());
7173 7170  
7174 7171                  lcbdata->sc_err = cbdata.sc_err;
7175 7172                  switch (cbdata.sc_err) {
7176 7173                  case ECONNABORTED:
7177 7174                          goto connaborted;
7178 7175  
7179 7176                  case ECANCELED:
7180 7177                          warn(ts_deleted, imp_tsname);
7181 7178                          lcbdata->sc_err = EBUSY;
7182 7179                          return (UU_WALK_ERROR);
7183 7180  
7184 7181                  case EEXIST:
7185 7182                          warn(ts_pg_added, imp_tsname);
7186 7183                          lcbdata->sc_err = EBUSY;
7187 7184                          return (UU_WALK_ERROR);
7188 7185                  }
7189 7186  
7190 7187                  r = UU_WALK_ERROR;
7191 7188                  goto deltemp;
7192 7189          }
7193 7190  
7194 7191          if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195 7192                  switch (scf_error()) {
7196 7193                  case SCF_ERROR_NOT_FOUND:
7197 7194                          break;
7198 7195  
7199 7196                  case SCF_ERROR_CONNECTION_BROKEN:
7200 7197                          goto connaborted;
7201 7198  
7202 7199                  case SCF_ERROR_INVALID_ARGUMENT:
7203 7200                  case SCF_ERROR_HANDLE_MISMATCH:
7204 7201                  case SCF_ERROR_NOT_BOUND:
7205 7202                  case SCF_ERROR_NOT_SET:
7206 7203                  default:
7207 7204                          bad_error("scf_scope_get_service", scf_error());
7208 7205                  }
7209 7206  
7210 7207                  if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211 7208                          switch (scf_error()) {
7212 7209                          case SCF_ERROR_CONNECTION_BROKEN:
7213 7210                                  goto connaborted;
7214 7211  
7215 7212                          case SCF_ERROR_NO_RESOURCES:
7216 7213                          case SCF_ERROR_BACKEND_READONLY:
7217 7214                          case SCF_ERROR_BACKEND_ACCESS:
7218 7215                                  r = stash_scferror(lcbdata);
7219 7216                                  goto deltemp;
7220 7217  
7221 7218                          case SCF_ERROR_EXISTS:
7222 7219                                  warn(gettext("Scope \"%s\" changed unexpectedly"
7223 7220                                      " (service \"%s\" added).\n"),
7224 7221                                      SCF_SCOPE_LOCAL, s->sc_name);
7225 7222                                  lcbdata->sc_err = EBUSY;
7226 7223                                  goto deltemp;
7227 7224  
7228 7225                          case SCF_ERROR_PERMISSION_DENIED:
7229 7226                                  warn(gettext("Could not create service \"%s\" "
7230 7227                                      "(permission denied).\n"), s->sc_name);
7231 7228                                  goto deltemp;
7232 7229  
7233 7230                          case SCF_ERROR_INVALID_ARGUMENT:
7234 7231                          case SCF_ERROR_HANDLE_MISMATCH:
7235 7232                          case SCF_ERROR_NOT_BOUND:
7236 7233                          case SCF_ERROR_NOT_SET:
7237 7234                          default:
7238 7235                                  bad_error("scf_scope_add_service", scf_error());
7239 7236                          }
7240 7237                  }
7241 7238  
7242 7239                  s->sc_import_state = IMPORT_PROP_BEGUN;
7243 7240  
7244 7241                  /* import service properties */
7245 7242                  cbdata.sc_handle = lcbdata->sc_handle;
7246 7243                  cbdata.sc_parent = imp_svc;
7247 7244                  cbdata.sc_service = 1;
7248 7245                  cbdata.sc_flags = lcbdata->sc_flags;
7249 7246                  cbdata.sc_source_fmri = s->sc_fmri;
7250 7247                  cbdata.sc_target_fmri = s->sc_fmri;
7251 7248  
7252 7249                  if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253 7250                      &cbdata, UU_DEFAULT) != 0) {
7254 7251                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255 7252                                  bad_error("uu_list_walk", uu_error());
7256 7253  
7257 7254                          lcbdata->sc_err = cbdata.sc_err;
7258 7255                          switch (cbdata.sc_err) {
7259 7256                          case ECONNABORTED:
7260 7257                                  goto connaborted;
7261 7258  
7262 7259                          case ECANCELED:
7263 7260                                  warn(s_deleted, s->sc_fmri);
7264 7261                                  lcbdata->sc_err = EBUSY;
7265 7262                                  return (UU_WALK_ERROR);
7266 7263  
7267 7264                          case EEXIST:
7268 7265                                  warn(gettext("%s changed unexpectedly "
7269 7266                                      "(property group added).\n"), s->sc_fmri);
7270 7267                                  lcbdata->sc_err = EBUSY;
7271 7268                                  return (UU_WALK_ERROR);
7272 7269  
7273 7270                          case EINVAL:
7274 7271                                  /* caught above */
7275 7272                                  bad_error("entity_pgroup_import",
7276 7273                                      cbdata.sc_err);
7277 7274                          }
7278 7275  
7279 7276                          r = UU_WALK_ERROR;
7280 7277                          goto deltemp;
7281 7278                  }
7282 7279  
7283 7280                  cbdata.sc_trans = NULL;
7284 7281                  cbdata.sc_flags = 0;
7285 7282                  if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286 7283                      &cbdata, UU_DEFAULT) != 0) {
7287 7284                          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288 7285                                  bad_error("uu_list_walk", uu_error());
7289 7286  
7290 7287                          lcbdata->sc_err = cbdata.sc_err;
7291 7288                          if (cbdata.sc_err == ECONNABORTED)
7292 7289                                  goto connaborted;
7293 7290                          r = UU_WALK_ERROR;
7294 7291                          goto deltemp;
7295 7292                  }
7296 7293  
7297 7294                  s->sc_import_state = IMPORT_PROP_DONE;
7298 7295  
7299 7296                  /*
7300 7297                   * This is a new service, so we can't take previous snapshots
7301 7298                   * or upgrade service properties.
7302 7299                   */
7303 7300                  fresh = 1;
7304 7301                  goto instances;
7305 7302          }
7306 7303  
7307 7304          /* Clear sc_seen for the instances. */
7308 7305          if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309 7306              (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310 7307                  bad_error("uu_list_walk", uu_error());
7311 7308  
7312 7309          /*
7313 7310           * Take previous snapshots for all instances.  Even for ones not
7314 7311           * mentioned in the bundle, since we might change their service
7315 7312           * properties.
7316 7313           */
7317 7314          if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318 7315                  switch (scf_error()) {
7319 7316                  case SCF_ERROR_CONNECTION_BROKEN:
7320 7317                          goto connaborted;
7321 7318  
7322 7319                  case SCF_ERROR_DELETED:
7323 7320                          warn(s_deleted, s->sc_fmri);
7324 7321                          lcbdata->sc_err = EBUSY;
7325 7322                          r = UU_WALK_ERROR;
7326 7323                          goto deltemp;
7327 7324  
7328 7325                  case SCF_ERROR_HANDLE_MISMATCH:
7329 7326                  case SCF_ERROR_NOT_BOUND:
7330 7327                  case SCF_ERROR_NOT_SET:
7331 7328                  default:
7332 7329                          bad_error("scf_iter_service_instances", scf_error());
7333 7330                  }
7334 7331          }
7335 7332  
7336 7333          for (;;) {
7337 7334                  r = scf_iter_next_instance(imp_iter, imp_inst);
7338 7335                  if (r == 0)
7339 7336                          break;
7340 7337                  if (r != 1) {
7341 7338                          switch (scf_error()) {
7342 7339                          case SCF_ERROR_DELETED:
7343 7340                                  warn(s_deleted, s->sc_fmri);
7344 7341                                  lcbdata->sc_err = EBUSY;
7345 7342                                  r = UU_WALK_ERROR;
7346 7343                                  goto deltemp;
7347 7344  
7348 7345                          case SCF_ERROR_CONNECTION_BROKEN:
7349 7346                                  goto connaborted;
7350 7347  
7351 7348                          case SCF_ERROR_NOT_BOUND:
7352 7349                          case SCF_ERROR_HANDLE_MISMATCH:
7353 7350                          case SCF_ERROR_INVALID_ARGUMENT:
7354 7351                          case SCF_ERROR_NOT_SET:
7355 7352                          default:
7356 7353                                  bad_error("scf_iter_next_instance",
7357 7354                                      scf_error());
7358 7355                          }
7359 7356                  }
7360 7357  
7361 7358                  if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362 7359                          switch (scf_error()) {
7363 7360                          case SCF_ERROR_DELETED:
7364 7361                                  continue;
7365 7362  
7366 7363                          case SCF_ERROR_CONNECTION_BROKEN:
7367 7364                                  goto connaborted;
7368 7365  
7369 7366                          case SCF_ERROR_NOT_SET:
7370 7367                          case SCF_ERROR_NOT_BOUND:
7371 7368                          default:
7372 7369                                  bad_error("scf_instance_get_name", scf_error());
7373 7370                          }
7374 7371                  }
7375 7372  
7376 7373                  if (g_verbose)
7377 7374                          warn(gettext(
7378 7375                              "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379 7376                              snap_previous, s->sc_name, imp_str);
7380 7377  
7381 7378                  r = take_snap(imp_inst, snap_previous, imp_snap);
7382 7379                  switch (r) {
7383 7380                  case 0:
7384 7381                          break;
7385 7382  
7386 7383                  case ECANCELED:
7387 7384                          continue;
7388 7385  
7389 7386                  case ECONNABORTED:
7390 7387                          goto connaborted;
7391 7388  
7392 7389                  case EPERM:
7393 7390                          warn(gettext("Could not take \"%s\" snapshot of "
7394 7391                              "svc:/%s:%s (permission denied).\n"),
7395 7392                              snap_previous, s->sc_name, imp_str);
7396 7393                          lcbdata->sc_err = r;
7397 7394                          return (UU_WALK_ERROR);
7398 7395  
7399 7396                  case ENOSPC:
7400 7397                  case -1:
7401 7398                          lcbdata->sc_err = r;
7402 7399                          r = UU_WALK_ERROR;
7403 7400                          goto deltemp;
7404 7401  
7405 7402                  default:
7406 7403                          bad_error("take_snap", r);
7407 7404                  }
7408 7405  
7409 7406                  linst.sc_name = imp_str;
7410 7407                  inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411 7408                      &linst, NULL, NULL);
7412 7409                  if (inst != NULL) {
7413 7410                          inst->sc_import_state = IMPORT_PREVIOUS;
7414 7411                          inst->sc_seen = 1;
7415 7412                  }
7416 7413          }
7417 7414  
7418 7415          /*
7419 7416           * Create the new instances and take previous snapshots of
7420 7417           * them.  This is not necessary, but it maximizes data preservation.
7421 7418           */
7422 7419          for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423 7420              inst != NULL;
7424 7421              inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425 7422              inst)) {
7426 7423                  if (inst->sc_seen)
7427 7424                          continue;
7428 7425  
7429 7426                  if (scf_service_add_instance(imp_svc, inst->sc_name,
7430 7427                      imp_inst) != 0) {
7431 7428                          switch (scf_error()) {
7432 7429                          case SCF_ERROR_CONNECTION_BROKEN:
7433 7430                                  goto connaborted;
7434 7431  
7435 7432                          case SCF_ERROR_BACKEND_READONLY:
7436 7433                          case SCF_ERROR_BACKEND_ACCESS:
7437 7434                          case SCF_ERROR_NO_RESOURCES:
7438 7435                                  r = stash_scferror(lcbdata);
7439 7436                                  goto deltemp;
7440 7437  
7441 7438                          case SCF_ERROR_EXISTS:
7442 7439                                  warn(gettext("%s changed unexpectedly "
7443 7440                                      "(instance \"%s\" added).\n"), s->sc_fmri,
7444 7441                                      inst->sc_name);
7445 7442                                  lcbdata->sc_err = EBUSY;
7446 7443                                  r = UU_WALK_ERROR;
7447 7444                                  goto deltemp;
7448 7445  
7449 7446                          case SCF_ERROR_INVALID_ARGUMENT:
7450 7447                                  warn(gettext("Service \"%s\" has instance with "
7451 7448                                      "invalid name \"%s\".\n"), s->sc_name,
7452 7449                                      inst->sc_name);
7453 7450                                  r = stash_scferror(lcbdata);
7454 7451                                  goto deltemp;
7455 7452  
7456 7453                          case SCF_ERROR_PERMISSION_DENIED:
7457 7454                                  warn(gettext("Could not create instance \"%s\" "
7458 7455                                      "in %s (permission denied).\n"),
7459 7456                                      inst->sc_name, s->sc_fmri);
7460 7457                                  r = stash_scferror(lcbdata);
7461 7458                                  goto deltemp;
7462 7459  
7463 7460                          case SCF_ERROR_HANDLE_MISMATCH:
7464 7461                          case SCF_ERROR_NOT_BOUND:
7465 7462                          case SCF_ERROR_NOT_SET:
7466 7463                          default:
7467 7464                                  bad_error("scf_service_add_instance",
7468 7465                                      scf_error());
7469 7466                          }
7470 7467                  }
7471 7468  
7472 7469                  if (g_verbose)
7473 7470                          warn(gettext("Taking \"%s\" snapshot for "
7474 7471                              "new service %s.\n"), snap_previous, inst->sc_fmri);
7475 7472                  r = take_snap(imp_inst, snap_previous, imp_snap);
7476 7473                  switch (r) {
7477 7474                  case 0:
7478 7475                          break;
7479 7476  
7480 7477                  case ECANCELED:
7481 7478                          warn(i_deleted, s->sc_fmri, inst->sc_name);
7482 7479                          lcbdata->sc_err = EBUSY;
7483 7480                          r = UU_WALK_ERROR;
7484 7481                          goto deltemp;
7485 7482  
7486 7483                  case ECONNABORTED:
7487 7484                          goto connaborted;
7488 7485  
7489 7486                  case EPERM:
7490 7487                          warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491 7488                          lcbdata->sc_err = r;
7492 7489                          r = UU_WALK_ERROR;
7493 7490                          goto deltemp;
7494 7491  
7495 7492                  case ENOSPC:
7496 7493                  case -1:
7497 7494                          r = UU_WALK_ERROR;
7498 7495                          goto deltemp;
7499 7496  
7500 7497                  default:
7501 7498                          bad_error("take_snap", r);
7502 7499                  }
7503 7500          }
7504 7501  
7505 7502          s->sc_import_state = IMPORT_PREVIOUS;
7506 7503  
7507 7504          /*
7508 7505           * Upgrade service properties, if we can find a last-import snapshot.
7509 7506           * Any will do because we don't support different service properties
7510 7507           * in different manifests, so all snaplevels of the service in all of
7511 7508           * the last-import snapshots of the instances should be the same.
7512 7509           */
7513 7510          if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514 7511                  switch (scf_error()) {
7515 7512                  case SCF_ERROR_CONNECTION_BROKEN:
7516 7513                          goto connaborted;
7517 7514  
7518 7515                  case SCF_ERROR_DELETED:
7519 7516                          warn(s_deleted, s->sc_fmri);
7520 7517                          lcbdata->sc_err = EBUSY;
7521 7518                          r = UU_WALK_ERROR;
7522 7519                          goto deltemp;
7523 7520  
7524 7521                  case SCF_ERROR_HANDLE_MISMATCH:
7525 7522                  case SCF_ERROR_NOT_BOUND:
7526 7523                  case SCF_ERROR_NOT_SET:
7527 7524                  default:
7528 7525                          bad_error("scf_iter_service_instances", scf_error());
7529 7526                  }
7530 7527          }
7531 7528  
7532 7529          for (;;) {
7533 7530                  r = scf_iter_next_instance(imp_iter, imp_inst);
7534 7531                  if (r == -1) {
7535 7532                          switch (scf_error()) {
7536 7533                          case SCF_ERROR_DELETED:
7537 7534                                  warn(s_deleted, s->sc_fmri);
7538 7535                                  lcbdata->sc_err = EBUSY;
7539 7536                                  r = UU_WALK_ERROR;
7540 7537                                  goto deltemp;
7541 7538  
7542 7539                          case SCF_ERROR_CONNECTION_BROKEN:
7543 7540                                  goto connaborted;
7544 7541  
7545 7542                          case SCF_ERROR_NOT_BOUND:
7546 7543                          case SCF_ERROR_HANDLE_MISMATCH:
7547 7544                          case SCF_ERROR_INVALID_ARGUMENT:
7548 7545                          case SCF_ERROR_NOT_SET:
7549 7546                          default:
7550 7547                                  bad_error("scf_iter_next_instance",
7551 7548                                      scf_error());
7552 7549                          }
7553 7550                  }
7554 7551  
7555 7552                  if (r == 0) {
7556 7553                          /*
7557 7554                           * Didn't find any last-import snapshots.  Override-
7558 7555                           * import the properties.  Unless one of the instances
7559 7556                           * has a general/enabled property, in which case we're
7560 7557                           * probably running a last-import-capable svccfg for
7561 7558                           * the first time, and we should only take the
7562 7559                           * last-import snapshot.
7563 7560                           */
7564 7561                          if (have_ge) {
7565 7562                                  pgroup_t *mfpg;
7566 7563                                  scf_callback_t mfcbdata;
7567 7564  
7568 7565                                  li_only = 1;
7569 7566                                  no_refresh = 1;
7570 7567                                  /*
7571 7568                                   * Need to go ahead and import the manifestfiles
7572 7569                                   * pg if it exists. If the last-import snapshot
7573 7570                                   * upgrade code is ever removed this code can
7574 7571                                   * be removed as well.
7575 7572                                   */
7576 7573                                  mfpg = internal_pgroup_find(s,
7577 7574                                      SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578 7575  
7579 7576                                  if (mfpg) {
7580 7577                                          mfcbdata.sc_handle = g_hndl;
7581 7578                                          mfcbdata.sc_parent = imp_svc;
7582 7579                                          mfcbdata.sc_service = 1;
7583 7580                                          mfcbdata.sc_flags = SCI_FORCE;
7584 7581                                          mfcbdata.sc_source_fmri = s->sc_fmri;
7585 7582                                          mfcbdata.sc_target_fmri = s->sc_fmri;
7586 7583                                          if (entity_pgroup_import(mfpg,
7587 7584                                              &mfcbdata) != UU_WALK_NEXT) {
7588 7585                                                  warn(s_mfile_upd, s->sc_fmri);
7589 7586                                                  r = UU_WALK_ERROR;
7590 7587                                                  goto deltemp;
7591 7588                                          }
7592 7589                                  }
7593 7590                                  break;
7594 7591                          }
7595 7592  
7596 7593                          s->sc_import_state = IMPORT_PROP_BEGUN;
7597 7594  
7598 7595                          cbdata.sc_handle = g_hndl;
7599 7596                          cbdata.sc_parent = imp_svc;
7600 7597                          cbdata.sc_service = 1;
7601 7598                          cbdata.sc_flags = SCI_FORCE;
7602 7599                          cbdata.sc_source_fmri = s->sc_fmri;
7603 7600                          cbdata.sc_target_fmri = s->sc_fmri;
7604 7601                          if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605 7602                              &cbdata, UU_DEFAULT) != 0) {
7606 7603                                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607 7604                                          bad_error("uu_list_walk", uu_error());
7608 7605                                  lcbdata->sc_err = cbdata.sc_err;
7609 7606                                  switch (cbdata.sc_err) {
7610 7607                                  case ECONNABORTED:
7611 7608                                          goto connaborted;
7612 7609  
7613 7610                                  case ECANCELED:
7614 7611                                          warn(s_deleted, s->sc_fmri);
7615 7612                                          lcbdata->sc_err = EBUSY;
7616 7613                                          break;
7617 7614  
7618 7615                                  case EINVAL:    /* caught above */
7619 7616                                  case EEXIST:
7620 7617                                          bad_error("entity_pgroup_import",
7621 7618                                              cbdata.sc_err);
7622 7619                                  }
7623 7620  
7624 7621                                  r = UU_WALK_ERROR;
7625 7622                                  goto deltemp;
7626 7623                          }
7627 7624  
7628 7625                          cbdata.sc_trans = NULL;
7629 7626                          cbdata.sc_flags = 0;
7630 7627                          if (uu_list_walk(s->sc_dependents,
7631 7628                              lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632 7629                                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633 7630                                          bad_error("uu_list_walk", uu_error());
7634 7631                                  lcbdata->sc_err = cbdata.sc_err;
7635 7632                                  if (cbdata.sc_err == ECONNABORTED)
7636 7633                                          goto connaborted;
7637 7634                                  r = UU_WALK_ERROR;
7638 7635                                  goto deltemp;
7639 7636                          }
7640 7637                          break;
7641 7638                  }
7642 7639  
7643 7640                  if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644 7641                      imp_snap) != 0) {
7645 7642                          switch (scf_error()) {
7646 7643                          case SCF_ERROR_DELETED:
7647 7644                                  continue;
7648 7645  
7649 7646                          case SCF_ERROR_NOT_FOUND:
7650 7647                                  break;
7651 7648  
7652 7649                          case SCF_ERROR_CONNECTION_BROKEN:
7653 7650                                  goto connaborted;
7654 7651  
7655 7652                          case SCF_ERROR_HANDLE_MISMATCH:
7656 7653                          case SCF_ERROR_NOT_BOUND:
7657 7654                          case SCF_ERROR_INVALID_ARGUMENT:
7658 7655                          case SCF_ERROR_NOT_SET:
7659 7656                          default:
7660 7657                                  bad_error("scf_instance_get_snapshot",
7661 7658                                      scf_error());
7662 7659                          }
7663 7660  
7664 7661                          if (have_ge)
7665 7662                                  continue;
7666 7663  
7667 7664                          /*
7668 7665                           * Check for a general/enabled property.  This is how
7669 7666                           * we tell whether to import if there turn out to be
7670 7667                           * no last-import snapshots.
7671 7668                           */
7672 7669                          if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673 7670                              imp_pg) == 0) {
7674 7671                                  if (scf_pg_get_property(imp_pg,
7675 7672                                      SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676 7673                                          have_ge = 1;
7677 7674                                  } else {
7678 7675                                          switch (scf_error()) {
7679 7676                                          case SCF_ERROR_DELETED:
7680 7677                                          case SCF_ERROR_NOT_FOUND:
7681 7678                                                  continue;
7682 7679  
7683 7680                                          case SCF_ERROR_INVALID_ARGUMENT:
7684 7681                                          case SCF_ERROR_HANDLE_MISMATCH:
7685 7682                                          case SCF_ERROR_CONNECTION_BROKEN:
7686 7683                                          case SCF_ERROR_NOT_BOUND:
7687 7684                                          case SCF_ERROR_NOT_SET:
7688 7685                                          default:
7689 7686                                                  bad_error("scf_pg_get_property",
7690 7687                                                      scf_error());
7691 7688                                          }
7692 7689                                  }
7693 7690                          } else {
7694 7691                                  switch (scf_error()) {
7695 7692                                  case SCF_ERROR_DELETED:
7696 7693                                  case SCF_ERROR_NOT_FOUND:
7697 7694                                          continue;
7698 7695  
7699 7696                                  case SCF_ERROR_CONNECTION_BROKEN:
7700 7697                                          goto connaborted;
7701 7698  
7702 7699                                  case SCF_ERROR_NOT_BOUND:
7703 7700                                  case SCF_ERROR_NOT_SET:
7704 7701                                  case SCF_ERROR_INVALID_ARGUMENT:
7705 7702                                  case SCF_ERROR_HANDLE_MISMATCH:
7706 7703                                  default:
7707 7704                                          bad_error("scf_instance_get_pg",
7708 7705                                              scf_error());
7709 7706                                  }
7710 7707                          }
7711 7708                          continue;
7712 7709                  }
7713 7710  
7714 7711                  /* find service snaplevel */
7715 7712                  r = get_snaplevel(imp_snap, 1, imp_snpl);
7716 7713                  switch (r) {
7717 7714                  case 0:
7718 7715                          break;
7719 7716  
7720 7717                  case ECONNABORTED:
7721 7718                          goto connaborted;
7722 7719  
7723 7720                  case ECANCELED:
7724 7721                          continue;
7725 7722  
7726 7723                  case ENOENT:
7727 7724                          if (scf_instance_get_name(imp_inst, imp_str,
7728 7725                              imp_str_sz) < 0)
7729 7726                                  (void) strcpy(imp_str, "?");
7730 7727                          warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731 7728                          lcbdata->sc_err = EBADF;
7732 7729                          r = UU_WALK_ERROR;
7733 7730                          goto deltemp;
7734 7731  
7735 7732                  default:
7736 7733                          bad_error("get_snaplevel", r);
7737 7734                  }
7738 7735  
7739 7736                  if (scf_instance_get_snapshot(imp_inst, snap_running,
7740 7737                      imp_rsnap) != 0) {
7741 7738                          switch (scf_error()) {
7742 7739                          case SCF_ERROR_DELETED:
7743 7740                                  continue;
7744 7741  
7745 7742                          case SCF_ERROR_NOT_FOUND:
7746 7743                                  break;
7747 7744  
7748 7745                          case SCF_ERROR_CONNECTION_BROKEN:
7749 7746                                  goto connaborted;
7750 7747  
7751 7748                          case SCF_ERROR_INVALID_ARGUMENT:
7752 7749                          case SCF_ERROR_HANDLE_MISMATCH:
7753 7750                          case SCF_ERROR_NOT_BOUND:
7754 7751                          case SCF_ERROR_NOT_SET:
7755 7752                          default:
7756 7753                                  bad_error("scf_instance_get_snapshot",
7757 7754                                      scf_error());
7758 7755                          }
7759 7756                          running = NULL;
7760 7757                  } else {
7761 7758                          r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762 7759                          switch (r) {
7763 7760                          case 0:
7764 7761                                  running = imp_rsnpl;
7765 7762                                  break;
7766 7763  
7767 7764                          case ECONNABORTED:
7768 7765                                  goto connaborted;
7769 7766  
7770 7767                          case ECANCELED:
7771 7768                                  continue;
7772 7769  
7773 7770                          case ENOENT:
7774 7771                                  if (scf_instance_get_name(imp_inst, imp_str,
7775 7772                                      imp_str_sz) < 0)
7776 7773                                          (void) strcpy(imp_str, "?");
7777 7774                                  warn(badsnap, snap_running, s->sc_name,
7778 7775                                      imp_str);
7779 7776                                  lcbdata->sc_err = EBADF;
7780 7777                                  r = UU_WALK_ERROR;
7781 7778                                  goto deltemp;
7782 7779  
7783 7780                          default:
7784 7781                                  bad_error("get_snaplevel", r);
7785 7782                          }
7786 7783                  }
7787 7784  
7788 7785                  if (g_verbose) {
7789 7786                          if (scf_instance_get_name(imp_inst, imp_str,
7790 7787                              imp_str_sz) < 0)
7791 7788                                  (void) strcpy(imp_str, "?");
7792 7789                          warn(gettext("Upgrading properties of %s according to "
7793 7790                              "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794 7791                  }
7795 7792  
7796 7793                  /* upgrade service properties */
7797 7794                  r = upgrade_props(imp_svc, running, imp_snpl, s);
7798 7795                  if (r == 0)
7799 7796                          break;
7800 7797  
7801 7798                  switch (r) {
7802 7799                  case ECONNABORTED:
7803 7800                          goto connaborted;
7804 7801  
7805 7802                  case ECANCELED:
7806 7803                          warn(s_deleted, s->sc_fmri);
7807 7804                          lcbdata->sc_err = EBUSY;
7808 7805                          break;
7809 7806  
7810 7807                  case ENODEV:
7811 7808                          if (scf_instance_get_name(imp_inst, imp_str,
7812 7809                              imp_str_sz) < 0)
7813 7810                                  (void) strcpy(imp_str, "?");
7814 7811                          warn(i_deleted, s->sc_fmri, imp_str);
7815 7812                          lcbdata->sc_err = EBUSY;
7816 7813                          break;
7817 7814  
7818 7815                  default:
7819 7816                          lcbdata->sc_err = r;
7820 7817                  }
7821 7818  
7822 7819                  r = UU_WALK_ERROR;
7823 7820                  goto deltemp;
7824 7821          }
7825 7822  
7826 7823          s->sc_import_state = IMPORT_PROP_DONE;
7827 7824  
7828 7825  instances:
7829 7826          /* import instances */
7830 7827          cbdata.sc_handle = lcbdata->sc_handle;
7831 7828          cbdata.sc_parent = imp_svc;
7832 7829          cbdata.sc_service = 1;
7833 7830          cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834 7831          cbdata.sc_general = NULL;
7835 7832  
7836 7833          if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837 7834              lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838 7835                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839 7836                          bad_error("uu_list_walk", uu_error());
7840 7837  
7841 7838                  lcbdata->sc_err = cbdata.sc_err;
7842 7839                  if (cbdata.sc_err == ECONNABORTED)
7843 7840                          goto connaborted;
7844 7841                  r = UU_WALK_ERROR;
7845 7842                  goto deltemp;
7846 7843          }
7847 7844  
7848 7845          s->sc_import_state = IMPORT_COMPLETE;
7849 7846          r = UU_WALK_NEXT;
7850 7847  
7851 7848  deltemp:
7852 7849          /* delete temporary service */
7853 7850          if (scf_service_delete(imp_tsvc) != 0) {
7854 7851                  switch (scf_error()) {
7855 7852                  case SCF_ERROR_DELETED:
7856 7853                          break;
7857 7854  
7858 7855                  case SCF_ERROR_CONNECTION_BROKEN:
7859 7856                          goto connaborted;
7860 7857  
7861 7858                  case SCF_ERROR_EXISTS:
7862 7859                          warn(gettext(
7863 7860                              "Could not delete svc:/%s (instances exist).\n"),
7864 7861                              imp_tsname);
7865 7862                          break;
7866 7863  
7867 7864                  case SCF_ERROR_NOT_SET:
7868 7865                  case SCF_ERROR_NOT_BOUND:
7869 7866                  default:
7870 7867                          bad_error("scf_service_delete", scf_error());
7871 7868                  }
7872 7869          }
7873 7870  
7874 7871          return (r);
7875 7872  
7876 7873  connaborted:
7877 7874          warn(gettext("Could not delete svc:/%s "
7878 7875              "(repository connection broken).\n"), imp_tsname);
7879 7876          lcbdata->sc_err = ECONNABORTED;
7880 7877          return (UU_WALK_ERROR);
7881 7878  }
7882 7879  
7883 7880  static const char *
7884 7881  import_progress(int st)
7885 7882  {
7886 7883          switch (st) {
7887 7884          case 0:
7888 7885                  return (gettext("not reached."));
7889 7886  
7890 7887          case IMPORT_PREVIOUS:
7891 7888                  return (gettext("previous snapshot taken."));
7892 7889  
7893 7890          case IMPORT_PROP_BEGUN:
7894 7891                  return (gettext("some properties imported."));
7895 7892  
7896 7893          case IMPORT_PROP_DONE:
7897 7894                  return (gettext("properties imported."));
7898 7895  
7899 7896          case IMPORT_COMPLETE:
7900 7897                  return (gettext("imported."));
7901 7898  
7902 7899          case IMPORT_REFRESHED:
7903 7900                  return (gettext("refresh requested."));
7904 7901  
7905 7902          default:
7906 7903  #ifndef NDEBUG
7907 7904                  (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908 7905                      __FILE__, __LINE__, st);
7909 7906  #endif
7910 7907                  abort();
7911 7908                  /* NOTREACHED */
7912 7909          }
7913 7910  }
7914 7911  
7915 7912  /*
7916 7913   * Returns
7917 7914   *   0 - success
7918 7915   *     - fmri wasn't found (error printed)
7919 7916   *     - entity was deleted (error printed)
7920 7917   *     - backend denied access (error printed)
7921 7918   *   ENOMEM - out of memory (error printed)
7922 7919   *   ECONNABORTED - repository connection broken (error printed)
7923 7920   *   EPERM - permission denied (error printed)
7924 7921   *   -1 - unknown libscf error (error printed)
7925 7922   */
7926 7923  static int
7927 7924  imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 7925  {
7929 7926          scf_error_t serr;
7930 7927          void *ent;
7931 7928          int issvc;
7932 7929          int r;
7933 7930  
7934 7931          const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935 7932          const char *dpt_deleted = gettext("Could not refresh %s "
7936 7933              "(dependent \"%s\" of %s) (deleted).\n");
7937 7934  
7938 7935          serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939 7936          switch (serr) {
7940 7937          case SCF_ERROR_NONE:
7941 7938                  break;
7942 7939  
7943 7940          case SCF_ERROR_NO_MEMORY:
7944 7941                  if (name == NULL)
7945 7942                          warn(gettext("Could not refresh %s (out of memory).\n"),
7946 7943                              fmri);
7947 7944                  else
7948 7945                          warn(gettext("Could not refresh %s "
7949 7946                              "(dependent \"%s\" of %s) (out of memory).\n"),
7950 7947                              fmri, name, d_fmri);
7951 7948                  return (ENOMEM);
7952 7949  
7953 7950          case SCF_ERROR_NOT_FOUND:
7954 7951                  if (name == NULL)
7955 7952                          warn(deleted, fmri);
7956 7953                  else
7957 7954                          warn(dpt_deleted, fmri, name, d_fmri);
7958 7955                  return (0);
7959 7956  
7960 7957          case SCF_ERROR_INVALID_ARGUMENT:
7961 7958          case SCF_ERROR_CONSTRAINT_VIOLATED:
7962 7959          default:
7963 7960                  bad_error("fmri_to_entity", serr);
7964 7961          }
7965 7962  
7966 7963          r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967 7964          switch (r) {
7968 7965          case 0:
7969 7966                  break;
7970 7967  
7971 7968          case ECONNABORTED:
7972 7969                  if (name != NULL)
7973 7970                          warn(gettext("Could not refresh %s "
7974 7971                              "(dependent \"%s\" of %s) "
7975 7972                              "(repository connection broken).\n"), fmri, name,
7976 7973                              d_fmri);
7977 7974                  return (r);
7978 7975  
7979 7976          case ECANCELED:
7980 7977                  if (name == NULL)
7981 7978                          warn(deleted, fmri);
7982 7979                  else
7983 7980                          warn(dpt_deleted, fmri, name, d_fmri);
7984 7981                  return (0);
7985 7982  
7986 7983          case EACCES:
7987 7984                  if (!g_verbose)
7988 7985                          return (0);
7989 7986                  if (name == NULL)
7990 7987                          warn(gettext("Could not refresh %s "
7991 7988                              "(backend access denied).\n"), fmri);
7992 7989                  else
7993 7990                          warn(gettext("Could not refresh %s "
7994 7991                              "(dependent \"%s\" of %s) "
7995 7992                              "(backend access denied).\n"), fmri, name, d_fmri);
7996 7993                  return (0);
7997 7994  
7998 7995          case EPERM:
7999 7996                  if (name == NULL)
8000 7997                          warn(gettext("Could not refresh %s "
8001 7998                              "(permission denied).\n"), fmri);
8002 7999                  else
8003 8000                          warn(gettext("Could not refresh %s "
8004 8001                              "(dependent \"%s\" of %s) "
8005 8002                              "(permission denied).\n"), fmri, name, d_fmri);
8006 8003                  return (r);
8007 8004  
8008 8005          case ENOSPC:
8009 8006                  if (name == NULL)
8010 8007                          warn(gettext("Could not refresh %s "
8011 8008                              "(repository server out of resources).\n"),
8012 8009                              fmri);
8013 8010                  else
8014 8011                          warn(gettext("Could not refresh %s "
8015 8012                              "(dependent \"%s\" of %s) "
8016 8013                              "(repository server out of resources).\n"),
8017 8014                              fmri, name, d_fmri);
8018 8015                  return (r);
8019 8016  
8020 8017          case -1:
8021 8018                  scfwarn();
8022 8019                  return (r);
8023 8020  
8024 8021          default:
8025 8022                  bad_error("refresh_entity", r);
8026 8023          }
8027 8024  
8028 8025          if (issvc)
8029 8026                  scf_service_destroy(ent);
8030 8027          else
8031 8028                  scf_instance_destroy(ent);
8032 8029  
8033 8030          return (0);
8034 8031  }
8035 8032  
8036 8033  static int
8037 8034  alloc_imp_globals()
8038 8035  {
8039 8036          int r;
8040 8037  
8041 8038          const char * const emsg_nomem = gettext("Out of memory.\n");
8042 8039          const char * const emsg_nores =
8043 8040              gettext("svc.configd is out of resources.\n");
8044 8041  
8045 8042          imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046 8043              max_scf_name_len : max_scf_fmri_len) + 1;
8047 8044  
8048 8045          if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049 8046              (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050 8047              (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051 8048              (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052 8049              (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053 8050              (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054 8051              (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 8052              (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056 8053              (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057 8054              (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058 8055              (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059 8056              (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060 8057              (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061 8058              (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062 8059              (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063 8060              (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064 8061              (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065 8062              (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066 8063              (imp_str = malloc(imp_str_sz)) == NULL ||
8067 8064              (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068 8065              (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069 8066              (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070 8067              (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071 8068              (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072 8069              (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 8070              (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074 8071              (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075 8072              (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076 8073              (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077 8074              (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078 8075              (ud_val = scf_value_create(g_hndl)) == NULL ||
8079 8076              (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080 8077              (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081 8078              (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082 8079              (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083 8080              (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084 8081              (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085 8082                  if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086 8083                          warn(emsg_nores);
8087 8084                  else
8088 8085                          warn(emsg_nomem);
8089 8086  
8090 8087                  return (-1);
8091 8088          }
8092 8089  
8093 8090          r = load_init();
8094 8091          switch (r) {
8095 8092          case 0:
8096 8093                  break;
8097 8094  
8098 8095          case ENOMEM:
8099 8096                  warn(emsg_nomem);
8100 8097                  return (-1);
8101 8098  
8102 8099          default:
8103 8100                  bad_error("load_init", r);
8104 8101          }
8105 8102  
8106 8103          return (0);
8107 8104  }
8108 8105  
8109 8106  static void
8110 8107  free_imp_globals()
8111 8108  {
8112 8109          pgroup_t *old_dpt;
8113 8110          void *cookie;
8114 8111  
8115 8112          load_fini();
8116 8113  
8117 8114          free(ud_ctarg);
8118 8115          free(ud_oldtarg);
8119 8116          free(ud_name);
8120 8117          ud_ctarg = ud_oldtarg = ud_name = NULL;
8121 8118  
8122 8119          scf_transaction_destroy(ud_tx);
8123 8120          ud_tx = NULL;
8124 8121          scf_iter_destroy(ud_iter);
8125 8122          scf_iter_destroy(ud_iter2);
8126 8123          ud_iter = ud_iter2 = NULL;
8127 8124          scf_value_destroy(ud_val);
8128 8125          ud_val = NULL;
8129 8126          scf_property_destroy(ud_prop);
8130 8127          scf_property_destroy(ud_dpt_prop);
8131 8128          ud_prop = ud_dpt_prop = NULL;
8132 8129          scf_pg_destroy(ud_pg);
8133 8130          scf_pg_destroy(ud_cur_depts_pg);
8134 8131          scf_pg_destroy(ud_run_dpts_pg);
8135 8132          ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136 8133          scf_snaplevel_destroy(ud_snpl);
8137 8134          ud_snpl = NULL;
8138 8135          scf_instance_destroy(ud_inst);
8139 8136          ud_inst = NULL;
8140 8137  
8141 8138          free(imp_str);
8142 8139          free(imp_tsname);
8143 8140          free(imp_fe1);
8144 8141          free(imp_fe2);
8145 8142          imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146 8143  
8147 8144          cookie = NULL;
8148 8145          while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149 8146              NULL) {
8150 8147                  free((char *)old_dpt->sc_pgroup_name);
8151 8148                  free((char *)old_dpt->sc_pgroup_fmri);
8152 8149                  internal_pgroup_free(old_dpt);
8153 8150          }
8154 8151          uu_list_destroy(imp_deleted_dpts);
8155 8152  
8156 8153          scf_transaction_destroy(imp_tx);
8157 8154          imp_tx = NULL;
8158 8155          scf_iter_destroy(imp_iter);
8159 8156          scf_iter_destroy(imp_rpg_iter);
8160 8157          scf_iter_destroy(imp_up_iter);
8161 8158          imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162 8159          scf_property_destroy(imp_prop);
8163 8160          imp_prop = NULL;
8164 8161          scf_pg_destroy(imp_pg);
8165 8162          scf_pg_destroy(imp_pg2);
8166 8163          imp_pg = imp_pg2 = NULL;
8167 8164          scf_snaplevel_destroy(imp_snpl);
8168 8165          scf_snaplevel_destroy(imp_rsnpl);
8169 8166          imp_snpl = imp_rsnpl = NULL;
8170 8167          scf_snapshot_destroy(imp_snap);
8171 8168          scf_snapshot_destroy(imp_lisnap);
8172 8169          scf_snapshot_destroy(imp_tlisnap);
8173 8170          scf_snapshot_destroy(imp_rsnap);
8174 8171          imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175 8172          scf_instance_destroy(imp_inst);
8176 8173          scf_instance_destroy(imp_tinst);
8177 8174          imp_inst = imp_tinst = NULL;
8178 8175          scf_service_destroy(imp_svc);
8179 8176          scf_service_destroy(imp_tsvc);
8180 8177          imp_svc = imp_tsvc = NULL;
8181 8178          scf_scope_destroy(imp_scope);
8182 8179          imp_scope = NULL;
8183 8180  
8184 8181          load_fini();
8185 8182  }
8186 8183  
8187 8184  int
8188 8185  lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 8186  {
8190 8187          scf_callback_t cbdata;
8191 8188          int result = 0;
8192 8189          entity_t *svc, *inst;
8193 8190          uu_list_t *insts;
8194 8191          int r;
8195 8192          pgroup_t *old_dpt;
8196 8193          int annotation_set = 0;
8197 8194  
8198 8195          const char * const emsg_nomem = gettext("Out of memory.\n");
8199 8196          const char * const emsg_nores =
8200 8197              gettext("svc.configd is out of resources.\n");
8201 8198  
8202 8199          lscf_prep_hndl();
8203 8200  
8204 8201          if (alloc_imp_globals())
8205 8202                  goto out;
8206 8203  
8207 8204          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208 8205                  switch (scf_error()) {
8209 8206                  case SCF_ERROR_CONNECTION_BROKEN:
8210 8207                          warn(gettext("Repository connection broken.\n"));
8211 8208                          repository_teardown();
8212 8209                          result = -1;
8213 8210                          goto out;
8214 8211  
8215 8212                  case SCF_ERROR_NOT_FOUND:
8216 8213                  case SCF_ERROR_INVALID_ARGUMENT:
8217 8214                  case SCF_ERROR_NOT_BOUND:
8218 8215                  case SCF_ERROR_HANDLE_MISMATCH:
8219 8216                  default:
8220 8217                          bad_error("scf_handle_get_scope", scf_error());
8221 8218                  }
8222 8219          }
8223 8220  
8224 8221          /* Set up the auditing annotation. */
8225 8222          if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226 8223                  annotation_set = 1;
8227 8224          } else {
8228 8225                  switch (scf_error()) {
8229 8226                  case SCF_ERROR_CONNECTION_BROKEN:
8230 8227                          warn(gettext("Repository connection broken.\n"));
8231 8228                          repository_teardown();
8232 8229                          result = -1;
8233 8230                          goto out;
8234 8231  
8235 8232                  case SCF_ERROR_INVALID_ARGUMENT:
8236 8233                  case SCF_ERROR_NOT_BOUND:
8237 8234                  case SCF_ERROR_NO_RESOURCES:
8238 8235                  case SCF_ERROR_INTERNAL:
8239 8236                          bad_error("_scf_set_annotation", scf_error());
8240 8237                          /* NOTREACHED */
8241 8238  
8242 8239                  default:
8243 8240                          /*
8244 8241                           * Do not terminate import because of inability to
8245 8242                           * generate annotation audit event.
8246 8243                           */
8247 8244                          warn(gettext("_scf_set_annotation() unexpectedly "
8248 8245                              "failed with return code of %d\n"), scf_error());
8249 8246                          break;
8250 8247                  }
8251 8248          }
8252 8249  
8253 8250          /*
8254 8251           * Clear the sc_import_state's of all services & instances so we can
8255 8252           * report how far we got if we fail.
8256 8253           */
8257 8254          for (svc = uu_list_first(bndl->sc_bundle_services);
8258 8255              svc != NULL;
8259 8256              svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260 8257                  svc->sc_import_state = 0;
8261 8258  
8262 8259                  if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263 8260                      clear_int, (void *)offsetof(entity_t, sc_import_state),
8264 8261                      UU_DEFAULT) != 0)
8265 8262                          bad_error("uu_list_walk", uu_error());
8266 8263          }
8267 8264  
8268 8265          cbdata.sc_handle = g_hndl;
8269 8266          cbdata.sc_parent = imp_scope;
8270 8267          cbdata.sc_flags = flags;
8271 8268          cbdata.sc_general = NULL;
8272 8269  
8273 8270          if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274 8271              &cbdata, UU_DEFAULT) == 0) {
8275 8272                  char *eptr;
8276 8273                  /* Success.  Refresh everything. */
8277 8274  
8278 8275                  if (flags & SCI_NOREFRESH || no_refresh) {
8279 8276                          no_refresh = 0;
8280 8277                          result = 0;
8281 8278                          goto out;
8282 8279                  }
8283 8280  
8284 8281                  for (svc = uu_list_first(bndl->sc_bundle_services);
8285 8282                      svc != NULL;
8286 8283                      svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287 8284                          pgroup_t *dpt;
8288 8285  
8289 8286                          insts = svc->sc_u.sc_service.sc_service_instances;
8290 8287  
8291 8288                          for (inst = uu_list_first(insts);
8292 8289                              inst != NULL;
8293 8290                              inst = uu_list_next(insts, inst)) {
8294 8291                                  r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295 8292                                  switch (r) {
8296 8293                                  case 0:
8297 8294                                          break;
8298 8295  
8299 8296                                  case ENOMEM:
8300 8297                                  case ECONNABORTED:
8301 8298                                  case EPERM:
8302 8299                                  case -1:
8303 8300                                          goto progress;
8304 8301  
8305 8302                                  default:
8306 8303                                          bad_error("imp_refresh_fmri", r);
8307 8304                                  }
8308 8305  
8309 8306                                  inst->sc_import_state = IMPORT_REFRESHED;
8310 8307  
8311 8308                                  for (dpt = uu_list_first(inst->sc_dependents);
8312 8309                                      dpt != NULL;
8313 8310                                      dpt = uu_list_next(inst->sc_dependents,
8314 8311                                      dpt))
8315 8312                                          if (imp_refresh_fmri(
8316 8313                                              dpt->sc_pgroup_fmri,
8317 8314                                              dpt->sc_pgroup_name,
8318 8315                                              inst->sc_fmri) != 0)
8319 8316                                                  goto progress;
8320 8317                          }
8321 8318  
8322 8319                          for (dpt = uu_list_first(svc->sc_dependents);
8323 8320                              dpt != NULL;
8324 8321                              dpt = uu_list_next(svc->sc_dependents, dpt))
8325 8322                                  if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326 8323                                      dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327 8324                                          goto progress;
8328 8325                  }
8329 8326  
8330 8327                  for (old_dpt = uu_list_first(imp_deleted_dpts);
8331 8328                      old_dpt != NULL;
8332 8329                      old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333 8330                          if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334 8331                              old_dpt->sc_pgroup_name,
8335 8332                              old_dpt->sc_parent->sc_fmri) != 0)
8336 8333                                  goto progress;
8337 8334  
8338 8335                  result = 0;
8339 8336  
8340 8337                  /*
8341 8338                   * This snippet of code assumes that we are running svccfg as we
8342 8339                   * normally do -- witih svc.startd running. Of course, that is
8343 8340                   * not actually the case all the time because we also use a
8344 8341                   * varient of svc.configd and svccfg which are only meant to
8345 8342                   * run during the build process. During this time we have no
8346 8343                   * svc.startd, so this check would hang the build process.
8347 8344                   *
8348 8345                   * However, we've also given other consolidations, a bit of a
8349 8346                   * means to tie themselves into a knot. They're not properly
8350 8347                   * using the native build equivalents, but they've been getting
8351 8348                   * away with it anyways. Therefore, if we've found that
8352 8349                   * SVCCFG_REPOSITORY is set indicating that a separate configd
8353 8350                   * should be spun up, then we have to assume it's not using a
8354 8351                   * startd and we should not do this check.
8355 8352                   */
8356 8353  #ifndef NATIVE_BUILD
8357 8354                  /*
8358 8355                   * Verify that the restarter group is preset
8359 8356                   */
8360 8357                  eptr = getenv("SVCCFG_REPOSITORY");
8361 8358                  for (svc = uu_list_first(bndl->sc_bundle_services);
8362 8359                      svc != NULL && eptr == NULL;
8363 8360                      svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364 8361  
8365 8362                          insts = svc->sc_u.sc_service.sc_service_instances;
8366 8363  
8367 8364                          for (inst = uu_list_first(insts);
8368 8365                              inst != NULL;
8369 8366                              inst = uu_list_next(insts, inst)) {
8370 8367                                  if (lscf_instance_verify(imp_scope, svc,
8371 8368                                      inst) != 0)
8372 8369                                          goto progress;
8373 8370                          }
8374 8371                  }
8375 8372  #endif
8376 8373                  goto out;
8377 8374  
8378 8375          }
8379 8376  
8380 8377          if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381 8378                  bad_error("uu_list_walk", uu_error());
8382 8379  
8383 8380  printerr:
8384 8381          /* If the error hasn't been printed yet, do so here. */
8385 8382          switch (cbdata.sc_err) {
8386 8383          case ECONNABORTED:
8387 8384                  warn(gettext("Repository connection broken.\n"));
8388 8385                  break;
8389 8386  
8390 8387          case ENOMEM:
8391 8388                  warn(emsg_nomem);
8392 8389                  break;
8393 8390  
8394 8391          case ENOSPC:
8395 8392                  warn(emsg_nores);
8396 8393                  break;
8397 8394  
8398 8395          case EROFS:
8399 8396                  warn(gettext("Repository is read-only.\n"));
8400 8397                  break;
8401 8398  
8402 8399          case EACCES:
8403 8400                  warn(gettext("Repository backend denied access.\n"));
8404 8401                  break;
8405 8402  
8406 8403          case EPERM:
8407 8404          case EINVAL:
8408 8405          case EEXIST:
8409 8406          case EBUSY:
8410 8407          case EBADF:
8411 8408          case -1:
8412 8409                  break;
8413 8410  
8414 8411          default:
8415 8412                  bad_error("lscf_service_import", cbdata.sc_err);
8416 8413          }
8417 8414  
8418 8415  progress:
8419 8416          warn(gettext("Import of %s failed.  Progress:\n"), filename);
8420 8417  
8421 8418          for (svc = uu_list_first(bndl->sc_bundle_services);
8422 8419              svc != NULL;
8423 8420              svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424 8421                  insts = svc->sc_u.sc_service.sc_service_instances;
8425 8422  
8426 8423                  warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8427 8424                      import_progress(svc->sc_import_state));
8428 8425  
8429 8426                  for (inst = uu_list_first(insts);
8430 8427                      inst != NULL;
8431 8428                      inst = uu_list_next(insts, inst))
8432 8429                          warn(gettext("    Instance \"%s\": %s\n"),
8433 8430                              inst->sc_name,
8434 8431                              import_progress(inst->sc_import_state));
8435 8432          }
8436 8433  
8437 8434          if (cbdata.sc_err == ECONNABORTED)
8438 8435                  repository_teardown();
8439 8436  
8440 8437  
8441 8438          result = -1;
8442 8439  
8443 8440  out:
8444 8441          if (annotation_set != 0) {
8445 8442                  /* Turn off annotation.  It is no longer needed. */
8446 8443                  (void) _scf_set_annotation(g_hndl, NULL, NULL);
8447 8444          }
8448 8445  
8449 8446          free_imp_globals();
8450 8447  
8451 8448          return (result);
8452 8449  }
8453 8450  
8454 8451  /*
8455 8452   * _lscf_import_err() summarize the error handling returned by
8456 8453   * lscf_import_{instance | service}_pgs
8457 8454   * Return values are:
8458 8455   * IMPORT_NEXT
8459 8456   * IMPORT_OUT
8460 8457   * IMPORT_BAD
8461 8458   */
8462 8459  
8463 8460  #define IMPORT_BAD      -1
8464 8461  #define IMPORT_NEXT     0
8465 8462  #define IMPORT_OUT      1
8466 8463  
8467 8464  static int
8468 8465  _lscf_import_err(int err, const char *fmri)
8469 8466  {
8470 8467          switch (err) {
8471 8468          case 0:
8472 8469                  if (g_verbose)
8473 8470                          warn(gettext("%s updated.\n"), fmri);
8474 8471                  return (IMPORT_NEXT);
8475 8472  
8476 8473          case ECONNABORTED:
8477 8474                  warn(gettext("Could not update %s "
8478 8475                      "(repository connection broken).\n"), fmri);
8479 8476                  return (IMPORT_OUT);
8480 8477  
8481 8478          case ENOMEM:
8482 8479                  warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483 8480                  return (IMPORT_OUT);
8484 8481  
8485 8482          case ENOSPC:
8486 8483                  warn(gettext("Could not update %s "
8487 8484                      "(repository server out of resources).\n"), fmri);
8488 8485                  return (IMPORT_OUT);
8489 8486  
8490 8487          case ECANCELED:
8491 8488                  warn(gettext(
8492 8489                      "Could not update %s (deleted).\n"), fmri);
8493 8490                  return (IMPORT_NEXT);
8494 8491  
8495 8492          case EPERM:
8496 8493          case EINVAL:
8497 8494          case EBUSY:
8498 8495                  return (IMPORT_NEXT);
8499 8496  
8500 8497          case EROFS:
8501 8498                  warn(gettext("Could not update %s (repository read-only).\n"),
8502 8499                      fmri);
8503 8500                  return (IMPORT_OUT);
8504 8501  
8505 8502          case EACCES:
8506 8503                  warn(gettext("Could not update %s "
8507 8504                      "(backend access denied).\n"), fmri);
8508 8505                  return (IMPORT_NEXT);
8509 8506  
8510 8507          case EEXIST:
8511 8508          default:
8512 8509                  return (IMPORT_BAD);
8513 8510          }
8514 8511  
8515 8512          /*NOTREACHED*/
8516 8513  }
8517 8514  
8518 8515  /*
8519 8516   * The global imp_svc and imp_inst should be set by the caller in the
8520 8517   * check to make sure the service and instance exist that the apply is
8521 8518   * working on.
8522 8519   */
8523 8520  static int
8524 8521  lscf_dependent_apply(void *dpg, void *e)
8525 8522  {
8526 8523          scf_callback_t cb;
8527 8524          pgroup_t *dpt_pgroup = dpg;
8528 8525          pgroup_t *deldpt;
8529 8526          entity_t *ent = e;
8530 8527          int tissvc;
8531 8528          void *sc_ent, *tent;
8532 8529          scf_error_t serr;
8533 8530          int r;
8534 8531  
8535 8532          const char * const dependents = "dependents";
8536 8533          const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537 8534  
8538 8535          if (issvc)
8539 8536                  sc_ent = imp_svc;
8540 8537          else
8541 8538                  sc_ent = imp_inst;
8542 8539  
8543 8540          if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544 8541              imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545 8542              scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546 8543              imp_prop) != 0) {
8547 8544                  switch (scf_error()) {
8548 8545                  case SCF_ERROR_NOT_FOUND:
8549 8546                  case SCF_ERROR_DELETED:
8550 8547                          break;
8551 8548  
8552 8549                  case SCF_ERROR_CONNECTION_BROKEN:
8553 8550                  case SCF_ERROR_NOT_SET:
8554 8551                  case SCF_ERROR_INVALID_ARGUMENT:
8555 8552                  case SCF_ERROR_HANDLE_MISMATCH:
8556 8553                  case SCF_ERROR_NOT_BOUND:
8557 8554                  default:
8558 8555                          bad_error("entity_get_pg", scf_error());
8559 8556                  }
8560 8557          } else {
8561 8558                  /*
8562 8559                   * Found the dependents/<wip dep> so check to
8563 8560                   * see if the service is different.  If so
8564 8561                   * store the service for later refresh, and
8565 8562                   * delete the wip dependency from the service
8566 8563                   */
8567 8564                  if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568 8565                          switch (scf_error()) {
8569 8566                                  case SCF_ERROR_DELETED:
8570 8567                                          break;
8571 8568  
8572 8569                                  case SCF_ERROR_CONNECTION_BROKEN:
8573 8570                                  case SCF_ERROR_NOT_SET:
8574 8571                                  case SCF_ERROR_INVALID_ARGUMENT:
8575 8572                                  case SCF_ERROR_HANDLE_MISMATCH:
8576 8573                                  case SCF_ERROR_NOT_BOUND:
8577 8574                                  default:
8578 8575                                          bad_error("scf_property_get_value",
8579 8576                                              scf_error());
8580 8577                          }
8581 8578                  }
8582 8579  
8583 8580                  if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584 8581                      max_scf_value_len + 1) < 0)
8585 8582                          bad_error("scf_value_get_as_string", scf_error());
8586 8583  
8587 8584                  r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588 8585                  switch (r) {
8589 8586                  case 1:
8590 8587                          break;
8591 8588                  case 0:
8592 8589                          if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593 8590                              &tissvc)) != SCF_ERROR_NONE) {
8594 8591                                  if (serr == SCF_ERROR_NOT_FOUND) {
8595 8592                                          break;
8596 8593                                  } else {
8597 8594                                          bad_error("fmri_to_entity", serr);
8598 8595                                  }
8599 8596                          }
8600 8597  
8601 8598                          if (entity_get_pg(tent, tissvc,
8602 8599                              dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603 8600                                  serr = scf_error();
8604 8601                                  if (serr == SCF_ERROR_NOT_FOUND ||
8605 8602                                      serr == SCF_ERROR_DELETED) {
8606 8603                                          break;
8607 8604                                  } else {
8608 8605                                          bad_error("entity_get_pg", scf_error());
8609 8606                                  }
8610 8607                          }
8611 8608  
8612 8609                          if (scf_pg_delete(imp_pg) != 0) {
8613 8610                                  serr = scf_error();
8614 8611                                  if (serr == SCF_ERROR_NOT_FOUND ||
8615 8612                                      serr == SCF_ERROR_DELETED) {
8616 8613                                          break;
8617 8614                                  } else {
8618 8615                                          bad_error("scf_pg_delete", scf_error());
8619 8616                                  }
8620 8617                          }
8621 8618  
8622 8619                          deldpt = internal_pgroup_new();
8623 8620                          if (deldpt == NULL)
8624 8621                                  return (ENOMEM);
8625 8622                          deldpt->sc_pgroup_name =
8626 8623                              strdup(dpt_pgroup->sc_pgroup_name);
8627 8624                          deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628 8625                          if (deldpt->sc_pgroup_name == NULL ||
8629 8626                              deldpt->sc_pgroup_fmri == NULL)
8630 8627                                  return (ENOMEM);
8631 8628                          deldpt->sc_parent = (entity_t *)ent;
8632 8629                          if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633 8630                              deldpt) != 0)
8634 8631                                  uu_die(gettext("libuutil error: %s\n"),
8635 8632                                      uu_strerror(uu_error()));
8636 8633  
8637 8634                          break;
8638 8635                  default:
8639 8636                          bad_error("fmri_equal", r);
8640 8637                  }
8641 8638          }
8642 8639  
8643 8640          cb.sc_handle = g_hndl;
8644 8641          cb.sc_parent = ent;
8645 8642          cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646 8643          cb.sc_source_fmri = ent->sc_fmri;
8647 8644          cb.sc_target_fmri = ent->sc_fmri;
8648 8645          cb.sc_trans = NULL;
8649 8646          cb.sc_flags = SCI_FORCE;
8650 8647  
8651 8648          if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652 8649                  return (UU_WALK_ERROR);
8653 8650  
8654 8651          r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655 8652          switch (r) {
8656 8653          case 0:
8657 8654                  break;
8658 8655  
8659 8656          case ENOMEM:
8660 8657          case ECONNABORTED:
8661 8658          case EPERM:
8662 8659          case -1:
8663 8660                  warn(gettext("Unable to refresh \"%s\"\n"),
8664 8661                      dpt_pgroup->sc_pgroup_fmri);
8665 8662                  return (UU_WALK_ERROR);
8666 8663  
8667 8664          default:
8668 8665                  bad_error("imp_refresh_fmri", r);
8669 8666          }
8670 8667  
8671 8668          return (UU_WALK_NEXT);
8672 8669  }
8673 8670  
8674 8671  /*
8675 8672   * Returns
8676 8673   *   0 - success
8677 8674   *   -1 - lscf_import_instance_pgs() failed.
8678 8675   */
8679 8676  int
8680 8677  lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 8678  {
8682 8679          pgroup_t *old_dpt;
8683 8680          entity_t *svc, *inst;
8684 8681          int annotation_set = 0;
8685 8682          int ret = 0;
8686 8683          int r = 0;
8687 8684  
8688 8685          lscf_prep_hndl();
8689 8686  
8690 8687          if ((ret = alloc_imp_globals()))
8691 8688                  goto out;
8692 8689  
8693 8690          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694 8691                  scfdie();
8695 8692  
8696 8693          /*
8697 8694           * Set the strings to be used for the security audit annotation
8698 8695           * event.
8699 8696           */
8700 8697          if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701 8698                  annotation_set = 1;
8702 8699          } else {
8703 8700                  switch (scf_error()) {
8704 8701                  case SCF_ERROR_CONNECTION_BROKEN:
8705 8702                          warn(gettext("Repository connection broken.\n"));
8706 8703                          goto out;
8707 8704  
8708 8705                  case SCF_ERROR_INVALID_ARGUMENT:
8709 8706                  case SCF_ERROR_NOT_BOUND:
8710 8707                  case SCF_ERROR_NO_RESOURCES:
8711 8708                  case SCF_ERROR_INTERNAL:
8712 8709                          bad_error("_scf_set_annotation", scf_error());
8713 8710                          /* NOTREACHED */
8714 8711  
8715 8712                  default:
8716 8713                          /*
8717 8714                           * Do not abort apply operation because of
8718 8715                           * inability to create annotation audit event.
8719 8716                           */
8720 8717                          warn(gettext("_scf_set_annotation() unexpectedly "
8721 8718                              "failed with return code of %d\n"), scf_error());
8722 8719                          break;
8723 8720                  }
8724 8721          }
8725 8722  
8726 8723          for (svc = uu_list_first(bndl->sc_bundle_services);
8727 8724              svc != NULL;
8728 8725              svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729 8726                  int refresh = 0;
8730 8727  
8731 8728                  if (scf_scope_get_service(imp_scope, svc->sc_name,
8732 8729                      imp_svc) != 0) {
8733 8730                          switch (scf_error()) {
8734 8731                          case SCF_ERROR_NOT_FOUND:
8735 8732                                  if (g_verbose)
8736 8733                                          warn(gettext("Ignoring nonexistent "
8737 8734                                              "service %s.\n"), svc->sc_name);
8738 8735                                  continue;
8739 8736  
8740 8737                          default:
8741 8738                                  scfdie();
8742 8739                          }
8743 8740                  }
8744 8741  
8745 8742                  /*
8746 8743                   * If there were missing types in the profile, then need to
8747 8744                   * attempt to find the types.
8748 8745                   */
8749 8746                  if (svc->sc_miss_type) {
8750 8747                          if (uu_list_numnodes(svc->sc_pgroups) &&
8751 8748                              uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752 8749                              svc, UU_DEFAULT) != 0) {
8753 8750                                  if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754 8751                                          bad_error("uu_list_walk", uu_error());
8755 8752  
8756 8753                                  ret = -1;
8757 8754                                  continue;
8758 8755                          }
8759 8756  
8760 8757                          for (inst = uu_list_first(
8761 8758                              svc->sc_u.sc_service.sc_service_instances);
8762 8759                              inst != NULL;
8763 8760                              inst = uu_list_next(
8764 8761                              svc->sc_u.sc_service.sc_service_instances, inst)) {
8765 8762                                  /*
8766 8763                                   * If the instance doesn't exist just
8767 8764                                   * skip to the next instance and let the
8768 8765                                   * import note the missing instance.
8769 8766                                   */
8770 8767                                  if (scf_service_get_instance(imp_svc,
8771 8768                                      inst->sc_name, imp_inst) != 0)
8772 8769                                          continue;
8773 8770  
8774 8771                                  if (uu_list_walk(inst->sc_pgroups,
8775 8772                                      find_current_pg_type, inst,
8776 8773                                      UU_DEFAULT) != 0) {
8777 8774                                          if (uu_error() !=
8778 8775                                              UU_ERROR_CALLBACK_FAILED)
8779 8776                                                  bad_error("uu_list_walk",
8780 8777                                                      uu_error());
8781 8778  
8782 8779                                          ret = -1;
8783 8780                                          inst->sc_miss_type = B_TRUE;
8784 8781                                  }
8785 8782                          }
8786 8783                  }
8787 8784  
8788 8785                  /*
8789 8786                   * if we have pgs in the profile, we need to refresh ALL
8790 8787                   * instances of the service
8791 8788                   */
8792 8789                  if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793 8790                          refresh = 1;
8794 8791                          r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795 8792                              SCI_FORCE | SCI_KEEP);
8796 8793                          switch (_lscf_import_err(r, svc->sc_fmri)) {
8797 8794                          case IMPORT_NEXT:
8798 8795                                  break;
8799 8796  
8800 8797                          case IMPORT_OUT:
8801 8798                                  goto out;
8802 8799  
8803 8800                          case IMPORT_BAD:
8804 8801                          default:
8805 8802                                  bad_error("lscf_import_service_pgs", r);
8806 8803                          }
8807 8804                  }
8808 8805  
8809 8806                  if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810 8807                          uu_list_walk(svc->sc_dependents,
8811 8808                              lscf_dependent_apply, svc, UU_DEFAULT);
8812 8809                  }
8813 8810  
8814 8811                  for (inst = uu_list_first(
8815 8812                      svc->sc_u.sc_service.sc_service_instances);
8816 8813                      inst != NULL;
8817 8814                      inst = uu_list_next(
8818 8815                      svc->sc_u.sc_service.sc_service_instances, inst)) {
8819 8816                          /*
8820 8817                           * This instance still has missing types
8821 8818                           * so skip it.
8822 8819                           */
8823 8820                          if (inst->sc_miss_type) {
8824 8821                                  if (g_verbose)
8825 8822                                          warn(gettext("Ignoring instance "
8826 8823                                              "%s:%s with missing types\n"),
8827 8824                                              inst->sc_parent->sc_name,
8828 8825                                              inst->sc_name);
8829 8826  
8830 8827                                  continue;
8831 8828                          }
8832 8829  
8833 8830                          if (scf_service_get_instance(imp_svc, inst->sc_name,
8834 8831                              imp_inst) != 0) {
8835 8832                                  switch (scf_error()) {
8836 8833                                  case SCF_ERROR_NOT_FOUND:
8837 8834                                          if (g_verbose)
8838 8835                                                  warn(gettext("Ignoring "
8839 8836                                                      "nonexistant instance "
8840 8837                                                      "%s:%s.\n"),
8841 8838                                                      inst->sc_parent->sc_name,
8842 8839                                                      inst->sc_name);
8843 8840                                          continue;
8844 8841  
8845 8842                                  default:
8846 8843                                          scfdie();
8847 8844                                  }
8848 8845                          }
8849 8846  
8850 8847                          /*
8851 8848                           * If the instance does not have a general/enabled
8852 8849                           * property and no last-import snapshot then the
8853 8850                           * instance is not a fully installed instance and
8854 8851                           * should not have a profile applied to it.
8855 8852                           *
8856 8853                           * This could happen if a service/instance declares
8857 8854                           * a dependent on behalf of another service/instance.
8858 8855                           *
8859 8856                           */
8860 8857                          if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861 8858                              imp_snap) != 0) {
8862 8859                                  if (scf_instance_get_pg(imp_inst,
8863 8860                                      SCF_PG_GENERAL, imp_pg) != 0 ||
8864 8861                                      scf_pg_get_property(imp_pg,
8865 8862                                      SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866 8863                                          if (g_verbose)
8867 8864                                                  warn(gettext("Ignoreing "
8868 8865                                                      "partial instance "
8869 8866                                                      "%s:%s.\n"),
8870 8867                                                      inst->sc_parent->sc_name,
8871 8868                                                      inst->sc_name);
8872 8869                                          continue;
8873 8870                                  }
8874 8871                          }
8875 8872  
8876 8873                          r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877 8874                              inst, SCI_FORCE | SCI_KEEP);
8878 8875                          switch (_lscf_import_err(r, inst->sc_fmri)) {
8879 8876                          case IMPORT_NEXT:
8880 8877                                  break;
8881 8878  
8882 8879                          case IMPORT_OUT:
8883 8880                                  goto out;
8884 8881  
8885 8882                          case IMPORT_BAD:
8886 8883                          default:
8887 8884                                  bad_error("lscf_import_instance_pgs", r);
8888 8885                          }
8889 8886  
8890 8887                          if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891 8888                                  uu_list_walk(inst->sc_dependents,
8892 8889                                      lscf_dependent_apply, inst, UU_DEFAULT);
8893 8890                          }
8894 8891  
8895 8892                          /* refresh only if there is no pgs in the service */
8896 8893                          if (refresh == 0)
8897 8894                                  (void) refresh_entity(0, imp_inst,
8898 8895                                      inst->sc_fmri, NULL, NULL, NULL);
8899 8896                  }
8900 8897  
8901 8898                  if (refresh == 1) {
8902 8899                          char *name_buf = safe_malloc(max_scf_name_len + 1);
8903 8900  
8904 8901                          (void) refresh_entity(1, imp_svc, svc->sc_name,
8905 8902                              imp_inst, imp_iter, name_buf);
8906 8903                          free(name_buf);
8907 8904                  }
8908 8905  
8909 8906                  for (old_dpt = uu_list_first(imp_deleted_dpts);
8910 8907                      old_dpt != NULL;
8911 8908                      old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912 8909                          if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913 8910                              old_dpt->sc_pgroup_name,
8914 8911                              old_dpt->sc_parent->sc_fmri) != 0) {
8915 8912                                  warn(gettext("Unable to refresh \"%s\"\n"),
8916 8913                                      old_dpt->sc_pgroup_fmri);
8917 8914                          }
8918 8915                  }
8919 8916          }
8920 8917  
8921 8918  out:
8922 8919          if (annotation_set) {
8923 8920                  /* Remove security audit annotation strings. */
8924 8921                  (void) _scf_set_annotation(g_hndl, NULL, NULL);
8925 8922          }
8926 8923  
8927 8924          free_imp_globals();
8928 8925          return (ret);
8929 8926  }
8930 8927  
8931 8928  
8932 8929  /*
8933 8930   * Export.  These functions create and output an XML tree of a service
8934 8931   * description from the repository.  This is largely the inverse of
8935 8932   * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936 8933   *
8937 8934   * - We must include any properties which are not represented specifically by
8938 8935   *   a service manifest, e.g., properties created by an admin post-import.  To
8939 8936   *   do so we'll iterate through all properties and deal with each
8940 8937   *   apropriately.
8941 8938   *
8942 8939   * - Children of services and instances must must be in the order set by the
8943 8940   *   DTD, but we iterate over the properties in undefined order.  The elements
8944 8941   *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8945 8942   *   number of classes of them, however, we'll keep the classes separate and
8946 8943   *   assemble them in order.
8947 8944   */
8948 8945  
8949 8946  /*
8950 8947   * Convenience function to handle xmlSetProp errors (and type casting).
8951 8948   */
8952 8949  static void
8953 8950  safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 8951  {
8955 8952          if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956 8953                  uu_die(gettext("Could not set XML property.\n"));
8957 8954  }
8958 8955  
8959 8956  /*
8960 8957   * Convenience function to set an XML attribute to the single value of an
8961 8958   * astring property.  If the value happens to be the default, don't set the
8962 8959   * attribute.  "dval" should be the default value supplied by the DTD, or
8963 8960   * NULL for no default.
8964 8961   */
8965 8962  static int
8966 8963  set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967 8964      const char *name, const char *dval)
8968 8965  {
8969 8966          scf_value_t *val;
8970 8967          ssize_t len;
8971 8968          char *str;
8972 8969  
8973 8970          val = scf_value_create(g_hndl);
8974 8971          if (val == NULL)
8975 8972                  scfdie();
8976 8973  
8977 8974          if (prop_get_val(prop, val) != 0) {
8978 8975                  scf_value_destroy(val);
8979 8976                  return (-1);
8980 8977          }
8981 8978  
8982 8979          len = scf_value_get_as_string(val, NULL, 0);
8983 8980          if (len < 0)
8984 8981                  scfdie();
8985 8982  
8986 8983          str = safe_malloc(len + 1);
8987 8984  
8988 8985          if (scf_value_get_as_string(val, str, len + 1) < 0)
8989 8986                  scfdie();
8990 8987  
8991 8988          scf_value_destroy(val);
8992 8989  
8993 8990          if (dval == NULL || strcmp(str, dval) != 0)
8994 8991                  safe_setprop(n, name, str);
8995 8992  
8996 8993          free(str);
8997 8994  
8998 8995          return (0);
8999 8996  }
9000 8997  
9001 8998  /*
9002 8999   * As above, but the attribute is always set.
9003 9000   */
9004 9001  static int
9005 9002  set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 9003  {
9007 9004          return (set_attr_from_prop_default(prop, n, name, NULL));
9008 9005  }
9009 9006  
9010 9007  /*
9011 9008   * Dump the given document onto f, with "'s replaced by ''s.
9012 9009   */
9013 9010  static int
9014 9011  write_service_bundle(xmlDocPtr doc, FILE *f)
9015 9012  {
9016 9013          xmlChar *mem;
9017 9014          int sz, i;
9018 9015  
9019 9016          mem = NULL;
9020 9017          xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021 9018  
9022 9019          if (mem == NULL) {
9023 9020                  semerr(gettext("Could not dump XML tree.\n"));
9024 9021                  return (-1);
9025 9022          }
9026 9023  
9027 9024          /*
9028 9025           * Fortunately libxml produces " instead of ", so we can blindly
9029 9026           * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9030 9027           * ' code?!
9031 9028           */
9032 9029          for (i = 0; i < sz; ++i) {
9033 9030                  char c = (char)mem[i];
9034 9031  
9035 9032                  if (c == '"')
9036 9033                          (void) fputc('\'', f);
9037 9034                  else if (c == '\'')
9038 9035                          (void) fwrite("'", sizeof ("'") - 1, 1, f);
9039 9036                  else
9040 9037                          (void) fputc(c, f);
9041 9038          }
9042 9039  
9043 9040          return (0);
9044 9041  }
9045 9042  
9046 9043  /*
9047 9044   * Create the DOM elements in elts necessary to (generically) represent prop
9048 9045   * (i.e., a property or propval element).  If the name of the property is
9049 9046   * known, it should be passed as name_arg.  Otherwise, pass NULL.
9050 9047   */
9051 9048  static void
9052 9049  export_property(scf_property_t *prop, const char *name_arg,
9053 9050      struct pg_elts *elts, int flags)
9054 9051  {
9055 9052          const char *type;
9056 9053          scf_error_t err = 0;
9057 9054          xmlNodePtr pnode, lnode;
9058 9055          char *lnname;
9059 9056          int ret;
9060 9057  
9061 9058          /* name */
9062 9059          if (name_arg != NULL) {
9063 9060                  (void) strcpy(exp_str, name_arg);
9064 9061          } else {
9065 9062                  if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066 9063                          scfdie();
9067 9064          }
9068 9065  
9069 9066          /* type */
9070 9067          type = prop_to_typestr(prop);
9071 9068          if (type == NULL)
9072 9069                  uu_die(gettext("Can't export property %s: unknown type.\n"),
9073 9070                      exp_str);
9074 9071  
9075 9072          /* If we're exporting values, and there's just one, export it here. */
9076 9073          if (!(flags & SCE_ALL_VALUES))
9077 9074                  goto empty;
9078 9075  
9079 9076          if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080 9077                  xmlNodePtr n;
9081 9078  
9082 9079                  /* Single value, so use propval */
9083 9080                  n = xmlNewNode(NULL, (xmlChar *)"propval");
9084 9081                  if (n == NULL)
9085 9082                          uu_die(emsg_create_xml);
9086 9083  
9087 9084                  safe_setprop(n, name_attr, exp_str);
9088 9085                  safe_setprop(n, type_attr, type);
9089 9086  
9090 9087                  if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091 9088                          scfdie();
9092 9089                  safe_setprop(n, value_attr, exp_str);
9093 9090  
9094 9091                  if (elts->propvals == NULL)
9095 9092                          elts->propvals = n;
9096 9093                  else
9097 9094                          (void) xmlAddSibling(elts->propvals, n);
9098 9095  
9099 9096                  return;
9100 9097          }
9101 9098  
9102 9099          err = scf_error();
9103 9100  
9104 9101          if (err == SCF_ERROR_PERMISSION_DENIED) {
9105 9102                  semerr(emsg_permission_denied);
9106 9103                  return;
9107 9104          }
9108 9105  
9109 9106          if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110 9107              err != SCF_ERROR_NOT_FOUND &&
9111 9108              err != SCF_ERROR_PERMISSION_DENIED)
9112 9109                  scfdie();
9113 9110  
9114 9111  empty:
9115 9112          /* Multiple (or no) values, so use property */
9116 9113          pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117 9114          if (pnode == NULL)
9118 9115                  uu_die(emsg_create_xml);
9119 9116  
9120 9117          safe_setprop(pnode, name_attr, exp_str);
9121 9118          safe_setprop(pnode, type_attr, type);
9122 9119  
9123 9120          if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124 9121                  lnname = uu_msprintf("%s_list", type);
9125 9122                  if (lnname == NULL)
9126 9123                          uu_die(gettext("Could not create string"));
9127 9124  
9128 9125                  lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129 9126                  if (lnode == NULL)
9130 9127                          uu_die(emsg_create_xml);
9131 9128  
9132 9129                  uu_free(lnname);
9133 9130  
9134 9131                  if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135 9132                          scfdie();
9136 9133  
9137 9134                  while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138 9135                      1) {
9139 9136                          xmlNodePtr vn;
9140 9137  
9141 9138                          vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142 9139                              NULL);
9143 9140                          if (vn == NULL)
9144 9141                                  uu_die(emsg_create_xml);
9145 9142  
9146 9143                          if (scf_value_get_as_string(exp_val, exp_str,
9147 9144                              exp_str_sz) < 0)
9148 9145                                  scfdie();
9149 9146                          safe_setprop(vn, value_attr, exp_str);
9150 9147                  }
9151 9148                  if (ret != 0)
9152 9149                          scfdie();
9153 9150          }
9154 9151  
9155 9152          if (elts->properties == NULL)
9156 9153                  elts->properties = pnode;
9157 9154          else
9158 9155                  (void) xmlAddSibling(elts->properties, pnode);
9159 9156  }
9160 9157  
9161 9158  /*
9162 9159   * Add a property_group element for this property group to elts.
9163 9160   */
9164 9161  static void
9165 9162  export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 9163  {
9167 9164          xmlNodePtr n;
9168 9165          struct pg_elts elts;
9169 9166          int ret;
9170 9167          boolean_t read_protected;
9171 9168  
9172 9169          n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173 9170  
9174 9171          /* name */
9175 9172          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176 9173                  scfdie();
9177 9174          safe_setprop(n, name_attr, exp_str);
9178 9175  
9179 9176          /* type */
9180 9177          if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181 9178                  scfdie();
9182 9179          safe_setprop(n, type_attr, exp_str);
9183 9180  
9184 9181          /* properties */
9185 9182          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186 9183                  scfdie();
9187 9184  
9188 9185          (void) memset(&elts, 0, sizeof (elts));
9189 9186  
9190 9187          /*
9191 9188           * If this property group is not read protected, we always want to
9192 9189           * output all the values.  Otherwise, we only output the values if the
9193 9190           * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194 9191           */
9195 9192          if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196 9193                  scfdie();
9197 9194  
9198 9195          if (!read_protected)
9199 9196                  flags |= SCE_ALL_VALUES;
9200 9197  
9201 9198          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202 9199                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203 9200                          scfdie();
9204 9201  
9205 9202                  if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206 9203                          xmlNodePtr m;
9207 9204  
9208 9205                          m = xmlNewNode(NULL, (xmlChar *)"stability");
9209 9206                          if (m == NULL)
9210 9207                                  uu_die(emsg_create_xml);
9211 9208  
9212 9209                          if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213 9210                                  elts.stability = m;
9214 9211                                  continue;
9215 9212                          }
9216 9213  
9217 9214                          xmlFreeNode(m);
9218 9215                  }
9219 9216  
9220 9217                  export_property(exp_prop, NULL, &elts, flags);
9221 9218          }
9222 9219          if (ret == -1)
9223 9220                  scfdie();
9224 9221  
9225 9222          (void) xmlAddChild(n, elts.stability);
9226 9223          (void) xmlAddChildList(n, elts.propvals);
9227 9224          (void) xmlAddChildList(n, elts.properties);
9228 9225  
9229 9226          if (eelts->property_groups == NULL)
9230 9227                  eelts->property_groups = n;
9231 9228          else
9232 9229                  (void) xmlAddSibling(eelts->property_groups, n);
9233 9230  }
9234 9231  
9235 9232  /*
9236 9233   * Create an XML node representing the dependency described by the given
9237 9234   * property group and put it in eelts.  Unless the dependency is not valid, in
9238 9235   * which case create a generic property_group element which represents it and
9239 9236   * put it in eelts.
9240 9237   */
9241 9238  static void
9242 9239  export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 9240  {
9244 9241          xmlNodePtr n;
9245 9242          int err = 0, ret;
9246 9243          struct pg_elts elts;
9247 9244  
9248 9245          n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249 9246          if (n == NULL)
9250 9247                  uu_die(emsg_create_xml);
9251 9248  
9252 9249          /*
9253 9250           * If the external flag is present, skip this dependency because it
9254 9251           * should have been created by another manifest.
9255 9252           */
9256 9253          if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257 9254                  if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258 9255                      prop_get_val(exp_prop, exp_val) == 0) {
9259 9256                          uint8_t b;
9260 9257  
9261 9258                          if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262 9259                                  scfdie();
9263 9260  
9264 9261                          if (b)
9265 9262                                  return;
9266 9263                  }
9267 9264          } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268 9265                  scfdie();
9269 9266  
9270 9267          /* Get the required attributes. */
9271 9268  
9272 9269          /* name */
9273 9270          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274 9271                  scfdie();
9275 9272          safe_setprop(n, name_attr, exp_str);
9276 9273  
9277 9274          /* grouping */
9278 9275          if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279 9276              set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280 9277                  err = 1;
9281 9278  
9282 9279          /* restart_on */
9283 9280          if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284 9281              set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285 9282                  err = 1;
9286 9283  
9287 9284          /* type */
9288 9285          if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289 9286              set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290 9287                  err = 1;
9291 9288  
9292 9289          /*
9293 9290           * entities: Not required, but if we create no children, it will be
9294 9291           * created as empty on import, so fail if it's missing.
9295 9292           */
9296 9293          if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297 9294              prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298 9295                  scf_iter_t *eiter;
9299 9296                  int ret2;
9300 9297  
9301 9298                  eiter = scf_iter_create(g_hndl);
9302 9299                  if (eiter == NULL)
9303 9300                          scfdie();
9304 9301  
9305 9302                  if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306 9303                          scfdie();
9307 9304  
9308 9305                  while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309 9306                          xmlNodePtr ch;
9310 9307  
9311 9308                          if (scf_value_get_astring(exp_val, exp_str,
9312 9309                              exp_str_sz) < 0)
9313 9310                                  scfdie();
9314 9311  
9315 9312                          /*
9316 9313                           * service_fmri's must be first, so we can add them
9317 9314                           * here.
9318 9315                           */
9319 9316                          ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320 9317                              NULL);
9321 9318                          if (ch == NULL)
9322 9319                                  uu_die(emsg_create_xml);
9323 9320  
9324 9321                          safe_setprop(ch, value_attr, exp_str);
9325 9322                  }
9326 9323                  if (ret2 == -1)
9327 9324                          scfdie();
9328 9325  
9329 9326                  scf_iter_destroy(eiter);
9330 9327          } else
9331 9328                  err = 1;
9332 9329  
9333 9330          if (err) {
9334 9331                  xmlFreeNode(n);
9335 9332  
9336 9333                  export_pg(pg, eelts, SCE_ALL_VALUES);
9337 9334  
9338 9335                  return;
9339 9336          }
9340 9337  
9341 9338          /* Iterate through the properties & handle each. */
9342 9339          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343 9340                  scfdie();
9344 9341  
9345 9342          (void) memset(&elts, 0, sizeof (elts));
9346 9343  
9347 9344          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348 9345                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349 9346                          scfdie();
9350 9347  
9351 9348                  if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352 9349                      strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353 9350                      strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354 9351                      strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355 9352                          continue;
9356 9353                  } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357 9354                          xmlNodePtr m;
9358 9355  
9359 9356                          m = xmlNewNode(NULL, (xmlChar *)"stability");
9360 9357                          if (m == NULL)
9361 9358                                  uu_die(emsg_create_xml);
9362 9359  
9363 9360                          if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364 9361                                  elts.stability = m;
9365 9362                                  continue;
9366 9363                          }
9367 9364  
9368 9365                          xmlFreeNode(m);
9369 9366                  }
9370 9367  
9371 9368                  export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372 9369          }
9373 9370          if (ret == -1)
9374 9371                  scfdie();
9375 9372  
9376 9373          (void) xmlAddChild(n, elts.stability);
9377 9374          (void) xmlAddChildList(n, elts.propvals);
9378 9375          (void) xmlAddChildList(n, elts.properties);
9379 9376  
9380 9377          if (eelts->dependencies == NULL)
9381 9378                  eelts->dependencies = n;
9382 9379          else
9383 9380                  (void) xmlAddSibling(eelts->dependencies, n);
9384 9381  }
9385 9382  
9386 9383  static xmlNodePtr
9387 9384  export_method_environment(scf_propertygroup_t *pg)
9388 9385  {
9389 9386          xmlNodePtr env;
9390 9387          int ret;
9391 9388          int children = 0;
9392 9389  
9393 9390          if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394 9391                  return (NULL);
9395 9392  
9396 9393          env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397 9394          if (env == NULL)
9398 9395                  uu_die(emsg_create_xml);
9399 9396  
9400 9397          if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401 9398                  scfdie();
9402 9399  
9403 9400          if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404 9401                  scfdie();
9405 9402  
9406 9403          while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407 9404                  xmlNodePtr ev;
9408 9405                  char *cp;
9409 9406  
9410 9407                  if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411 9408                          scfdie();
9412 9409  
9413 9410                  if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414 9411                          warn(gettext("Invalid environment variable \"%s\".\n"),
9415 9412                              exp_str);
9416 9413                          continue;
9417 9414                  } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418 9415                          warn(gettext("Invalid environment variable \"%s\"; "
9419 9416                              "\"SMF_\" prefix is reserved.\n"), exp_str);
9420 9417                          continue;
9421 9418                  }
9422 9419  
9423 9420                  *cp = '\0';
9424 9421                  cp++;
9425 9422  
9426 9423                  ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427 9424                  if (ev == NULL)
9428 9425                          uu_die(emsg_create_xml);
9429 9426  
9430 9427                  safe_setprop(ev, name_attr, exp_str);
9431 9428                  safe_setprop(ev, value_attr, cp);
9432 9429                  children++;
9433 9430          }
9434 9431  
9435 9432          if (ret != 0)
9436 9433                  scfdie();
9437 9434  
9438 9435          if (children == 0) {
9439 9436                  xmlFreeNode(env);
9440 9437                  return (NULL);
9441 9438          }
9442 9439  
9443 9440          return (env);
9444 9441  }
9445 9442  
9446 9443  /*
9447 9444   * As above, but for a method property group.
9448 9445   */
9449 9446  static void
9450 9447  export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 9448  {
9452 9449          xmlNodePtr n, env;
9453 9450          char *str;
9454 9451          int err = 0, nonenv, ret;
9455 9452          uint8_t use_profile;
9456 9453          struct pg_elts elts;
9457 9454          xmlNodePtr ctxt = NULL;
9458 9455  
9459 9456          n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460 9457  
9461 9458          /* Get the required attributes. */
9462 9459  
9463 9460          /* name */
9464 9461          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465 9462                  scfdie();
9466 9463          safe_setprop(n, name_attr, exp_str);
9467 9464  
9468 9465          /* type */
9469 9466          if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470 9467              set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471 9468                  err = 1;
9472 9469  
9473 9470          /* exec */
9474 9471          if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475 9472              set_attr_from_prop(exp_prop, n, "exec") != 0)
9476 9473                  err = 1;
9477 9474  
9478 9475          /* timeout */
9479 9476          if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480 9477              prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481 9478              prop_get_val(exp_prop, exp_val) == 0) {
9482 9479                  uint64_t c;
9483 9480  
9484 9481                  if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485 9482                          scfdie();
9486 9483  
9487 9484                  str = uu_msprintf("%llu", c);
9488 9485                  if (str == NULL)
9489 9486                          uu_die(gettext("Could not create string"));
9490 9487  
9491 9488                  safe_setprop(n, "timeout_seconds", str);
9492 9489                  free(str);
9493 9490          } else
9494 9491                  err = 1;
9495 9492  
9496 9493          if (err) {
9497 9494                  xmlFreeNode(n);
9498 9495  
9499 9496                  export_pg(pg, eelts, SCE_ALL_VALUES);
9500 9497  
9501 9498                  return;
9502 9499          }
9503 9500  
9504 9501  
9505 9502          /*
9506 9503           * If we're going to have a method_context child, we need to know
9507 9504           * before we iterate through the properties.  Since method_context's
9508 9505           * are optional, we don't want to complain about any properties
9509 9506           * missing if none of them are there.  Thus we can't use the
9510 9507           * convenience functions.
9511 9508           */
9512 9509          nonenv =
9513 9510              scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514 9511              SCF_SUCCESS ||
9515 9512              scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516 9513              SCF_SUCCESS ||
9517 9514              scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9518 9515              SCF_SUCCESS ||
9519 9516              scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9520 9517              SCF_SUCCESS ||
9521 9518              scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9522 9519              SCF_SUCCESS;
9523 9520  
9524 9521          if (nonenv) {
9525 9522                  ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9526 9523                  if (ctxt == NULL)
9527 9524                          uu_die(emsg_create_xml);
9528 9525  
9529 9526                  if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9530 9527                      0 &&
9531 9528                      set_attr_from_prop_default(exp_prop, ctxt,
9532 9529                      "working_directory", ":default") != 0)
9533 9530                          err = 1;
9534 9531  
9535 9532                  if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9536 9533                      set_attr_from_prop_default(exp_prop, ctxt, "project",
9537 9534                      ":default") != 0)
9538 9535                          err = 1;
9539 9536  
9540 9537                  if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9541 9538                      0 &&
9542 9539                      set_attr_from_prop_default(exp_prop, ctxt,
9543 9540                      "resource_pool", ":default") != 0)
9544 9541                          err = 1;
9545 9542  
9546 9543                  if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9547 9544                      set_attr_from_prop_default(exp_prop, ctxt,
9548 9545                      "security_flags", ":default") != 0)
9549 9546                          err = 1;
9550 9547  
9551 9548                  /*
9552 9549                   * We only want to complain about profile or credential
9553 9550                   * properties if we will use them.  To determine that we must
9554 9551                   * examine USE_PROFILE.
9555 9552                   */
9556 9553                  if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9557 9554                      prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9558 9555                      prop_get_val(exp_prop, exp_val) == 0) {
9559 9556                          if (scf_value_get_boolean(exp_val, &use_profile) !=
9560 9557                              SCF_SUCCESS) {
9561 9558                                  scfdie();
9562 9559                          }
9563 9560  
9564 9561                          if (use_profile) {
9565 9562                                  xmlNodePtr prof;
9566 9563  
9567 9564                                  prof = xmlNewChild(ctxt, NULL,
9568 9565                                      (xmlChar *)"method_profile", NULL);
9569 9566                                  if (prof == NULL)
9570 9567                                          uu_die(emsg_create_xml);
9571 9568  
9572 9569                                  if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9573 9570                                      exp_prop) != 0 ||
9574 9571                                      set_attr_from_prop(exp_prop, prof,
9575 9572                                      name_attr) != 0)
9576 9573                                          err = 1;
9577 9574                          } else {
9578 9575                                  xmlNodePtr cred;
9579 9576  
9580 9577                                  cred = xmlNewChild(ctxt, NULL,
9581 9578                                      (xmlChar *)"method_credential", NULL);
9582 9579                                  if (cred == NULL)
9583 9580                                          uu_die(emsg_create_xml);
9584 9581  
9585 9582                                  if (pg_get_prop(pg, SCF_PROPERTY_USER,
9586 9583                                      exp_prop) != 0 ||
9587 9584                                      set_attr_from_prop(exp_prop, cred,
9588 9585                                      "user") != 0) {
9589 9586                                          err = 1;
9590 9587                                  }
9591 9588  
9592 9589                                  if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9593 9590                                      exp_prop) == 0 &&
9594 9591                                      set_attr_from_prop_default(exp_prop, cred,
9595 9592                                      "group", ":default") != 0)
9596 9593                                          err = 1;
9597 9594  
9598 9595                                  if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9599 9596                                      exp_prop) == 0 &&
9600 9597                                      set_attr_from_prop_default(exp_prop, cred,
9601 9598                                      "supp_groups", ":default") != 0)
9602 9599                                          err = 1;
9603 9600  
9604 9601                                  if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9605 9602                                      exp_prop) == 0 &&
9606 9603                                      set_attr_from_prop_default(exp_prop, cred,
9607 9604                                      "privileges", ":default") != 0)
9608 9605                                          err = 1;
9609 9606  
9610 9607                                  if (pg_get_prop(pg,
9611 9608                                      SCF_PROPERTY_LIMIT_PRIVILEGES,
9612 9609                                      exp_prop) == 0 &&
9613 9610                                      set_attr_from_prop_default(exp_prop, cred,
9614 9611                                      "limit_privileges", ":default") != 0)
9615 9612                                          err = 1;
9616 9613                          }
9617 9614                  }
9618 9615          }
9619 9616  
9620 9617          if ((env = export_method_environment(pg)) != NULL) {
9621 9618                  if (ctxt == NULL) {
9622 9619                          ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9623 9620                          if (ctxt == NULL)
9624 9621                                  uu_die(emsg_create_xml);
9625 9622                  }
9626 9623                  (void) xmlAddChild(ctxt, env);
9627 9624          }
9628 9625  
9629 9626          if (env != NULL || (nonenv && err == 0))
9630 9627                  (void) xmlAddChild(n, ctxt);
9631 9628          else
9632 9629                  xmlFreeNode(ctxt);
9633 9630  
9634 9631          nonenv = (err == 0);
9635 9632  
9636 9633          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9637 9634                  scfdie();
9638 9635  
9639 9636          (void) memset(&elts, 0, sizeof (elts));
9640 9637  
9641 9638          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9642 9639                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9643 9640                          scfdie();
9644 9641  
9645 9642                  if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9646 9643                      strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9647 9644                      strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9648 9645                          continue;
9649 9646                  } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9650 9647                          xmlNodePtr m;
9651 9648  
9652 9649                          m = xmlNewNode(NULL, (xmlChar *)"stability");
9653 9650                          if (m == NULL)
9654 9651                                  uu_die(emsg_create_xml);
9655 9652  
9656 9653                          if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9657 9654                                  elts.stability = m;
9658 9655                                  continue;
9659 9656                          }
9660 9657  
9661 9658                          xmlFreeNode(m);
9662 9659                  } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9663 9660                      0 ||
9664 9661                      strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9665 9662                      strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9666 9663                      strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9667 9664                          if (nonenv)
9668 9665                                  continue;
9669 9666                  } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9670 9667                      strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9671 9668                      strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9672 9669                      strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9673 9670                      strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9674 9671                      strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9675 9672                          if (nonenv && !use_profile)
9676 9673                                  continue;
9677 9674                  } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9678 9675                          if (nonenv && use_profile)
9679 9676                                  continue;
9680 9677                  } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9681 9678                          if (env != NULL)
9682 9679                                  continue;
9683 9680                  }
9684 9681  
9685 9682                  export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9686 9683          }
9687 9684          if (ret == -1)
9688 9685                  scfdie();
9689 9686  
9690 9687          (void) xmlAddChild(n, elts.stability);
9691 9688          (void) xmlAddChildList(n, elts.propvals);
9692 9689          (void) xmlAddChildList(n, elts.properties);
9693 9690  
9694 9691          if (eelts->exec_methods == NULL)
9695 9692                  eelts->exec_methods = n;
9696 9693          else
9697 9694                  (void) xmlAddSibling(eelts->exec_methods, n);
9698 9695  }
9699 9696  
9700 9697  static void
9701 9698  export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9702 9699      struct entity_elts *eelts)
9703 9700  {
9704 9701          xmlNodePtr pgnode;
9705 9702  
9706 9703          pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9707 9704          if (pgnode == NULL)
9708 9705                  uu_die(emsg_create_xml);
9709 9706  
9710 9707          safe_setprop(pgnode, name_attr, name);
9711 9708          safe_setprop(pgnode, type_attr, type);
9712 9709  
9713 9710          (void) xmlAddChildList(pgnode, elts->propvals);
9714 9711          (void) xmlAddChildList(pgnode, elts->properties);
9715 9712  
9716 9713          if (eelts->property_groups == NULL)
9717 9714                  eelts->property_groups = pgnode;
9718 9715          else
9719 9716                  (void) xmlAddSibling(eelts->property_groups, pgnode);
9720 9717  }
9721 9718  
9722 9719  /*
9723 9720   * Process the general property group for a service.  This is the one with the
9724 9721   * goodies.
9725 9722   */
9726 9723  static void
9727 9724  export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9728 9725  {
9729 9726          struct pg_elts elts;
9730 9727          int ret;
9731 9728  
9732 9729          /*
9733 9730           * In case there are properties which don't correspond to child
9734 9731           * entities of the service entity, we'll set up a pg_elts structure to
9735 9732           * put them in.
9736 9733           */
9737 9734          (void) memset(&elts, 0, sizeof (elts));
9738 9735  
9739 9736          /* Walk the properties, looking for special ones. */
9740 9737          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9741 9738                  scfdie();
9742 9739  
9743 9740          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9744 9741                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9745 9742                          scfdie();
9746 9743  
9747 9744                  if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9748 9745                          if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9749 9746                              prop_get_val(exp_prop, exp_val) == 0) {
9750 9747                                  uint8_t b;
9751 9748  
9752 9749                                  if (scf_value_get_boolean(exp_val, &b) !=
9753 9750                                      SCF_SUCCESS)
9754 9751                                          scfdie();
9755 9752  
9756 9753                                  if (b) {
9757 9754                                          selts->single_instance =
9758 9755                                              xmlNewNode(NULL,
9759 9756                                              (xmlChar *)"single_instance");
9760 9757                                          if (selts->single_instance == NULL)
9761 9758                                                  uu_die(emsg_create_xml);
9762 9759                                  }
9763 9760  
9764 9761                                  continue;
9765 9762                          }
9766 9763                  } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9767 9764                          xmlNodePtr rnode, sfnode;
9768 9765  
9769 9766                          rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9770 9767                          if (rnode == NULL)
9771 9768                                  uu_die(emsg_create_xml);
9772 9769  
9773 9770                          sfnode = xmlNewChild(rnode, NULL,
9774 9771                              (xmlChar *)"service_fmri", NULL);
9775 9772                          if (sfnode == NULL)
9776 9773                                  uu_die(emsg_create_xml);
9777 9774  
9778 9775                          if (set_attr_from_prop(exp_prop, sfnode,
9779 9776                              value_attr) == 0) {
9780 9777                                  selts->restarter = rnode;
9781 9778                                  continue;
9782 9779                          }
9783 9780  
9784 9781                          xmlFreeNode(rnode);
9785 9782                  } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9786 9783                      0) {
9787 9784                          xmlNodePtr s;
9788 9785  
9789 9786                          s = xmlNewNode(NULL, (xmlChar *)"stability");
9790 9787                          if (s == NULL)
9791 9788                                  uu_die(emsg_create_xml);
9792 9789  
9793 9790                          if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9794 9791                                  selts->stability = s;
9795 9792                                  continue;
9796 9793                          }
9797 9794  
9798 9795                          xmlFreeNode(s);
9799 9796                  }
9800 9797  
9801 9798                  export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9802 9799          }
9803 9800          if (ret == -1)
9804 9801                  scfdie();
9805 9802  
9806 9803          if (elts.propvals != NULL || elts.properties != NULL)
9807 9804                  export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9808 9805                      selts);
9809 9806  }
9810 9807  
9811 9808  static void
9812 9809  export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9813 9810  {
9814 9811          xmlNodePtr n, prof, cred, env;
9815 9812          uint8_t use_profile;
9816 9813          int ret, err = 0;
9817 9814  
9818 9815          n = xmlNewNode(NULL, (xmlChar *)"method_context");
9819 9816  
9820 9817          env = export_method_environment(pg);
9821 9818  
9822 9819          /* Need to know whether we'll use a profile or not. */
9823 9820          if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9824 9821              prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9825 9822              prop_get_val(exp_prop, exp_val) == 0) {
9826 9823                  if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9827 9824                          scfdie();
9828 9825  
9829 9826                  if (use_profile)
9830 9827                          prof =
9831 9828                              xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9832 9829                              NULL);
9833 9830                  else
9834 9831                          cred =
9835 9832                              xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9836 9833                              NULL);
9837 9834          }
9838 9835  
9839 9836          if (env != NULL)
9840 9837                  (void) xmlAddChild(n, env);
9841 9838  
9842 9839          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9843 9840                  scfdie();
9844 9841  
9845 9842          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9846 9843                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9847 9844                          scfdie();
9848 9845  
9849 9846                  if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9850 9847                          if (set_attr_from_prop(exp_prop, n,
9851 9848                              "working_directory") != 0)
9852 9849                                  err = 1;
9853 9850                  } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9854 9851                          if (set_attr_from_prop(exp_prop, n, "project") != 0)
9855 9852                                  err = 1;
9856 9853                  } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9857 9854                          if (set_attr_from_prop(exp_prop, n,
9858 9855                              "resource_pool") != 0)
9859 9856                                  err = 1;
9860 9857                  } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9861 9858                          if (set_attr_from_prop(exp_prop, n,
9862 9859                              "security_flags") != 0)
9863 9860                                  err = 1;
9864 9861                  } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9865 9862                          /* EMPTY */
9866 9863                  } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9867 9864                          if (use_profile ||
9868 9865                              set_attr_from_prop(exp_prop, cred, "user") != 0)
9869 9866                                  err = 1;
9870 9867                  } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9871 9868                          if (use_profile ||
9872 9869                              set_attr_from_prop(exp_prop, cred, "group") != 0)
9873 9870                                  err = 1;
9874 9871                  } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9875 9872                          if (use_profile || set_attr_from_prop(exp_prop, cred,
9876 9873                              "supp_groups") != 0)
9877 9874                                  err = 1;
9878 9875                  } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9879 9876                          if (use_profile || set_attr_from_prop(exp_prop, cred,
9880 9877                              "privileges") != 0)
9881 9878                                  err = 1;
9882 9879                  } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9883 9880                      0) {
9884 9881                          if (use_profile || set_attr_from_prop(exp_prop, cred,
9885 9882                              "limit_privileges") != 0)
9886 9883                                  err = 1;
9887 9884                  } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9888 9885                          if (!use_profile || set_attr_from_prop(exp_prop,
9889 9886                              prof, name_attr) != 0)
9890 9887                                  err = 1;
9891 9888                  } else {
9892 9889                          /* Can't have generic properties in method_context's */
9893 9890                          err = 1;
9894 9891                  }
9895 9892          }
9896 9893          if (ret == -1)
9897 9894                  scfdie();
9898 9895  
9899 9896          if (err && env == NULL) {
9900 9897                  xmlFreeNode(n);
9901 9898                  export_pg(pg, elts, SCE_ALL_VALUES);
9902 9899                  return;
9903 9900          }
9904 9901  
9905 9902          elts->method_context = n;
9906 9903  }
9907 9904  
9908 9905  /*
9909 9906   * Given a dependency property group in the tfmri entity (target fmri), return
9910 9907   * a dependent element which represents it.
9911 9908   */
9912 9909  static xmlNodePtr
9913 9910  export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9914 9911  {
9915 9912          uint8_t b;
9916 9913          xmlNodePtr n, sf;
9917 9914          int err = 0, ret;
9918 9915          struct pg_elts pgelts;
9919 9916  
9920 9917          /*
9921 9918           * If external isn't set to true then exporting the service will
9922 9919           * export this as a normal dependency, so we should stop to avoid
9923 9920           * duplication.
9924 9921           */
9925 9922          if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9926 9923              scf_property_get_value(exp_prop, exp_val) != 0 ||
9927 9924              scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9928 9925                  if (g_verbose) {
9929 9926                          warn(gettext("Dependent \"%s\" cannot be exported "
9930 9927                              "properly because the \"%s\" property of the "
9931 9928                              "\"%s\" dependency of %s is not set to true.\n"),
9932 9929                              name, scf_property_external, name, tfmri);
9933 9930                  }
9934 9931  
9935 9932                  return (NULL);
9936 9933          }
9937 9934  
9938 9935          n = xmlNewNode(NULL, (xmlChar *)"dependent");
9939 9936          if (n == NULL)
9940 9937                  uu_die(emsg_create_xml);
9941 9938  
9942 9939          safe_setprop(n, name_attr, name);
9943 9940  
9944 9941          /* Get the required attributes */
9945 9942          if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9946 9943              set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9947 9944                  err = 1;
9948 9945  
9949 9946          if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9950 9947              set_attr_from_prop(exp_prop, n, "grouping") != 0)
9951 9948                  err = 1;
9952 9949  
9953 9950          if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9954 9951              prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9955 9952              prop_get_val(exp_prop, exp_val) == 0) {
9956 9953                  /* EMPTY */
9957 9954          } else
9958 9955                  err = 1;
9959 9956  
9960 9957          if (err) {
9961 9958                  xmlFreeNode(n);
9962 9959                  return (NULL);
9963 9960          }
9964 9961  
9965 9962          sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9966 9963          if (sf == NULL)
9967 9964                  uu_die(emsg_create_xml);
9968 9965  
9969 9966          safe_setprop(sf, value_attr, tfmri);
9970 9967  
9971 9968          /*
9972 9969           * Now add elements for the other properties.
9973 9970           */
9974 9971          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9975 9972                  scfdie();
9976 9973  
9977 9974          (void) memset(&pgelts, 0, sizeof (pgelts));
9978 9975  
9979 9976          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9980 9977                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9981 9978                          scfdie();
9982 9979  
9983 9980                  if (strcmp(exp_str, scf_property_external) == 0 ||
9984 9981                      strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9985 9982                      strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9986 9983                      strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9987 9984                          continue;
9988 9985                  } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9989 9986                          if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9990 9987                              prop_get_val(exp_prop, exp_val) == 0) {
9991 9988                                  char type[sizeof ("service") + 1];
9992 9989  
9993 9990                                  if (scf_value_get_astring(exp_val, type,
9994 9991                                      sizeof (type)) < 0)
9995 9992                                          scfdie();
9996 9993  
9997 9994                                  if (strcmp(type, "service") == 0)
9998 9995                                          continue;
9999 9996                          }
10000 9997                  } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10001 9998                          xmlNodePtr s;
10002 9999  
10003 10000                          s = xmlNewNode(NULL, (xmlChar *)"stability");
10004 10001                          if (s == NULL)
10005 10002                                  uu_die(emsg_create_xml);
10006 10003  
10007 10004                          if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10008 10005                                  pgelts.stability = s;
10009 10006                                  continue;
10010 10007                          }
10011 10008  
10012 10009                          xmlFreeNode(s);
10013 10010                  }
10014 10011  
10015 10012                  export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10016 10013          }
10017 10014          if (ret == -1)
10018 10015                  scfdie();
10019 10016  
10020 10017          (void) xmlAddChild(n, pgelts.stability);
10021 10018          (void) xmlAddChildList(n, pgelts.propvals);
10022 10019          (void) xmlAddChildList(n, pgelts.properties);
10023 10020  
10024 10021          return (n);
10025 10022  }
10026 10023  
10027 10024  static void
10028 10025  export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10029 10026  {
10030 10027          scf_propertygroup_t *opg;
10031 10028          scf_iter_t *iter;
10032 10029          char *type, *fmri;
10033 10030          int ret;
10034 10031          struct pg_elts pgelts;
10035 10032          xmlNodePtr n;
10036 10033          scf_error_t serr;
10037 10034  
10038 10035          if ((opg = scf_pg_create(g_hndl)) == NULL ||
10039 10036              (iter = scf_iter_create(g_hndl)) == NULL)
10040 10037                  scfdie();
10041 10038  
10042 10039          /* Can't use exp_prop_iter due to export_dependent(). */
10043 10040          if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10044 10041                  scfdie();
10045 10042  
10046 10043          type = safe_malloc(max_scf_pg_type_len + 1);
10047 10044  
10048 10045          /* Get an extra byte so we can tell if values are too long. */
10049 10046          fmri = safe_malloc(max_scf_fmri_len + 2);
10050 10047  
10051 10048          (void) memset(&pgelts, 0, sizeof (pgelts));
10052 10049  
10053 10050          while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10054 10051                  void *entity;
10055 10052                  int isservice;
10056 10053                  scf_type_t ty;
10057 10054  
10058 10055                  if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10059 10056                          scfdie();
10060 10057  
10061 10058                  if ((ty != SCF_TYPE_ASTRING &&
10062 10059                      prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10063 10060                      prop_get_val(exp_prop, exp_val) != 0) {
10064 10061                          export_property(exp_prop, NULL, &pgelts,
10065 10062                              SCE_ALL_VALUES);
10066 10063                          continue;
10067 10064                  }
10068 10065  
10069 10066                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10070 10067                          scfdie();
10071 10068  
10072 10069                  if (scf_value_get_astring(exp_val, fmri,
10073 10070                      max_scf_fmri_len + 2) < 0)
10074 10071                          scfdie();
10075 10072  
10076 10073                  /* Look for a dependency group in the target fmri. */
10077 10074                  serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10078 10075                  switch (serr) {
10079 10076                  case SCF_ERROR_NONE:
10080 10077                          break;
10081 10078  
10082 10079                  case SCF_ERROR_NO_MEMORY:
10083 10080                          uu_die(gettext("Out of memory.\n"));
10084 10081                          /* NOTREACHED */
10085 10082  
10086 10083                  case SCF_ERROR_INVALID_ARGUMENT:
10087 10084                          if (g_verbose) {
10088 10085                                  if (scf_property_to_fmri(exp_prop, fmri,
10089 10086                                      max_scf_fmri_len + 2) < 0)
10090 10087                                          scfdie();
10091 10088  
10092 10089                                  warn(gettext("The value of %s is not a valid "
10093 10090                                      "FMRI.\n"), fmri);
10094 10091                          }
10095 10092  
10096 10093                          export_property(exp_prop, exp_str, &pgelts,
10097 10094                              SCE_ALL_VALUES);
10098 10095                          continue;
10099 10096  
10100 10097                  case SCF_ERROR_CONSTRAINT_VIOLATED:
10101 10098                          if (g_verbose) {
10102 10099                                  if (scf_property_to_fmri(exp_prop, fmri,
10103 10100                                      max_scf_fmri_len + 2) < 0)
10104 10101                                          scfdie();
10105 10102  
10106 10103                                  warn(gettext("The value of %s does not specify "
10107 10104                                      "a service or an instance.\n"), fmri);
10108 10105                          }
10109 10106  
10110 10107                          export_property(exp_prop, exp_str, &pgelts,
10111 10108                              SCE_ALL_VALUES);
10112 10109                          continue;
10113 10110  
10114 10111                  case SCF_ERROR_NOT_FOUND:
10115 10112                          if (g_verbose) {
10116 10113                                  if (scf_property_to_fmri(exp_prop, fmri,
10117 10114                                      max_scf_fmri_len + 2) < 0)
10118 10115                                          scfdie();
10119 10116  
10120 10117                                  warn(gettext("The entity specified by %s does "
10121 10118                                      "not exist.\n"), fmri);
10122 10119                          }
10123 10120  
10124 10121                          export_property(exp_prop, exp_str, &pgelts,
10125 10122                              SCE_ALL_VALUES);
10126 10123                          continue;
10127 10124  
10128 10125                  default:
10129 10126  #ifndef NDEBUG
10130 10127                          (void) fprintf(stderr, "%s:%d: %s() failed with "
10131 10128                              "unexpected error %d.\n", __FILE__, __LINE__,
10132 10129                              "fmri_to_entity", serr);
10133 10130  #endif
10134 10131                          abort();
10135 10132                  }
10136 10133  
10137 10134                  if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10138 10135                          if (scf_error() != SCF_ERROR_NOT_FOUND)
10139 10136                                  scfdie();
10140 10137  
10141 10138                          warn(gettext("Entity %s is missing dependency property "
10142 10139                              "group %s.\n"), fmri, exp_str);
10143 10140  
10144 10141                          export_property(exp_prop, NULL, &pgelts,
10145 10142                              SCE_ALL_VALUES);
10146 10143                          continue;
10147 10144                  }
10148 10145  
10149 10146                  if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10150 10147                          scfdie();
10151 10148  
10152 10149                  if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10153 10150                          if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10154 10151                                  scfdie();
10155 10152  
10156 10153                          warn(gettext("Property group %s is not of "
10157 10154                              "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10158 10155  
10159 10156                          export_property(exp_prop, NULL, &pgelts,
10160 10157                              SCE_ALL_VALUES);
10161 10158                          continue;
10162 10159                  }
10163 10160  
10164 10161                  n = export_dependent(opg, exp_str, fmri);
10165 10162                  if (n == NULL) {
10166 10163                          export_property(exp_prop, exp_str, &pgelts,
10167 10164                              SCE_ALL_VALUES);
10168 10165                  } else {
10169 10166                          if (eelts->dependents == NULL)
10170 10167                                  eelts->dependents = n;
10171 10168                          else
10172 10169                                  (void) xmlAddSibling(eelts->dependents,
10173 10170                                      n);
10174 10171                  }
10175 10172          }
10176 10173          if (ret == -1)
10177 10174                  scfdie();
10178 10175  
10179 10176          free(fmri);
10180 10177          free(type);
10181 10178  
10182 10179          scf_iter_destroy(iter);
10183 10180          scf_pg_destroy(opg);
10184 10181  
10185 10182          if (pgelts.propvals != NULL || pgelts.properties != NULL)
10186 10183                  export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10187 10184                      eelts);
10188 10185  }
10189 10186  
10190 10187  static void
10191 10188  make_node(xmlNodePtr *nodep, const char *name)
10192 10189  {
10193 10190          if (*nodep == NULL) {
10194 10191                  *nodep = xmlNewNode(NULL, (xmlChar *)name);
10195 10192                  if (*nodep == NULL)
10196 10193                          uu_die(emsg_create_xml);
10197 10194          }
10198 10195  }
10199 10196  
10200 10197  static xmlNodePtr
10201 10198  export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10202 10199  {
10203 10200          int ret;
10204 10201          xmlNodePtr parent = NULL;
10205 10202          xmlNodePtr loctext = NULL;
10206 10203  
10207 10204          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10208 10205                  scfdie();
10209 10206  
10210 10207          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10211 10208                  if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10212 10209                      prop_get_val(exp_prop, exp_val) != 0)
10213 10210                          continue;
10214 10211  
10215 10212                  if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10216 10213                          scfdie();
10217 10214  
10218 10215                  make_node(&parent, parname);
10219 10216                  loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10220 10217                      (xmlChar *)exp_str);
10221 10218                  if (loctext == NULL)
10222 10219                          uu_die(emsg_create_xml);
10223 10220  
10224 10221                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10225 10222                          scfdie();
10226 10223  
10227 10224                  safe_setprop(loctext, "xml:lang", exp_str);
10228 10225          }
10229 10226  
10230 10227          if (ret == -1)
10231 10228                  scfdie();
10232 10229  
10233 10230          return (parent);
10234 10231  }
10235 10232  
10236 10233  static xmlNodePtr
10237 10234  export_tm_manpage(scf_propertygroup_t *pg)
10238 10235  {
10239 10236          xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10240 10237          if (manpage == NULL)
10241 10238                  uu_die(emsg_create_xml);
10242 10239  
10243 10240          if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10244 10241              set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10245 10242              pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10246 10243              set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10247 10244                  xmlFreeNode(manpage);
10248 10245                  return (NULL);
10249 10246          }
10250 10247  
10251 10248          if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10252 10249                  (void) set_attr_from_prop_default(exp_prop,
10253 10250                      manpage, "manpath", ":default");
10254 10251  
10255 10252          return (manpage);
10256 10253  }
10257 10254  
10258 10255  static xmlNodePtr
10259 10256  export_tm_doc_link(scf_propertygroup_t *pg)
10260 10257  {
10261 10258          xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10262 10259          if (doc_link == NULL)
10263 10260                  uu_die(emsg_create_xml);
10264 10261  
10265 10262          if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10266 10263              set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10267 10264              pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10268 10265              set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10269 10266                  xmlFreeNode(doc_link);
10270 10267                  return (NULL);
10271 10268          }
10272 10269          return (doc_link);
10273 10270  }
10274 10271  
10275 10272  /*
10276 10273   * Process template information for a service or instances.
10277 10274   */
10278 10275  static void
10279 10276  export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10280 10277      struct template_elts *telts)
10281 10278  {
10282 10279          size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10283 10280          size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10284 10281          xmlNodePtr child = NULL;
10285 10282  
10286 10283          if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10287 10284                  scfdie();
10288 10285  
10289 10286          if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10290 10287                  telts->common_name = export_tm_loctext(pg, "common_name");
10291 10288                  if (telts->common_name == NULL)
10292 10289                          export_pg(pg, elts, SCE_ALL_VALUES);
10293 10290                  return;
10294 10291          } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10295 10292                  telts->description = export_tm_loctext(pg, "description");
10296 10293                  if (telts->description == NULL)
10297 10294                          export_pg(pg, elts, SCE_ALL_VALUES);
10298 10295                  return;
10299 10296          }
10300 10297  
10301 10298          if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10302 10299                  child = export_tm_manpage(pg);
10303 10300          } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10304 10301                  child = export_tm_doc_link(pg);
10305 10302          }
10306 10303  
10307 10304          if (child != NULL) {
10308 10305                  make_node(&telts->documentation, "documentation");
10309 10306                  (void) xmlAddChild(telts->documentation, child);
10310 10307          } else {
10311 10308                  export_pg(pg, elts, SCE_ALL_VALUES);
10312 10309          }
10313 10310  }
10314 10311  
10315 10312  /*
10316 10313   * Process parameter and paramval elements
10317 10314   */
10318 10315  static void
10319 10316  export_parameter(scf_property_t *prop, const char *name,
10320 10317      struct params_elts *elts)
10321 10318  {
10322 10319          xmlNodePtr param;
10323 10320          scf_error_t err = 0;
10324 10321          int ret;
10325 10322  
10326 10323          if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10327 10324                  if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10328 10325                          uu_die(emsg_create_xml);
10329 10326  
10330 10327                  safe_setprop(param, name_attr, name);
10331 10328  
10332 10329                  if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10333 10330                          scfdie();
10334 10331                  safe_setprop(param, value_attr, exp_str);
10335 10332  
10336 10333                  if (elts->paramval == NULL)
10337 10334                          elts->paramval = param;
10338 10335                  else
10339 10336                          (void) xmlAddSibling(elts->paramval, param);
10340 10337  
10341 10338                  return;
10342 10339          }
10343 10340  
10344 10341          err = scf_error();
10345 10342  
10346 10343          if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10347 10344              err != SCF_ERROR_NOT_FOUND)
10348 10345                  scfdie();
10349 10346  
10350 10347          if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10351 10348                  uu_die(emsg_create_xml);
10352 10349  
10353 10350          safe_setprop(param, name_attr, name);
10354 10351  
10355 10352          if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10356 10353                  if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10357 10354                          scfdie();
10358 10355  
10359 10356                  while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10360 10357                      1) {
10361 10358                          xmlNodePtr vn;
10362 10359  
10363 10360                          if ((vn = xmlNewChild(param, NULL,
10364 10361                              (xmlChar *)"value_node", NULL)) == NULL)
10365 10362                                  uu_die(emsg_create_xml);
10366 10363  
10367 10364                          if (scf_value_get_as_string(exp_val, exp_str,
10368 10365                              exp_str_sz) < 0)
10369 10366                                  scfdie();
10370 10367  
10371 10368                          safe_setprop(vn, value_attr, exp_str);
10372 10369                  }
10373 10370                  if (ret != 0)
10374 10371                          scfdie();
10375 10372          }
10376 10373  
10377 10374          if (elts->parameter == NULL)
10378 10375                  elts->parameter = param;
10379 10376          else
10380 10377                  (void) xmlAddSibling(elts->parameter, param);
10381 10378  }
10382 10379  
10383 10380  /*
10384 10381   * Process notification parameters for a service or instance
10385 10382   */
10386 10383  static void
10387 10384  export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10388 10385  {
10389 10386          xmlNodePtr n, event, *type;
10390 10387          struct params_elts *eelts;
10391 10388          int ret, err, i;
10392 10389  
10393 10390          n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10394 10391          event = xmlNewNode(NULL, (xmlChar *)"event");
10395 10392          if (n == NULL || event == NULL)
10396 10393                  uu_die(emsg_create_xml);
10397 10394  
10398 10395          /* event value */
10399 10396          if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10400 10397                  scfdie();
10401 10398          safe_setprop(event, value_attr, exp_str);
10402 10399  
10403 10400          (void) xmlAddChild(n, event);
10404 10401  
10405 10402          if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10406 10403              (eelts = calloc(URI_SCHEME_NUM,
10407 10404              sizeof (struct params_elts))) == NULL)
10408 10405                  uu_die(gettext("Out of memory.\n"));
10409 10406  
10410 10407          err = 0;
10411 10408  
10412 10409          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10413 10410                  scfdie();
10414 10411  
10415 10412          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10416 10413                  char *t, *p;
10417 10414  
10418 10415                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10419 10416                          scfdie();
10420 10417  
10421 10418                  if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10422 10419                          /*
10423 10420                           * this is not a well formed notification parameters
10424 10421                           * element, we should export as regular pg
10425 10422                           */
10426 10423                          err = 1;
10427 10424                          break;
10428 10425                  }
10429 10426  
10430 10427                  if ((i = check_uri_protocol(t)) < 0) {
10431 10428                          err = 1;
10432 10429                          break;
10433 10430                  }
10434 10431  
10435 10432                  if (type[i] == NULL) {
10436 10433                          if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10437 10434                              NULL)
10438 10435                                  uu_die(emsg_create_xml);
10439 10436  
10440 10437                          safe_setprop(type[i], name_attr, t);
10441 10438                  }
10442 10439                  if (strcmp(p, active_attr) == 0) {
10443 10440                          if (set_attr_from_prop(exp_prop, type[i],
10444 10441                              active_attr) != 0) {
10445 10442                                  err = 1;
10446 10443                                  break;
10447 10444                          }
10448 10445                          continue;
10449 10446                  }
10450 10447                  /*
10451 10448                   * We export the parameter
10452 10449                   */
10453 10450                  export_parameter(exp_prop, p, &eelts[i]);
10454 10451          }
10455 10452  
10456 10453          if (ret == -1)
10457 10454                  scfdie();
10458 10455  
10459 10456          if (err == 1) {
10460 10457                  for (i = 0; i < URI_SCHEME_NUM; ++i)
10461 10458                          xmlFree(type[i]);
10462 10459                  free(type);
10463 10460  
10464 10461                  export_pg(pg, elts, SCE_ALL_VALUES);
10465 10462  
10466 10463                  return;
10467 10464          } else {
10468 10465                  for (i = 0; i < URI_SCHEME_NUM; ++i)
10469 10466                          if (type[i] != NULL) {
10470 10467                                  (void) xmlAddChildList(type[i],
10471 10468                                      eelts[i].paramval);
10472 10469                                  (void) xmlAddChildList(type[i],
10473 10470                                      eelts[i].parameter);
10474 10471                                  (void) xmlAddSibling(event, type[i]);
10475 10472                          }
10476 10473          }
10477 10474          free(type);
10478 10475  
10479 10476          if (elts->notify_params == NULL)
10480 10477                  elts->notify_params = n;
10481 10478          else
10482 10479                  (void) xmlAddSibling(elts->notify_params, n);
10483 10480  }
10484 10481  
10485 10482  /*
10486 10483   * Process the general property group for an instance.
10487 10484   */
10488 10485  static void
10489 10486  export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10490 10487      struct entity_elts *elts)
10491 10488  {
10492 10489          uint8_t enabled;
10493 10490          struct pg_elts pgelts;
10494 10491          int ret;
10495 10492  
10496 10493          /* enabled */
10497 10494          if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10498 10495              prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10499 10496              prop_get_val(exp_prop, exp_val) == 0) {
10500 10497                  if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10501 10498                          scfdie();
10502 10499          } else {
10503 10500                  enabled = 0;
10504 10501          }
10505 10502  
10506 10503          safe_setprop(inode, enabled_attr, enabled ? true : false);
10507 10504  
10508 10505          if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10509 10506                  scfdie();
10510 10507  
10511 10508          (void) memset(&pgelts, 0, sizeof (pgelts));
10512 10509  
10513 10510          while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10514 10511                  if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10515 10512                          scfdie();
10516 10513  
10517 10514                  if (strcmp(exp_str, scf_property_enabled) == 0) {
10518 10515                          continue;
10519 10516                  } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10520 10517                          xmlNodePtr rnode, sfnode;
10521 10518  
10522 10519                          rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10523 10520                          if (rnode == NULL)
10524 10521                                  uu_die(emsg_create_xml);
10525 10522  
10526 10523                          sfnode = xmlNewChild(rnode, NULL,
10527 10524                              (xmlChar *)"service_fmri", NULL);
10528 10525                          if (sfnode == NULL)
10529 10526                                  uu_die(emsg_create_xml);
10530 10527  
10531 10528                          if (set_attr_from_prop(exp_prop, sfnode,
10532 10529                              value_attr) == 0) {
10533 10530                                  elts->restarter = rnode;
10534 10531                                  continue;
10535 10532                          }
10536 10533  
10537 10534                          xmlFreeNode(rnode);
10538 10535                  }
10539 10536  
10540 10537                  export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10541 10538          }
10542 10539          if (ret == -1)
10543 10540                  scfdie();
10544 10541  
10545 10542          if (pgelts.propvals != NULL || pgelts.properties != NULL)
10546 10543                  export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10547 10544                      elts);
10548 10545  }
10549 10546  
10550 10547  /*
10551 10548   * Put an instance element for the given instance into selts.
10552 10549   */
10553 10550  static void
10554 10551  export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10555 10552  {
10556 10553          xmlNodePtr n;
10557 10554          boolean_t isdefault;
10558 10555          struct entity_elts elts;
10559 10556          struct template_elts template_elts;
10560 10557          int ret;
10561 10558  
10562 10559          n = xmlNewNode(NULL, (xmlChar *)"instance");
10563 10560          if (n == NULL)
10564 10561                  uu_die(emsg_create_xml);
10565 10562  
10566 10563          /* name */
10567 10564          if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10568 10565                  scfdie();
10569 10566          safe_setprop(n, name_attr, exp_str);
10570 10567          isdefault = strcmp(exp_str, "default") == 0;
10571 10568  
10572 10569          /* check existance of general pg (since general/enabled is required) */
10573 10570          if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10574 10571                  if (scf_error() != SCF_ERROR_NOT_FOUND)
10575 10572                          scfdie();
10576 10573  
10577 10574                  if (g_verbose) {
10578 10575                          if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10579 10576                                  scfdie();
10580 10577  
10581 10578                          warn(gettext("Instance %s has no general property "
10582 10579                              "group; it will be marked disabled.\n"), exp_str);
10583 10580                  }
10584 10581  
10585 10582                  safe_setprop(n, enabled_attr, false);
10586 10583          } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10587 10584              strcmp(exp_str, scf_group_framework) != 0) {
10588 10585                  if (g_verbose) {
10589 10586                          if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10590 10587                                  scfdie();
10591 10588  
10592 10589                          warn(gettext("Property group %s is not of type "
10593 10590                              "framework; the instance will be marked "
10594 10591                              "disabled.\n"), exp_str);
10595 10592                  }
10596 10593  
10597 10594                  safe_setprop(n, enabled_attr, false);
10598 10595          }
10599 10596  
10600 10597          /* property groups */
10601 10598          if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10602 10599                  scfdie();
10603 10600  
10604 10601          (void) memset(&elts, 0, sizeof (elts));
10605 10602          (void) memset(&template_elts, 0, sizeof (template_elts));
10606 10603  
10607 10604          while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10608 10605                  uint32_t pgflags;
10609 10606  
10610 10607                  if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10611 10608                          scfdie();
10612 10609  
10613 10610                  if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10614 10611                          continue;
10615 10612  
10616 10613                  if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10617 10614                          scfdie();
10618 10615  
10619 10616                  if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10620 10617                          export_dependency(exp_pg, &elts);
10621 10618                          continue;
10622 10619                  } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10623 10620                          export_method(exp_pg, &elts);
10624 10621                          continue;
10625 10622                  } else if (strcmp(exp_str, scf_group_framework) == 0) {
10626 10623                          if (scf_pg_get_name(exp_pg, exp_str,
10627 10624                              max_scf_name_len + 1) < 0)
10628 10625                                  scfdie();
10629 10626  
10630 10627                          if (strcmp(exp_str, scf_pg_general) == 0) {
10631 10628                                  export_inst_general(exp_pg, n, &elts);
10632 10629                                  continue;
10633 10630                          } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10634 10631                              0) {
10635 10632                                  export_method_context(exp_pg, &elts);
10636 10633                                  continue;
10637 10634                          } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10638 10635                                  export_dependents(exp_pg, &elts);
10639 10636                                  continue;
10640 10637                          }
10641 10638                  } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10642 10639                          export_template(exp_pg, &elts, &template_elts);
10643 10640                          continue;
10644 10641                  } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10645 10642                          export_notify_params(exp_pg, &elts);
10646 10643                          continue;
10647 10644                  }
10648 10645  
10649 10646                  /* Ordinary pg. */
10650 10647                  export_pg(exp_pg, &elts, flags);
10651 10648          }
10652 10649          if (ret == -1)
10653 10650                  scfdie();
10654 10651  
10655 10652          if (template_elts.common_name != NULL) {
10656 10653                  elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10657 10654                  (void) xmlAddChild(elts.template, template_elts.common_name);
10658 10655                  (void) xmlAddChild(elts.template, template_elts.description);
10659 10656                  (void) xmlAddChild(elts.template, template_elts.documentation);
10660 10657          } else {
10661 10658                  xmlFreeNode(template_elts.description);
10662 10659                  xmlFreeNode(template_elts.documentation);
10663 10660          }
10664 10661  
10665 10662          if (isdefault && elts.restarter == NULL &&
10666 10663              elts.dependencies == NULL && elts.method_context == NULL &&
10667 10664              elts.exec_methods == NULL && elts.notify_params == NULL &&
10668 10665              elts.property_groups == NULL && elts.template == NULL) {
10669 10666                  xmlChar *eval;
10670 10667  
10671 10668                  /* This is a default instance */
10672 10669                  eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10673 10670  
10674 10671                  xmlFreeNode(n);
10675 10672  
10676 10673                  n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10677 10674                  if (n == NULL)
10678 10675                          uu_die(emsg_create_xml);
10679 10676  
10680 10677                  safe_setprop(n, enabled_attr, (char *)eval);
10681 10678                  xmlFree(eval);
10682 10679  
10683 10680                  selts->create_default_instance = n;
10684 10681          } else {
10685 10682                  /* Assemble the children in order. */
10686 10683                  (void) xmlAddChild(n, elts.restarter);
10687 10684                  (void) xmlAddChildList(n, elts.dependencies);
10688 10685                  (void) xmlAddChildList(n, elts.dependents);
10689 10686                  (void) xmlAddChild(n, elts.method_context);
10690 10687                  (void) xmlAddChildList(n, elts.exec_methods);
10691 10688                  (void) xmlAddChildList(n, elts.notify_params);
10692 10689                  (void) xmlAddChildList(n, elts.property_groups);
10693 10690                  (void) xmlAddChild(n, elts.template);
10694 10691  
10695 10692                  if (selts->instances == NULL)
10696 10693                          selts->instances = n;
10697 10694                  else
10698 10695                          (void) xmlAddSibling(selts->instances, n);
10699 10696          }
10700 10697  }
10701 10698  
10702 10699  /*
10703 10700   * Return a service element for the given service.
10704 10701   */
10705 10702  static xmlNodePtr
10706 10703  export_service(scf_service_t *svc, int flags)
10707 10704  {
10708 10705          xmlNodePtr snode;
10709 10706          struct entity_elts elts;
10710 10707          struct template_elts template_elts;
10711 10708          int ret;
10712 10709  
10713 10710          snode = xmlNewNode(NULL, (xmlChar *)"service");
10714 10711          if (snode == NULL)
10715 10712                  uu_die(emsg_create_xml);
10716 10713  
10717 10714          /* Get & set name attribute */
10718 10715          if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10719 10716                  scfdie();
10720 10717          safe_setprop(snode, name_attr, exp_str);
10721 10718  
10722 10719          safe_setprop(snode, type_attr, "service");
10723 10720          safe_setprop(snode, "version", "0");
10724 10721  
10725 10722          /* Acquire child elements. */
10726 10723          if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10727 10724                  scfdie();
10728 10725  
10729 10726          (void) memset(&elts, 0, sizeof (elts));
10730 10727          (void) memset(&template_elts, 0, sizeof (template_elts));
10731 10728  
10732 10729          while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10733 10730                  uint32_t pgflags;
10734 10731  
10735 10732                  if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10736 10733                          scfdie();
10737 10734  
10738 10735                  if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10739 10736                          continue;
10740 10737  
10741 10738                  if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10742 10739                          scfdie();
10743 10740  
10744 10741                  if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10745 10742                          export_dependency(exp_pg, &elts);
10746 10743                          continue;
10747 10744                  } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10748 10745                          export_method(exp_pg, &elts);
10749 10746                          continue;
10750 10747                  } else if (strcmp(exp_str, scf_group_framework) == 0) {
10751 10748                          if (scf_pg_get_name(exp_pg, exp_str,
10752 10749                              max_scf_name_len + 1) < 0)
10753 10750                                  scfdie();
10754 10751  
10755 10752                          if (strcmp(exp_str, scf_pg_general) == 0) {
10756 10753                                  export_svc_general(exp_pg, &elts);
10757 10754                                  continue;
10758 10755                          } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10759 10756                              0) {
10760 10757                                  export_method_context(exp_pg, &elts);
10761 10758                                  continue;
10762 10759                          } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10763 10760                                  export_dependents(exp_pg, &elts);
10764 10761                                  continue;
10765 10762                          } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10766 10763                                  continue;
10767 10764                          }
10768 10765                  } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10769 10766                          export_template(exp_pg, &elts, &template_elts);
10770 10767                          continue;
10771 10768                  } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10772 10769                          export_notify_params(exp_pg, &elts);
10773 10770                          continue;
10774 10771                  }
10775 10772  
10776 10773                  export_pg(exp_pg, &elts, flags);
10777 10774          }
10778 10775          if (ret == -1)
10779 10776                  scfdie();
10780 10777  
10781 10778          if (template_elts.common_name != NULL) {
10782 10779                  elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10783 10780                  (void) xmlAddChild(elts.template, template_elts.common_name);
10784 10781                  (void) xmlAddChild(elts.template, template_elts.description);
10785 10782                  (void) xmlAddChild(elts.template, template_elts.documentation);
10786 10783          } else {
10787 10784                  xmlFreeNode(template_elts.description);
10788 10785                  xmlFreeNode(template_elts.documentation);
10789 10786          }
10790 10787  
10791 10788          /* Iterate instances */
10792 10789          if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10793 10790                  scfdie();
10794 10791  
10795 10792          while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10796 10793                  export_instance(exp_inst, &elts, flags);
10797 10794          if (ret == -1)
10798 10795                  scfdie();
10799 10796  
10800 10797          /* Now add all of the accumulated elements in order. */
10801 10798          (void) xmlAddChild(snode, elts.create_default_instance);
10802 10799          (void) xmlAddChild(snode, elts.single_instance);
10803 10800          (void) xmlAddChild(snode, elts.restarter);
10804 10801          (void) xmlAddChildList(snode, elts.dependencies);
10805 10802          (void) xmlAddChildList(snode, elts.dependents);
10806 10803          (void) xmlAddChild(snode, elts.method_context);
10807 10804          (void) xmlAddChildList(snode, elts.exec_methods);
10808 10805          (void) xmlAddChildList(snode, elts.notify_params);
10809 10806          (void) xmlAddChildList(snode, elts.property_groups);
10810 10807          (void) xmlAddChildList(snode, elts.instances);
10811 10808          (void) xmlAddChild(snode, elts.stability);
10812 10809          (void) xmlAddChild(snode, elts.template);
10813 10810  
10814 10811          return (snode);
10815 10812  }
10816 10813  
10817 10814  static int
10818 10815  export_callback(void *data, scf_walkinfo_t *wip)
10819 10816  {
10820 10817          FILE *f;
10821 10818          xmlDocPtr doc;
10822 10819          xmlNodePtr sb;
10823 10820          int result;
10824 10821          struct export_args *argsp = (struct export_args *)data;
10825 10822  
10826 10823          if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10827 10824              (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10828 10825              (exp_prop = scf_property_create(g_hndl)) == NULL ||
10829 10826              (exp_val = scf_value_create(g_hndl)) == NULL ||
10830 10827              (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10831 10828              (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10832 10829              (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10833 10830              (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10834 10831                  scfdie();
10835 10832  
10836 10833          exp_str_sz = max_scf_len + 1;
10837 10834          exp_str = safe_malloc(exp_str_sz);
10838 10835  
10839 10836          if (argsp->filename != NULL) {
10840 10837                  errno = 0;
10841 10838                  f = fopen(argsp->filename, "wb");
10842 10839                  if (f == NULL) {
10843 10840                          if (errno == 0)
10844 10841                                  uu_die(gettext("Could not open \"%s\": no free "
10845 10842                                      "stdio streams.\n"), argsp->filename);
10846 10843                          else
10847 10844                                  uu_die(gettext("Could not open \"%s\""),
10848 10845                                      argsp->filename);
10849 10846                  }
10850 10847          } else
10851 10848                  f = stdout;
10852 10849  
10853 10850          doc = xmlNewDoc((xmlChar *)"1.0");
10854 10851          if (doc == NULL)
10855 10852                  uu_die(gettext("Could not create XML document.\n"));
10856 10853  
10857 10854          if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10858 10855              (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10859 10856                  uu_die(emsg_create_xml);
10860 10857  
10861 10858          sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10862 10859          if (sb == NULL)
10863 10860                  uu_die(emsg_create_xml);
10864 10861          safe_setprop(sb, type_attr, "manifest");
10865 10862          safe_setprop(sb, name_attr, "export");
10866 10863          (void) xmlAddSibling(doc->children, sb);
10867 10864  
10868 10865          (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10869 10866  
10870 10867          result = write_service_bundle(doc, f);
10871 10868  
10872 10869          free(exp_str);
10873 10870          scf_iter_destroy(exp_val_iter);
10874 10871          scf_iter_destroy(exp_prop_iter);
10875 10872          scf_iter_destroy(exp_pg_iter);
10876 10873          scf_iter_destroy(exp_inst_iter);
10877 10874          scf_value_destroy(exp_val);
10878 10875          scf_property_destroy(exp_prop);
10879 10876          scf_pg_destroy(exp_pg);
10880 10877          scf_instance_destroy(exp_inst);
10881 10878  
10882 10879          xmlFreeDoc(doc);
10883 10880  
10884 10881          if (f != stdout)
10885 10882                  (void) fclose(f);
10886 10883  
10887 10884          return (result);
10888 10885  }
10889 10886  
10890 10887  /*
10891 10888   * Get the service named by fmri, build an XML tree which represents it, and
10892 10889   * dump it into filename (or stdout if filename is NULL).
10893 10890   */
10894 10891  int
10895 10892  lscf_service_export(char *fmri, const char *filename, int flags)
10896 10893  {
10897 10894          struct export_args args;
10898 10895          char *fmridup;
10899 10896          const char *scope, *svc, *inst;
10900 10897          size_t cblen = 3 * max_scf_name_len;
10901 10898          char *canonbuf = alloca(cblen);
10902 10899          int ret, err;
10903 10900  
10904 10901          lscf_prep_hndl();
10905 10902  
10906 10903          bzero(&args, sizeof (args));
10907 10904          args.filename = filename;
10908 10905          args.flags = flags;
10909 10906  
10910 10907          /*
10911 10908           * If some poor user has passed an exact instance FMRI, of the sort
10912 10909           * one might cut and paste from svcs(1) or an error message, warn
10913 10910           * and chop off the instance instead of failing.
10914 10911           */
10915 10912          fmridup = alloca(strlen(fmri) + 1);
10916 10913          (void) strcpy(fmridup, fmri);
10917 10914          if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10918 10915              sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10919 10916              scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10920 10917              inst != NULL) {
10921 10918                  (void) strlcpy(canonbuf, "svc:/", cblen);
10922 10919                  if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10923 10920                          (void) strlcat(canonbuf, "/", cblen);
10924 10921                          (void) strlcat(canonbuf, scope, cblen);
10925 10922                  }
10926 10923                  (void) strlcat(canonbuf, svc, cblen);
10927 10924                  fmri = canonbuf;
10928 10925  
10929 10926                  warn(gettext("Only services may be exported; ignoring "
10930 10927                      "instance portion of argument.\n"));
10931 10928          }
10932 10929  
10933 10930          err = 0;
10934 10931          if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10935 10932              SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10936 10933              &args, &err, semerr)) != 0) {
10937 10934                  if (ret != -1)
10938 10935                          semerr(gettext("Failed to walk instances: %s\n"),
10939 10936                              scf_strerror(ret));
10940 10937                  return (-1);
10941 10938          }
10942 10939  
10943 10940          /*
10944 10941           * Error message has already been printed.
10945 10942           */
10946 10943          if (err != 0)
10947 10944                  return (-1);
10948 10945  
10949 10946          return (0);
10950 10947  }
10951 10948  
10952 10949  
10953 10950  /*
10954 10951   * Archive
10955 10952   */
10956 10953  
10957 10954  static xmlNodePtr
10958 10955  make_archive(int flags)
10959 10956  {
10960 10957          xmlNodePtr sb;
10961 10958          scf_scope_t *scope;
10962 10959          scf_service_t *svc;
10963 10960          scf_iter_t *iter;
10964 10961          int r;
10965 10962  
10966 10963          if ((scope = scf_scope_create(g_hndl)) == NULL ||
10967 10964              (svc = scf_service_create(g_hndl)) == NULL ||
10968 10965              (iter = scf_iter_create(g_hndl)) == NULL ||
10969 10966              (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10970 10967              (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10971 10968              (exp_prop = scf_property_create(g_hndl)) == NULL ||
10972 10969              (exp_val = scf_value_create(g_hndl)) == NULL ||
10973 10970              (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10974 10971              (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10975 10972              (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10976 10973              (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10977 10974                  scfdie();
10978 10975  
10979 10976          exp_str_sz = max_scf_len + 1;
10980 10977          exp_str = safe_malloc(exp_str_sz);
10981 10978  
10982 10979          sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10983 10980          if (sb == NULL)
10984 10981                  uu_die(emsg_create_xml);
10985 10982          safe_setprop(sb, type_attr, "archive");
10986 10983          safe_setprop(sb, name_attr, "none");
10987 10984  
10988 10985          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10989 10986                  scfdie();
10990 10987          if (scf_iter_scope_services(iter, scope) != 0)
10991 10988                  scfdie();
10992 10989  
10993 10990          for (;;) {
10994 10991                  r = scf_iter_next_service(iter, svc);
10995 10992                  if (r == 0)
10996 10993                          break;
10997 10994                  if (r != 1)
10998 10995                          scfdie();
10999 10996  
11000 10997                  if (scf_service_get_name(svc, exp_str,
11001 10998                      max_scf_name_len + 1) < 0)
11002 10999                          scfdie();
11003 11000  
11004 11001                  if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11005 11002                          continue;
11006 11003  
11007 11004                  (void) xmlAddChild(sb, export_service(svc, flags));
11008 11005          }
11009 11006  
11010 11007          free(exp_str);
11011 11008  
11012 11009          scf_iter_destroy(exp_val_iter);
11013 11010          scf_iter_destroy(exp_prop_iter);
11014 11011          scf_iter_destroy(exp_pg_iter);
11015 11012          scf_iter_destroy(exp_inst_iter);
11016 11013          scf_value_destroy(exp_val);
11017 11014          scf_property_destroy(exp_prop);
11018 11015          scf_pg_destroy(exp_pg);
11019 11016          scf_instance_destroy(exp_inst);
11020 11017          scf_iter_destroy(iter);
11021 11018          scf_service_destroy(svc);
11022 11019          scf_scope_destroy(scope);
11023 11020  
11024 11021          return (sb);
11025 11022  }
11026 11023  
11027 11024  int
11028 11025  lscf_archive(const char *filename, int flags)
11029 11026  {
11030 11027          FILE *f;
11031 11028          xmlDocPtr doc;
11032 11029          int result;
11033 11030  
11034 11031          lscf_prep_hndl();
11035 11032  
11036 11033          if (filename != NULL) {
11037 11034                  errno = 0;
11038 11035                  f = fopen(filename, "wb");
11039 11036                  if (f == NULL) {
11040 11037                          if (errno == 0)
11041 11038                                  uu_die(gettext("Could not open \"%s\": no free "
11042 11039                                      "stdio streams.\n"), filename);
11043 11040                          else
11044 11041                                  uu_die(gettext("Could not open \"%s\""),
11045 11042                                      filename);
11046 11043                  }
11047 11044          } else
11048 11045                  f = stdout;
11049 11046  
11050 11047          doc = xmlNewDoc((xmlChar *)"1.0");
11051 11048          if (doc == NULL)
11052 11049                  uu_die(gettext("Could not create XML document.\n"));
11053 11050  
11054 11051          if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11055 11052              (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11056 11053                  uu_die(emsg_create_xml);
11057 11054  
11058 11055          (void) xmlAddSibling(doc->children, make_archive(flags));
11059 11056  
11060 11057          result = write_service_bundle(doc, f);
11061 11058  
11062 11059          xmlFreeDoc(doc);
11063 11060  
11064 11061          if (f != stdout)
11065 11062                  (void) fclose(f);
11066 11063  
11067 11064          return (result);
11068 11065  }
11069 11066  
11070 11067  
11071 11068  /*
11072 11069   * "Extract" a profile.
11073 11070   */
11074 11071  int
11075 11072  lscf_profile_extract(const char *filename)
11076 11073  {
11077 11074          FILE *f;
11078 11075          xmlDocPtr doc;
11079 11076          xmlNodePtr sb, snode, inode;
11080 11077          scf_scope_t *scope;
11081 11078          scf_service_t *svc;
11082 11079          scf_instance_t *inst;
11083 11080          scf_propertygroup_t *pg;
11084 11081          scf_property_t *prop;
11085 11082          scf_value_t *val;
11086 11083          scf_iter_t *siter, *iiter;
11087 11084          int r, s;
11088 11085          char *namebuf;
11089 11086          uint8_t b;
11090 11087          int result;
11091 11088  
11092 11089          lscf_prep_hndl();
11093 11090  
11094 11091          if (filename != NULL) {
11095 11092                  errno = 0;
11096 11093                  f = fopen(filename, "wb");
11097 11094                  if (f == NULL) {
11098 11095                          if (errno == 0)
11099 11096                                  uu_die(gettext("Could not open \"%s\": no "
11100 11097                                      "free stdio streams.\n"), filename);
11101 11098                          else
11102 11099                                  uu_die(gettext("Could not open \"%s\""),
11103 11100                                      filename);
11104 11101                  }
11105 11102          } else
11106 11103                  f = stdout;
11107 11104  
11108 11105          doc = xmlNewDoc((xmlChar *)"1.0");
11109 11106          if (doc == NULL)
11110 11107                  uu_die(gettext("Could not create XML document.\n"));
11111 11108  
11112 11109          if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11113 11110              (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11114 11111                  uu_die(emsg_create_xml);
11115 11112  
11116 11113          sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11117 11114          if (sb == NULL)
11118 11115                  uu_die(emsg_create_xml);
11119 11116          safe_setprop(sb, type_attr, "profile");
11120 11117          safe_setprop(sb, name_attr, "extract");
11121 11118          (void) xmlAddSibling(doc->children, sb);
11122 11119  
11123 11120          if ((scope = scf_scope_create(g_hndl)) == NULL ||
11124 11121              (svc = scf_service_create(g_hndl)) == NULL ||
11125 11122              (inst = scf_instance_create(g_hndl)) == NULL ||
11126 11123              (pg = scf_pg_create(g_hndl)) == NULL ||
11127 11124              (prop = scf_property_create(g_hndl)) == NULL ||
11128 11125              (val = scf_value_create(g_hndl)) == NULL ||
11129 11126              (siter = scf_iter_create(g_hndl)) == NULL ||
11130 11127              (iiter = scf_iter_create(g_hndl)) == NULL)
11131 11128                  scfdie();
11132 11129  
11133 11130          if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11134 11131                  scfdie();
11135 11132  
11136 11133          if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11137 11134                  scfdie();
11138 11135  
11139 11136          namebuf = safe_malloc(max_scf_name_len + 1);
11140 11137  
11141 11138          while ((r = scf_iter_next_service(siter, svc)) == 1) {
11142 11139                  if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11143 11140                          scfdie();
11144 11141  
11145 11142                  snode = xmlNewNode(NULL, (xmlChar *)"service");
11146 11143                  if (snode == NULL)
11147 11144                          uu_die(emsg_create_xml);
11148 11145  
11149 11146                  if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11150 11147                      0)
11151 11148                          scfdie();
11152 11149  
11153 11150                  safe_setprop(snode, name_attr, namebuf);
11154 11151  
11155 11152                  safe_setprop(snode, type_attr, "service");
11156 11153                  safe_setprop(snode, "version", "0");
11157 11154  
11158 11155                  while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11159 11156                          if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11160 11157                              SCF_SUCCESS) {
11161 11158                                  if (scf_error() != SCF_ERROR_NOT_FOUND)
11162 11159                                          scfdie();
11163 11160  
11164 11161                                  if (g_verbose) {
11165 11162                                          ssize_t len;
11166 11163                                          char *fmri;
11167 11164  
11168 11165                                          len =
11169 11166                                              scf_instance_to_fmri(inst, NULL, 0);
11170 11167                                          if (len < 0)
11171 11168                                                  scfdie();
11172 11169  
11173 11170                                          fmri = safe_malloc(len + 1);
11174 11171  
11175 11172                                          if (scf_instance_to_fmri(inst, fmri,
11176 11173                                              len + 1) < 0)
11177 11174                                                  scfdie();
11178 11175  
11179 11176                                          warn("Instance %s has no \"%s\" "
11180 11177                                              "property group.\n", fmri,
11181 11178                                              scf_pg_general);
11182 11179  
11183 11180                                          free(fmri);
11184 11181                                  }
11185 11182  
11186 11183                                  continue;
11187 11184                          }
11188 11185  
11189 11186                          if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11190 11187                              prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11191 11188                              prop_get_val(prop, val) != 0)
11192 11189                                  continue;
11193 11190  
11194 11191                          inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11195 11192                              NULL);
11196 11193                          if (inode == NULL)
11197 11194                                  uu_die(emsg_create_xml);
11198 11195  
11199 11196                          if (scf_instance_get_name(inst, namebuf,
11200 11197                              max_scf_name_len + 1) < 0)
11201 11198                                  scfdie();
11202 11199  
11203 11200                          safe_setprop(inode, name_attr, namebuf);
11204 11201  
11205 11202                          if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11206 11203                                  scfdie();
11207 11204  
11208 11205                          safe_setprop(inode, enabled_attr, b ? true : false);
11209 11206                  }
11210 11207                  if (s < 0)
11211 11208                          scfdie();
11212 11209  
11213 11210                  if (snode->children != NULL)
11214 11211                          (void) xmlAddChild(sb, snode);
11215 11212                  else
11216 11213                          xmlFreeNode(snode);
11217 11214          }
11218 11215          if (r < 0)
11219 11216                  scfdie();
11220 11217  
11221 11218          free(namebuf);
11222 11219  
11223 11220          result = write_service_bundle(doc, f);
11224 11221  
11225 11222          xmlFreeDoc(doc);
11226 11223  
11227 11224          if (f != stdout)
11228 11225                  (void) fclose(f);
11229 11226  
11230 11227          return (result);
11231 11228  }
11232 11229  
11233 11230  
11234 11231  /*
11235 11232   * Entity manipulation commands
11236 11233   */
11237 11234  
11238 11235  /*
11239 11236   * Entity selection.  If no entity is selected, then the current scope is in
11240 11237   * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11241 11238   * only cur_inst is NULL, and when an instance is selected, none are NULL.
11242 11239   * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11243 11240   * cur_inst will be non-NULL.
11244 11241   */
11245 11242  
11246 11243  /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11247 11244  static int
11248 11245  select_inst(const char *name)
11249 11246  {
11250 11247          scf_instance_t *inst;
11251 11248          scf_error_t err;
11252 11249  
11253 11250          assert(cur_svc != NULL);
11254 11251  
11255 11252          inst = scf_instance_create(g_hndl);
11256 11253          if (inst == NULL)
11257 11254                  scfdie();
11258 11255  
11259 11256          if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11260 11257                  cur_inst = inst;
11261 11258                  return (0);
11262 11259          }
11263 11260  
11264 11261          err = scf_error();
11265 11262          if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11266 11263                  scfdie();
11267 11264  
11268 11265          scf_instance_destroy(inst);
11269 11266          return (1);
11270 11267  }
11271 11268  
11272 11269  /* Returns as above. */
11273 11270  static int
11274 11271  select_svc(const char *name)
11275 11272  {
11276 11273          scf_service_t *svc;
11277 11274          scf_error_t err;
11278 11275  
11279 11276          assert(cur_scope != NULL);
11280 11277  
11281 11278          svc = scf_service_create(g_hndl);
11282 11279          if (svc == NULL)
11283 11280                  scfdie();
11284 11281  
11285 11282          if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11286 11283                  cur_svc = svc;
11287 11284                  return (0);
11288 11285          }
11289 11286  
11290 11287          err = scf_error();
11291 11288          if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11292 11289                  scfdie();
11293 11290  
11294 11291          scf_service_destroy(svc);
11295 11292          return (1);
11296 11293  }
11297 11294  
11298 11295  /* ARGSUSED */
11299 11296  static int
11300 11297  select_callback(void *unused, scf_walkinfo_t *wip)
11301 11298  {
11302 11299          scf_instance_t *inst;
11303 11300          scf_service_t *svc;
11304 11301          scf_scope_t *scope;
11305 11302  
11306 11303          if (wip->inst != NULL) {
11307 11304                  if ((scope = scf_scope_create(g_hndl)) == NULL ||
11308 11305                      (svc = scf_service_create(g_hndl)) == NULL ||
11309 11306                      (inst = scf_instance_create(g_hndl)) == NULL)
11310 11307                          scfdie();
11311 11308  
11312 11309                  if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11313 11310                      inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11314 11311                          scfdie();
11315 11312          } else {
11316 11313                  assert(wip->svc != NULL);
11317 11314  
11318 11315                  if ((scope = scf_scope_create(g_hndl)) == NULL ||
11319 11316                      (svc = scf_service_create(g_hndl)) == NULL)
11320 11317                          scfdie();
11321 11318  
11322 11319                  if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11323 11320                      NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11324 11321                          scfdie();
11325 11322  
11326 11323                  inst = NULL;
11327 11324          }
11328 11325  
11329 11326          /* Clear out the current selection */
11330 11327          assert(cur_scope != NULL);
11331 11328          scf_scope_destroy(cur_scope);
11332 11329          scf_service_destroy(cur_svc);
11333 11330          scf_instance_destroy(cur_inst);
11334 11331  
11335 11332          cur_scope = scope;
11336 11333          cur_svc = svc;
11337 11334          cur_inst = inst;
11338 11335  
11339 11336          return (0);
11340 11337  }
11341 11338  
11342 11339  static int
11343 11340  validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11344 11341  {
11345 11342          char **fmri = fmri_p;
11346 11343  
11347 11344          *fmri = strdup(wip->fmri);
11348 11345          if (*fmri == NULL)
11349 11346                  uu_die(gettext("Out of memory.\n"));
11350 11347  
11351 11348          return (0);
11352 11349  }
11353 11350  
11354 11351  /*
11355 11352   * validate [fmri]
11356 11353   * Perform the validation of an FMRI instance.
11357 11354   */
11358 11355  void
11359 11356  lscf_validate_fmri(const char *fmri)
11360 11357  {
11361 11358          int ret = 0;
11362 11359          size_t inst_sz;
11363 11360          char *inst_fmri = NULL;
11364 11361          scf_tmpl_errors_t *errs = NULL;
11365 11362          char *snapbuf = NULL;
11366 11363  
11367 11364          lscf_prep_hndl();
11368 11365  
11369 11366          if (fmri == NULL) {
11370 11367                  inst_sz = max_scf_fmri_len + 1;
11371 11368                  inst_fmri = safe_malloc(inst_sz);
11372 11369  
11373 11370                  if (cur_snap != NULL) {
11374 11371                          snapbuf = safe_malloc(max_scf_name_len + 1);
11375 11372                          if (scf_snapshot_get_name(cur_snap, snapbuf,
11376 11373                              max_scf_name_len + 1) < 0)
11377 11374                                  scfdie();
11378 11375                  }
11379 11376                  if (cur_inst == NULL) {
11380 11377                          semerr(gettext("No instance selected\n"));
11381 11378                          goto cleanup;
11382 11379                  } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11383 11380                      inst_sz) >= inst_sz) {
11384 11381                          /* sanity check. Should never get here */
11385 11382                          uu_die(gettext("Unexpected error! file %s, line %d\n"),
11386 11383                              __FILE__, __LINE__);
11387 11384                  }
11388 11385          } else {
11389 11386                  scf_error_t scf_err;
11390 11387                  int err = 0;
11391 11388  
11392 11389                  if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11393 11390                      validate_callback, &inst_fmri, &err, semerr)) != 0) {
11394 11391                          uu_warn("Failed to walk instances: %s\n",
11395 11392                              scf_strerror(scf_err));
11396 11393                          goto cleanup;
11397 11394                  }
11398 11395                  if (err != 0) {
11399 11396                          /* error message displayed by scf_walk_fmri */
11400 11397                          goto cleanup;
11401 11398                  }
11402 11399          }
11403 11400  
11404 11401          ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11405 11402              SCF_TMPL_VALIDATE_FLAG_CURRENT);
11406 11403          if (ret == -1) {
11407 11404                  if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11408 11405                          warn(gettext("Template data for %s is invalid. "
11409 11406                              "Consider reverting to a previous snapshot or "
11410 11407                              "restoring original configuration.\n"), inst_fmri);
11411 11408                  } else {
11412 11409                          uu_warn("%s: %s\n",
11413 11410                              gettext("Error validating the instance"),
11414 11411                              scf_strerror(scf_error()));
11415 11412                  }
11416 11413          } else if (ret == 1 && errs != NULL) {
11417 11414                  scf_tmpl_error_t *err = NULL;
11418 11415                  char *msg;
11419 11416                  size_t len = 256;       /* initial error buffer size */
11420 11417                  int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11421 11418                      SCF_TMPL_STRERROR_HUMAN : 0;
11422 11419  
11423 11420                  msg = safe_malloc(len);
11424 11421  
11425 11422                  while ((err = scf_tmpl_next_error(errs)) != NULL) {
11426 11423                          int ret;
11427 11424  
11428 11425                          if ((ret = scf_tmpl_strerror(err, msg, len,
11429 11426                              flag)) >= len) {
11430 11427                                  len = ret + 1;
11431 11428                                  msg = realloc(msg, len);
11432 11429                                  if (msg == NULL)
11433 11430                                          uu_die(gettext(
11434 11431                                              "Out of memory.\n"));
11435 11432                                  (void) scf_tmpl_strerror(err, msg, len,
11436 11433                                      flag);
11437 11434                          }
11438 11435                          (void) fprintf(stderr, "%s\n", msg);
11439 11436                  }
11440 11437                  if (msg != NULL)
11441 11438                          free(msg);
11442 11439          }
11443 11440          if (errs != NULL)
11444 11441                  scf_tmpl_errors_destroy(errs);
11445 11442  
11446 11443  cleanup:
11447 11444          free(inst_fmri);
11448 11445          free(snapbuf);
11449 11446  }
11450 11447  
11451 11448  static void
11452 11449  lscf_validate_file(const char *filename)
11453 11450  {
11454 11451          tmpl_errors_t *errs;
11455 11452  
11456 11453          bundle_t *b = internal_bundle_new();
11457 11454          if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11458 11455                  if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11459 11456                          tmpl_errors_print(stderr, errs, "");
11460 11457                          semerr(gettext("Validation failed.\n"));
11461 11458                  }
11462 11459                  tmpl_errors_destroy(errs);
11463 11460          }
11464 11461          (void) internal_bundle_free(b);
11465 11462  }
11466 11463  
11467 11464  /*
11468 11465   * validate [fmri|file]
11469 11466   */
11470 11467  void
11471 11468  lscf_validate(const char *arg)
11472 11469  {
11473 11470          const char *str;
11474 11471  
11475 11472          if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11476 11473              sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11477 11474                  str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11478 11475                  lscf_validate_file(str);
11479 11476          } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11480 11477              sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11481 11478                  str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11482 11479                  lscf_validate_fmri(str);
11483 11480          } else if (access(arg, R_OK | F_OK) == 0) {
11484 11481                  lscf_validate_file(arg);
11485 11482          } else {
11486 11483                  lscf_validate_fmri(arg);
11487 11484          }
11488 11485  }
11489 11486  
11490 11487  void
11491 11488  lscf_select(const char *fmri)
11492 11489  {
11493 11490          int ret, err;
11494 11491  
11495 11492          lscf_prep_hndl();
11496 11493  
11497 11494          if (cur_snap != NULL) {
11498 11495                  struct snaplevel *elt;
11499 11496                  char *buf;
11500 11497  
11501 11498                  /* Error unless name is that of the next level. */
11502 11499                  elt = uu_list_next(cur_levels, cur_elt);
11503 11500                  if (elt == NULL) {
11504 11501                          semerr(gettext("No children.\n"));
11505 11502                          return;
11506 11503                  }
11507 11504  
11508 11505                  buf = safe_malloc(max_scf_name_len + 1);
11509 11506  
11510 11507                  if (scf_snaplevel_get_instance_name(elt->sl, buf,
11511 11508                      max_scf_name_len + 1) < 0)
11512 11509                          scfdie();
11513 11510  
11514 11511                  if (strcmp(buf, fmri) != 0) {
11515 11512                          semerr(gettext("No such child.\n"));
11516 11513                          free(buf);
11517 11514                          return;
11518 11515                  }
11519 11516  
11520 11517                  free(buf);
11521 11518  
11522 11519                  cur_elt = elt;
11523 11520                  cur_level = elt->sl;
11524 11521                  return;
11525 11522          }
11526 11523  
11527 11524          /*
11528 11525           * Special case for 'svc:', which takes the user to the scope level.
11529 11526           */
11530 11527          if (strcmp(fmri, "svc:") == 0) {
11531 11528                  scf_instance_destroy(cur_inst);
11532 11529                  scf_service_destroy(cur_svc);
11533 11530                  cur_inst = NULL;
11534 11531                  cur_svc = NULL;
11535 11532                  return;
11536 11533          }
11537 11534  
11538 11535          /*
11539 11536           * Special case for ':properties'.  This appears as part of 'list' but
11540 11537           * can't be selected.  Give a more helpful error message in this case.
11541 11538           */
11542 11539          if (strcmp(fmri, ":properties") == 0) {
11543 11540                  semerr(gettext(":properties is not an entity.  Try 'listprop' "
11544 11541                      "to list properties.\n"));
11545 11542                  return;
11546 11543          }
11547 11544  
11548 11545          /*
11549 11546           * First try the argument as relative to the current selection.
11550 11547           */
11551 11548          if (cur_inst != NULL) {
11552 11549                  /* EMPTY */;
11553 11550          } else if (cur_svc != NULL) {
11554 11551                  if (select_inst(fmri) != 1)
11555 11552                          return;
11556 11553          } else {
11557 11554                  if (select_svc(fmri) != 1)
11558 11555                          return;
11559 11556          }
11560 11557  
11561 11558          err = 0;
11562 11559          if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11563 11560              select_callback, NULL, &err, semerr)) != 0) {
11564 11561                  semerr(gettext("Failed to walk instances: %s\n"),
11565 11562                      scf_strerror(ret));
11566 11563          }
11567 11564  }
11568 11565  
11569 11566  void
11570 11567  lscf_unselect(void)
11571 11568  {
11572 11569          lscf_prep_hndl();
11573 11570  
11574 11571          if (cur_snap != NULL) {
11575 11572                  struct snaplevel *elt;
11576 11573  
11577 11574                  elt = uu_list_prev(cur_levels, cur_elt);
11578 11575                  if (elt == NULL) {
11579 11576                          semerr(gettext("No parent levels.\n"));
11580 11577                  } else {
11581 11578                          cur_elt = elt;
11582 11579                          cur_level = elt->sl;
11583 11580                  }
11584 11581          } else if (cur_inst != NULL) {
11585 11582                  scf_instance_destroy(cur_inst);
11586 11583                  cur_inst = NULL;
11587 11584          } else if (cur_svc != NULL) {
11588 11585                  scf_service_destroy(cur_svc);
11589 11586                  cur_svc = NULL;
11590 11587          } else {
11591 11588                  semerr(gettext("Cannot unselect at scope level.\n"));
11592 11589          }
11593 11590  }
11594 11591  
11595 11592  /*
11596 11593   * Return the FMRI of the current selection, for the prompt.
11597 11594   */
11598 11595  void
11599 11596  lscf_get_selection_str(char *buf, size_t bufsz)
11600 11597  {
11601 11598          char *cp;
11602 11599          ssize_t fmrilen, szret;
11603 11600          boolean_t deleted = B_FALSE;
11604 11601  
11605 11602          if (g_hndl == NULL) {
11606 11603                  (void) strlcpy(buf, "svc:", bufsz);
11607 11604                  return;
11608 11605          }
11609 11606  
11610 11607          if (cur_level != NULL) {
11611 11608                  assert(cur_snap != NULL);
11612 11609  
11613 11610                  /* [ snapshot ] FMRI [: instance ] */
11614 11611                  assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11615 11612                      + 2 + max_scf_name_len + 1 + 1);
11616 11613  
11617 11614                  buf[0] = '[';
11618 11615  
11619 11616                  szret = scf_snapshot_get_name(cur_snap, buf + 1,
11620 11617                      max_scf_name_len + 1);
11621 11618                  if (szret < 0) {
11622 11619                          if (scf_error() != SCF_ERROR_DELETED)
11623 11620                                  scfdie();
11624 11621  
11625 11622                          goto snap_deleted;
11626 11623                  }
11627 11624  
11628 11625                  (void) strcat(buf, "]svc:/");
11629 11626  
11630 11627                  cp = strchr(buf, '\0');
11631 11628  
11632 11629                  szret = scf_snaplevel_get_service_name(cur_level, cp,
11633 11630                      max_scf_name_len + 1);
11634 11631                  if (szret < 0) {
11635 11632                          if (scf_error() != SCF_ERROR_DELETED)
11636 11633                                  scfdie();
11637 11634  
11638 11635                          goto snap_deleted;
11639 11636                  }
11640 11637  
11641 11638                  cp = strchr(cp, '\0');
11642 11639  
11643 11640                  if (snaplevel_is_instance(cur_level)) {
11644 11641                          *cp++ = ':';
11645 11642  
11646 11643                          if (scf_snaplevel_get_instance_name(cur_level, cp,
11647 11644                              max_scf_name_len + 1) < 0) {
11648 11645                                  if (scf_error() != SCF_ERROR_DELETED)
11649 11646                                          scfdie();
11650 11647  
11651 11648                                  goto snap_deleted;
11652 11649                          }
11653 11650                  } else {
11654 11651                          *cp++ = '[';
11655 11652                          *cp++ = ':';
11656 11653  
11657 11654                          if (scf_instance_get_name(cur_inst, cp,
11658 11655                              max_scf_name_len + 1) < 0) {
11659 11656                                  if (scf_error() != SCF_ERROR_DELETED)
11660 11657                                          scfdie();
11661 11658  
11662 11659                                  goto snap_deleted;
11663 11660                          }
11664 11661  
11665 11662                          (void) strcat(buf, "]");
11666 11663                  }
11667 11664  
11668 11665                  return;
11669 11666  
11670 11667  snap_deleted:
11671 11668                  deleted = B_TRUE;
11672 11669                  free(buf);
11673 11670                  unselect_cursnap();
11674 11671          }
11675 11672  
11676 11673          assert(cur_snap == NULL);
11677 11674  
11678 11675          if (cur_inst != NULL) {
11679 11676                  assert(cur_svc != NULL);
11680 11677                  assert(cur_scope != NULL);
11681 11678  
11682 11679                  fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11683 11680                  if (fmrilen >= 0) {
11684 11681                          assert(fmrilen < bufsz);
11685 11682                          if (deleted)
11686 11683                                  warn(emsg_deleted);
11687 11684                          return;
11688 11685                  }
11689 11686  
11690 11687                  if (scf_error() != SCF_ERROR_DELETED)
11691 11688                          scfdie();
11692 11689  
11693 11690                  deleted = B_TRUE;
11694 11691  
11695 11692                  scf_instance_destroy(cur_inst);
11696 11693                  cur_inst = NULL;
11697 11694          }
11698 11695  
11699 11696          if (cur_svc != NULL) {
11700 11697                  assert(cur_scope != NULL);
11701 11698  
11702 11699                  szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11703 11700                  if (szret >= 0) {
11704 11701                          assert(szret < bufsz);
11705 11702                          if (deleted)
11706 11703                                  warn(emsg_deleted);
11707 11704                          return;
11708 11705                  }
11709 11706  
11710 11707                  if (scf_error() != SCF_ERROR_DELETED)
11711 11708                          scfdie();
11712 11709  
11713 11710                  deleted = B_TRUE;
11714 11711                  scf_service_destroy(cur_svc);
11715 11712                  cur_svc = NULL;
11716 11713          }
11717 11714  
11718 11715          assert(cur_scope != NULL);
11719 11716          fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11720 11717  
11721 11718          if (fmrilen < 0)
11722 11719                  scfdie();
11723 11720  
11724 11721          assert(fmrilen < bufsz);
11725 11722          if (deleted)
11726 11723                  warn(emsg_deleted);
11727 11724  }
11728 11725  
11729 11726  /*
11730 11727   * Entity listing.  Entities and colon namespaces (e.g., :properties and
11731 11728   * :statistics) are listed for the current selection.
11732 11729   */
11733 11730  void
11734 11731  lscf_list(const char *pattern)
11735 11732  {
11736 11733          scf_iter_t *iter;
11737 11734          char *buf;
11738 11735          int ret;
11739 11736  
11740 11737          lscf_prep_hndl();
11741 11738  
11742 11739          if (cur_level != NULL) {
11743 11740                  struct snaplevel *elt;
11744 11741  
11745 11742                  (void) fputs(COLON_NAMESPACES, stdout);
11746 11743  
11747 11744                  elt = uu_list_next(cur_levels, cur_elt);
11748 11745                  if (elt == NULL)
11749 11746                          return;
11750 11747  
11751 11748                  /*
11752 11749                   * For now, we know that the next level is an instance.  But
11753 11750                   * if we ever have multiple scopes, this could be complicated.
11754 11751                   */
11755 11752                  buf = safe_malloc(max_scf_name_len + 1);
11756 11753                  if (scf_snaplevel_get_instance_name(elt->sl, buf,
11757 11754                      max_scf_name_len + 1) >= 0) {
11758 11755                          (void) puts(buf);
11759 11756                  } else {
11760 11757                          if (scf_error() != SCF_ERROR_DELETED)
11761 11758                                  scfdie();
11762 11759                  }
11763 11760  
11764 11761                  free(buf);
11765 11762  
11766 11763                  return;
11767 11764          }
11768 11765  
11769 11766          if (cur_inst != NULL) {
11770 11767                  (void) fputs(COLON_NAMESPACES, stdout);
11771 11768                  return;
11772 11769          }
11773 11770  
11774 11771          iter = scf_iter_create(g_hndl);
11775 11772          if (iter == NULL)
11776 11773                  scfdie();
11777 11774  
11778 11775          buf = safe_malloc(max_scf_name_len + 1);
11779 11776  
11780 11777          if (cur_svc != NULL) {
11781 11778                  /* List the instances in this service. */
11782 11779                  scf_instance_t *inst;
11783 11780  
11784 11781                  inst = scf_instance_create(g_hndl);
11785 11782                  if (inst == NULL)
11786 11783                          scfdie();
11787 11784  
11788 11785                  if (scf_iter_service_instances(iter, cur_svc) == 0) {
11789 11786                          safe_printf(COLON_NAMESPACES);
11790 11787  
11791 11788                          for (;;) {
11792 11789                                  ret = scf_iter_next_instance(iter, inst);
11793 11790                                  if (ret == 0)
11794 11791                                          break;
11795 11792                                  if (ret != 1) {
11796 11793                                          if (scf_error() != SCF_ERROR_DELETED)
11797 11794                                                  scfdie();
11798 11795  
11799 11796                                          break;
11800 11797                                  }
11801 11798  
11802 11799                                  if (scf_instance_get_name(inst, buf,
11803 11800                                      max_scf_name_len + 1) >= 0) {
11804 11801                                          if (pattern == NULL ||
11805 11802                                              fnmatch(pattern, buf, 0) == 0)
11806 11803                                                  (void) puts(buf);
11807 11804                                  } else {
11808 11805                                          if (scf_error() != SCF_ERROR_DELETED)
11809 11806                                                  scfdie();
11810 11807                                  }
11811 11808                          }
11812 11809                  } else {
11813 11810                          if (scf_error() != SCF_ERROR_DELETED)
11814 11811                                  scfdie();
11815 11812                  }
11816 11813  
11817 11814                  scf_instance_destroy(inst);
11818 11815          } else {
11819 11816                  /* List the services in this scope. */
11820 11817                  scf_service_t *svc;
11821 11818  
11822 11819                  assert(cur_scope != NULL);
11823 11820  
11824 11821                  svc = scf_service_create(g_hndl);
11825 11822                  if (svc == NULL)
11826 11823                          scfdie();
11827 11824  
11828 11825                  if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11829 11826                          scfdie();
11830 11827  
11831 11828                  for (;;) {
11832 11829                          ret = scf_iter_next_service(iter, svc);
11833 11830                          if (ret == 0)
11834 11831                                  break;
11835 11832                          if (ret != 1)
11836 11833                                  scfdie();
11837 11834  
11838 11835                          if (scf_service_get_name(svc, buf,
11839 11836                              max_scf_name_len + 1) >= 0) {
11840 11837                                  if (pattern == NULL ||
11841 11838                                      fnmatch(pattern, buf, 0) == 0)
11842 11839                                          safe_printf("%s\n", buf);
11843 11840                          } else {
11844 11841                                  if (scf_error() != SCF_ERROR_DELETED)
11845 11842                                          scfdie();
11846 11843                          }
11847 11844                  }
11848 11845  
11849 11846                  scf_service_destroy(svc);
11850 11847          }
11851 11848  
11852 11849          free(buf);
11853 11850          scf_iter_destroy(iter);
11854 11851  }
11855 11852  
11856 11853  /*
11857 11854   * Entity addition.  Creates an empty entity in the current selection.
11858 11855   */
11859 11856  void
11860 11857  lscf_add(const char *name)
11861 11858  {
11862 11859          lscf_prep_hndl();
11863 11860  
11864 11861          if (cur_snap != NULL) {
11865 11862                  semerr(emsg_cant_modify_snapshots);
11866 11863          } else if (cur_inst != NULL) {
11867 11864                  semerr(gettext("Cannot add entities to an instance.\n"));
11868 11865          } else if (cur_svc != NULL) {
11869 11866  
11870 11867                  if (scf_service_add_instance(cur_svc, name, NULL) !=
11871 11868                      SCF_SUCCESS) {
11872 11869                          switch (scf_error()) {
11873 11870                          case SCF_ERROR_INVALID_ARGUMENT:
11874 11871                                  semerr(gettext("Invalid name.\n"));
11875 11872                                  break;
11876 11873  
11877 11874                          case SCF_ERROR_EXISTS:
11878 11875                                  semerr(gettext("Instance already exists.\n"));
11879 11876                                  break;
11880 11877  
11881 11878                          case SCF_ERROR_PERMISSION_DENIED:
11882 11879                                  semerr(emsg_permission_denied);
11883 11880                                  break;
11884 11881  
11885 11882                          default:
11886 11883                                  scfdie();
11887 11884                          }
11888 11885                  }
11889 11886          } else {
11890 11887                  assert(cur_scope != NULL);
11891 11888  
11892 11889                  if (scf_scope_add_service(cur_scope, name, NULL) !=
11893 11890                      SCF_SUCCESS) {
11894 11891                          switch (scf_error()) {
11895 11892                          case SCF_ERROR_INVALID_ARGUMENT:
11896 11893                                  semerr(gettext("Invalid name.\n"));
11897 11894                                  break;
11898 11895  
11899 11896                          case SCF_ERROR_EXISTS:
11900 11897                                  semerr(gettext("Service already exists.\n"));
11901 11898                                  break;
11902 11899  
11903 11900                          case SCF_ERROR_PERMISSION_DENIED:
11904 11901                                  semerr(emsg_permission_denied);
11905 11902                                  break;
11906 11903  
11907 11904                          case SCF_ERROR_BACKEND_READONLY:
11908 11905                                  semerr(emsg_read_only);
11909 11906                                  break;
11910 11907  
11911 11908                          default:
11912 11909                                  scfdie();
11913 11910                          }
11914 11911                  }
11915 11912          }
11916 11913  }
11917 11914  
11918 11915  /* return 1 if the entity has no persistent pgs, else return 0 */
11919 11916  static int
11920 11917  entity_has_no_pgs(void *ent, int isservice)
11921 11918  {
11922 11919          scf_iter_t *iter = NULL;
11923 11920          scf_propertygroup_t *pg = NULL;
11924 11921          uint32_t flags;
11925 11922          int err;
11926 11923          int ret = 1;
11927 11924  
11928 11925          if ((iter = scf_iter_create(g_hndl)) == NULL ||
11929 11926              (pg = scf_pg_create(g_hndl)) == NULL)
11930 11927                  scfdie();
11931 11928  
11932 11929          if (isservice) {
11933 11930                  if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11934 11931                          scfdie();
11935 11932          } else {
11936 11933                  if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11937 11934                          scfdie();
11938 11935          }
11939 11936  
11940 11937          while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11941 11938                  if (scf_pg_get_flags(pg, &flags) != 0)
11942 11939                          scfdie();
11943 11940  
11944 11941                  /* skip nonpersistent pgs */
11945 11942                  if (flags & SCF_PG_FLAG_NONPERSISTENT)
11946 11943                          continue;
11947 11944  
11948 11945                  ret = 0;
11949 11946                  break;
11950 11947          }
11951 11948  
11952 11949          if (err == -1)
11953 11950                  scfdie();
11954 11951  
11955 11952          scf_pg_destroy(pg);
11956 11953          scf_iter_destroy(iter);
11957 11954  
11958 11955          return (ret);
11959 11956  }
11960 11957  
11961 11958  /* return 1 if the service has no instances, else return 0 */
11962 11959  static int
11963 11960  svc_has_no_insts(scf_service_t *svc)
11964 11961  {
11965 11962          scf_instance_t *inst;
11966 11963          scf_iter_t *iter;
11967 11964          int r;
11968 11965          int ret = 1;
11969 11966  
11970 11967          if ((inst = scf_instance_create(g_hndl)) == NULL ||
11971 11968              (iter = scf_iter_create(g_hndl)) == NULL)
11972 11969                  scfdie();
11973 11970  
11974 11971          if (scf_iter_service_instances(iter, svc) != 0)
11975 11972                  scfdie();
11976 11973  
11977 11974          r = scf_iter_next_instance(iter, inst);
11978 11975          if (r == 1) {
11979 11976                  ret = 0;
11980 11977          } else if (r == 0) {
11981 11978                  ret = 1;
11982 11979          } else if (r == -1) {
11983 11980                  scfdie();
11984 11981          } else {
11985 11982                  bad_error("scf_iter_next_instance", r);
11986 11983          }
11987 11984  
11988 11985          scf_iter_destroy(iter);
11989 11986          scf_instance_destroy(inst);
11990 11987  
11991 11988          return (ret);
11992 11989  }
11993 11990  
11994 11991  /*
11995 11992   * Entity deletion.
11996 11993   */
11997 11994  
11998 11995  /*
11999 11996   * Delete the property group <fmri>/:properties/<name>.  Returns
12000 11997   * SCF_ERROR_NONE on success (or if the entity is not found),
12001 11998   * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12002 11999   * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12003 12000   * denied.
12004 12001   */
12005 12002  static scf_error_t
12006 12003  delete_dependency_pg(const char *fmri, const char *name)
12007 12004  {
12008 12005          void *entity = NULL;
12009 12006          int isservice;
12010 12007          scf_propertygroup_t *pg = NULL;
12011 12008          scf_error_t result;
12012 12009          char *pgty;
12013 12010          scf_service_t *svc = NULL;
12014 12011          scf_instance_t *inst = NULL;
12015 12012          scf_iter_t *iter = NULL;
12016 12013          char *name_buf = NULL;
12017 12014  
12018 12015          result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12019 12016          switch (result) {
12020 12017          case SCF_ERROR_NONE:
12021 12018                  break;
12022 12019  
12023 12020          case SCF_ERROR_NO_MEMORY:
12024 12021                  uu_die(gettext("Out of memory.\n"));
12025 12022                  /* NOTREACHED */
12026 12023  
12027 12024          case SCF_ERROR_INVALID_ARGUMENT:
12028 12025          case SCF_ERROR_CONSTRAINT_VIOLATED:
12029 12026                  return (SCF_ERROR_INVALID_ARGUMENT);
12030 12027  
12031 12028          case SCF_ERROR_NOT_FOUND:
12032 12029                  result = SCF_ERROR_NONE;
12033 12030                  goto out;
12034 12031  
12035 12032          default:
12036 12033                  bad_error("fmri_to_entity", result);
12037 12034          }
12038 12035  
12039 12036          pg = scf_pg_create(g_hndl);
12040 12037          if (pg == NULL)
12041 12038                  scfdie();
12042 12039  
12043 12040          if (entity_get_pg(entity, isservice, name, pg) != 0) {
12044 12041                  if (scf_error() != SCF_ERROR_NOT_FOUND)
12045 12042                          scfdie();
12046 12043  
12047 12044                  result = SCF_ERROR_NONE;
12048 12045                  goto out;
12049 12046          }
12050 12047  
12051 12048          pgty = safe_malloc(max_scf_pg_type_len + 1);
12052 12049  
12053 12050          if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12054 12051                  scfdie();
12055 12052  
12056 12053          if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12057 12054                  result = SCF_ERROR_TYPE_MISMATCH;
12058 12055                  free(pgty);
12059 12056                  goto out;
12060 12057          }
12061 12058  
12062 12059          free(pgty);
12063 12060  
12064 12061          if (scf_pg_delete(pg) != 0) {
12065 12062                  result = scf_error();
12066 12063                  if (result != SCF_ERROR_PERMISSION_DENIED)
12067 12064                          scfdie();
12068 12065                  goto out;
12069 12066          }
12070 12067  
12071 12068          /*
12072 12069           * We have to handle the case where we've just deleted the last
12073 12070           * property group of a "dummy" entity (instance or service).
12074 12071           * A "dummy" entity is an entity only present to hold an
12075 12072           * external dependency.
12076 12073           * So, in the case we deleted the last property group then we
12077 12074           * can also delete the entity. If the entity is an instance then
12078 12075           * we must verify if this was the last instance for the service
12079 12076           * and if it is, we can also delete the service if it doesn't
12080 12077           * have any property group either.
12081 12078           */
12082 12079  
12083 12080          result = SCF_ERROR_NONE;
12084 12081  
12085 12082          if (isservice) {
12086 12083                  svc = (scf_service_t *)entity;
12087 12084  
12088 12085                  if ((inst = scf_instance_create(g_hndl)) == NULL ||
12089 12086                      (iter = scf_iter_create(g_hndl)) == NULL)
12090 12087                          scfdie();
12091 12088  
12092 12089                  name_buf = safe_malloc(max_scf_name_len + 1);
12093 12090          } else {
12094 12091                  inst = (scf_instance_t *)entity;
12095 12092          }
12096 12093  
12097 12094          /*
12098 12095           * If the entity is an instance and we've just deleted its last
12099 12096           * property group then we should delete it.
12100 12097           */
12101 12098          if (!isservice && entity_has_no_pgs(entity, isservice)) {
12102 12099                  /* find the service before deleting the inst. - needed later */
12103 12100                  if ((svc = scf_service_create(g_hndl)) == NULL)
12104 12101                          scfdie();
12105 12102  
12106 12103                  if (scf_instance_get_parent(inst, svc) != 0)
12107 12104                          scfdie();
12108 12105  
12109 12106                  /* delete the instance */
12110 12107                  if (scf_instance_delete(inst) != 0) {
12111 12108                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12112 12109                                  scfdie();
12113 12110  
12114 12111                          result = SCF_ERROR_PERMISSION_DENIED;
12115 12112                          goto out;
12116 12113                  }
12117 12114                  /* no need to refresh the instance */
12118 12115                  inst = NULL;
12119 12116          }
12120 12117  
12121 12118          /*
12122 12119           * If the service has no more instances and pgs or we just deleted the
12123 12120           * last instance and the service doesn't have anymore propery groups
12124 12121           * then the service should be deleted.
12125 12122           */
12126 12123          if (svc != NULL &&
12127 12124              svc_has_no_insts(svc) &&
12128 12125              entity_has_no_pgs((void *)svc, 1)) {
12129 12126                  if (scf_service_delete(svc) == 0) {
12130 12127                          if (isservice) {
12131 12128                                  /* no need to refresh the service */
12132 12129                                  svc = NULL;
12133 12130                          }
12134 12131  
12135 12132                          goto out;
12136 12133                  }
12137 12134  
12138 12135                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12139 12136                          scfdie();
12140 12137  
12141 12138                  result = SCF_ERROR_PERMISSION_DENIED;
12142 12139          }
12143 12140  
12144 12141          /* if the entity has not been deleted, refresh it */
12145 12142          if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12146 12143                  (void) refresh_entity(isservice, entity, fmri, inst, iter,
12147 12144                      name_buf);
12148 12145          }
12149 12146  
12150 12147  out:
12151 12148          if (isservice && (inst != NULL && iter != NULL)) {
12152 12149                  free(name_buf);
12153 12150                  scf_iter_destroy(iter);
12154 12151                  scf_instance_destroy(inst);
12155 12152          }
12156 12153  
12157 12154          if (!isservice && svc != NULL) {
12158 12155                  scf_service_destroy(svc);
12159 12156          }
12160 12157  
12161 12158          scf_pg_destroy(pg);
12162 12159          if (entity != NULL)
12163 12160                  entity_destroy(entity, isservice);
12164 12161  
12165 12162          return (result);
12166 12163  }
12167 12164  
12168 12165  static int
12169 12166  delete_dependents(scf_propertygroup_t *pg)
12170 12167  {
12171 12168          char *pgty, *name, *fmri;
12172 12169          scf_property_t *prop;
12173 12170          scf_value_t *val;
12174 12171          scf_iter_t *iter;
12175 12172          int r;
12176 12173          scf_error_t err;
12177 12174  
12178 12175          /* Verify that the pg has the correct type. */
12179 12176          pgty = safe_malloc(max_scf_pg_type_len + 1);
12180 12177          if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12181 12178                  scfdie();
12182 12179  
12183 12180          if (strcmp(pgty, scf_group_framework) != 0) {
12184 12181                  if (g_verbose) {
12185 12182                          fmri = safe_malloc(max_scf_fmri_len + 1);
12186 12183                          if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12187 12184                                  scfdie();
12188 12185  
12189 12186                          warn(gettext("Property group %s is not of expected "
12190 12187                              "type %s.\n"), fmri, scf_group_framework);
12191 12188  
12192 12189                          free(fmri);
12193 12190                  }
12194 12191  
12195 12192                  free(pgty);
12196 12193                  return (-1);
12197 12194          }
12198 12195  
12199 12196          free(pgty);
12200 12197  
12201 12198          /* map delete_dependency_pg onto the properties. */
12202 12199          if ((prop = scf_property_create(g_hndl)) == NULL ||
12203 12200              (val = scf_value_create(g_hndl)) == NULL ||
12204 12201              (iter = scf_iter_create(g_hndl)) == NULL)
12205 12202                  scfdie();
12206 12203  
12207 12204          if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12208 12205                  scfdie();
12209 12206  
12210 12207          name = safe_malloc(max_scf_name_len + 1);
12211 12208          fmri = safe_malloc(max_scf_fmri_len + 2);
12212 12209  
12213 12210          while ((r = scf_iter_next_property(iter, prop)) == 1) {
12214 12211                  scf_type_t ty;
12215 12212  
12216 12213                  if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12217 12214                          scfdie();
12218 12215  
12219 12216                  if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12220 12217                          scfdie();
12221 12218  
12222 12219                  if ((ty != SCF_TYPE_ASTRING &&
12223 12220                      prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12224 12221                      prop_get_val(prop, val) != 0)
12225 12222                          continue;
12226 12223  
12227 12224                  if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12228 12225                          scfdie();
12229 12226  
12230 12227                  err = delete_dependency_pg(fmri, name);
12231 12228                  if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12232 12229                          if (scf_property_to_fmri(prop, fmri,
12233 12230                              max_scf_fmri_len + 2) < 0)
12234 12231                                  scfdie();
12235 12232  
12236 12233                          warn(gettext("Value of %s is not a valid FMRI.\n"),
12237 12234                              fmri);
12238 12235                  } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12239 12236                          warn(gettext("Property group \"%s\" of entity \"%s\" "
12240 12237                              "does not have dependency type.\n"), name, fmri);
12241 12238                  } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12242 12239                          warn(gettext("Could not delete property group \"%s\" "
12243 12240                              "of entity \"%s\" (permission denied).\n"), name,
12244 12241                              fmri);
12245 12242                  }
12246 12243          }
12247 12244          if (r == -1)
12248 12245                  scfdie();
12249 12246  
12250 12247          scf_value_destroy(val);
12251 12248          scf_property_destroy(prop);
12252 12249  
12253 12250          return (0);
12254 12251  }
12255 12252  
12256 12253  /*
12257 12254   * Returns 1 if the instance may be running, and 0 otherwise.
12258 12255   */
12259 12256  static int
12260 12257  inst_is_running(scf_instance_t *inst)
12261 12258  {
12262 12259          scf_propertygroup_t *pg;
12263 12260          scf_property_t *prop;
12264 12261          scf_value_t *val;
12265 12262          char buf[MAX_SCF_STATE_STRING_SZ];
12266 12263          int ret = 0;
12267 12264          ssize_t szret;
12268 12265  
12269 12266          if ((pg = scf_pg_create(g_hndl)) == NULL ||
12270 12267              (prop = scf_property_create(g_hndl)) == NULL ||
12271 12268              (val = scf_value_create(g_hndl)) == NULL)
12272 12269                  scfdie();
12273 12270  
12274 12271          if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12275 12272                  if (scf_error() != SCF_ERROR_NOT_FOUND)
12276 12273                          scfdie();
12277 12274                  goto out;
12278 12275          }
12279 12276  
12280 12277          if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12281 12278              prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12282 12279              prop_get_val(prop, val) != 0)
12283 12280                  goto out;
12284 12281  
12285 12282          szret = scf_value_get_astring(val, buf, sizeof (buf));
12286 12283          assert(szret >= 0);
12287 12284  
12288 12285          ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12289 12286              strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12290 12287  
12291 12288  out:
12292 12289          scf_value_destroy(val);
12293 12290          scf_property_destroy(prop);
12294 12291          scf_pg_destroy(pg);
12295 12292          return (ret);
12296 12293  }
12297 12294  
12298 12295  static uint8_t
12299 12296  pg_is_external_dependency(scf_propertygroup_t *pg)
12300 12297  {
12301 12298          char *type;
12302 12299          scf_value_t *val;
12303 12300          scf_property_t *prop;
12304 12301          uint8_t b = B_FALSE;
12305 12302  
12306 12303          type = safe_malloc(max_scf_pg_type_len + 1);
12307 12304  
12308 12305          if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12309 12306                  scfdie();
12310 12307  
12311 12308          if ((prop = scf_property_create(g_hndl)) == NULL ||
12312 12309              (val = scf_value_create(g_hndl)) == NULL)
12313 12310                  scfdie();
12314 12311  
12315 12312          if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12316 12313                  if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12317 12314                          if (scf_property_get_value(prop, val) != 0)
12318 12315                                  scfdie();
12319 12316                          if (scf_value_get_boolean(val, &b) != 0)
12320 12317                                  scfdie();
12321 12318                  }
12322 12319          }
12323 12320  
12324 12321          free(type);
12325 12322          (void) scf_value_destroy(val);
12326 12323          (void) scf_property_destroy(prop);
12327 12324  
12328 12325          return (b);
12329 12326  }
12330 12327  
12331 12328  #define DELETE_FAILURE                  -1
12332 12329  #define DELETE_SUCCESS_NOEXTDEPS        0
12333 12330  #define DELETE_SUCCESS_EXTDEPS          1
12334 12331  
12335 12332  /*
12336 12333   * lscf_instance_delete() deletes an instance.  Before calling
12337 12334   * scf_instance_delete(), though, we make sure the instance isn't
12338 12335   * running and delete dependencies in other entities which the instance
12339 12336   * declared as "dependents".  If there are dependencies which were
12340 12337   * created for other entities, then instead of deleting the instance we
12341 12338   * make it "empty" by deleting all other property groups and all
12342 12339   * snapshots.
12343 12340   *
12344 12341   * lscf_instance_delete() verifies that there is no external dependency pgs
12345 12342   * before suppressing the instance. If there is, then we must not remove them
12346 12343   * now in case the instance is re-created otherwise the dependencies would be
12347 12344   * lost. The external dependency pgs will be removed if the dependencies are
12348 12345   * removed.
12349 12346   *
12350 12347   * Returns:
12351 12348   *  DELETE_FAILURE              on failure
12352 12349   *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12353 12350   *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12354 12351   */
12355 12352  static int
12356 12353  lscf_instance_delete(scf_instance_t *inst, int force)
12357 12354  {
12358 12355          scf_propertygroup_t *pg;
12359 12356          scf_snapshot_t *snap;
12360 12357          scf_iter_t *iter;
12361 12358          int err;
12362 12359          int external = 0;
12363 12360  
12364 12361          /* If we're not forcing and the instance is running, refuse. */
12365 12362          if (!force && inst_is_running(inst)) {
12366 12363                  char *fmri;
12367 12364  
12368 12365                  fmri = safe_malloc(max_scf_fmri_len + 1);
12369 12366  
12370 12367                  if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12371 12368                          scfdie();
12372 12369  
12373 12370                  semerr(gettext("Instance %s may be running.  "
12374 12371                      "Use delete -f if it is not.\n"), fmri);
12375 12372  
12376 12373                  free(fmri);
12377 12374                  return (DELETE_FAILURE);
12378 12375          }
12379 12376  
12380 12377          pg = scf_pg_create(g_hndl);
12381 12378          if (pg == NULL)
12382 12379                  scfdie();
12383 12380  
12384 12381          if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12385 12382                  (void) delete_dependents(pg);
12386 12383          else if (scf_error() != SCF_ERROR_NOT_FOUND)
12387 12384                  scfdie();
12388 12385  
12389 12386          scf_pg_destroy(pg);
12390 12387  
12391 12388          /*
12392 12389           * If the instance has some external dependencies then we must
12393 12390           * keep them in case the instance is reimported otherwise the
12394 12391           * dependencies would be lost on reimport.
12395 12392           */
12396 12393          if ((iter = scf_iter_create(g_hndl)) == NULL ||
12397 12394              (pg = scf_pg_create(g_hndl)) == NULL)
12398 12395                  scfdie();
12399 12396  
12400 12397          if (scf_iter_instance_pgs(iter, inst) < 0)
12401 12398                  scfdie();
12402 12399  
12403 12400          while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12404 12401                  if (pg_is_external_dependency(pg)) {
12405 12402                          external = 1;
12406 12403                          continue;
12407 12404                  }
12408 12405  
12409 12406                  if (scf_pg_delete(pg) != 0) {
12410 12407                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12411 12408                                  scfdie();
12412 12409                          else {
12413 12410                                  semerr(emsg_permission_denied);
12414 12411  
12415 12412                                  (void) scf_iter_destroy(iter);
12416 12413                                  (void) scf_pg_destroy(pg);
12417 12414                                  return (DELETE_FAILURE);
12418 12415                          }
12419 12416                  }
12420 12417          }
12421 12418  
12422 12419          if (err == -1)
12423 12420                  scfdie();
12424 12421  
12425 12422          (void) scf_iter_destroy(iter);
12426 12423          (void) scf_pg_destroy(pg);
12427 12424  
12428 12425          if (external) {
12429 12426                  /*
12430 12427                   * All the pgs have been deleted for the instance except
12431 12428                   * the ones holding the external dependencies.
12432 12429                   * For the job to be complete, we must also delete the
12433 12430                   * snapshots associated with the instance.
12434 12431                   */
12435 12432                  if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12436 12433                      NULL)
12437 12434                          scfdie();
12438 12435                  if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12439 12436                          scfdie();
12440 12437  
12441 12438                  if (scf_iter_instance_snapshots(iter, inst) == -1)
12442 12439                          scfdie();
12443 12440  
12444 12441                  while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12445 12442                          if (_scf_snapshot_delete(snap) != 0) {
12446 12443                                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12447 12444                                          scfdie();
12448 12445  
12449 12446                                  semerr(emsg_permission_denied);
12450 12447  
12451 12448                                  (void) scf_iter_destroy(iter);
12452 12449                                  (void) scf_snapshot_destroy(snap);
12453 12450                                  return (DELETE_FAILURE);
12454 12451                          }
12455 12452                  }
12456 12453  
12457 12454                  if (err == -1)
12458 12455                          scfdie();
12459 12456  
12460 12457                  (void) scf_iter_destroy(iter);
12461 12458                  (void) scf_snapshot_destroy(snap);
12462 12459                  return (DELETE_SUCCESS_EXTDEPS);
12463 12460          }
12464 12461  
12465 12462          if (scf_instance_delete(inst) != 0) {
12466 12463                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12467 12464                          scfdie();
12468 12465  
12469 12466                  semerr(emsg_permission_denied);
12470 12467  
12471 12468                  return (DELETE_FAILURE);
12472 12469          }
12473 12470  
12474 12471          return (DELETE_SUCCESS_NOEXTDEPS);
12475 12472  }
12476 12473  
12477 12474  /*
12478 12475   * lscf_service_delete() deletes a service.  Before calling
12479 12476   * scf_service_delete(), though, we call lscf_instance_delete() for
12480 12477   * each of the instances and delete dependencies in other entities
12481 12478   * which were created as "dependents" of this service.  If there are
12482 12479   * dependencies which were created for other entities, then we delete
12483 12480   * all other property groups in the service and leave it as "empty".
12484 12481   *
12485 12482   * lscf_service_delete() verifies that there is no external dependency
12486 12483   * pgs at the instance & service level before suppressing the service.
12487 12484   * If there is, then we must not remove them now in case the service
12488 12485   * is re-imported otherwise the dependencies would be lost. The external
12489 12486   * dependency pgs will be removed if the dependencies are removed.
12490 12487   *
12491 12488   * Returns:
12492 12489   *   DELETE_FAILURE             on failure
12493 12490   *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12494 12491   *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12495 12492   */
12496 12493  static int
12497 12494  lscf_service_delete(scf_service_t *svc, int force)
12498 12495  {
12499 12496          int r;
12500 12497          scf_instance_t *inst;
12501 12498          scf_propertygroup_t *pg;
12502 12499          scf_iter_t *iter;
12503 12500          int ret;
12504 12501          int external = 0;
12505 12502  
12506 12503          if ((inst = scf_instance_create(g_hndl)) == NULL ||
12507 12504              (pg = scf_pg_create(g_hndl)) == NULL ||
12508 12505              (iter = scf_iter_create(g_hndl)) == NULL)
12509 12506                  scfdie();
12510 12507  
12511 12508          if (scf_iter_service_instances(iter, svc) != 0)
12512 12509                  scfdie();
12513 12510  
12514 12511          for (r = scf_iter_next_instance(iter, inst);
12515 12512              r == 1;
12516 12513              r = scf_iter_next_instance(iter, inst)) {
12517 12514  
12518 12515                  ret = lscf_instance_delete(inst, force);
12519 12516                  if (ret == DELETE_FAILURE) {
12520 12517                          scf_iter_destroy(iter);
12521 12518                          scf_pg_destroy(pg);
12522 12519                          scf_instance_destroy(inst);
12523 12520                          return (DELETE_FAILURE);
12524 12521                  }
12525 12522  
12526 12523                  /*
12527 12524                   * Record the fact that there is some external dependencies
12528 12525                   * at the instance level.
12529 12526                   */
12530 12527                  if (ret == DELETE_SUCCESS_EXTDEPS)
12531 12528                          external |= 1;
12532 12529          }
12533 12530  
12534 12531          if (r != 0)
12535 12532                  scfdie();
12536 12533  
12537 12534          /* Delete dependency property groups in dependent services. */
12538 12535          if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12539 12536                  (void) delete_dependents(pg);
12540 12537          else if (scf_error() != SCF_ERROR_NOT_FOUND)
12541 12538                  scfdie();
12542 12539  
12543 12540          scf_iter_destroy(iter);
12544 12541          scf_pg_destroy(pg);
12545 12542          scf_instance_destroy(inst);
12546 12543  
12547 12544          /*
12548 12545           * If the service has some external dependencies then we don't
12549 12546           * want to remove them in case the service is re-imported.
12550 12547           */
12551 12548          if ((pg = scf_pg_create(g_hndl)) == NULL ||
12552 12549              (iter = scf_iter_create(g_hndl)) == NULL)
12553 12550                  scfdie();
12554 12551  
12555 12552          if (scf_iter_service_pgs(iter, svc) < 0)
12556 12553                  scfdie();
12557 12554  
12558 12555          while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12559 12556                  if (pg_is_external_dependency(pg)) {
12560 12557                          external |= 2;
12561 12558                          continue;
12562 12559                  }
12563 12560  
12564 12561                  if (scf_pg_delete(pg) != 0) {
12565 12562                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12566 12563                                  scfdie();
12567 12564                          else {
12568 12565                                  semerr(emsg_permission_denied);
12569 12566  
12570 12567                                  (void) scf_iter_destroy(iter);
12571 12568                                  (void) scf_pg_destroy(pg);
12572 12569                                  return (DELETE_FAILURE);
12573 12570                          }
12574 12571                  }
12575 12572          }
12576 12573  
12577 12574          if (r == -1)
12578 12575                  scfdie();
12579 12576  
12580 12577          (void) scf_iter_destroy(iter);
12581 12578          (void) scf_pg_destroy(pg);
12582 12579  
12583 12580          if (external != 0)
12584 12581                  return (DELETE_SUCCESS_EXTDEPS);
12585 12582  
12586 12583          if (scf_service_delete(svc) == 0)
12587 12584                  return (DELETE_SUCCESS_NOEXTDEPS);
12588 12585  
12589 12586          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12590 12587                  scfdie();
12591 12588  
12592 12589          semerr(emsg_permission_denied);
12593 12590          return (DELETE_FAILURE);
12594 12591  }
12595 12592  
12596 12593  static int
12597 12594  delete_callback(void *data, scf_walkinfo_t *wip)
12598 12595  {
12599 12596          int force = (int)data;
12600 12597  
12601 12598          if (wip->inst != NULL)
12602 12599                  (void) lscf_instance_delete(wip->inst, force);
12603 12600          else
12604 12601                  (void) lscf_service_delete(wip->svc, force);
12605 12602  
12606 12603          return (0);
12607 12604  }
12608 12605  
12609 12606  void
12610 12607  lscf_delete(const char *fmri, int force)
12611 12608  {
12612 12609          scf_service_t *svc;
12613 12610          scf_instance_t *inst;
12614 12611          int ret;
12615 12612  
12616 12613          lscf_prep_hndl();
12617 12614  
12618 12615          if (cur_snap != NULL) {
12619 12616                  if (!snaplevel_is_instance(cur_level)) {
12620 12617                          char *buf;
12621 12618  
12622 12619                          buf = safe_malloc(max_scf_name_len + 1);
12623 12620                          if (scf_instance_get_name(cur_inst, buf,
12624 12621                              max_scf_name_len + 1) >= 0) {
12625 12622                                  if (strcmp(buf, fmri) == 0) {
12626 12623                                          semerr(emsg_cant_modify_snapshots);
12627 12624                                          free(buf);
12628 12625                                          return;
12629 12626                                  }
12630 12627                          } else if (scf_error() != SCF_ERROR_DELETED) {
12631 12628                                  scfdie();
12632 12629                          }
12633 12630                          free(buf);
12634 12631                  }
12635 12632          } else if (cur_inst != NULL) {
12636 12633                  /* EMPTY */;
12637 12634          } else if (cur_svc != NULL) {
12638 12635                  inst = scf_instance_create(g_hndl);
12639 12636                  if (inst == NULL)
12640 12637                          scfdie();
12641 12638  
12642 12639                  if (scf_service_get_instance(cur_svc, fmri, inst) ==
12643 12640                      SCF_SUCCESS) {
12644 12641                          (void) lscf_instance_delete(inst, force);
12645 12642                          scf_instance_destroy(inst);
12646 12643                          return;
12647 12644                  }
12648 12645  
12649 12646                  if (scf_error() != SCF_ERROR_NOT_FOUND &&
12650 12647                      scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12651 12648                          scfdie();
12652 12649  
12653 12650                  scf_instance_destroy(inst);
12654 12651          } else {
12655 12652                  assert(cur_scope != NULL);
12656 12653  
12657 12654                  svc = scf_service_create(g_hndl);
12658 12655                  if (svc == NULL)
12659 12656                          scfdie();
12660 12657  
12661 12658                  if (scf_scope_get_service(cur_scope, fmri, svc) ==
12662 12659                      SCF_SUCCESS) {
12663 12660                          (void) lscf_service_delete(svc, force);
12664 12661                          scf_service_destroy(svc);
12665 12662                          return;
12666 12663                  }
12667 12664  
12668 12665                  if (scf_error() != SCF_ERROR_NOT_FOUND &&
12669 12666                      scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12670 12667                          scfdie();
12671 12668  
12672 12669                  scf_service_destroy(svc);
12673 12670          }
12674 12671  
12675 12672          /*
12676 12673           * Match FMRI to entity.
12677 12674           */
12678 12675          if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12679 12676              delete_callback, (void *)force, NULL, semerr)) != 0) {
12680 12677                  semerr(gettext("Failed to walk instances: %s\n"),
12681 12678                      scf_strerror(ret));
12682 12679          }
12683 12680  }
12684 12681  
12685 12682  
12686 12683  
12687 12684  /*
12688 12685   * :properties commands.  These all end with "pg" or "prop" and generally
12689 12686   * operate on the currently selected entity.
12690 12687   */
12691 12688  
12692 12689  /*
12693 12690   * Property listing.  List the property groups, properties, their types and
12694 12691   * their values for the currently selected entity.
12695 12692   */
12696 12693  static void
12697 12694  list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12698 12695  {
12699 12696          char *buf;
12700 12697          uint32_t flags;
12701 12698  
12702 12699          buf = safe_malloc(max_scf_pg_type_len + 1);
12703 12700  
12704 12701          if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12705 12702                  scfdie();
12706 12703  
12707 12704          if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12708 12705                  scfdie();
12709 12706  
12710 12707          safe_printf("%-*s  %s", namewidth, name, buf);
12711 12708  
12712 12709          if (flags & SCF_PG_FLAG_NONPERSISTENT)
12713 12710                  safe_printf("\tNONPERSISTENT");
12714 12711  
12715 12712          safe_printf("\n");
12716 12713  
12717 12714          free(buf);
12718 12715  }
12719 12716  
12720 12717  static boolean_t
12721 12718  prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12722 12719  {
12723 12720          if (scf_property_get_value(prop, val) == 0) {
12724 12721                  return (B_FALSE);
12725 12722          } else {
12726 12723                  switch (scf_error()) {
12727 12724                  case SCF_ERROR_NOT_FOUND:
12728 12725                          return (B_FALSE);
12729 12726                  case SCF_ERROR_PERMISSION_DENIED:
12730 12727                  case SCF_ERROR_CONSTRAINT_VIOLATED:
12731 12728                          return (B_TRUE);
12732 12729                  default:
12733 12730                          scfdie();
12734 12731                          /*NOTREACHED*/
12735 12732                  }
12736 12733          }
12737 12734  }
12738 12735  
12739 12736  static void
12740 12737  list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12741 12738  {
12742 12739          scf_iter_t *iter;
12743 12740          scf_value_t *val;
12744 12741          const char *type;
12745 12742          int multiple_strings = 0;
12746 12743          int ret;
12747 12744  
12748 12745          if ((iter = scf_iter_create(g_hndl)) == NULL ||
12749 12746              (val = scf_value_create(g_hndl)) == NULL)
12750 12747                  scfdie();
12751 12748  
12752 12749          type = prop_to_typestr(prop);
12753 12750          assert(type != NULL);
12754 12751  
12755 12752          safe_printf("%-*s  %-7s ", len, name, type);
12756 12753  
12757 12754          if (prop_has_multiple_values(prop, val) &&
12758 12755              (scf_value_type(val) == SCF_TYPE_ASTRING ||
12759 12756              scf_value_type(val) == SCF_TYPE_USTRING))
12760 12757                  multiple_strings = 1;
12761 12758  
12762 12759          if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12763 12760                  scfdie();
12764 12761  
12765 12762          while ((ret = scf_iter_next_value(iter, val)) == 1) {
12766 12763                  char *buf;
12767 12764                  ssize_t vlen, szret;
12768 12765  
12769 12766                  vlen = scf_value_get_as_string(val, NULL, 0);
12770 12767                  if (vlen < 0)
12771 12768                          scfdie();
12772 12769  
12773 12770                  buf = safe_malloc(vlen + 1);
12774 12771  
12775 12772                  szret = scf_value_get_as_string(val, buf, vlen + 1);
12776 12773                  if (szret < 0)
12777 12774                          scfdie();
12778 12775                  assert(szret <= vlen);
12779 12776  
12780 12777                  /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12781 12778                  if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12782 12779                          safe_printf(" \"");
12783 12780                          (void) quote_and_print(buf, stdout, 0);
12784 12781                          (void) putchar('"');
12785 12782                          if (ferror(stdout)) {
12786 12783                                  (void) putchar('\n');
12787 12784                                  uu_die(gettext("Error writing to stdout.\n"));
12788 12785                          }
12789 12786                  } else {
12790 12787                          safe_printf(" %s", buf);
12791 12788                  }
12792 12789  
12793 12790                  free(buf);
12794 12791          }
12795 12792          if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12796 12793                  scfdie();
12797 12794  
12798 12795          if (putchar('\n') != '\n')
12799 12796                  uu_die(gettext("Could not output newline"));
12800 12797  }
12801 12798  
12802 12799  /*
12803 12800   * Outputs template property group info for the describe subcommand.
12804 12801   * If 'templates' == 2, verbose output is printed in the format expected
12805 12802   * for describe -v, which includes all templates fields.  If pg is
12806 12803   * not NULL, we're describing the template data, not an existing property
12807 12804   * group, and formatting should be appropriate for describe -t.
12808 12805   */
12809 12806  static void
12810 12807  list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12811 12808  {
12812 12809          char *buf;
12813 12810          uint8_t required;
12814 12811          scf_property_t *stability_prop;
12815 12812          scf_value_t *stability_val;
12816 12813  
12817 12814          if (templates == 0)
12818 12815                  return;
12819 12816  
12820 12817          if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12821 12818              (stability_val = scf_value_create(g_hndl)) == NULL)
12822 12819                  scfdie();
12823 12820  
12824 12821          if (templates == 2 && pg != NULL) {
12825 12822                  if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12826 12823                      stability_prop) == 0) {
12827 12824                          if (prop_check_type(stability_prop,
12828 12825                              SCF_TYPE_ASTRING) == 0 &&
12829 12826                              prop_get_val(stability_prop, stability_val) == 0) {
12830 12827                                  char *stability;
12831 12828  
12832 12829                                  stability = safe_malloc(max_scf_value_len + 1);
12833 12830  
12834 12831                                  if (scf_value_get_astring(stability_val,
12835 12832                                      stability, max_scf_value_len + 1) == -1 &&
12836 12833                                      scf_error() != SCF_ERROR_NOT_FOUND)
12837 12834                                          scfdie();
12838 12835  
12839 12836                                  safe_printf("%s%s: %s\n", TMPL_INDENT,
12840 12837                                      gettext("stability"), stability);
12841 12838  
12842 12839                                  free(stability);
12843 12840                          }
12844 12841                  } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12845 12842                          scfdie();
12846 12843          }
12847 12844  
12848 12845          scf_property_destroy(stability_prop);
12849 12846          scf_value_destroy(stability_val);
12850 12847  
12851 12848          if (pgt == NULL)
12852 12849                  return;
12853 12850  
12854 12851          if (pg == NULL || templates == 2) {
12855 12852                  /* print type info only if scf_tmpl_pg_name succeeds */
12856 12853                  if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12857 12854                          if (pg != NULL)
12858 12855                                  safe_printf("%s", TMPL_INDENT);
12859 12856                          safe_printf("%s: ", gettext("name"));
12860 12857                          safe_printf("%s\n", buf);
12861 12858                          free(buf);
12862 12859                  }
12863 12860  
12864 12861                  /* print type info only if scf_tmpl_pg_type succeeds */
12865 12862                  if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12866 12863                          if (pg != NULL)
12867 12864                                  safe_printf("%s", TMPL_INDENT);
12868 12865                          safe_printf("%s: ", gettext("type"));
12869 12866                          safe_printf("%s\n", buf);
12870 12867                          free(buf);
12871 12868                  }
12872 12869          }
12873 12870  
12874 12871          if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12875 12872                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12876 12873                      required ? "true" : "false");
12877 12874  
12878 12875          if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12879 12876                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12880 12877                      buf);
12881 12878                  free(buf);
12882 12879          }
12883 12880  
12884 12881          if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12885 12882                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12886 12883                      buf);
12887 12884                  free(buf);
12888 12885          }
12889 12886  
12890 12887          if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12891 12888                  if (templates == 2)
12892 12889                          safe_printf("%s%s: %s\n", TMPL_INDENT,
12893 12890                              gettext("description"), buf);
12894 12891                  else
12895 12892                          safe_printf("%s%s\n", TMPL_INDENT, buf);
12896 12893                  free(buf);
12897 12894          }
12898 12895  
12899 12896  }
12900 12897  
12901 12898  /*
12902 12899   * With as_value set to true, indent as appropriate for the value level.
12903 12900   * If false, indent to appropriate level for inclusion in constraint
12904 12901   * or choice printout.
12905 12902   */
12906 12903  static void
12907 12904  print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12908 12905      int as_value)
12909 12906  {
12910 12907          char *buf;
12911 12908  
12912 12909          if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12913 12910                  if (as_value == 0)
12914 12911                          safe_printf("%s", TMPL_CHOICE_INDENT);
12915 12912                  else
12916 12913                          safe_printf("%s", TMPL_INDENT);
12917 12914                  safe_printf("%s: %s\n", gettext("value common name"), buf);
12918 12915                  free(buf);
12919 12916          }
12920 12917  
12921 12918          if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12922 12919                  if (as_value == 0)
12923 12920                          safe_printf("%s", TMPL_CHOICE_INDENT);
12924 12921                  else
12925 12922                          safe_printf("%s", TMPL_INDENT);
12926 12923                  safe_printf("%s: %s\n", gettext("value description"), buf);
12927 12924                  free(buf);
12928 12925          }
12929 12926  }
12930 12927  
12931 12928  static void
12932 12929  print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12933 12930  {
12934 12931          safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12935 12932          /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12936 12933          safe_printf("%s\n", val_buf);
12937 12934  
12938 12935          print_template_value_details(prt, val_buf, 1);
12939 12936  }
12940 12937  
12941 12938  static void
12942 12939  print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12943 12940  {
12944 12941          int i, printed = 0;
12945 12942          scf_values_t values;
12946 12943          scf_count_ranges_t c_ranges;
12947 12944          scf_int_ranges_t i_ranges;
12948 12945  
12949 12946          printed = 0;
12950 12947          i = 0;
12951 12948          if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12952 12949                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12953 12950                      gettext("value constraints"));
12954 12951                  printed++;
12955 12952                  for (i = 0; i < values.value_count; ++i) {
12956 12953                          safe_printf("%s%s: %s\n", TMPL_INDENT,
12957 12954                              gettext("value name"), values.values_as_strings[i]);
12958 12955                          if (verbose == 1)
12959 12956                                  print_template_value_details(prt,
12960 12957                                      values.values_as_strings[i], 0);
12961 12958                  }
12962 12959  
12963 12960                  scf_values_destroy(&values);
12964 12961          }
12965 12962  
12966 12963          if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12967 12964                  if (printed++ == 0)
12968 12965                          safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12969 12966                              gettext("value constraints"));
12970 12967                  for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12971 12968                          safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12972 12969                              gettext("range"), c_ranges.scr_min[i],
12973 12970                              c_ranges.scr_max[i]);
12974 12971                  }
12975 12972                  scf_count_ranges_destroy(&c_ranges);
12976 12973          } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12977 12974              scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12978 12975                  if (printed++ == 0)
12979 12976                          safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12980 12977                              gettext("value constraints"));
12981 12978                  for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12982 12979                          safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12983 12980                              gettext("range"), i_ranges.sir_min[i],
12984 12981                              i_ranges.sir_max[i]);
12985 12982                  }
12986 12983                  scf_int_ranges_destroy(&i_ranges);
12987 12984          }
12988 12985  }
12989 12986  
12990 12987  static void
12991 12988  print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12992 12989  {
12993 12990          int i = 0, printed = 0;
12994 12991          scf_values_t values;
12995 12992          scf_count_ranges_t c_ranges;
12996 12993          scf_int_ranges_t i_ranges;
12997 12994  
12998 12995          printed = 0;
12999 12996          if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13000 12997                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13001 12998                      gettext("value constraints"));
13002 12999                  printed++;
13003 13000                  for (i = 0; i < values.value_count; i++) {
13004 13001                          safe_printf("%s%s: %s\n", TMPL_INDENT,
13005 13002                              gettext("value name"), values.values_as_strings[i]);
13006 13003                          if (verbose == 1)
13007 13004                                  print_template_value_details(prt,
13008 13005                                      values.values_as_strings[i], 0);
13009 13006                  }
13010 13007  
13011 13008                  scf_values_destroy(&values);
13012 13009          }
13013 13010  
13014 13011          if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13015 13012                  for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13016 13013                          if (printed++ == 0)
13017 13014                                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13018 13015                                      gettext("value choices"));
13019 13016                          safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13020 13017                              gettext("range"), c_ranges.scr_min[i],
13021 13018                              c_ranges.scr_max[i]);
13022 13019                  }
13023 13020                  scf_count_ranges_destroy(&c_ranges);
13024 13021          } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13025 13022              scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13026 13023                  for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13027 13024                          if (printed++ == 0)
13028 13025                                  safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13029 13026                                      gettext("value choices"));
13030 13027                          safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13031 13028                              gettext("range"), i_ranges.sir_min[i],
13032 13029                              i_ranges.sir_max[i]);
13033 13030                  }
13034 13031                  scf_int_ranges_destroy(&i_ranges);
13035 13032          }
13036 13033  }
13037 13034  
13038 13035  static void
13039 13036  list_values_by_template(scf_prop_tmpl_t *prt)
13040 13037  {
13041 13038          print_template_constraints(prt, 1);
13042 13039          print_template_choices(prt, 1);
13043 13040  }
13044 13041  
13045 13042  static void
13046 13043  list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13047 13044  {
13048 13045          char *val_buf;
13049 13046          scf_iter_t *iter;
13050 13047          scf_value_t *val;
13051 13048          int ret;
13052 13049  
13053 13050          if ((iter = scf_iter_create(g_hndl)) == NULL ||
13054 13051              (val = scf_value_create(g_hndl)) == NULL)
13055 13052                  scfdie();
13056 13053  
13057 13054          if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13058 13055                  scfdie();
13059 13056  
13060 13057          val_buf = safe_malloc(max_scf_value_len + 1);
13061 13058  
13062 13059          while ((ret = scf_iter_next_value(iter, val)) == 1) {
13063 13060                  if (scf_value_get_as_string(val, val_buf,
13064 13061                      max_scf_value_len + 1) < 0)
13065 13062                          scfdie();
13066 13063  
13067 13064                  print_template_value(prt, val_buf);
13068 13065          }
13069 13066          if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13070 13067                  scfdie();
13071 13068          free(val_buf);
13072 13069  
13073 13070          print_template_constraints(prt, 0);
13074 13071          print_template_choices(prt, 0);
13075 13072  
13076 13073  }
13077 13074  
13078 13075  /*
13079 13076   * Outputs property info for the describe subcommand
13080 13077   * Verbose output if templates == 2, -v option of svccfg describe
13081 13078   * Displays template data if prop is not NULL, -t option of svccfg describe
13082 13079   */
13083 13080  static void
13084 13081  list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13085 13082  {
13086 13083          char *buf;
13087 13084          uint8_t u_buf;
13088 13085          int i;
13089 13086          uint64_t min, max;
13090 13087          scf_values_t values;
13091 13088  
13092 13089          if (prt == NULL || templates == 0)
13093 13090                  return;
13094 13091  
13095 13092          if (prop == NULL) {
13096 13093                  safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13097 13094                  if (scf_tmpl_prop_name(prt, &buf) > 0) {
13098 13095                          safe_printf("%s\n", buf);
13099 13096                          free(buf);
13100 13097                  } else
13101 13098                          safe_printf("(%s)\n", gettext("any"));
13102 13099          }
13103 13100  
13104 13101          if (prop == NULL || templates == 2) {
13105 13102                  if (prop != NULL)
13106 13103                          safe_printf("%s", TMPL_INDENT);
13107 13104                  else
13108 13105                          safe_printf("%s", TMPL_VALUE_INDENT);
13109 13106                  safe_printf("%s: ", gettext("type"));
13110 13107                  if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13111 13108                          safe_printf("%s\n", buf);
13112 13109                          free(buf);
13113 13110                  } else
13114 13111                          safe_printf("(%s)\n", gettext("any"));
13115 13112          }
13116 13113  
13117 13114          if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13118 13115                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13119 13116                      u_buf ? "true" : "false");
13120 13117  
13121 13118          if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13122 13119                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13123 13120                      buf);
13124 13121                  free(buf);
13125 13122          }
13126 13123  
13127 13124          if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13128 13125                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13129 13126                      buf);
13130 13127                  free(buf);
13131 13128          }
13132 13129  
13133 13130          if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13134 13131                  safe_printf("%s%s\n", TMPL_INDENT, buf);
13135 13132                  free(buf);
13136 13133          }
13137 13134  
13138 13135          if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13139 13136                  safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13140 13137                      scf_tmpl_visibility_to_string(u_buf));
13141 13138  
13142 13139          if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13143 13140                  safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13144 13141                      gettext("minimum number of values"), min);
13145 13142                  if (max == ULLONG_MAX) {
13146 13143                          safe_printf("%s%s: %s\n", TMPL_INDENT,
13147 13144                              gettext("maximum number of values"),
13148 13145                              gettext("unlimited"));
13149 13146                  } else {
13150 13147                          safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13151 13148                              gettext("maximum number of values"), max);
13152 13149                  }
13153 13150          }
13154 13151  
13155 13152          if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13156 13153                  for (i = 0; i < values.value_count; i++) {
13157 13154                          if (i == 0) {
13158 13155                                  safe_printf("%s%s:", TMPL_INDENT,
13159 13156                                      gettext("internal separators"));
13160 13157                          }
13161 13158                          safe_printf(" \"%s\"", values.values_as_strings[i]);
13162 13159                  }
13163 13160                  safe_printf("\n");
13164 13161          }
13165 13162  
13166 13163          if (templates != 2)
13167 13164                  return;
13168 13165  
13169 13166          if (prop != NULL)
13170 13167                  list_values_tmpl(prt, prop);
13171 13168          else
13172 13169                  list_values_by_template(prt);
13173 13170  }
13174 13171  
13175 13172  static char *
13176 13173  read_astring(scf_propertygroup_t *pg, const char *prop_name)
13177 13174  {
13178 13175          char *rv;
13179 13176  
13180 13177          rv = _scf_read_single_astring_from_pg(pg, prop_name);
13181 13178          if (rv == NULL) {
13182 13179                  switch (scf_error()) {
13183 13180                  case SCF_ERROR_NOT_FOUND:
13184 13181                          break;
13185 13182                  default:
13186 13183                          scfdie();
13187 13184                  }
13188 13185          }
13189 13186          return (rv);
13190 13187  }
13191 13188  
13192 13189  static void
13193 13190  display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13194 13191  {
13195 13192          size_t doc_len;
13196 13193          size_t man_len;
13197 13194          char *pg_name;
13198 13195          char *text = NULL;
13199 13196          int rv;
13200 13197  
13201 13198          doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13202 13199          man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13203 13200          pg_name = safe_malloc(max_scf_name_len + 1);
13204 13201          while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13205 13202                  if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13206 13203                          scfdie();
13207 13204                  }
13208 13205                  if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13209 13206                          /* Display doc_link and and uri */
13210 13207                          safe_printf("%s%s:\n", TMPL_INDENT,
13211 13208                              gettext("doc_link"));
13212 13209                          text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13213 13210                          if (text != NULL) {
13214 13211                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13215 13212                                      TMPL_INDENT, gettext("name"), text);
13216 13213                                  uu_free(text);
13217 13214                          }
13218 13215                          text = read_astring(pg, SCF_PROPERTY_TM_URI);
13219 13216                          if (text != NULL) {
13220 13217                                  safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13221 13218                                      gettext("uri"), text);
13222 13219                                  uu_free(text);
13223 13220                          }
13224 13221                  } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13225 13222                      man_len) == 0) {
13226 13223                          /* Display manpage title, section and path */
13227 13224                          safe_printf("%s%s:\n", TMPL_INDENT,
13228 13225                              gettext("manpage"));
13229 13226                          text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13230 13227                          if (text != NULL) {
13231 13228                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13232 13229                                      TMPL_INDENT, gettext("title"), text);
13233 13230                                  uu_free(text);
13234 13231                          }
13235 13232                          text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13236 13233                          if (text != NULL) {
13237 13234                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13238 13235                                      TMPL_INDENT, gettext("section"), text);
13239 13236                                  uu_free(text);
13240 13237                          }
13241 13238                          text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13242 13239                          if (text != NULL) {
13243 13240                                  safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13244 13241                                      TMPL_INDENT, gettext("manpath"), text);
13245 13242                                  uu_free(text);
13246 13243                          }
13247 13244                  }
13248 13245          }
13249 13246          if (rv == -1)
13250 13247                  scfdie();
13251 13248  
13252 13249  done:
13253 13250          free(pg_name);
13254 13251  }
13255 13252  
13256 13253  static void
13257 13254  list_entity_tmpl(int templates)
13258 13255  {
13259 13256          char *common_name = NULL;
13260 13257          char *description = NULL;
13261 13258          char *locale = NULL;
13262 13259          scf_iter_t *iter;
13263 13260          scf_propertygroup_t *pg;
13264 13261          scf_property_t *prop;
13265 13262          int r;
13266 13263          scf_value_t *val;
13267 13264  
13268 13265          if ((pg = scf_pg_create(g_hndl)) == NULL ||
13269 13266              (prop = scf_property_create(g_hndl)) == NULL ||
13270 13267              (val = scf_value_create(g_hndl)) == NULL ||
13271 13268              (iter = scf_iter_create(g_hndl)) == NULL)
13272 13269                  scfdie();
13273 13270  
13274 13271          locale = setlocale(LC_MESSAGES, NULL);
13275 13272  
13276 13273          if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13277 13274                  common_name = safe_malloc(max_scf_value_len + 1);
13278 13275  
13279 13276                  /* Try both the current locale and the "C" locale. */
13280 13277                  if (scf_pg_get_property(pg, locale, prop) == 0 ||
13281 13278                      (scf_error() == SCF_ERROR_NOT_FOUND &&
13282 13279                      scf_pg_get_property(pg, "C", prop) == 0)) {
13283 13280                          if (prop_get_val(prop, val) == 0 &&
13284 13281                              scf_value_get_ustring(val, common_name,
13285 13282                              max_scf_value_len + 1) != -1) {
13286 13283                                  safe_printf("%s%s: %s\n", TMPL_INDENT,
13287 13284                                      gettext("common name"), common_name);
13288 13285                          }
13289 13286                  }
13290 13287          }
13291 13288  
13292 13289          /*
13293 13290           * Do description, manpages, and doc links if templates == 2.
13294 13291           */
13295 13292          if (templates == 2) {
13296 13293                  /* Get the description. */
13297 13294                  if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13298 13295                          description = safe_malloc(max_scf_value_len + 1);
13299 13296  
13300 13297                          /* Try both the current locale and the "C" locale. */
13301 13298                          if (scf_pg_get_property(pg, locale, prop) == 0 ||
13302 13299                              (scf_error() == SCF_ERROR_NOT_FOUND &&
13303 13300                              scf_pg_get_property(pg, "C", prop) == 0)) {
13304 13301                                  if (prop_get_val(prop, val) == 0 &&
13305 13302                                      scf_value_get_ustring(val, description,
13306 13303                                      max_scf_value_len + 1) != -1) {
13307 13304                                          safe_printf("%s%s: %s\n", TMPL_INDENT,
13308 13305                                              gettext("description"),
13309 13306                                              description);
13310 13307                                  }
13311 13308                          }
13312 13309                  }
13313 13310  
13314 13311                  /* Process doc_link & manpage elements. */
13315 13312                  if (cur_level != NULL) {
13316 13313                          r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13317 13314                              SCF_GROUP_TEMPLATE);
13318 13315                  } else if (cur_inst != NULL) {
13319 13316                          r = scf_iter_instance_pgs_typed(iter, cur_inst,
13320 13317                              SCF_GROUP_TEMPLATE);
13321 13318                  } else {
13322 13319                          r = scf_iter_service_pgs_typed(iter, cur_svc,
13323 13320                              SCF_GROUP_TEMPLATE);
13324 13321                  }
13325 13322                  if (r == 0) {
13326 13323                          display_documentation(iter, pg);
13327 13324                  }
13328 13325          }
13329 13326  
13330 13327          free(common_name);
13331 13328          free(description);
13332 13329          scf_pg_destroy(pg);
13333 13330          scf_property_destroy(prop);
13334 13331          scf_value_destroy(val);
13335 13332          scf_iter_destroy(iter);
13336 13333  }
13337 13334  
13338 13335  static void
13339 13336  listtmpl(const char *pattern, int templates)
13340 13337  {
13341 13338          scf_pg_tmpl_t *pgt;
13342 13339          scf_prop_tmpl_t *prt;
13343 13340          char *snapbuf = NULL;
13344 13341          char *fmribuf;
13345 13342          char *pg_name = NULL, *prop_name = NULL;
13346 13343          ssize_t prop_name_size;
13347 13344          char *qual_prop_name;
13348 13345          char *search_name;
13349 13346          int listed = 0;
13350 13347  
13351 13348          if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13352 13349              (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13353 13350                  scfdie();
13354 13351  
13355 13352          fmribuf = safe_malloc(max_scf_name_len + 1);
13356 13353          qual_prop_name = safe_malloc(max_scf_name_len + 1);
13357 13354  
13358 13355          if (cur_snap != NULL) {
13359 13356                  snapbuf = safe_malloc(max_scf_name_len + 1);
13360 13357                  if (scf_snapshot_get_name(cur_snap, snapbuf,
13361 13358                      max_scf_name_len + 1) < 0)
13362 13359                          scfdie();
13363 13360          }
13364 13361  
13365 13362          if (cur_inst != NULL) {
13366 13363                  if (scf_instance_to_fmri(cur_inst, fmribuf,
13367 13364                      max_scf_name_len + 1) < 0)
13368 13365                          scfdie();
13369 13366          } else if (cur_svc != NULL) {
13370 13367                  if (scf_service_to_fmri(cur_svc, fmribuf,
13371 13368                      max_scf_name_len + 1) < 0)
13372 13369                          scfdie();
13373 13370          } else
13374 13371                  abort();
13375 13372  
13376 13373          /* If pattern is specified, we want to list only those items. */
13377 13374          while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13378 13375                  listed = 0;
13379 13376                  if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13380 13377                      fnmatch(pattern, pg_name, 0) == 0)) {
13381 13378                          list_pg_tmpl(pgt, NULL, templates);
13382 13379                          listed++;
13383 13380                  }
13384 13381  
13385 13382                  scf_tmpl_prop_reset(prt);
13386 13383  
13387 13384                  while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13388 13385                          search_name = NULL;
13389 13386                          prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13390 13387                          if ((prop_name_size > 0) && (pg_name != NULL)) {
13391 13388                                  if (snprintf(qual_prop_name,
13392 13389                                      max_scf_name_len + 1, "%s/%s",
13393 13390                                      pg_name, prop_name) >=
13394 13391                                      max_scf_name_len + 1) {
13395 13392                                          prop_name_size = -1;
13396 13393                                  } else {
13397 13394                                          search_name = qual_prop_name;
13398 13395                                  }
13399 13396                          }
13400 13397                          if (listed > 0 || pattern == NULL ||
13401 13398                              (prop_name_size > 0 &&
13402 13399                              fnmatch(pattern, search_name,
13403 13400                              FNM_PATHNAME) == 0))
13404 13401                                  list_prop_tmpl(prt, NULL, templates);
13405 13402                          if (prop_name != NULL) {
13406 13403                                  free(prop_name);
13407 13404                                  prop_name = NULL;
13408 13405                          }
13409 13406                  }
13410 13407                  if (pg_name != NULL) {
13411 13408                          free(pg_name);
13412 13409                          pg_name = NULL;
13413 13410                  }
13414 13411          }
13415 13412  
13416 13413          scf_tmpl_prop_destroy(prt);
13417 13414          scf_tmpl_pg_destroy(pgt);
13418 13415          free(snapbuf);
13419 13416          free(fmribuf);
13420 13417          free(qual_prop_name);
13421 13418  }
13422 13419  
13423 13420  static void
13424 13421  listprop(const char *pattern, int only_pgs, int templates)
13425 13422  {
13426 13423          scf_propertygroup_t *pg;
13427 13424          scf_property_t *prop;
13428 13425          scf_iter_t *iter, *piter;
13429 13426          char *pgnbuf, *prnbuf, *ppnbuf;
13430 13427          scf_pg_tmpl_t *pgt, *pgtp;
13431 13428          scf_prop_tmpl_t *prt;
13432 13429  
13433 13430          void **objects;
13434 13431          char **names;
13435 13432          void **tmpls;
13436 13433          int allocd, i;
13437 13434  
13438 13435          int ret;
13439 13436          ssize_t pgnlen, prnlen, szret;
13440 13437          size_t max_len = 0;
13441 13438  
13442 13439          if (cur_svc == NULL && cur_inst == NULL) {
13443 13440                  semerr(emsg_entity_not_selected);
13444 13441                  return;
13445 13442          }
13446 13443  
13447 13444          if ((pg = scf_pg_create(g_hndl)) == NULL ||
13448 13445              (prop = scf_property_create(g_hndl)) == NULL ||
13449 13446              (iter = scf_iter_create(g_hndl)) == NULL ||
13450 13447              (piter = scf_iter_create(g_hndl)) == NULL ||
13451 13448              (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13452 13449              (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13453 13450                  scfdie();
13454 13451  
13455 13452          prnbuf = safe_malloc(max_scf_name_len + 1);
13456 13453  
13457 13454          if (cur_level != NULL)
13458 13455                  ret = scf_iter_snaplevel_pgs(iter, cur_level);
13459 13456          else if (cur_inst != NULL)
13460 13457                  ret = scf_iter_instance_pgs(iter, cur_inst);
13461 13458          else
13462 13459                  ret = scf_iter_service_pgs(iter, cur_svc);
13463 13460          if (ret != 0) {
13464 13461                  return;
13465 13462          }
13466 13463  
13467 13464          /*
13468 13465           * We want to only list items which match pattern, and we want the
13469 13466           * second column to line up, so during the first pass we'll save
13470 13467           * matching items, their names, and their templates in objects,
13471 13468           * names, and tmpls, computing the maximum name length as we go,
13472 13469           * and then we'll print them out.
13473 13470           *
13474 13471           * Note: We always keep an extra slot available so the array can be
13475 13472           * NULL-terminated.
13476 13473           */
13477 13474          i = 0;
13478 13475          allocd = 1;
13479 13476          objects = safe_malloc(sizeof (*objects));
13480 13477          names = safe_malloc(sizeof (*names));
13481 13478          tmpls = safe_malloc(sizeof (*tmpls));
13482 13479  
13483 13480          while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13484 13481                  int new_pg = 0;
13485 13482                  int print_props = 0;
13486 13483                  pgtp = NULL;
13487 13484  
13488 13485                  pgnlen = scf_pg_get_name(pg, NULL, 0);
13489 13486                  if (pgnlen < 0)
13490 13487                          scfdie();
13491 13488  
13492 13489                  pgnbuf = safe_malloc(pgnlen + 1);
13493 13490  
13494 13491                  szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13495 13492                  if (szret < 0)
13496 13493                          scfdie();
13497 13494                  assert(szret <= pgnlen);
13498 13495  
13499 13496                  if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13500 13497                          if (scf_error() != SCF_ERROR_NOT_FOUND)
13501 13498                                  scfdie();
13502 13499                          pgtp = NULL;
13503 13500                  } else {
13504 13501                          pgtp = pgt;
13505 13502                  }
13506 13503  
13507 13504                  if (pattern == NULL ||
13508 13505                      fnmatch(pattern, pgnbuf, 0) == 0) {
13509 13506                          if (i+1 >= allocd) {
13510 13507                                  allocd *= 2;
13511 13508                                  objects = realloc(objects,
13512 13509                                      sizeof (*objects) * allocd);
13513 13510                                  names =
13514 13511                                      realloc(names, sizeof (*names) * allocd);
13515 13512                                  tmpls = realloc(tmpls,
13516 13513                                      sizeof (*tmpls) * allocd);
13517 13514                                  if (objects == NULL || names == NULL ||
13518 13515                                      tmpls == NULL)
13519 13516                                          uu_die(gettext("Out of memory"));
13520 13517                          }
13521 13518                          objects[i] = pg;
13522 13519                          names[i] = pgnbuf;
13523 13520  
13524 13521                          if (pgtp == NULL)
13525 13522                                  tmpls[i] = NULL;
13526 13523                          else
13527 13524                                  tmpls[i] = pgt;
13528 13525  
13529 13526                          ++i;
13530 13527  
13531 13528                          if (pgnlen > max_len)
13532 13529                                  max_len = pgnlen;
13533 13530  
13534 13531                          new_pg = 1;
13535 13532                          print_props = 1;
13536 13533                  }
13537 13534  
13538 13535                  if (only_pgs) {
13539 13536                          if (new_pg) {
13540 13537                                  pg = scf_pg_create(g_hndl);
13541 13538                                  if (pg == NULL)
13542 13539                                          scfdie();
13543 13540                                  pgt = scf_tmpl_pg_create(g_hndl);
13544 13541                                  if (pgt == NULL)
13545 13542                                          scfdie();
13546 13543                          } else
13547 13544                                  free(pgnbuf);
13548 13545  
13549 13546                          continue;
13550 13547                  }
13551 13548  
13552 13549                  if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13553 13550                          scfdie();
13554 13551  
13555 13552                  while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13556 13553                          prnlen = scf_property_get_name(prop, prnbuf,
13557 13554                              max_scf_name_len + 1);
13558 13555                          if (prnlen < 0)
13559 13556                                  scfdie();
13560 13557  
13561 13558                          /* Will prepend the property group name and a slash. */
13562 13559                          prnlen += pgnlen + 1;
13563 13560  
13564 13561                          ppnbuf = safe_malloc(prnlen + 1);
13565 13562  
13566 13563                          if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13567 13564                              prnbuf) < 0)
13568 13565                                  uu_die("snprintf");
13569 13566  
13570 13567                          if (pattern == NULL || print_props == 1 ||
13571 13568                              fnmatch(pattern, ppnbuf, 0) == 0) {
13572 13569                                  if (i+1 >= allocd) {
13573 13570                                          allocd *= 2;
13574 13571                                          objects = realloc(objects,
13575 13572                                              sizeof (*objects) * allocd);
13576 13573                                          names = realloc(names,
13577 13574                                              sizeof (*names) * allocd);
13578 13575                                          tmpls = realloc(tmpls,
13579 13576                                              sizeof (*tmpls) * allocd);
13580 13577                                          if (objects == NULL || names == NULL ||
13581 13578                                              tmpls == NULL)
13582 13579                                                  uu_die(gettext(
13583 13580                                                      "Out of memory"));
13584 13581                                  }
13585 13582  
13586 13583                                  objects[i] = prop;
13587 13584                                  names[i] = ppnbuf;
13588 13585  
13589 13586                                  if (pgtp != NULL) {
13590 13587                                          if (scf_tmpl_get_by_prop(pgt, prnbuf,
13591 13588                                              prt, 0) < 0) {
13592 13589                                                  if (scf_error() !=
13593 13590                                                      SCF_ERROR_NOT_FOUND)
13594 13591                                                          scfdie();
13595 13592                                                  tmpls[i] = NULL;
13596 13593                                          } else {
13597 13594                                                  tmpls[i] = prt;
13598 13595                                          }
13599 13596                                  } else {
13600 13597                                          tmpls[i] = NULL;
13601 13598                                  }
13602 13599  
13603 13600                                  ++i;
13604 13601  
13605 13602                                  if (prnlen > max_len)
13606 13603                                          max_len = prnlen;
13607 13604  
13608 13605                                  prop = scf_property_create(g_hndl);
13609 13606                                  prt = scf_tmpl_prop_create(g_hndl);
13610 13607                          } else {
13611 13608                                  free(ppnbuf);
13612 13609                          }
13613 13610                  }
13614 13611  
13615 13612                  if (new_pg) {
13616 13613                          pg = scf_pg_create(g_hndl);
13617 13614                          if (pg == NULL)
13618 13615                                  scfdie();
13619 13616                          pgt = scf_tmpl_pg_create(g_hndl);
13620 13617                          if (pgt == NULL)
13621 13618                                  scfdie();
13622 13619                  } else
13623 13620                          free(pgnbuf);
13624 13621          }
13625 13622          if (ret != 0)
13626 13623                  scfdie();
13627 13624  
13628 13625          objects[i] = NULL;
13629 13626  
13630 13627          scf_pg_destroy(pg);
13631 13628          scf_tmpl_pg_destroy(pgt);
13632 13629          scf_property_destroy(prop);
13633 13630          scf_tmpl_prop_destroy(prt);
13634 13631  
13635 13632          for (i = 0; objects[i] != NULL; ++i) {
13636 13633                  if (strchr(names[i], '/') == NULL) {
13637 13634                          /* property group */
13638 13635                          pg = (scf_propertygroup_t *)objects[i];
13639 13636                          pgt = (scf_pg_tmpl_t *)tmpls[i];
13640 13637                          list_pg_info(pg, names[i], max_len);
13641 13638                          list_pg_tmpl(pgt, pg, templates);
13642 13639                          free(names[i]);
13643 13640                          scf_pg_destroy(pg);
13644 13641                          if (pgt != NULL)
13645 13642                                  scf_tmpl_pg_destroy(pgt);
13646 13643                  } else {
13647 13644                          /* property */
13648 13645                          prop = (scf_property_t *)objects[i];
13649 13646                          prt = (scf_prop_tmpl_t *)tmpls[i];
13650 13647                          list_prop_info(prop, names[i], max_len);
13651 13648                          list_prop_tmpl(prt, prop, templates);
13652 13649                          free(names[i]);
13653 13650                          scf_property_destroy(prop);
13654 13651                          if (prt != NULL)
13655 13652                                  scf_tmpl_prop_destroy(prt);
13656 13653                  }
13657 13654          }
13658 13655  
13659 13656          free(names);
13660 13657          free(objects);
13661 13658          free(tmpls);
13662 13659  }
13663 13660  
13664 13661  void
13665 13662  lscf_listpg(const char *pattern)
13666 13663  {
13667 13664          lscf_prep_hndl();
13668 13665  
13669 13666          listprop(pattern, 1, 0);
13670 13667  }
13671 13668  
13672 13669  /*
13673 13670   * Property group and property creation, setting, and deletion.  setprop (and
13674 13671   * its alias, addprop) can either create a property group of a given type, or
13675 13672   * it can create or set a property to a given type and list of values.
13676 13673   */
13677 13674  void
13678 13675  lscf_addpg(const char *name, const char *type, const char *flags)
13679 13676  {
13680 13677          scf_propertygroup_t *pg;
13681 13678          int ret;
13682 13679          uint32_t flgs = 0;
13683 13680          const char *cp;
13684 13681  
13685 13682  
13686 13683          lscf_prep_hndl();
13687 13684  
13688 13685          if (cur_snap != NULL) {
13689 13686                  semerr(emsg_cant_modify_snapshots);
13690 13687                  return;
13691 13688          }
13692 13689  
13693 13690          if (cur_inst == NULL && cur_svc == NULL) {
13694 13691                  semerr(emsg_entity_not_selected);
13695 13692                  return;
13696 13693          }
13697 13694  
13698 13695          if (flags != NULL) {
13699 13696                  for (cp = flags; *cp != '\0'; ++cp) {
13700 13697                          switch (*cp) {
13701 13698                          case 'P':
13702 13699                                  flgs |= SCF_PG_FLAG_NONPERSISTENT;
13703 13700                                  break;
13704 13701  
13705 13702                          case 'p':
13706 13703                                  flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13707 13704                                  break;
13708 13705  
13709 13706                          default:
13710 13707                                  semerr(gettext("Invalid property group flag "
13711 13708                                      "%c."), *cp);
13712 13709                                  return;
13713 13710                          }
13714 13711                  }
13715 13712          }
13716 13713  
13717 13714          pg = scf_pg_create(g_hndl);
13718 13715          if (pg == NULL)
13719 13716                  scfdie();
13720 13717  
13721 13718          if (cur_inst != NULL)
13722 13719                  ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13723 13720          else
13724 13721                  ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13725 13722  
13726 13723          if (ret != SCF_SUCCESS) {
13727 13724                  switch (scf_error()) {
13728 13725                  case SCF_ERROR_INVALID_ARGUMENT:
13729 13726                          semerr(gettext("Name, type, or flags are invalid.\n"));
13730 13727                          break;
13731 13728  
13732 13729                  case SCF_ERROR_EXISTS:
13733 13730                          semerr(gettext("Property group already exists.\n"));
13734 13731                          break;
13735 13732  
13736 13733                  case SCF_ERROR_PERMISSION_DENIED:
13737 13734                          semerr(emsg_permission_denied);
13738 13735                          break;
13739 13736  
13740 13737                  case SCF_ERROR_BACKEND_ACCESS:
13741 13738                          semerr(gettext("Backend refused access.\n"));
13742 13739                          break;
13743 13740  
13744 13741                  default:
13745 13742                          scfdie();
13746 13743                  }
13747 13744          }
13748 13745  
13749 13746          scf_pg_destroy(pg);
13750 13747  
13751 13748          private_refresh();
13752 13749  }
13753 13750  
13754 13751  void
13755 13752  lscf_delpg(char *name)
13756 13753  {
13757 13754          lscf_prep_hndl();
13758 13755  
13759 13756          if (cur_snap != NULL) {
13760 13757                  semerr(emsg_cant_modify_snapshots);
13761 13758                  return;
13762 13759          }
13763 13760  
13764 13761          if (cur_inst == NULL && cur_svc == NULL) {
13765 13762                  semerr(emsg_entity_not_selected);
13766 13763                  return;
13767 13764          }
13768 13765  
13769 13766          if (strchr(name, '/') != NULL) {
13770 13767                  semerr(emsg_invalid_pg_name, name);
13771 13768                  return;
13772 13769          }
13773 13770  
13774 13771          lscf_delprop(name);
13775 13772  }
13776 13773  
13777 13774  /*
13778 13775   * scf_delhash() is used to remove the property group related to the
13779 13776   * hash entry for a specific manifest in the repository. pgname will be
13780 13777   * constructed from the location of the manifest file. If deathrow isn't 0,
13781 13778   * manifest file doesn't need to exist (manifest string will be used as
13782 13779   * an absolute path).
13783 13780   */
13784 13781  void
13785 13782  lscf_delhash(char *manifest, int deathrow)
13786 13783  {
13787 13784          char *pgname;
13788 13785  
13789 13786          if (cur_snap != NULL ||
13790 13787              cur_inst != NULL || cur_svc != NULL) {
13791 13788                  warn(gettext("error, an entity is selected\n"));
13792 13789                  return;
13793 13790          }
13794 13791  
13795 13792          /* select smf/manifest */
13796 13793          lscf_select(HASH_SVC);
13797 13794          /*
13798 13795           * Translate the manifest file name to property name. In the deathrow
13799 13796           * case, the manifest file does not need to exist.
13800 13797           */
13801 13798          pgname = mhash_filename_to_propname(manifest,
13802 13799              deathrow ? B_TRUE : B_FALSE);
13803 13800          if (pgname == NULL) {
13804 13801                  warn(gettext("cannot resolve pathname for %s\n"), manifest);
13805 13802                  return;
13806 13803          }
13807 13804          /* delete the hash property name */
13808 13805          lscf_delpg(pgname);
13809 13806  }
13810 13807  
13811 13808  void
13812 13809  lscf_listprop(const char *pattern)
13813 13810  {
13814 13811          lscf_prep_hndl();
13815 13812  
13816 13813          listprop(pattern, 0, 0);
13817 13814  }
13818 13815  
13819 13816  int
13820 13817  lscf_setprop(const char *pgname, const char *type, const char *value,
13821 13818      const uu_list_t *values)
13822 13819  {
13823 13820          scf_type_t ty, current_ty;
13824 13821          scf_service_t *svc;
13825 13822          scf_propertygroup_t *pg, *parent_pg;
13826 13823          scf_property_t *prop, *parent_prop;
13827 13824          scf_pg_tmpl_t *pgt;
13828 13825          scf_prop_tmpl_t *prt;
13829 13826          int ret, result = 0;
13830 13827          scf_transaction_t *tx;
13831 13828          scf_transaction_entry_t *e;
13832 13829          scf_value_t *v;
13833 13830          uu_list_walk_t *walk;
13834 13831          string_list_t *sp;
13835 13832          char *propname;
13836 13833          int req_quotes = 0;
13837 13834  
13838 13835          lscf_prep_hndl();
13839 13836  
13840 13837          if ((e = scf_entry_create(g_hndl)) == NULL ||
13841 13838              (svc = scf_service_create(g_hndl)) == NULL ||
13842 13839              (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13843 13840              (pg = scf_pg_create(g_hndl)) == NULL ||
13844 13841              (parent_prop = scf_property_create(g_hndl)) == NULL ||
13845 13842              (prop = scf_property_create(g_hndl)) == NULL ||
13846 13843              (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13847 13844              (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13848 13845              (tx = scf_transaction_create(g_hndl)) == NULL)
13849 13846                  scfdie();
13850 13847  
13851 13848          if (cur_snap != NULL) {
13852 13849                  semerr(emsg_cant_modify_snapshots);
13853 13850                  goto fail;
13854 13851          }
13855 13852  
13856 13853          if (cur_inst == NULL && cur_svc == NULL) {
13857 13854                  semerr(emsg_entity_not_selected);
13858 13855                  goto fail;
13859 13856          }
13860 13857  
13861 13858          propname = strchr(pgname, '/');
13862 13859          if (propname == NULL) {
13863 13860                  semerr(gettext("Property names must contain a `/'.\n"));
13864 13861                  goto fail;
13865 13862          }
13866 13863  
13867 13864          *propname = '\0';
13868 13865          ++propname;
13869 13866  
13870 13867          if (type != NULL) {
13871 13868                  ty = string_to_type(type);
13872 13869                  if (ty == SCF_TYPE_INVALID) {
13873 13870                          semerr(gettext("Unknown type \"%s\".\n"), type);
13874 13871                          goto fail;
13875 13872                  }
13876 13873          }
13877 13874  
13878 13875          if (cur_inst != NULL)
13879 13876                  ret = scf_instance_get_pg(cur_inst, pgname, pg);
13880 13877          else
13881 13878                  ret = scf_service_get_pg(cur_svc, pgname, pg);
13882 13879          if (ret != SCF_SUCCESS) {
13883 13880                  switch (scf_error()) {
13884 13881                  case SCF_ERROR_NOT_FOUND:
13885 13882                          semerr(emsg_no_such_pg, pgname);
13886 13883                          goto fail;
13887 13884  
13888 13885                  case SCF_ERROR_INVALID_ARGUMENT:
13889 13886                          semerr(emsg_invalid_pg_name, pgname);
13890 13887                          goto fail;
13891 13888  
13892 13889                  default:
13893 13890                          scfdie();
13894 13891                          break;
13895 13892                  }
13896 13893          }
13897 13894  
13898 13895          do {
13899 13896                  if (scf_pg_update(pg) == -1)
13900 13897                          scfdie();
13901 13898                  if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13902 13899                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13903 13900                                  scfdie();
13904 13901  
13905 13902                          semerr(emsg_permission_denied);
13906 13903                          goto fail;
13907 13904                  }
13908 13905  
13909 13906                  ret = scf_pg_get_property(pg, propname, prop);
13910 13907                  if (ret == SCF_SUCCESS) {
13911 13908                          if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13912 13909                                  scfdie();
13913 13910  
13914 13911                          if (type == NULL)
13915 13912                                  ty = current_ty;
13916 13913                          if (scf_transaction_property_change_type(tx, e,
13917 13914                              propname, ty) == -1)
13918 13915                                  scfdie();
13919 13916  
13920 13917                  } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13921 13918                          /* Infer the type, if possible. */
13922 13919                          if (type == NULL) {
13923 13920                                  /*
13924 13921                                   * First check if we're an instance and the
13925 13922                                   * property is set on the service.
13926 13923                                   */
13927 13924                                  if (cur_inst != NULL &&
13928 13925                                      scf_instance_get_parent(cur_inst,
13929 13926                                      svc) == 0 &&
13930 13927                                      scf_service_get_pg(cur_svc, pgname,
13931 13928                                      parent_pg) == 0 &&
13932 13929                                      scf_pg_get_property(parent_pg, propname,
13933 13930                                      parent_prop) == 0 &&
13934 13931                                      scf_property_type(parent_prop,
13935 13932                                      ¤t_ty) == 0) {
13936 13933                                          ty = current_ty;
13937 13934  
13938 13935                                  /* Then check for a type set in a template. */
13939 13936                                  } else if (scf_tmpl_get_by_pg(pg, pgt,
13940 13937                                      0) == 0 &&
13941 13938                                      scf_tmpl_get_by_prop(pgt, propname, prt,
13942 13939                                      0) == 0 &&
13943 13940                                      scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13944 13941                                          ty = current_ty;
13945 13942  
13946 13943                                  /* If type can't be inferred, fail. */
13947 13944                                  } else {
13948 13945                                          semerr(gettext("Type required for new "
13949 13946                                              "properties.\n"));
13950 13947                                          goto fail;
13951 13948                                  }
13952 13949                          }
13953 13950                          if (scf_transaction_property_new(tx, e, propname,
13954 13951                              ty) == -1)
13955 13952                                  scfdie();
13956 13953                  } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13957 13954                          semerr(emsg_invalid_prop_name, propname);
13958 13955                          goto fail;
13959 13956                  } else {
13960 13957                          scfdie();
13961 13958                  }
13962 13959  
13963 13960                  if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13964 13961                          req_quotes = 1;
13965 13962  
13966 13963                  if (value != NULL) {
13967 13964                          v = string_to_value(value, ty, 0);
13968 13965  
13969 13966                          if (v == NULL)
13970 13967                                  goto fail;
13971 13968  
13972 13969                          ret = scf_entry_add_value(e, v);
13973 13970                          assert(ret == SCF_SUCCESS);
13974 13971                  } else {
13975 13972                          assert(values != NULL);
13976 13973  
13977 13974                          walk = uu_list_walk_start((uu_list_t *)values,
13978 13975                              UU_DEFAULT);
13979 13976                          if (walk == NULL)
13980 13977                                  uu_die(gettext("Could not walk list"));
13981 13978  
13982 13979                          for (sp = uu_list_walk_next(walk); sp != NULL;
13983 13980                              sp = uu_list_walk_next(walk)) {
13984 13981                                  v = string_to_value(sp->str, ty, req_quotes);
13985 13982  
13986 13983                                  if (v == NULL) {
13987 13984                                          scf_entry_destroy_children(e);
13988 13985                                          goto fail;
13989 13986                                  }
13990 13987  
13991 13988                                  ret = scf_entry_add_value(e, v);
13992 13989                                  assert(ret == SCF_SUCCESS);
13993 13990                          }
13994 13991                          uu_list_walk_end(walk);
13995 13992                  }
13996 13993                  result = scf_transaction_commit(tx);
13997 13994  
13998 13995                  scf_transaction_reset(tx);
13999 13996                  scf_entry_destroy_children(e);
14000 13997          } while (result == 0);
14001 13998  
14002 13999          if (result < 0) {
14003 14000                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14004 14001                          scfdie();
14005 14002  
14006 14003                  semerr(emsg_permission_denied);
14007 14004                  goto fail;
14008 14005          }
14009 14006  
14010 14007          ret = 0;
14011 14008  
14012 14009          private_refresh();
14013 14010  
14014 14011          goto cleanup;
14015 14012  
14016 14013  fail:
14017 14014          ret = -1;
14018 14015  
14019 14016  cleanup:
14020 14017          scf_transaction_destroy(tx);
14021 14018          scf_entry_destroy(e);
14022 14019          scf_service_destroy(svc);
14023 14020          scf_pg_destroy(parent_pg);
14024 14021          scf_pg_destroy(pg);
14025 14022          scf_property_destroy(parent_prop);
14026 14023          scf_property_destroy(prop);
14027 14024          scf_tmpl_pg_destroy(pgt);
14028 14025          scf_tmpl_prop_destroy(prt);
14029 14026  
14030 14027          return (ret);
14031 14028  }
14032 14029  
14033 14030  void
14034 14031  lscf_delprop(char *pgn)
14035 14032  {
14036 14033          char *slash, *pn;
14037 14034          scf_propertygroup_t *pg;
14038 14035          scf_transaction_t *tx;
14039 14036          scf_transaction_entry_t *e;
14040 14037          int ret;
14041 14038  
14042 14039  
14043 14040          lscf_prep_hndl();
14044 14041  
14045 14042          if (cur_snap != NULL) {
14046 14043                  semerr(emsg_cant_modify_snapshots);
14047 14044                  return;
14048 14045          }
14049 14046  
14050 14047          if (cur_inst == NULL && cur_svc == NULL) {
14051 14048                  semerr(emsg_entity_not_selected);
14052 14049                  return;
14053 14050          }
14054 14051  
14055 14052          pg = scf_pg_create(g_hndl);
14056 14053          if (pg == NULL)
14057 14054                  scfdie();
14058 14055  
14059 14056          slash = strchr(pgn, '/');
14060 14057          if (slash == NULL) {
14061 14058                  pn = NULL;
14062 14059          } else {
14063 14060                  *slash = '\0';
14064 14061                  pn = slash + 1;
14065 14062          }
14066 14063  
14067 14064          if (cur_inst != NULL)
14068 14065                  ret = scf_instance_get_pg(cur_inst, pgn, pg);
14069 14066          else
14070 14067                  ret = scf_service_get_pg(cur_svc, pgn, pg);
14071 14068          if (ret != SCF_SUCCESS) {
14072 14069                  switch (scf_error()) {
14073 14070                  case SCF_ERROR_NOT_FOUND:
14074 14071                          semerr(emsg_no_such_pg, pgn);
14075 14072                          break;
14076 14073  
14077 14074                  case SCF_ERROR_INVALID_ARGUMENT:
14078 14075                          semerr(emsg_invalid_pg_name, pgn);
14079 14076                          break;
14080 14077  
14081 14078                  default:
14082 14079                          scfdie();
14083 14080                  }
14084 14081  
14085 14082                  scf_pg_destroy(pg);
14086 14083  
14087 14084                  return;
14088 14085          }
14089 14086  
14090 14087          if (pn == NULL) {
14091 14088                  /* Try to delete the property group. */
14092 14089                  if (scf_pg_delete(pg) != SCF_SUCCESS) {
14093 14090                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14094 14091                                  scfdie();
14095 14092  
14096 14093                          semerr(emsg_permission_denied);
14097 14094                  } else {
14098 14095                          private_refresh();
14099 14096                  }
14100 14097  
14101 14098                  scf_pg_destroy(pg);
14102 14099                  return;
14103 14100          }
14104 14101  
14105 14102          e = scf_entry_create(g_hndl);
14106 14103          tx = scf_transaction_create(g_hndl);
14107 14104  
14108 14105          do {
14109 14106                  if (scf_pg_update(pg) == -1)
14110 14107                          scfdie();
14111 14108                  if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14112 14109                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14113 14110                                  scfdie();
14114 14111  
14115 14112                          semerr(emsg_permission_denied);
14116 14113                          break;
14117 14114                  }
14118 14115  
14119 14116                  if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14120 14117                          if (scf_error() == SCF_ERROR_NOT_FOUND) {
14121 14118                                  semerr(gettext("No such property %s/%s.\n"),
14122 14119                                      pgn, pn);
14123 14120                                  break;
14124 14121                          } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14125 14122                                  semerr(emsg_invalid_prop_name, pn);
14126 14123                                  break;
14127 14124                          } else {
14128 14125                                  scfdie();
14129 14126                          }
14130 14127                  }
14131 14128  
14132 14129                  ret = scf_transaction_commit(tx);
14133 14130  
14134 14131                  if (ret == 0)
14135 14132                          scf_transaction_reset(tx);
14136 14133          } while (ret == 0);
14137 14134  
14138 14135          if (ret < 0) {
14139 14136                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14140 14137                          scfdie();
14141 14138  
14142 14139                  semerr(emsg_permission_denied);
14143 14140          } else {
14144 14141                  private_refresh();
14145 14142          }
14146 14143  
14147 14144          scf_transaction_destroy(tx);
14148 14145          scf_entry_destroy(e);
14149 14146          scf_pg_destroy(pg);
14150 14147  }
14151 14148  
14152 14149  /*
14153 14150   * Property editing.
14154 14151   */
14155 14152  
14156 14153  static int
14157 14154  write_edit_script(FILE *strm)
14158 14155  {
14159 14156          char *fmribuf;
14160 14157          ssize_t fmrilen;
14161 14158  
14162 14159          scf_propertygroup_t *pg;
14163 14160          scf_property_t *prop;
14164 14161          scf_value_t *val;
14165 14162          scf_type_t ty;
14166 14163          int ret, result = 0;
14167 14164          scf_iter_t *iter, *piter, *viter;
14168 14165          char *buf, *tybuf, *pname;
14169 14166          const char *emsg_write_error;
14170 14167  
14171 14168  
14172 14169          emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14173 14170  
14174 14171  
14175 14172          /* select fmri */
14176 14173          if (cur_inst != NULL) {
14177 14174                  fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14178 14175                  if (fmrilen < 0)
14179 14176                          scfdie();
14180 14177                  fmribuf = safe_malloc(fmrilen + 1);
14181 14178                  if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14182 14179                          scfdie();
14183 14180          } else {
14184 14181                  assert(cur_svc != NULL);
14185 14182                  fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14186 14183                  if (fmrilen < 0)
14187 14184                          scfdie();
14188 14185                  fmribuf = safe_malloc(fmrilen + 1);
14189 14186                  if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14190 14187                          scfdie();
14191 14188          }
14192 14189  
14193 14190          if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14194 14191                  warn(emsg_write_error, strerror(errno));
14195 14192                  free(fmribuf);
14196 14193                  return (-1);
14197 14194          }
14198 14195  
14199 14196          free(fmribuf);
14200 14197  
14201 14198  
14202 14199          if ((pg = scf_pg_create(g_hndl)) == NULL ||
14203 14200              (prop = scf_property_create(g_hndl)) == NULL ||
14204 14201              (val = scf_value_create(g_hndl)) == NULL ||
14205 14202              (iter = scf_iter_create(g_hndl)) == NULL ||
14206 14203              (piter = scf_iter_create(g_hndl)) == NULL ||
14207 14204              (viter = scf_iter_create(g_hndl)) == NULL)
14208 14205                  scfdie();
14209 14206  
14210 14207          buf = safe_malloc(max_scf_name_len + 1);
14211 14208          tybuf = safe_malloc(max_scf_pg_type_len + 1);
14212 14209          pname = safe_malloc(max_scf_name_len + 1);
14213 14210  
14214 14211          if (cur_inst != NULL)
14215 14212                  ret = scf_iter_instance_pgs(iter, cur_inst);
14216 14213          else
14217 14214                  ret = scf_iter_service_pgs(iter, cur_svc);
14218 14215          if (ret != SCF_SUCCESS)
14219 14216                  scfdie();
14220 14217  
14221 14218          while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14222 14219                  int ret2;
14223 14220  
14224 14221                  /*
14225 14222                   * # delprop pg
14226 14223                   * # addpg pg type
14227 14224                   */
14228 14225                  if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14229 14226                          scfdie();
14230 14227  
14231 14228                  if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14232 14229                          scfdie();
14233 14230  
14234 14231                  if (fprintf(strm, "# Property group \"%s\"\n"
14235 14232                      "# delprop %s\n"
14236 14233                      "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14237 14234                          warn(emsg_write_error, strerror(errno));
14238 14235                          result = -1;
14239 14236                          goto out;
14240 14237                  }
14241 14238  
14242 14239                  /* # setprop pg/prop = (values) */
14243 14240  
14244 14241                  if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14245 14242                          scfdie();
14246 14243  
14247 14244                  while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14248 14245                          int first = 1;
14249 14246                          int ret3;
14250 14247                          int multiple;
14251 14248                          int is_str;
14252 14249                          scf_type_t bty;
14253 14250  
14254 14251                          if (scf_property_get_name(prop, pname,
14255 14252                              max_scf_name_len + 1) < 0)
14256 14253                                  scfdie();
14257 14254  
14258 14255                          if (scf_property_type(prop, &ty) != 0)
14259 14256                                  scfdie();
14260 14257  
14261 14258                          multiple = prop_has_multiple_values(prop, val);
14262 14259  
14263 14260                          if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14264 14261                              pname, scf_type_to_string(ty), multiple ? "(" : "")
14265 14262                              < 0) {
14266 14263                                  warn(emsg_write_error, strerror(errno));
14267 14264                                  result = -1;
14268 14265                                  goto out;
14269 14266                          }
14270 14267  
14271 14268                          (void) scf_type_base_type(ty, &bty);
14272 14269                          is_str = (bty == SCF_TYPE_ASTRING);
14273 14270  
14274 14271                          if (scf_iter_property_values(viter, prop) !=
14275 14272                              SCF_SUCCESS)
14276 14273                                  scfdie();
14277 14274  
14278 14275                          while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14279 14276                                  char *buf;
14280 14277                                  ssize_t buflen;
14281 14278  
14282 14279                                  buflen = scf_value_get_as_string(val, NULL, 0);
14283 14280                                  if (buflen < 0)
14284 14281                                          scfdie();
14285 14282  
14286 14283                                  buf = safe_malloc(buflen + 1);
14287 14284  
14288 14285                                  if (scf_value_get_as_string(val, buf,
14289 14286                                      buflen + 1) < 0)
14290 14287                                          scfdie();
14291 14288  
14292 14289                                  if (first)
14293 14290                                          first = 0;
14294 14291                                  else {
14295 14292                                          if (putc(' ', strm) != ' ') {
14296 14293                                                  warn(emsg_write_error,
14297 14294                                                      strerror(errno));
14298 14295                                                  result = -1;
14299 14296                                                  goto out;
14300 14297                                          }
14301 14298                                  }
14302 14299  
14303 14300                                  if ((is_str && multiple) ||
14304 14301                                      strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14305 14302                                          (void) putc('"', strm);
14306 14303                                          (void) quote_and_print(buf, strm, 1);
14307 14304                                          (void) putc('"', strm);
14308 14305  
14309 14306                                          if (ferror(strm)) {
14310 14307                                                  warn(emsg_write_error,
14311 14308                                                      strerror(errno));
14312 14309                                                  result = -1;
14313 14310                                                  goto out;
14314 14311                                          }
14315 14312                                  } else {
14316 14313                                          if (fprintf(strm, "%s", buf) < 0) {
14317 14314                                                  warn(emsg_write_error,
14318 14315                                                      strerror(errno));
14319 14316                                                  result = -1;
14320 14317                                                  goto out;
14321 14318                                          }
14322 14319                                  }
14323 14320  
14324 14321                                  free(buf);
14325 14322                          }
14326 14323                          if (ret3 < 0 &&
14327 14324                              scf_error() != SCF_ERROR_PERMISSION_DENIED)
14328 14325                                  scfdie();
14329 14326  
14330 14327                          /* Write closing paren if mult-value property */
14331 14328                          if ((multiple && putc(')', strm) == EOF) ||
14332 14329  
14333 14330                              /* Write final newline */
14334 14331                              fputc('\n', strm) == EOF) {
14335 14332                                  warn(emsg_write_error, strerror(errno));
14336 14333                                  result = -1;
14337 14334                                  goto out;
14338 14335                          }
14339 14336                  }
14340 14337                  if (ret2 < 0)
14341 14338                          scfdie();
14342 14339  
14343 14340                  if (fputc('\n', strm) == EOF) {
14344 14341                          warn(emsg_write_error, strerror(errno));
14345 14342                          result = -1;
14346 14343                          goto out;
14347 14344                  }
14348 14345          }
14349 14346          if (ret < 0)
14350 14347                  scfdie();
14351 14348  
14352 14349  out:
14353 14350          free(pname);
14354 14351          free(tybuf);
14355 14352          free(buf);
14356 14353          scf_iter_destroy(viter);
14357 14354          scf_iter_destroy(piter);
14358 14355          scf_iter_destroy(iter);
14359 14356          scf_value_destroy(val);
14360 14357          scf_property_destroy(prop);
14361 14358          scf_pg_destroy(pg);
14362 14359  
14363 14360          if (result == 0) {
14364 14361                  if (fflush(strm) != 0) {
14365 14362                          warn(emsg_write_error, strerror(errno));
14366 14363                          return (-1);
14367 14364                  }
14368 14365          }
14369 14366  
14370 14367          return (result);
14371 14368  }
14372 14369  
14373 14370  int
14374 14371  lscf_editprop()
14375 14372  {
14376 14373          char *buf, *editor;
14377 14374          size_t bufsz;
14378 14375          int tmpfd;
14379 14376          char tempname[] = TEMP_FILE_PATTERN;
14380 14377  
14381 14378          lscf_prep_hndl();
14382 14379  
14383 14380          if (cur_snap != NULL) {
14384 14381                  semerr(emsg_cant_modify_snapshots);
14385 14382                  return (-1);
14386 14383          }
14387 14384  
14388 14385          if (cur_svc == NULL && cur_inst == NULL) {
14389 14386                  semerr(emsg_entity_not_selected);
14390 14387                  return (-1);
14391 14388          }
14392 14389  
14393 14390          tmpfd = mkstemp(tempname);
14394 14391          if (tmpfd == -1) {
14395 14392                  semerr(gettext("Could not create temporary file.\n"));
14396 14393                  return (-1);
14397 14394          }
14398 14395  
14399 14396          (void) strcpy(tempfilename, tempname);
14400 14397  
14401 14398          tempfile = fdopen(tmpfd, "r+");
14402 14399          if (tempfile == NULL) {
14403 14400                  warn(gettext("Could not create temporary file.\n"));
14404 14401                  if (close(tmpfd) == -1)
14405 14402                          warn(gettext("Could not close temporary file: %s.\n"),
14406 14403                              strerror(errno));
14407 14404  
14408 14405                  remove_tempfile();
14409 14406  
14410 14407                  return (-1);
14411 14408          }
14412 14409  
14413 14410          if (write_edit_script(tempfile) == -1) {
14414 14411                  remove_tempfile();
14415 14412                  return (-1);
14416 14413          }
14417 14414  
14418 14415          editor = getenv("EDITOR");
14419 14416          if (editor == NULL)
14420 14417                  editor = "vi";
14421 14418  
14422 14419          bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14423 14420          buf = safe_malloc(bufsz);
14424 14421  
14425 14422          if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14426 14423                  uu_die(gettext("Error creating editor command"));
14427 14424  
14428 14425          if (system(buf) == -1) {
14429 14426                  semerr(gettext("Could not launch editor %s: %s\n"), editor,
14430 14427                      strerror(errno));
14431 14428                  free(buf);
14432 14429                  remove_tempfile();
14433 14430                  return (-1);
14434 14431          }
14435 14432  
14436 14433          free(buf);
14437 14434  
14438 14435          (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14439 14436  
14440 14437          remove_tempfile();
14441 14438  
14442 14439          return (0);
14443 14440  }
14444 14441  
14445 14442  static void
14446 14443  add_string(uu_list_t *strlist, const char *str)
14447 14444  {
14448 14445          string_list_t *elem;
14449 14446          elem = safe_malloc(sizeof (*elem));
14450 14447          uu_list_node_init(elem, &elem->node, string_pool);
14451 14448          elem->str = safe_strdup(str);
14452 14449          if (uu_list_append(strlist, elem) != 0)
14453 14450                  uu_die(gettext("libuutil error: %s\n"),
14454 14451                      uu_strerror(uu_error()));
14455 14452  }
14456 14453  
14457 14454  static int
14458 14455  remove_string(uu_list_t *strlist, const char *str)
14459 14456  {
14460 14457          uu_list_walk_t  *elems;
14461 14458          string_list_t   *sp;
14462 14459  
14463 14460          /*
14464 14461           * Find the element that needs to be removed.
14465 14462           */
14466 14463          elems = uu_list_walk_start(strlist, UU_DEFAULT);
14467 14464          while ((sp = uu_list_walk_next(elems)) != NULL) {
14468 14465                  if (strcmp(sp->str, str) == 0)
14469 14466                          break;
14470 14467          }
14471 14468          uu_list_walk_end(elems);
14472 14469  
14473 14470          /*
14474 14471           * Returning 1 here as the value was not found, this
14475 14472           * might not be an error.  Leave it to the caller to
14476 14473           * decide.
14477 14474           */
14478 14475          if (sp == NULL) {
14479 14476                  return (1);
14480 14477          }
14481 14478  
14482 14479          uu_list_remove(strlist, sp);
14483 14480  
14484 14481          free(sp->str);
14485 14482          free(sp);
14486 14483  
14487 14484          return (0);
14488 14485  }
14489 14486  
14490 14487  /*
14491 14488   * Get all property values that don't match the given glob pattern,
14492 14489   * if a pattern is specified.
14493 14490   */
14494 14491  static void
14495 14492  get_prop_values(scf_property_t *prop, uu_list_t *values,
14496 14493      const char *pattern)
14497 14494  {
14498 14495          scf_iter_t *iter;
14499 14496          scf_value_t *val;
14500 14497          int ret;
14501 14498  
14502 14499          if ((iter = scf_iter_create(g_hndl)) == NULL ||
14503 14500              (val = scf_value_create(g_hndl)) == NULL)
14504 14501                  scfdie();
14505 14502  
14506 14503          if (scf_iter_property_values(iter, prop) != 0)
14507 14504                  scfdie();
14508 14505  
14509 14506          while ((ret = scf_iter_next_value(iter, val)) == 1) {
14510 14507                  char *buf;
14511 14508                  ssize_t vlen, szret;
14512 14509  
14513 14510                  vlen = scf_value_get_as_string(val, NULL, 0);
14514 14511                  if (vlen < 0)
14515 14512                          scfdie();
14516 14513  
14517 14514                  buf = safe_malloc(vlen + 1);
14518 14515  
14519 14516                  szret = scf_value_get_as_string(val, buf, vlen + 1);
14520 14517                  if (szret < 0)
14521 14518                          scfdie();
14522 14519                  assert(szret <= vlen);
14523 14520  
14524 14521                  if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14525 14522                          add_string(values, buf);
14526 14523  
14527 14524                  free(buf);
14528 14525          }
14529 14526  
14530 14527          if (ret == -1)
14531 14528                  scfdie();
14532 14529  
14533 14530          scf_value_destroy(val);
14534 14531          scf_iter_destroy(iter);
14535 14532  }
14536 14533  
14537 14534  static int
14538 14535  lscf_setpropvalue(const char *pgname, const char *type,
14539 14536      const char *arg, int isadd, int isnotfoundok)
14540 14537  {
14541 14538          scf_type_t ty;
14542 14539          scf_propertygroup_t *pg;
14543 14540          scf_property_t *prop;
14544 14541          int ret, result = 0;
14545 14542          scf_transaction_t *tx;
14546 14543          scf_transaction_entry_t *e;
14547 14544          scf_value_t *v;
14548 14545          string_list_t *sp;
14549 14546          char *propname;
14550 14547          uu_list_t *values;
14551 14548          uu_list_walk_t *walk;
14552 14549          void *cookie = NULL;
14553 14550          char *pattern = NULL;
14554 14551  
14555 14552          lscf_prep_hndl();
14556 14553  
14557 14554          if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14558 14555                  uu_die(gettext("Could not create property list: %s\n"),
14559 14556                      uu_strerror(uu_error()));
14560 14557  
14561 14558          if (!isadd)
14562 14559                  pattern = safe_strdup(arg);
14563 14560  
14564 14561          if ((e = scf_entry_create(g_hndl)) == NULL ||
14565 14562              (pg = scf_pg_create(g_hndl)) == NULL ||
14566 14563              (prop = scf_property_create(g_hndl)) == NULL ||
14567 14564              (tx = scf_transaction_create(g_hndl)) == NULL)
14568 14565                  scfdie();
14569 14566  
14570 14567          if (cur_snap != NULL) {
14571 14568                  semerr(emsg_cant_modify_snapshots);
14572 14569                  goto fail;
14573 14570          }
14574 14571  
14575 14572          if (cur_inst == NULL && cur_svc == NULL) {
14576 14573                  semerr(emsg_entity_not_selected);
14577 14574                  goto fail;
14578 14575          }
14579 14576  
14580 14577          propname = strchr(pgname, '/');
14581 14578          if (propname == NULL) {
14582 14579                  semerr(gettext("Property names must contain a `/'.\n"));
14583 14580                  goto fail;
14584 14581          }
14585 14582  
14586 14583          *propname = '\0';
14587 14584          ++propname;
14588 14585  
14589 14586          if (type != NULL) {
14590 14587                  ty = string_to_type(type);
14591 14588                  if (ty == SCF_TYPE_INVALID) {
14592 14589                          semerr(gettext("Unknown type \"%s\".\n"), type);
14593 14590                          goto fail;
14594 14591                  }
14595 14592          }
14596 14593  
14597 14594          if (cur_inst != NULL)
14598 14595                  ret = scf_instance_get_pg(cur_inst, pgname, pg);
14599 14596          else
14600 14597                  ret = scf_service_get_pg(cur_svc, pgname, pg);
14601 14598          if (ret != 0) {
14602 14599                  switch (scf_error()) {
14603 14600                  case SCF_ERROR_NOT_FOUND:
14604 14601                          if (isnotfoundok) {
14605 14602                                  result = 0;
14606 14603                          } else {
14607 14604                                  semerr(emsg_no_such_pg, pgname);
14608 14605                                  result = -1;
14609 14606                          }
14610 14607                          goto out;
14611 14608  
14612 14609                  case SCF_ERROR_INVALID_ARGUMENT:
14613 14610                          semerr(emsg_invalid_pg_name, pgname);
14614 14611                          goto fail;
14615 14612  
14616 14613                  default:
14617 14614                          scfdie();
14618 14615                  }
14619 14616          }
14620 14617  
14621 14618          do {
14622 14619                  if (scf_pg_update(pg) == -1)
14623 14620                          scfdie();
14624 14621                  if (scf_transaction_start(tx, pg) != 0) {
14625 14622                          if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14626 14623                                  scfdie();
14627 14624  
14628 14625                          semerr(emsg_permission_denied);
14629 14626                          goto fail;
14630 14627                  }
14631 14628  
14632 14629                  ret = scf_pg_get_property(pg, propname, prop);
14633 14630                  if (ret == 0) {
14634 14631                          scf_type_t ptype;
14635 14632                          char *pat = pattern;
14636 14633  
14637 14634                          if (scf_property_type(prop, &ptype) != 0)
14638 14635                                  scfdie();
14639 14636  
14640 14637                          if (isadd) {
14641 14638                                  if (type != NULL && ptype != ty) {
14642 14639                                          semerr(gettext("Property \"%s\" is not "
14643 14640                                              "of type \"%s\".\n"), propname,
14644 14641                                              type);
14645 14642                                          goto fail;
14646 14643                                  }
14647 14644  
14648 14645                                  pat = NULL;
14649 14646                          } else {
14650 14647                                  size_t len = strlen(pat);
14651 14648                                  if (len > 0 && pat[len - 1] == '\"')
14652 14649                                          pat[len - 1] = '\0';
14653 14650                                  if (len > 0 && pat[0] == '\"')
14654 14651                                          pat++;
14655 14652                          }
14656 14653  
14657 14654                          ty = ptype;
14658 14655  
14659 14656                          get_prop_values(prop, values, pat);
14660 14657  
14661 14658                          if (isadd)
14662 14659                                  add_string(values, arg);
14663 14660  
14664 14661                          if (scf_transaction_property_change(tx, e,
14665 14662                              propname, ty) == -1)
14666 14663                                  scfdie();
14667 14664                  } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14668 14665                          if (isadd) {
14669 14666                                  if (type == NULL) {
14670 14667                                          semerr(gettext("Type required "
14671 14668                                              "for new properties.\n"));
14672 14669                                          goto fail;
14673 14670                                  }
14674 14671  
14675 14672                                  add_string(values, arg);
14676 14673  
14677 14674                                  if (scf_transaction_property_new(tx, e,
14678 14675                                      propname, ty) == -1)
14679 14676                                          scfdie();
14680 14677                          } else if (isnotfoundok) {
14681 14678                                  result = 0;
14682 14679                                  goto out;
14683 14680                          } else {
14684 14681                                  semerr(gettext("No such property %s/%s.\n"),
14685 14682                                      pgname, propname);
14686 14683                                  result = -1;
14687 14684                                  goto out;
14688 14685                          }
14689 14686                  } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14690 14687                          semerr(emsg_invalid_prop_name, propname);
14691 14688                          goto fail;
14692 14689                  } else {
14693 14690                          scfdie();
14694 14691                  }
14695 14692  
14696 14693                  walk = uu_list_walk_start(values, UU_DEFAULT);
14697 14694                  if (walk == NULL)
14698 14695                          uu_die(gettext("Could not walk property list.\n"));
14699 14696  
14700 14697                  for (sp = uu_list_walk_next(walk); sp != NULL;
14701 14698                      sp = uu_list_walk_next(walk)) {
14702 14699                          v = string_to_value(sp->str, ty, 0);
14703 14700  
14704 14701                          if (v == NULL) {
14705 14702                                  scf_entry_destroy_children(e);
14706 14703                                  goto fail;
14707 14704                          }
14708 14705                          ret = scf_entry_add_value(e, v);
14709 14706                          assert(ret == 0);
14710 14707                  }
14711 14708                  uu_list_walk_end(walk);
14712 14709  
14713 14710                  result = scf_transaction_commit(tx);
14714 14711  
14715 14712                  scf_transaction_reset(tx);
14716 14713                  scf_entry_destroy_children(e);
14717 14714          } while (result == 0);
14718 14715  
14719 14716          if (result < 0) {
14720 14717                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14721 14718                          scfdie();
14722 14719  
14723 14720                  semerr(emsg_permission_denied);
14724 14721                  goto fail;
14725 14722          }
14726 14723  
14727 14724          result = 0;
14728 14725  
14729 14726          private_refresh();
14730 14727  
14731 14728  out:
14732 14729          scf_transaction_destroy(tx);
14733 14730          scf_entry_destroy(e);
14734 14731          scf_pg_destroy(pg);
14735 14732          scf_property_destroy(prop);
14736 14733          free(pattern);
14737 14734  
14738 14735          while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14739 14736                  free(sp->str);
14740 14737                  free(sp);
14741 14738          }
14742 14739  
14743 14740          uu_list_destroy(values);
14744 14741  
14745 14742          return (result);
14746 14743  
14747 14744  fail:
14748 14745          result = -1;
14749 14746          goto out;
14750 14747  }
14751 14748  
14752 14749  int
14753 14750  lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14754 14751  {
14755 14752          return (lscf_setpropvalue(pgname, type, value, 1, 0));
14756 14753  }
14757 14754  
14758 14755  int
14759 14756  lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14760 14757  {
14761 14758          return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14762 14759  }
14763 14760  
14764 14761  /*
14765 14762   * Look for a standard start method, first in the instance (if any),
14766 14763   * then the service.
14767 14764   */
14768 14765  static const char *
14769 14766  start_method_name(int *in_instance)
14770 14767  {
14771 14768          scf_propertygroup_t *pg;
14772 14769          char **p;
14773 14770          int ret;
14774 14771          scf_instance_t *inst = cur_inst;
14775 14772  
14776 14773          if ((pg = scf_pg_create(g_hndl)) == NULL)
14777 14774                  scfdie();
14778 14775  
14779 14776  again:
14780 14777          for (p = start_method_names; *p != NULL; p++) {
14781 14778                  if (inst != NULL)
14782 14779                          ret = scf_instance_get_pg(inst, *p, pg);
14783 14780                  else
14784 14781                          ret = scf_service_get_pg(cur_svc, *p, pg);
14785 14782  
14786 14783                  if (ret == 0) {
14787 14784                          size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14788 14785                          char *buf = safe_malloc(bufsz);
14789 14786  
14790 14787                          if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14791 14788                                  free(buf);
14792 14789                                  continue;
14793 14790                          }
14794 14791                          if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14795 14792                                  free(buf);
14796 14793                                  continue;
14797 14794                          }
14798 14795  
14799 14796                          free(buf);
14800 14797                          *in_instance = (inst != NULL);
14801 14798                          scf_pg_destroy(pg);
14802 14799                          return (*p);
14803 14800                  }
14804 14801  
14805 14802                  if (scf_error() == SCF_ERROR_NOT_FOUND)
14806 14803                          continue;
14807 14804  
14808 14805                  scfdie();
14809 14806          }
14810 14807  
14811 14808          if (inst != NULL) {
14812 14809                  inst = NULL;
14813 14810                  goto again;
14814 14811          }
14815 14812  
14816 14813          scf_pg_destroy(pg);
14817 14814          return (NULL);
14818 14815  }
14819 14816  
14820 14817  static int
14821 14818  addpg(const char *name, const char *type)
14822 14819  {
14823 14820          scf_propertygroup_t *pg;
14824 14821          int ret;
14825 14822  
14826 14823          pg = scf_pg_create(g_hndl);
14827 14824          if (pg == NULL)
14828 14825                  scfdie();
14829 14826  
14830 14827          if (cur_inst != NULL)
14831 14828                  ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14832 14829          else
14833 14830                  ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14834 14831  
14835 14832          if (ret != 0) {
14836 14833                  switch (scf_error()) {
14837 14834                  case SCF_ERROR_EXISTS:
14838 14835                          ret = 0;
14839 14836                          break;
14840 14837  
14841 14838                  case SCF_ERROR_PERMISSION_DENIED:
14842 14839                          semerr(emsg_permission_denied);
14843 14840                          break;
14844 14841  
14845 14842                  default:
14846 14843                          scfdie();
14847 14844                  }
14848 14845          }
14849 14846  
14850 14847          scf_pg_destroy(pg);
14851 14848          return (ret);
14852 14849  }
14853 14850  
14854 14851  int
14855 14852  lscf_setenv(uu_list_t *args, int isunset)
14856 14853  {
14857 14854          int ret = 0;
14858 14855          size_t i;
14859 14856          int argc;
14860 14857          char **argv = NULL;
14861 14858          string_list_t *slp;
14862 14859          char *pattern;
14863 14860          char *prop;
14864 14861          int do_service = 0;
14865 14862          int do_instance = 0;
14866 14863          const char *method = NULL;
14867 14864          const char *name = NULL;
14868 14865          const char *value = NULL;
14869 14866          scf_instance_t *saved_cur_inst = cur_inst;
14870 14867  
14871 14868          lscf_prep_hndl();
14872 14869  
14873 14870          argc = uu_list_numnodes(args);
14874 14871          if (argc < 1)
14875 14872                  goto usage;
14876 14873  
14877 14874          argv = calloc(argc + 1, sizeof (char *));
14878 14875          if (argv == NULL)
14879 14876                  uu_die(gettext("Out of memory.\n"));
14880 14877  
14881 14878          for (slp = uu_list_first(args), i = 0;
14882 14879              slp != NULL;
14883 14880              slp = uu_list_next(args, slp), ++i)
14884 14881                  argv[i] = slp->str;
14885 14882  
14886 14883          argv[i] = NULL;
14887 14884  
14888 14885          opterr = 0;
14889 14886          optind = 0;
14890 14887          for (;;) {
14891 14888                  ret = getopt(argc, argv, "sim:");
14892 14889                  if (ret == -1)
14893 14890                          break;
14894 14891  
14895 14892                  switch (ret) {
14896 14893                  case 's':
14897 14894                          do_service = 1;
14898 14895                          cur_inst = NULL;
14899 14896                          break;
14900 14897  
14901 14898                  case 'i':
14902 14899                          do_instance = 1;
14903 14900                          break;
14904 14901  
14905 14902                  case 'm':
14906 14903                          method = optarg;
14907 14904                          break;
14908 14905  
14909 14906                  case '?':
14910 14907                          goto usage;
14911 14908  
14912 14909                  default:
14913 14910                          bad_error("getopt", ret);
14914 14911                  }
14915 14912          }
14916 14913  
14917 14914          argc -= optind;
14918 14915          if ((do_service && do_instance) ||
14919 14916              (isunset && argc != 1) ||
14920 14917              (!isunset && argc != 2))
14921 14918                  goto usage;
14922 14919  
14923 14920          name = argv[optind];
14924 14921          if (!isunset)
14925 14922                  value = argv[optind + 1];
14926 14923  
14927 14924          if (cur_snap != NULL) {
14928 14925                  semerr(emsg_cant_modify_snapshots);
14929 14926                  ret = -1;
14930 14927                  goto out;
14931 14928          }
14932 14929  
14933 14930          if (cur_inst == NULL && cur_svc == NULL) {
14934 14931                  semerr(emsg_entity_not_selected);
14935 14932                  ret = -1;
14936 14933                  goto out;
14937 14934          }
14938 14935  
14939 14936          if (do_instance && cur_inst == NULL) {
14940 14937                  semerr(gettext("No instance is selected.\n"));
14941 14938                  ret = -1;
14942 14939                  goto out;
14943 14940          }
14944 14941  
14945 14942          if (do_service && cur_svc == NULL) {
14946 14943                  semerr(gettext("No service is selected.\n"));
14947 14944                  ret = -1;
14948 14945                  goto out;
14949 14946          }
14950 14947  
14951 14948          if (method == NULL) {
14952 14949                  if (do_instance || do_service) {
14953 14950                          method = "method_context";
14954 14951                          if (!isunset) {
14955 14952                                  ret = addpg("method_context",
14956 14953                                      SCF_GROUP_FRAMEWORK);
14957 14954                                  if (ret != 0)
14958 14955                                          goto out;
14959 14956                          }
14960 14957                  } else {
14961 14958                          int in_instance;
14962 14959                          method = start_method_name(&in_instance);
14963 14960                          if (method == NULL) {
14964 14961                                  semerr(gettext(
14965 14962                                      "Couldn't find start method; please "
14966 14963                                      "specify a method with '-m'.\n"));
14967 14964                                  ret = -1;
14968 14965                                  goto out;
14969 14966                          }
14970 14967                          if (!in_instance)
14971 14968                                  cur_inst = NULL;
14972 14969                  }
14973 14970          } else {
14974 14971                  scf_propertygroup_t *pg;
14975 14972                  size_t bufsz;
14976 14973                  char *buf;
14977 14974                  int ret;
14978 14975  
14979 14976                  if ((pg = scf_pg_create(g_hndl)) == NULL)
14980 14977                          scfdie();
14981 14978  
14982 14979                  if (cur_inst != NULL)
14983 14980                          ret = scf_instance_get_pg(cur_inst, method, pg);
14984 14981                  else
14985 14982                          ret = scf_service_get_pg(cur_svc, method, pg);
14986 14983  
14987 14984                  if (ret != 0) {
14988 14985                          scf_pg_destroy(pg);
14989 14986                          switch (scf_error()) {
14990 14987                          case SCF_ERROR_NOT_FOUND:
14991 14988                                  semerr(gettext("Couldn't find the method "
14992 14989                                      "\"%s\".\n"), method);
14993 14990                                  goto out;
14994 14991  
14995 14992                          case SCF_ERROR_INVALID_ARGUMENT:
14996 14993                                  semerr(gettext("Invalid method name \"%s\".\n"),
14997 14994                                      method);
14998 14995                                  goto out;
14999 14996  
15000 14997                          default:
15001 14998                                  scfdie();
15002 14999                          }
15003 15000                  }
15004 15001  
15005 15002                  bufsz = strlen(SCF_GROUP_METHOD) + 1;
15006 15003                  buf = safe_malloc(bufsz);
15007 15004  
15008 15005                  if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15009 15006                      strcmp(buf, SCF_GROUP_METHOD) != 0) {
15010 15007                          semerr(gettext("Property group \"%s\" is not of type "
15011 15008                              "\"method\".\n"), method);
15012 15009                          ret = -1;
15013 15010                          free(buf);
15014 15011                          scf_pg_destroy(pg);
15015 15012                          goto out;
15016 15013                  }
15017 15014  
15018 15015                  free(buf);
15019 15016                  scf_pg_destroy(pg);
15020 15017          }
15021 15018  
15022 15019          prop = uu_msprintf("%s/environment", method);
15023 15020          pattern = uu_msprintf("%s=*", name);
15024 15021  
15025 15022          if (prop == NULL || pattern == NULL)
15026 15023                  uu_die(gettext("Out of memory.\n"));
15027 15024  
15028 15025          ret = lscf_delpropvalue(prop, pattern, !isunset);
15029 15026  
15030 15027          if (ret == 0 && !isunset) {
15031 15028                  uu_free(pattern);
15032 15029                  uu_free(prop);
15033 15030                  prop = uu_msprintf("%s/environment", method);
15034 15031                  pattern = uu_msprintf("%s=%s", name, value);
15035 15032                  if (prop == NULL || pattern == NULL)
15036 15033                          uu_die(gettext("Out of memory.\n"));
15037 15034                  ret = lscf_addpropvalue(prop, "astring:", pattern);
15038 15035          }
15039 15036          uu_free(pattern);
15040 15037          uu_free(prop);
15041 15038  
15042 15039  out:
15043 15040          cur_inst = saved_cur_inst;
15044 15041  
15045 15042          free(argv);
15046 15043          return (ret);
15047 15044  usage:
15048 15045          ret = -2;
15049 15046          goto out;
15050 15047  }
15051 15048  
15052 15049  /*
15053 15050   * Snapshot commands
15054 15051   */
15055 15052  
15056 15053  void
15057 15054  lscf_listsnap()
15058 15055  {
15059 15056          scf_snapshot_t *snap;
15060 15057          scf_iter_t *iter;
15061 15058          char *nb;
15062 15059          int r;
15063 15060  
15064 15061          lscf_prep_hndl();
15065 15062  
15066 15063          if (cur_inst == NULL) {
15067 15064                  semerr(gettext("Instance not selected.\n"));
15068 15065                  return;
15069 15066          }
15070 15067  
15071 15068          if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15072 15069              (iter = scf_iter_create(g_hndl)) == NULL)
15073 15070                  scfdie();
15074 15071  
15075 15072          if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15076 15073                  scfdie();
15077 15074  
15078 15075          nb = safe_malloc(max_scf_name_len + 1);
15079 15076  
15080 15077          while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15081 15078                  if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15082 15079                          scfdie();
15083 15080  
15084 15081                  (void) puts(nb);
15085 15082          }
15086 15083          if (r < 0)
15087 15084                  scfdie();
15088 15085  
15089 15086          free(nb);
15090 15087          scf_iter_destroy(iter);
15091 15088          scf_snapshot_destroy(snap);
15092 15089  }
15093 15090  
15094 15091  void
15095 15092  lscf_selectsnap(const char *name)
15096 15093  {
15097 15094          scf_snapshot_t *snap;
15098 15095          scf_snaplevel_t *level;
15099 15096  
15100 15097          lscf_prep_hndl();
15101 15098  
15102 15099          if (cur_inst == NULL) {
15103 15100                  semerr(gettext("Instance not selected.\n"));
15104 15101                  return;
15105 15102          }
15106 15103  
15107 15104          if (cur_snap != NULL) {
15108 15105                  if (name != NULL) {
15109 15106                          char *cur_snap_name;
15110 15107                          boolean_t nochange;
15111 15108  
15112 15109                          cur_snap_name = safe_malloc(max_scf_name_len + 1);
15113 15110  
15114 15111                          if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15115 15112                              max_scf_name_len + 1) < 0)
15116 15113                                  scfdie();
15117 15114  
15118 15115                          nochange = strcmp(name, cur_snap_name) == 0;
15119 15116  
15120 15117                          free(cur_snap_name);
15121 15118  
15122 15119                          if (nochange)
15123 15120                                  return;
15124 15121                  }
15125 15122  
15126 15123                  unselect_cursnap();
15127 15124          }
15128 15125  
15129 15126          if (name == NULL)
15130 15127                  return;
15131 15128  
15132 15129          if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15133 15130              (level = scf_snaplevel_create(g_hndl)) == NULL)
15134 15131                  scfdie();
15135 15132  
15136 15133          if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15137 15134              SCF_SUCCESS) {
15138 15135                  switch (scf_error()) {
15139 15136                  case SCF_ERROR_INVALID_ARGUMENT:
15140 15137                          semerr(gettext("Invalid name \"%s\".\n"), name);
15141 15138                          break;
15142 15139  
15143 15140                  case SCF_ERROR_NOT_FOUND:
15144 15141                          semerr(gettext("No such snapshot \"%s\".\n"), name);
15145 15142                          break;
15146 15143  
15147 15144                  default:
15148 15145                          scfdie();
15149 15146                  }
15150 15147  
15151 15148                  scf_snaplevel_destroy(level);
15152 15149                  scf_snapshot_destroy(snap);
15153 15150                  return;
15154 15151          }
15155 15152  
15156 15153          /* Load the snaplevels into our list. */
15157 15154          cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15158 15155          if (cur_levels == NULL)
15159 15156                  uu_die(gettext("Could not create list: %s\n"),
15160 15157                      uu_strerror(uu_error()));
15161 15158  
15162 15159          if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15163 15160                  if (scf_error() != SCF_ERROR_NOT_FOUND)
15164 15161                          scfdie();
15165 15162  
15166 15163                  semerr(gettext("Snapshot has no snaplevels.\n"));
15167 15164  
15168 15165                  scf_snaplevel_destroy(level);
15169 15166                  scf_snapshot_destroy(snap);
15170 15167                  return;
15171 15168          }
15172 15169  
15173 15170          cur_snap = snap;
15174 15171  
15175 15172          for (;;) {
15176 15173                  cur_elt = safe_malloc(sizeof (*cur_elt));
15177 15174                  uu_list_node_init(cur_elt, &cur_elt->list_node,
15178 15175                      snaplevel_pool);
15179 15176                  cur_elt->sl = level;
15180 15177                  if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15181 15178                          uu_die(gettext("libuutil error: %s\n"),
15182 15179                              uu_strerror(uu_error()));
15183 15180  
15184 15181                  level = scf_snaplevel_create(g_hndl);
15185 15182                  if (level == NULL)
15186 15183                          scfdie();
15187 15184  
15188 15185                  if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15189 15186                      level) != SCF_SUCCESS) {
15190 15187                          if (scf_error() != SCF_ERROR_NOT_FOUND)
15191 15188                                  scfdie();
15192 15189  
15193 15190                          scf_snaplevel_destroy(level);
15194 15191                          break;
15195 15192                  }
15196 15193          }
15197 15194  
15198 15195          cur_elt = uu_list_last(cur_levels);
15199 15196          cur_level = cur_elt->sl;
15200 15197  }
15201 15198  
15202 15199  /*
15203 15200   * Copies the properties & values in src to dst.  Assumes src won't change.
15204 15201   * Returns -1 if permission is denied, -2 if another transaction interrupts,
15205 15202   * and 0 on success.
15206 15203   *
15207 15204   * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15208 15205   * property, if it is copied and has type boolean.  (See comment in
15209 15206   * lscf_revert()).
15210 15207   */
15211 15208  static int
15212 15209  pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15213 15210      uint8_t enabled)
15214 15211  {
15215 15212          scf_transaction_t *tx;
15216 15213          scf_iter_t *iter, *viter;
15217 15214          scf_property_t *prop;
15218 15215          scf_value_t *v;
15219 15216          char *nbuf;
15220 15217          int r;
15221 15218  
15222 15219          tx = scf_transaction_create(g_hndl);
15223 15220          if (tx == NULL)
15224 15221                  scfdie();
15225 15222  
15226 15223          if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15227 15224                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15228 15225                          scfdie();
15229 15226  
15230 15227                  scf_transaction_destroy(tx);
15231 15228  
15232 15229                  return (-1);
15233 15230          }
15234 15231  
15235 15232          if ((iter = scf_iter_create(g_hndl)) == NULL ||
15236 15233              (prop = scf_property_create(g_hndl)) == NULL ||
15237 15234              (viter = scf_iter_create(g_hndl)) == NULL)
15238 15235                  scfdie();
15239 15236  
15240 15237          nbuf = safe_malloc(max_scf_name_len + 1);
15241 15238  
15242 15239          if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15243 15240                  scfdie();
15244 15241  
15245 15242          for (;;) {
15246 15243                  scf_transaction_entry_t *e;
15247 15244                  scf_type_t ty;
15248 15245  
15249 15246                  r = scf_iter_next_property(iter, prop);
15250 15247                  if (r == -1)
15251 15248                          scfdie();
15252 15249                  if (r == 0)
15253 15250                          break;
15254 15251  
15255 15252                  e = scf_entry_create(g_hndl);
15256 15253                  if (e == NULL)
15257 15254                          scfdie();
15258 15255  
15259 15256                  if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15260 15257                          scfdie();
15261 15258  
15262 15259                  if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15263 15260                          scfdie();
15264 15261  
15265 15262                  if (scf_transaction_property_new(tx, e, nbuf,
15266 15263                      ty) != SCF_SUCCESS)
15267 15264                          scfdie();
15268 15265  
15269 15266                  if ((enabled == 0 || enabled == 1) &&
15270 15267                      strcmp(nbuf, scf_property_enabled) == 0 &&
15271 15268                      ty == SCF_TYPE_BOOLEAN) {
15272 15269                          v = scf_value_create(g_hndl);
15273 15270                          if (v == NULL)
15274 15271                                  scfdie();
15275 15272  
15276 15273                          scf_value_set_boolean(v, enabled);
15277 15274  
15278 15275                          if (scf_entry_add_value(e, v) != 0)
15279 15276                                  scfdie();
15280 15277                  } else {
15281 15278                          if (scf_iter_property_values(viter, prop) != 0)
15282 15279                                  scfdie();
15283 15280  
15284 15281                          for (;;) {
15285 15282                                  v = scf_value_create(g_hndl);
15286 15283                                  if (v == NULL)
15287 15284                                          scfdie();
15288 15285  
15289 15286                                  r = scf_iter_next_value(viter, v);
15290 15287                                  if (r == -1)
15291 15288                                          scfdie();
15292 15289                                  if (r == 0) {
15293 15290                                          scf_value_destroy(v);
15294 15291                                          break;
15295 15292                                  }
15296 15293  
15297 15294                                  if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15298 15295                                          scfdie();
15299 15296                          }
15300 15297                  }
15301 15298          }
15302 15299  
15303 15300          free(nbuf);
15304 15301          scf_iter_destroy(viter);
15305 15302          scf_property_destroy(prop);
15306 15303          scf_iter_destroy(iter);
15307 15304  
15308 15305          r = scf_transaction_commit(tx);
15309 15306          if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15310 15307                  scfdie();
15311 15308  
15312 15309          scf_transaction_destroy_children(tx);
15313 15310          scf_transaction_destroy(tx);
15314 15311  
15315 15312          switch (r) {
15316 15313          case 1:         return (0);
15317 15314          case 0:         return (-2);
15318 15315          case -1:        return (-1);
15319 15316  
15320 15317          default:
15321 15318                  abort();
15322 15319          }
15323 15320  
15324 15321          /* NOTREACHED */
15325 15322  }
15326 15323  
15327 15324  void
15328 15325  lscf_revert(const char *snapname)
15329 15326  {
15330 15327          scf_snapshot_t *snap, *prev;
15331 15328          scf_snaplevel_t *level, *nlevel;
15332 15329          scf_iter_t *iter;
15333 15330          scf_propertygroup_t *pg, *npg;
15334 15331          scf_property_t *prop;
15335 15332          scf_value_t *val;
15336 15333          char *nbuf, *tbuf;
15337 15334          uint8_t enabled;
15338 15335  
15339 15336          lscf_prep_hndl();
15340 15337  
15341 15338          if (cur_inst == NULL) {
15342 15339                  semerr(gettext("Instance not selected.\n"));
15343 15340                  return;
15344 15341          }
15345 15342  
15346 15343          if (snapname != NULL) {
15347 15344                  snap = scf_snapshot_create(g_hndl);
15348 15345                  if (snap == NULL)
15349 15346                          scfdie();
15350 15347  
15351 15348                  if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15352 15349                      SCF_SUCCESS) {
15353 15350                          switch (scf_error()) {
15354 15351                          case SCF_ERROR_INVALID_ARGUMENT:
15355 15352                                  semerr(gettext("Invalid snapshot name "
15356 15353                                      "\"%s\".\n"), snapname);
15357 15354                                  break;
15358 15355  
15359 15356                          case SCF_ERROR_NOT_FOUND:
15360 15357                                  semerr(gettext("No such snapshot.\n"));
15361 15358                                  break;
15362 15359  
15363 15360                          default:
15364 15361                                  scfdie();
15365 15362                          }
15366 15363  
15367 15364                          scf_snapshot_destroy(snap);
15368 15365                          return;
15369 15366                  }
15370 15367          } else {
15371 15368                  if (cur_snap != NULL) {
15372 15369                          snap = cur_snap;
15373 15370                  } else {
15374 15371                          semerr(gettext("No snapshot selected.\n"));
15375 15372                          return;
15376 15373                  }
15377 15374          }
15378 15375  
15379 15376          if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15380 15377              (level = scf_snaplevel_create(g_hndl)) == NULL ||
15381 15378              (iter = scf_iter_create(g_hndl)) == NULL ||
15382 15379              (pg = scf_pg_create(g_hndl)) == NULL ||
15383 15380              (npg = scf_pg_create(g_hndl)) == NULL ||
15384 15381              (prop = scf_property_create(g_hndl)) == NULL ||
15385 15382              (val = scf_value_create(g_hndl)) == NULL)
15386 15383                  scfdie();
15387 15384  
15388 15385          nbuf = safe_malloc(max_scf_name_len + 1);
15389 15386          tbuf = safe_malloc(max_scf_pg_type_len + 1);
15390 15387  
15391 15388          /* Take the "previous" snapshot before we blow away the properties. */
15392 15389          if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15393 15390                  if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15394 15391                          scfdie();
15395 15392          } else {
15396 15393                  if (scf_error() != SCF_ERROR_NOT_FOUND)
15397 15394                          scfdie();
15398 15395  
15399 15396                  if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15400 15397                          scfdie();
15401 15398          }
15402 15399  
15403 15400          /* Save general/enabled, since we're probably going to replace it. */
15404 15401          enabled = 2;
15405 15402          if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15406 15403              scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15407 15404              scf_property_get_value(prop, val) == 0)
15408 15405                  (void) scf_value_get_boolean(val, &enabled);
15409 15406  
15410 15407          if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15411 15408                  if (scf_error() != SCF_ERROR_NOT_FOUND)
15412 15409                          scfdie();
15413 15410  
15414 15411                  goto out;
15415 15412          }
15416 15413  
15417 15414          for (;;) {
15418 15415                  boolean_t isinst;
15419 15416                  uint32_t flags;
15420 15417                  int r;
15421 15418  
15422 15419                  /* Clear the properties from the corresponding entity. */
15423 15420                  isinst = snaplevel_is_instance(level);
15424 15421  
15425 15422                  if (!isinst)
15426 15423                          r = scf_iter_service_pgs(iter, cur_svc);
15427 15424                  else
15428 15425                          r = scf_iter_instance_pgs(iter, cur_inst);
15429 15426                  if (r != SCF_SUCCESS)
15430 15427                          scfdie();
15431 15428  
15432 15429                  while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15433 15430                          if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15434 15431                                  scfdie();
15435 15432  
15436 15433                          /* Skip nonpersistent pgs. */
15437 15434                          if (flags & SCF_PG_FLAG_NONPERSISTENT)
15438 15435                                  continue;
15439 15436  
15440 15437                          if (scf_pg_delete(pg) != SCF_SUCCESS) {
15441 15438                                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15442 15439                                          scfdie();
15443 15440  
15444 15441                                  semerr(emsg_permission_denied);
15445 15442                                  goto out;
15446 15443                          }
15447 15444                  }
15448 15445                  if (r == -1)
15449 15446                          scfdie();
15450 15447  
15451 15448                  /* Copy the properties to the corresponding entity. */
15452 15449                  if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15453 15450                          scfdie();
15454 15451  
15455 15452                  while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15456 15453                          if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15457 15454                                  scfdie();
15458 15455  
15459 15456                          if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15460 15457                              0)
15461 15458                                  scfdie();
15462 15459  
15463 15460                          if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15464 15461                                  scfdie();
15465 15462  
15466 15463                          if (!isinst)
15467 15464                                  r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15468 15465                                      flags, npg);
15469 15466                          else
15470 15467                                  r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15471 15468                                      flags, npg);
15472 15469                          if (r != SCF_SUCCESS) {
15473 15470                                  if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15474 15471                                          scfdie();
15475 15472  
15476 15473                                  semerr(emsg_permission_denied);
15477 15474                                  goto out;
15478 15475                          }
15479 15476  
15480 15477                          if ((enabled == 0 || enabled == 1) &&
15481 15478                              strcmp(nbuf, scf_pg_general) == 0)
15482 15479                                  r = pg_copy(pg, npg, enabled);
15483 15480                          else
15484 15481                                  r = pg_copy(pg, npg, 2);
15485 15482  
15486 15483                          switch (r) {
15487 15484                          case 0:
15488 15485                                  break;
15489 15486  
15490 15487                          case -1:
15491 15488                                  semerr(emsg_permission_denied);
15492 15489                                  goto out;
15493 15490  
15494 15491                          case -2:
15495 15492                                  semerr(gettext(
15496 15493                                      "Interrupted by another change.\n"));
15497 15494                                  goto out;
15498 15495  
15499 15496                          default:
15500 15497                                  abort();
15501 15498                          }
15502 15499                  }
15503 15500                  if (r == -1)
15504 15501                          scfdie();
15505 15502  
15506 15503                  /* Get next level. */
15507 15504                  nlevel = scf_snaplevel_create(g_hndl);
15508 15505                  if (nlevel == NULL)
15509 15506                          scfdie();
15510 15507  
15511 15508                  if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15512 15509                      SCF_SUCCESS) {
15513 15510                          if (scf_error() != SCF_ERROR_NOT_FOUND)
15514 15511                                  scfdie();
15515 15512  
15516 15513                          scf_snaplevel_destroy(nlevel);
15517 15514                          break;
15518 15515                  }
15519 15516  
15520 15517                  scf_snaplevel_destroy(level);
15521 15518                  level = nlevel;
15522 15519          }
15523 15520  
15524 15521          if (snapname == NULL) {
15525 15522                  lscf_selectsnap(NULL);
15526 15523                  snap = NULL;            /* cur_snap has been destroyed */
15527 15524          }
15528 15525  
15529 15526  out:
15530 15527          free(tbuf);
15531 15528          free(nbuf);
15532 15529          scf_value_destroy(val);
15533 15530          scf_property_destroy(prop);
15534 15531          scf_pg_destroy(npg);
15535 15532          scf_pg_destroy(pg);
15536 15533          scf_iter_destroy(iter);
15537 15534          scf_snaplevel_destroy(level);
15538 15535          scf_snapshot_destroy(prev);
15539 15536          if (snap != cur_snap)
15540 15537                  scf_snapshot_destroy(snap);
15541 15538  }
15542 15539  
15543 15540  void
15544 15541  lscf_refresh(void)
15545 15542  {
15546 15543          ssize_t fmrilen;
15547 15544          size_t bufsz;
15548 15545          char *fmribuf;
15549 15546          int r;
15550 15547  
15551 15548          lscf_prep_hndl();
15552 15549  
15553 15550          if (cur_inst == NULL) {
15554 15551                  semerr(gettext("Instance not selected.\n"));
15555 15552                  return;
15556 15553          }
15557 15554  
15558 15555          bufsz = max_scf_fmri_len + 1;
15559 15556          fmribuf = safe_malloc(bufsz);
15560 15557          fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15561 15558          if (fmrilen < 0) {
15562 15559                  free(fmribuf);
15563 15560                  if (scf_error() != SCF_ERROR_DELETED)
15564 15561                          scfdie();
15565 15562                  scf_instance_destroy(cur_inst);
15566 15563                  cur_inst = NULL;
15567 15564                  warn(emsg_deleted);
15568 15565                  return;
15569 15566          }
15570 15567          assert(fmrilen < bufsz);
15571 15568  
15572 15569          r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15573 15570          switch (r) {
15574 15571          case 0:
15575 15572                  break;
15576 15573  
15577 15574          case ECONNABORTED:
15578 15575                  warn(gettext("Could not refresh %s "
15579 15576                      "(repository connection broken).\n"), fmribuf);
15580 15577                  break;
15581 15578  
15582 15579          case ECANCELED:
15583 15580                  warn(emsg_deleted);
15584 15581                  break;
15585 15582  
15586 15583          case EPERM:
15587 15584                  warn(gettext("Could not refresh %s "
15588 15585                      "(permission denied).\n"), fmribuf);
15589 15586                  break;
15590 15587  
15591 15588          case ENOSPC:
15592 15589                  warn(gettext("Could not refresh %s "
15593 15590                      "(repository server out of resources).\n"),
15594 15591                      fmribuf);
15595 15592                  break;
15596 15593  
15597 15594          case EACCES:
15598 15595          default:
15599 15596                  bad_error("refresh_entity", scf_error());
15600 15597          }
15601 15598  
15602 15599          free(fmribuf);
15603 15600  }
15604 15601  
15605 15602  /*
15606 15603   * describe [-v] [-t] [pg/prop]
15607 15604   */
15608 15605  int
15609 15606  lscf_describe(uu_list_t *args, int hasargs)
15610 15607  {
15611 15608          int ret = 0;
15612 15609          size_t i;
15613 15610          int argc;
15614 15611          char **argv = NULL;
15615 15612          string_list_t *slp;
15616 15613          int do_verbose = 0;
15617 15614          int do_templates = 0;
15618 15615          char *pattern = NULL;
15619 15616  
15620 15617          lscf_prep_hndl();
15621 15618  
15622 15619          if (hasargs != 0)  {
15623 15620                  argc = uu_list_numnodes(args);
15624 15621                  if (argc < 1)
15625 15622                          goto usage;
15626 15623  
15627 15624                  argv = calloc(argc + 1, sizeof (char *));
15628 15625                  if (argv == NULL)
15629 15626                          uu_die(gettext("Out of memory.\n"));
15630 15627  
15631 15628                  for (slp = uu_list_first(args), i = 0;
15632 15629                      slp != NULL;
15633 15630                      slp = uu_list_next(args, slp), ++i)
15634 15631                          argv[i] = slp->str;
15635 15632  
15636 15633                  argv[i] = NULL;
15637 15634  
15638 15635                  /*
15639 15636                   * We start optind = 0 because our list of arguments
15640 15637                   * starts at argv[0]
15641 15638                   */
15642 15639                  optind = 0;
15643 15640                  opterr = 0;
15644 15641                  for (;;) {
15645 15642                          ret = getopt(argc, argv, "vt");
15646 15643                          if (ret == -1)
15647 15644                                  break;
15648 15645  
15649 15646                          switch (ret) {
15650 15647                          case 'v':
15651 15648                                  do_verbose = 1;
15652 15649                                  break;
15653 15650  
15654 15651                          case 't':
15655 15652                                  do_templates = 1;
15656 15653                                  break;
15657 15654  
15658 15655                          case '?':
15659 15656                                  goto usage;
15660 15657  
15661 15658                          default:
15662 15659                                  bad_error("getopt", ret);
15663 15660                          }
15664 15661                  }
15665 15662  
15666 15663                  pattern = argv[optind];
15667 15664          }
15668 15665  
15669 15666          if (cur_inst == NULL && cur_svc == NULL) {
15670 15667                  semerr(emsg_entity_not_selected);
15671 15668                  ret = -1;
15672 15669                  goto out;
15673 15670          }
15674 15671  
15675 15672          /*
15676 15673           * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15677 15674           * output if their last parameter is set to 2.  Less information is
15678 15675           * produced if the parameter is set to 1.
15679 15676           */
15680 15677          if (pattern == NULL) {
15681 15678                  if (do_verbose == 1)
15682 15679                          list_entity_tmpl(2);
15683 15680                  else
15684 15681                          list_entity_tmpl(1);
15685 15682          }
15686 15683  
15687 15684          if (do_templates == 0) {
15688 15685                  if (do_verbose == 1)
15689 15686                          listprop(pattern, 0, 2);
15690 15687                  else
15691 15688                          listprop(pattern, 0, 1);
15692 15689          } else {
15693 15690                  if (do_verbose == 1)
15694 15691                          listtmpl(pattern, 2);
15695 15692                  else
15696 15693                          listtmpl(pattern, 1);
15697 15694          }
15698 15695  
15699 15696          ret = 0;
15700 15697  out:
15701 15698          if (argv != NULL)
15702 15699                  free(argv);
15703 15700          return (ret);
15704 15701  usage:
15705 15702          ret = -2;
15706 15703          goto out;
15707 15704  }
15708 15705  
15709 15706  #define PARAM_ACTIVE    ((const char *) "active")
15710 15707  #define PARAM_INACTIVE  ((const char *) "inactive")
15711 15708  #define PARAM_SMTP_TO   ((const char *) "to")
15712 15709  
15713 15710  /*
15714 15711   * tokenize()
15715 15712   * Breaks down the string according to the tokens passed.
15716 15713   * Caller is responsible for freeing array of pointers returned.
15717 15714   * Returns NULL on failure
15718 15715   */
15719 15716  char **
15720 15717  tokenize(char *str, const char *sep)
15721 15718  {
15722 15719          char *token, *lasts;
15723 15720          char **buf;
15724 15721          int n = 0;      /* number of elements */
15725 15722          int size = 8;   /* size of the array (initial) */
15726 15723  
15727 15724          buf = safe_malloc(size * sizeof (char *));
15728 15725  
15729 15726          for (token = strtok_r(str, sep, &lasts); token != NULL;
15730 15727              token = strtok_r(NULL, sep, &lasts), ++n) {
15731 15728                  if (n + 1 >= size) {
15732 15729                          size *= 2;
15733 15730                          if ((buf = realloc(buf, size * sizeof (char *))) ==
15734 15731                              NULL) {
15735 15732                                  uu_die(gettext("Out of memory"));
15736 15733                          }
15737 15734                  }
15738 15735                  buf[n] = token;
15739 15736          }
15740 15737          /* NULL terminate the pointer array */
15741 15738          buf[n] = NULL;
15742 15739  
15743 15740          return (buf);
15744 15741  }
15745 15742  
15746 15743  int32_t
15747 15744  check_tokens(char **p)
15748 15745  {
15749 15746          int32_t smf = 0;
15750 15747          int32_t fma = 0;
15751 15748  
15752 15749          while (*p) {
15753 15750                  int32_t t = string_to_tset(*p);
15754 15751  
15755 15752                  if (t == 0) {
15756 15753                          if (is_fma_token(*p) == 0)
15757 15754                                  return (INVALID_TOKENS);
15758 15755                          fma = 1; /* this token is an fma event */
15759 15756                  } else {
15760 15757                          smf |= t;
15761 15758                  }
15762 15759  
15763 15760                  if (smf != 0 && fma == 1)
15764 15761                          return (MIXED_TOKENS);
15765 15762                  ++p;
15766 15763          }
15767 15764  
15768 15765          if (smf > 0)
15769 15766                  return (smf);
15770 15767          else if (fma == 1)
15771 15768                  return (FMA_TOKENS);
15772 15769  
15773 15770          return (INVALID_TOKENS);
15774 15771  }
15775 15772  
15776 15773  static int
15777 15774  get_selection_str(char *fmri, size_t sz)
15778 15775  {
15779 15776          if (g_hndl == NULL) {
15780 15777                  semerr(emsg_entity_not_selected);
15781 15778                  return (-1);
15782 15779          } else if (cur_level != NULL) {
15783 15780                  semerr(emsg_invalid_for_snapshot);
15784 15781                  return (-1);
15785 15782          } else {
15786 15783                  lscf_get_selection_str(fmri, sz);
15787 15784          }
15788 15785  
15789 15786          return (0);
15790 15787  }
15791 15788  
15792 15789  void
15793 15790  lscf_delnotify(const char *set, int global)
15794 15791  {
15795 15792          char *str = strdup(set);
15796 15793          char **pgs;
15797 15794          char **p;
15798 15795          int32_t tset;
15799 15796          char *fmri = NULL;
15800 15797  
15801 15798          if (str == NULL)
15802 15799                  uu_die(gettext("Out of memory.\n"));
15803 15800  
15804 15801          pgs = tokenize(str, ",");
15805 15802  
15806 15803          if ((tset = check_tokens(pgs)) > 0) {
15807 15804                  size_t sz = max_scf_fmri_len + 1;
15808 15805  
15809 15806                  fmri = safe_malloc(sz);
15810 15807                  if (global) {
15811 15808                          (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15812 15809                  } else if (get_selection_str(fmri, sz) != 0) {
15813 15810                          goto out;
15814 15811                  }
15815 15812  
15816 15813                  if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15817 15814                      tset) != SCF_SUCCESS) {
15818 15815                          uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15819 15816                              scf_strerror(scf_error()));
15820 15817                  }
15821 15818          } else if (tset == FMA_TOKENS) {
15822 15819                  if (global) {
15823 15820                          semerr(gettext("Can't use option '-g' with FMA event "
15824 15821                              "definitions\n"));
15825 15822                          goto out;
15826 15823                  }
15827 15824  
15828 15825                  for (p = pgs; *p; ++p) {
15829 15826                          if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15830 15827                              SCF_SUCCESS) {
15831 15828                                  uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15832 15829                                      scf_strerror(scf_error()));
15833 15830                                  goto out;
15834 15831                          }
15835 15832                  }
15836 15833          } else if (tset == MIXED_TOKENS) {
15837 15834                  semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15838 15835                  goto out;
15839 15836          } else {
15840 15837                  uu_die(gettext("Invalid input.\n"));
15841 15838          }
15842 15839  
15843 15840  out:
15844 15841          free(fmri);
15845 15842          free(pgs);
15846 15843          free(str);
15847 15844  }
15848 15845  
15849 15846  void
15850 15847  lscf_listnotify(const char *set, int global)
15851 15848  {
15852 15849          char *str = safe_strdup(set);
15853 15850          char **pgs;
15854 15851          char **p;
15855 15852          int32_t tset;
15856 15853          nvlist_t *nvl;
15857 15854          char *fmri = NULL;
15858 15855  
15859 15856          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15860 15857                  uu_die(gettext("Out of memory.\n"));
15861 15858  
15862 15859          pgs = tokenize(str, ",");
15863 15860  
15864 15861          if ((tset = check_tokens(pgs)) > 0) {
15865 15862                  size_t sz = max_scf_fmri_len + 1;
15866 15863  
15867 15864                  fmri = safe_malloc(sz);
15868 15865                  if (global) {
15869 15866                          (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15870 15867                  } else if (get_selection_str(fmri, sz) != 0) {
15871 15868                          goto out;
15872 15869                  }
15873 15870  
15874 15871                  if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15875 15872                      SCF_SUCCESS) {
15876 15873                          if (scf_error() != SCF_ERROR_NOT_FOUND &&
15877 15874                              scf_error() != SCF_ERROR_DELETED)
15878 15875                                  uu_warn(gettext(
15879 15876                                      "Failed listnotify: %s\n"),
15880 15877                                      scf_strerror(scf_error()));
15881 15878                          goto out;
15882 15879                  }
15883 15880  
15884 15881                  listnotify_print(nvl, NULL);
15885 15882          } else if (tset == FMA_TOKENS) {
15886 15883                  if (global) {
15887 15884                          semerr(gettext("Can't use option '-g' with FMA event "
15888 15885                              "definitions\n"));
15889 15886                          goto out;
15890 15887                  }
15891 15888  
15892 15889                  for (p = pgs; *p; ++p) {
15893 15890                          if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15894 15891                              SCF_SUCCESS) {
15895 15892                                  /*
15896 15893                                   * if the preferences have just been deleted
15897 15894                                   * or does not exist, just skip.
15898 15895                                   */
15899 15896                                  if (scf_error() == SCF_ERROR_NOT_FOUND ||
15900 15897                                      scf_error() == SCF_ERROR_DELETED)
15901 15898                                          continue;
15902 15899                                  uu_warn(gettext(
15903 15900                                      "Failed listnotify: %s\n"),
15904 15901                                      scf_strerror(scf_error()));
15905 15902                                  goto out;
15906 15903                          }
15907 15904                          listnotify_print(nvl, re_tag(*p));
15908 15905                  }
15909 15906          } else if (tset == MIXED_TOKENS) {
15910 15907                  semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15911 15908                  goto out;
15912 15909          } else {
15913 15910                  semerr(gettext("Invalid input.\n"));
15914 15911          }
15915 15912  
15916 15913  out:
15917 15914          nvlist_free(nvl);
15918 15915          free(fmri);
15919 15916          free(pgs);
15920 15917          free(str);
15921 15918  }
15922 15919  
15923 15920  static char *
15924 15921  strip_quotes_and_blanks(char *s)
15925 15922  {
15926 15923          char *start = s;
15927 15924          char *end = strrchr(s, '\"');
15928 15925  
15929 15926          if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15930 15927                  start = s + 1;
15931 15928                  while (isblank(*start))
15932 15929                          start++;
15933 15930                  while (isblank(*(end - 1)) && end > start) {
15934 15931                          end--;
15935 15932                  }
15936 15933                  *end = '\0';
15937 15934          }
15938 15935  
15939 15936          return (start);
15940 15937  }
15941 15938  
15942 15939  static int
15943 15940  set_active(nvlist_t *mech, const char *hier_part)
15944 15941  {
15945 15942          boolean_t b;
15946 15943  
15947 15944          if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15948 15945                  b = B_TRUE;
15949 15946          } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15950 15947                  b = B_FALSE;
15951 15948          } else {
15952 15949                  return (-1);
15953 15950          }
15954 15951  
15955 15952          if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15956 15953                  uu_die(gettext("Out of memory.\n"));
15957 15954  
15958 15955          return (0);
15959 15956  }
15960 15957  
15961 15958  static int
15962 15959  add_snmp_params(nvlist_t *mech, char *hier_part)
15963 15960  {
15964 15961          return (set_active(mech, hier_part));
15965 15962  }
15966 15963  
15967 15964  static int
15968 15965  add_syslog_params(nvlist_t *mech, char *hier_part)
15969 15966  {
15970 15967          return (set_active(mech, hier_part));
15971 15968  }
15972 15969  
15973 15970  /*
15974 15971   * add_mailto_paramas()
15975 15972   * parse the hier_part of mailto URI
15976 15973   * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15977 15974   * or mailto:{[active]|inactive}
15978 15975   */
15979 15976  static int
15980 15977  add_mailto_params(nvlist_t *mech, char *hier_part)
15981 15978  {
15982 15979          const char *tok = "?&";
15983 15980          char *p;
15984 15981          char *lasts;
15985 15982          char *param;
15986 15983          char *val;
15987 15984  
15988 15985          /*
15989 15986           * If the notification parametes are in the form of
15990 15987           *
15991 15988           *   malito:{[active]|inactive}
15992 15989           *
15993 15990           * we set the property accordingly and return.
15994 15991           * Otherwise, we make the notification type active and
15995 15992           * process the hier_part.
15996 15993           */
15997 15994          if (set_active(mech, hier_part) == 0)
15998 15995                  return (0);
15999 15996          else if (set_active(mech, PARAM_ACTIVE) != 0)
16000 15997                  return (-1);
16001 15998  
16002 15999          if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16003 16000                  /*
16004 16001                   * sanity check: we only get here if hier_part = "", but
16005 16002                   * that's handled by set_active
16006 16003                   */
16007 16004                  uu_die("strtok_r");
16008 16005          }
16009 16006  
16010 16007          if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16011 16008                  uu_die(gettext("Out of memory.\n"));
16012 16009  
16013 16010          while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16014 16011                  if ((param = strtok_r(p, "=", &val)) != NULL)
16015 16012                          if (nvlist_add_string(mech, param, val) != 0)
16016 16013                                  uu_die(gettext("Out of memory.\n"));
16017 16014  
16018 16015          return (0);
16019 16016  }
16020 16017  
16021 16018  static int
16022 16019  uri_split(char *uri, char **scheme, char **hier_part)
16023 16020  {
16024 16021          int r = -1;
16025 16022  
16026 16023          if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16027 16024              *hier_part == NULL) {
16028 16025                  semerr(gettext("'%s' is not an URI\n"), uri);
16029 16026                  return (r);
16030 16027          }
16031 16028  
16032 16029          if ((r = check_uri_scheme(*scheme)) < 0) {
16033 16030                  semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16034 16031                  return (r);
16035 16032          }
16036 16033  
16037 16034          return (r);
16038 16035  }
16039 16036  
16040 16037  static int
16041 16038  process_uri(nvlist_t *params, char *uri)
16042 16039  {
16043 16040          char *scheme;
16044 16041          char *hier_part;
16045 16042          nvlist_t *mech;
16046 16043          int index;
16047 16044          int r;
16048 16045  
16049 16046          if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16050 16047                  return (-1);
16051 16048  
16052 16049          if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16053 16050                  uu_die(gettext("Out of memory.\n"));
16054 16051  
16055 16052          switch (index) {
16056 16053          case 0:
16057 16054                  /* error messages displayed by called function */
16058 16055                  r = add_mailto_params(mech, hier_part);
16059 16056                  break;
16060 16057  
16061 16058          case 1:
16062 16059                  if ((r = add_snmp_params(mech, hier_part)) != 0)
16063 16060                          semerr(gettext("Not valid parameters: '%s'\n"),
16064 16061                              hier_part);
16065 16062                  break;
16066 16063  
16067 16064          case 2:
16068 16065                  if ((r = add_syslog_params(mech, hier_part)) != 0)
16069 16066                          semerr(gettext("Not valid parameters: '%s'\n"),
16070 16067                              hier_part);
16071 16068                  break;
16072 16069  
16073 16070          default:
16074 16071                  r = -1;
16075 16072          }
16076 16073  
16077 16074          if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16078 16075              mech) != 0)
16079 16076                  uu_die(gettext("Out of memory.\n"));
16080 16077  
16081 16078          nvlist_free(mech);
16082 16079          return (r);
16083 16080  }
16084 16081  
16085 16082  static int
16086 16083  set_params(nvlist_t *params, char **p)
16087 16084  {
16088 16085          char *uri;
16089 16086  
16090 16087          if (p == NULL)
16091 16088                  /* sanity check */
16092 16089                  uu_die("set_params");
16093 16090  
16094 16091          while (*p) {
16095 16092                  uri = strip_quotes_and_blanks(*p);
16096 16093                  if (process_uri(params, uri) != 0)
16097 16094                          return (-1);
16098 16095  
16099 16096                  ++p;
16100 16097          }
16101 16098  
16102 16099          return (0);
16103 16100  }
16104 16101  
16105 16102  static int
16106 16103  setnotify(const char *e, char **p, int global)
16107 16104  {
16108 16105          char *str = safe_strdup(e);
16109 16106          char **events;
16110 16107          int32_t tset;
16111 16108          int r = -1;
16112 16109          nvlist_t *nvl, *params;
16113 16110          char *fmri = NULL;
16114 16111  
16115 16112          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16116 16113              nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16117 16114              nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16118 16115              SCF_NOTIFY_PARAMS_VERSION) != 0)
16119 16116                  uu_die(gettext("Out of memory.\n"));
16120 16117  
16121 16118          events = tokenize(str, ",");
16122 16119  
16123 16120          if ((tset = check_tokens(events)) > 0) {
16124 16121                  /* SMF state transitions parameters */
16125 16122                  size_t sz = max_scf_fmri_len + 1;
16126 16123  
16127 16124                  fmri = safe_malloc(sz);
16128 16125                  if (global) {
16129 16126                          (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16130 16127                  } else if (get_selection_str(fmri, sz) != 0) {
16131 16128                          goto out;
16132 16129                  }
16133 16130  
16134 16131                  if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16135 16132                      nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16136 16133                          uu_die(gettext("Out of memory.\n"));
16137 16134  
16138 16135                  if ((r = set_params(params, p)) == 0) {
16139 16136                          if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16140 16137                              params) != 0)
16141 16138                                  uu_die(gettext("Out of memory.\n"));
16142 16139  
16143 16140                          if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16144 16141                              nvl) != SCF_SUCCESS) {
16145 16142                                  r = -1;
16146 16143                                  uu_warn(gettext(
16147 16144                                      "Failed smf_notify_set_params(3SCF): %s\n"),
16148 16145                                      scf_strerror(scf_error()));
16149 16146                          }
16150 16147                  }
16151 16148          } else if (tset == FMA_TOKENS) {
16152 16149                  /* FMA event parameters */
16153 16150                  if (global) {
16154 16151                          semerr(gettext("Can't use option '-g' with FMA event "
16155 16152                              "definitions\n"));
16156 16153                          goto out;
16157 16154                  }
16158 16155  
16159 16156                  if ((r = set_params(params, p)) != 0)
16160 16157                          goto out;
16161 16158  
16162 16159                  if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16163 16160                          uu_die(gettext("Out of memory.\n"));
16164 16161  
16165 16162                  while (*events) {
16166 16163                          if (smf_notify_set_params(de_tag(*events), nvl) !=
16167 16164                              SCF_SUCCESS)
16168 16165                                  uu_warn(gettext(
16169 16166                                      "Failed smf_notify_set_params(3SCF) for "
16170 16167                                      "event %s: %s\n"), *events,
16171 16168                                      scf_strerror(scf_error()));
16172 16169                          events++;
16173 16170                  }
16174 16171          } else if (tset == MIXED_TOKENS) {
16175 16172                  semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16176 16173          } else {
16177 16174                  /* Sanity check */
16178 16175                  uu_die(gettext("Invalid input.\n"));
16179 16176          }
16180 16177  
16181 16178  out:
16182 16179          nvlist_free(nvl);
16183 16180          nvlist_free(params);
16184 16181          free(fmri);
16185 16182          free(str);
16186 16183  
16187 16184          return (r);
16188 16185  }
16189 16186  
16190 16187  int
16191 16188  lscf_setnotify(uu_list_t *args)
16192 16189  {
16193 16190          int argc;
16194 16191          char **argv = NULL;
16195 16192          string_list_t *slp;
16196 16193          int global;
16197 16194          char *events;
16198 16195          char **p;
16199 16196          int i;
16200 16197          int ret;
16201 16198  
16202 16199          if ((argc = uu_list_numnodes(args)) < 2)
16203 16200                  goto usage;
16204 16201  
16205 16202          argv = calloc(argc + 1, sizeof (char *));
16206 16203          if (argv == NULL)
16207 16204                  uu_die(gettext("Out of memory.\n"));
16208 16205  
16209 16206          for (slp = uu_list_first(args), i = 0;
16210 16207              slp != NULL;
16211 16208              slp = uu_list_next(args, slp), ++i)
16212 16209                  argv[i] = slp->str;
16213 16210  
16214 16211          argv[i] = NULL;
16215 16212  
16216 16213          if (strcmp(argv[0], "-g") == 0) {
16217 16214                  global = 1;
16218 16215                  events = argv[1];
16219 16216                  p = argv + 2;
16220 16217          } else {
16221 16218                  global = 0;
16222 16219                  events = argv[0];
16223 16220                  p = argv + 1;
16224 16221          }
16225 16222  
16226 16223          ret = setnotify(events, p, global);
16227 16224  
16228 16225  out:
16229 16226          free(argv);
16230 16227          return (ret);
16231 16228  
16232 16229  usage:
16233 16230          ret = -2;
16234 16231          goto out;
16235 16232  }
16236 16233  
16237 16234  /*
16238 16235   * Creates a list of instance name strings associated with a service. If
16239 16236   * wohandcrafted flag is set, get only instances that have a last-import
16240 16237   * snapshot, instances that were imported via svccfg.
16241 16238   */
16242 16239  static uu_list_t *
16243 16240  create_instance_list(scf_service_t *svc, int wohandcrafted)
16244 16241  {
16245 16242          scf_snapshot_t  *snap = NULL;
16246 16243          scf_instance_t  *inst;
16247 16244          scf_iter_t      *inst_iter;
16248 16245          uu_list_t       *instances;
16249 16246          char            *instname;
16250 16247          int             r;
16251 16248  
16252 16249          inst_iter = scf_iter_create(g_hndl);
16253 16250          inst = scf_instance_create(g_hndl);
16254 16251          if (inst_iter == NULL || inst == NULL) {
16255 16252                  uu_warn(gettext("Could not create instance or iterator\n"));
16256 16253                  scfdie();
16257 16254          }
16258 16255  
16259 16256          if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16260 16257                  return (instances);
16261 16258  
16262 16259          if (scf_iter_service_instances(inst_iter, svc) != 0) {
16263 16260                  switch (scf_error()) {
16264 16261                  case SCF_ERROR_CONNECTION_BROKEN:
16265 16262                  case SCF_ERROR_DELETED:
16266 16263                          uu_list_destroy(instances);
16267 16264                          instances = NULL;
16268 16265                          goto out;
16269 16266  
16270 16267                  case SCF_ERROR_HANDLE_MISMATCH:
16271 16268                  case SCF_ERROR_NOT_BOUND:
16272 16269                  case SCF_ERROR_NOT_SET:
16273 16270                  default:
16274 16271                          bad_error("scf_iter_service_instances", scf_error());
16275 16272                  }
16276 16273          }
16277 16274  
16278 16275          instname = safe_malloc(max_scf_name_len + 1);
16279 16276          while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16280 16277                  if (r == -1) {
16281 16278                          (void) uu_warn(gettext("Unable to iterate through "
16282 16279                              "instances to create instance list : %s\n"),
16283 16280                              scf_strerror(scf_error()));
16284 16281  
16285 16282                          uu_list_destroy(instances);
16286 16283                          instances = NULL;
16287 16284                          goto out;
16288 16285                  }
16289 16286  
16290 16287                  /*
16291 16288                   * If the instance does not have a last-import snapshot
16292 16289                   * then do not add it to the list as it is a hand-crafted
16293 16290                   * instance that should not be managed.
16294 16291                   */
16295 16292                  if (wohandcrafted) {
16296 16293                          if (snap == NULL &&
16297 16294                              (snap = scf_snapshot_create(g_hndl)) == NULL) {
16298 16295                                  uu_warn(gettext("Unable to create snapshot "
16299 16296                                      "entity\n"));
16300 16297                                  scfdie();
16301 16298                          }
16302 16299  
16303 16300                          if (scf_instance_get_snapshot(inst,
16304 16301                              snap_lastimport, snap) != 0) {
16305 16302                                  switch (scf_error()) {
16306 16303                                  case SCF_ERROR_NOT_FOUND :
16307 16304                                  case SCF_ERROR_DELETED:
16308 16305                                          continue;
16309 16306  
16310 16307                                  case SCF_ERROR_CONNECTION_BROKEN:
16311 16308                                          uu_list_destroy(instances);
16312 16309                                          instances = NULL;
16313 16310                                          goto out;
16314 16311  
16315 16312                                  case SCF_ERROR_HANDLE_MISMATCH:
16316 16313                                  case SCF_ERROR_NOT_BOUND:
16317 16314                                  case SCF_ERROR_NOT_SET:
16318 16315                                  default:
16319 16316                                          bad_error("scf_iter_service_instances",
16320 16317                                              scf_error());
16321 16318                                  }
16322 16319                          }
16323 16320                  }
16324 16321  
16325 16322                  if (scf_instance_get_name(inst, instname,
16326 16323                      max_scf_name_len + 1) < 0) {
16327 16324                          switch (scf_error()) {
16328 16325                          case SCF_ERROR_NOT_FOUND :
16329 16326                                  continue;
16330 16327  
16331 16328                          case SCF_ERROR_CONNECTION_BROKEN:
16332 16329                          case SCF_ERROR_DELETED:
16333 16330                                  uu_list_destroy(instances);
16334 16331                                  instances = NULL;
16335 16332                                  goto out;
16336 16333  
16337 16334                          case SCF_ERROR_HANDLE_MISMATCH:
16338 16335                          case SCF_ERROR_NOT_BOUND:
16339 16336                          case SCF_ERROR_NOT_SET:
16340 16337                          default:
16341 16338                                  bad_error("scf_iter_service_instances",
16342 16339                                      scf_error());
16343 16340                          }
16344 16341                  }
16345 16342  
16346 16343                  add_string(instances, instname);
16347 16344          }
16348 16345  
16349 16346  out:
16350 16347          if (snap)
16351 16348                  scf_snapshot_destroy(snap);
16352 16349  
16353 16350          scf_instance_destroy(inst);
16354 16351          scf_iter_destroy(inst_iter);
16355 16352          free(instname);
16356 16353          return (instances);
16357 16354  }
16358 16355  
16359 16356  /*
16360 16357   * disable an instance but wait for the instance to
16361 16358   * move out of the running state.
16362 16359   *
16363 16360   * Returns 0 : if the instance did not disable
16364 16361   * Returns non-zero : if the instance disabled.
16365 16362   *
16366 16363   */
16367 16364  static int
16368 16365  disable_instance(scf_instance_t *instance)
16369 16366  {
16370 16367          char    *fmribuf;
16371 16368          int     enabled = 10000;
16372 16369  
16373 16370          if (inst_is_running(instance)) {
16374 16371                  fmribuf = safe_malloc(max_scf_name_len + 1);
16375 16372                  if (scf_instance_to_fmri(instance, fmribuf,
16376 16373                      max_scf_name_len + 1) < 0) {
16377 16374                          free(fmribuf);
16378 16375                          return (0);
16379 16376                  }
16380 16377  
16381 16378                  /*
16382 16379                   * If the instance cannot be disabled then return
16383 16380                   * failure to disable and let the caller decide
16384 16381                   * if that is of importance.
16385 16382                   */
16386 16383                  if (smf_disable_instance(fmribuf, 0) != 0) {
16387 16384                          free(fmribuf);
16388 16385                          return (0);
16389 16386                  }
16390 16387  
16391 16388                  while (enabled) {
16392 16389                          if (!inst_is_running(instance))
16393 16390                                  break;
16394 16391  
16395 16392                          (void) poll(NULL, 0, 5);
16396 16393                          enabled = enabled - 5;
16397 16394                  }
16398 16395  
16399 16396                  free(fmribuf);
16400 16397          }
16401 16398  
16402 16399          return (enabled);
16403 16400  }
16404 16401  
16405 16402  /*
16406 16403   * Function to compare two service_manifest structures.
16407 16404   */
16408 16405  /* ARGSUSED2 */
16409 16406  static int
16410 16407  service_manifest_compare(const void *left, const void *right, void *unused)
16411 16408  {
16412 16409          service_manifest_t *l = (service_manifest_t *)left;
16413 16410          service_manifest_t *r = (service_manifest_t *)right;
16414 16411          int rc;
16415 16412  
16416 16413          rc = strcmp(l->servicename, r->servicename);
16417 16414  
16418 16415          return (rc);
16419 16416  }
16420 16417  
16421 16418  /*
16422 16419   * Look for the provided service in the service to manifest
16423 16420   * tree.  If the service exists, and a manifest was provided
16424 16421   * then add the manifest to that service.  If the service
16425 16422   * does not exist, then add the service and manifest to the
16426 16423   * list.
16427 16424   *
16428 16425   * If the manifest is NULL, return the element if found.  If
16429 16426   * the service is not found return NULL.
16430 16427   */
16431 16428  service_manifest_t *
16432 16429  find_add_svc_mfst(const char *svnbuf, const char *mfst)
16433 16430  {
16434 16431          service_manifest_t      elem;
16435 16432          service_manifest_t      *fnelem;
16436 16433          uu_avl_index_t          marker;
16437 16434  
16438 16435          elem.servicename = svnbuf;
16439 16436          fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16440 16437  
16441 16438          if (mfst) {
16442 16439                  if (fnelem) {
16443 16440                          add_string(fnelem->mfstlist, strdup(mfst));
16444 16441                  } else {
16445 16442                          fnelem = safe_malloc(sizeof (*fnelem));
16446 16443                          fnelem->servicename = safe_strdup(svnbuf);
16447 16444                          if ((fnelem->mfstlist =
16448 16445                              uu_list_create(string_pool, NULL, 0)) == NULL)
16449 16446                                  uu_die(gettext("Could not create property "
16450 16447                                      "list: %s\n"), uu_strerror(uu_error()));
16451 16448  
16452 16449                          add_string(fnelem->mfstlist, safe_strdup(mfst));
16453 16450  
16454 16451                          uu_avl_insert(service_manifest_tree, fnelem, marker);
16455 16452                  }
16456 16453          }
16457 16454  
16458 16455          return (fnelem);
16459 16456  }
16460 16457  
16461 16458  /*
16462 16459   * Create the service to manifest avl tree.
16463 16460   *
16464 16461   * Walk each of the manifests currently installed in the supported
16465 16462   * directories, /lib/svc/manifests and /var/svc/manifests.  For
16466 16463   * each of the manifests, inventory the services and add them to
16467 16464   * the tree.
16468 16465   *
16469 16466   * Code that calls this function should make sure fileystem/minimal is online,
16470 16467   * /var is available, since this function walks the /var/svc/manifest directory.
16471 16468   */
16472 16469  static void
16473 16470  create_manifest_tree(void)
16474 16471  {
16475 16472          manifest_info_t **entry;
16476 16473          manifest_info_t **manifests;
16477 16474          uu_list_walk_t  *svcs;
16478 16475          bundle_t        *b;
16479 16476          entity_t        *mfsvc;
16480 16477          char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16481 16478          int             c, status;
16482 16479  
16483 16480          if (service_manifest_pool)
16484 16481                  return;
16485 16482  
16486 16483          /*
16487 16484           * Create the list pool for the service manifest list
16488 16485           */
16489 16486          service_manifest_pool = uu_avl_pool_create("service_manifest",
16490 16487              sizeof (service_manifest_t),
16491 16488              offsetof(service_manifest_t, svcmfst_node),
16492 16489              service_manifest_compare, UU_DEFAULT);
16493 16490          if (service_manifest_pool == NULL)
16494 16491                  uu_die(gettext("service_manifest pool creation failed: %s\n"),
16495 16492                      uu_strerror(uu_error()));
16496 16493  
16497 16494          /*
16498 16495           * Create the list
16499 16496           */
16500 16497          service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16501 16498              UU_DEFAULT);
16502 16499          if (service_manifest_tree == NULL)
16503 16500                  uu_die(gettext("service_manifest tree creation failed: %s\n"),
16504 16501                      uu_strerror(uu_error()));
16505 16502  
16506 16503          /*
16507 16504           * Walk the manifests adding the service(s) from each manifest.
16508 16505           *
16509 16506           * If a service already exists add the manifest to the manifest
16510 16507           * list for that service.  This covers the case of a service that
16511 16508           * is supported by multiple manifest files.
16512 16509           */
16513 16510          for (c = 0; dirs[c]; c++) {
16514 16511                  status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16515 16512                  if (status < 0) {
16516 16513                          uu_warn(gettext("file tree walk of %s encountered "
16517 16514                              "error %s\n"), dirs[c], strerror(errno));
16518 16515  
16519 16516                          uu_avl_destroy(service_manifest_tree);
16520 16517                          service_manifest_tree = NULL;
16521 16518                          return;
16522 16519                  }
16523 16520  
16524 16521                  /*
16525 16522                   * If a manifest that was in the list is not found
16526 16523                   * then skip and go to the next manifest file.
16527 16524                   */
16528 16525                  if (manifests != NULL) {
16529 16526                          for (entry = manifests; *entry != NULL; entry++) {
16530 16527                                  b = internal_bundle_new();
16531 16528                                  if (lxml_get_bundle_file(b, (*entry)->mi_path,
16532 16529                                      SVCCFG_OP_IMPORT) != 0) {
16533 16530                                          internal_bundle_free(b);
16534 16531                                          continue;
16535 16532                                  }
16536 16533  
16537 16534                                  svcs = uu_list_walk_start(b->sc_bundle_services,
16538 16535                                      0);
16539 16536                                  if (svcs == NULL) {
16540 16537                                          internal_bundle_free(b);
16541 16538                                          continue;
16542 16539                                  }
16543 16540  
16544 16541                                  while ((mfsvc = uu_list_walk_next(svcs)) !=
16545 16542                                      NULL) {
16546 16543                                          /* Add manifest to service */
16547 16544                                          (void) find_add_svc_mfst(mfsvc->sc_name,
16548 16545                                              (*entry)->mi_path);
16549 16546                                  }
16550 16547  
16551 16548                                  uu_list_walk_end(svcs);
16552 16549                                  internal_bundle_free(b);
16553 16550                          }
16554 16551  
16555 16552                          free_manifest_array(manifests);
16556 16553                  }
16557 16554          }
16558 16555  }
16559 16556  
16560 16557  /*
16561 16558   * Check the manifest history file to see
16562 16559   * if the service was ever installed from
16563 16560   * one of the supported directories.
16564 16561   *
16565 16562   * Return Values :
16566 16563   *      -1 - if there's error reading manifest history file
16567 16564   *       1 - if the service is not found
16568 16565   *       0 - if the service is found
16569 16566   */
16570 16567  static int
16571 16568  check_mfst_history(const char *svcname)
16572 16569  {
16573 16570          struct stat     st;
16574 16571          caddr_t         mfsthist_start;
16575 16572          char            *svnbuf;
16576 16573          int             fd;
16577 16574          int             r = 1;
16578 16575  
16579 16576          fd = open(MFSTHISTFILE, O_RDONLY);
16580 16577          if (fd == -1) {
16581 16578                  uu_warn(gettext("Unable to open the history file\n"));
16582 16579                  return (-1);
16583 16580          }
16584 16581  
16585 16582          if (fstat(fd, &st) == -1) {
16586 16583                  uu_warn(gettext("Unable to stat the history file\n"));
16587 16584                  return (-1);
16588 16585          }
16589 16586  
16590 16587          mfsthist_start = mmap(0, st.st_size, PROT_READ,
16591 16588              MAP_PRIVATE, fd, 0);
16592 16589  
16593 16590          (void) close(fd);
16594 16591          if (mfsthist_start == MAP_FAILED ||
16595 16592              *(mfsthist_start + st.st_size) != '\0') {
16596 16593                  (void) munmap(mfsthist_start, st.st_size);
16597 16594                  return (-1);
16598 16595          }
16599 16596  
16600 16597          /*
16601 16598           * The manifest history file is a space delimited list
16602 16599           * of service and instance to manifest linkage.  Adding
16603 16600           * a space to the end of the service name so to get only
16604 16601           * the service that is being searched for.
16605 16602           */
16606 16603          svnbuf = uu_msprintf("%s ", svcname);
16607 16604          if (svnbuf == NULL)
16608 16605                  uu_die(gettext("Out of memory"));
16609 16606  
16610 16607          if (strstr(mfsthist_start, svnbuf) != NULL)
16611 16608                  r = 0;
16612 16609  
16613 16610          (void) munmap(mfsthist_start, st.st_size);
16614 16611          uu_free(svnbuf);
16615 16612          return (r);
16616 16613  }
16617 16614  
16618 16615  /*
16619 16616   * Take down each of the instances in the service
16620 16617   * and remove them, then delete the service.
16621 16618   */
16622 16619  static void
16623 16620  teardown_service(scf_service_t *svc, const char *svnbuf)
16624 16621  {
16625 16622          scf_instance_t  *instance;
16626 16623          scf_iter_t      *iter;
16627 16624          int             r;
16628 16625  
16629 16626          safe_printf(gettext("Delete service %s as there are no "
16630 16627              "supporting manifests\n"), svnbuf);
16631 16628  
16632 16629          instance = scf_instance_create(g_hndl);
16633 16630          iter = scf_iter_create(g_hndl);
16634 16631          if (iter == NULL || instance == NULL) {
16635 16632                  uu_warn(gettext("Unable to create supporting entities to "
16636 16633                      "teardown the service\n"));
16637 16634                  uu_warn(gettext("scf error is : %s\n"),
16638 16635                      scf_strerror(scf_error()));
16639 16636                  scfdie();
16640 16637          }
16641 16638  
16642 16639          if (scf_iter_service_instances(iter, svc) != 0) {
16643 16640                  switch (scf_error()) {
16644 16641                  case SCF_ERROR_CONNECTION_BROKEN:
16645 16642                  case SCF_ERROR_DELETED:
16646 16643                          goto out;
16647 16644  
16648 16645                  case SCF_ERROR_HANDLE_MISMATCH:
16649 16646                  case SCF_ERROR_NOT_BOUND:
16650 16647                  case SCF_ERROR_NOT_SET:
16651 16648                  default:
16652 16649                          bad_error("scf_iter_service_instances",
16653 16650                              scf_error());
16654 16651                  }
16655 16652          }
16656 16653  
16657 16654          while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16658 16655                  if (r == -1) {
16659 16656                          uu_warn(gettext("Error - %s\n"),
16660 16657                              scf_strerror(scf_error()));
16661 16658                          goto out;
16662 16659                  }
16663 16660  
16664 16661                  (void) disable_instance(instance);
16665 16662          }
16666 16663  
16667 16664          /*
16668 16665           * Delete the service... forcing the deletion in case
16669 16666           * any of the instances did not disable.
16670 16667           */
16671 16668          (void) lscf_service_delete(svc, 1);
16672 16669  out:
16673 16670          scf_instance_destroy(instance);
16674 16671          scf_iter_destroy(iter);
16675 16672  }
16676 16673  
16677 16674  /*
16678 16675   * Get the list of instances supported by the manifest
16679 16676   * file.
16680 16677   *
16681 16678   * Return 0 if there are no instances.
16682 16679   *
16683 16680   * Return -1 if there are errors attempting to collect instances.
16684 16681   *
16685 16682   * Return the count of instances found if there are no errors.
16686 16683   *
16687 16684   */
16688 16685  static int
16689 16686  check_instance_support(char *mfstfile, const char *svcname,
16690 16687      uu_list_t *instances)
16691 16688  {
16692 16689          uu_list_walk_t  *svcs, *insts;
16693 16690          uu_list_t       *ilist;
16694 16691          bundle_t        *b;
16695 16692          entity_t        *mfsvc, *mfinst;
16696 16693          const char      *svcn;
16697 16694          int             rminstcnt = 0;
16698 16695  
16699 16696  
16700 16697          b = internal_bundle_new();
16701 16698  
16702 16699          if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16703 16700                  /*
16704 16701                   * Unable to process the manifest file for
16705 16702                   * instance support, so just return as
16706 16703                   * don't want to remove instances that could
16707 16704                   * not be accounted for that might exist here.
16708 16705                   */
16709 16706                  internal_bundle_free(b);
16710 16707                  return (0);
16711 16708          }
16712 16709  
16713 16710          svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16714 16711          if (svcs == NULL) {
16715 16712                  internal_bundle_free(b);
16716 16713                  return (0);
16717 16714          }
16718 16715  
16719 16716          svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16720 16717              (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16721 16718  
16722 16719          while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16723 16720                  if (strcmp(mfsvc->sc_name, svcn) == 0)
16724 16721                          break;
16725 16722          }
16726 16723          uu_list_walk_end(svcs);
16727 16724  
16728 16725          if (mfsvc == NULL) {
16729 16726                  internal_bundle_free(b);
16730 16727                  return (-1);
16731 16728          }
16732 16729  
16733 16730          ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16734 16731          if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16735 16732                  internal_bundle_free(b);
16736 16733                  return (0);
16737 16734          }
16738 16735  
16739 16736          while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16740 16737                  /*
16741 16738                   * Remove the instance from the instances list.
16742 16739                   * The unaccounted for instances will be removed
16743 16740                   * from the service once all manifests are
16744 16741                   * processed.
16745 16742                   */
16746 16743                  (void) remove_string(instances,
16747 16744                      mfinst->sc_name);
16748 16745                  rminstcnt++;
16749 16746          }
16750 16747  
16751 16748          uu_list_walk_end(insts);
16752 16749          internal_bundle_free(b);
16753 16750  
16754 16751          return (rminstcnt);
16755 16752  }
16756 16753  
16757 16754  /*
16758 16755   * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16759 16756   * 'false' to indicate there's no manifest file(s) found for the service.
16760 16757   */
16761 16758  static void
16762 16759  svc_add_no_support(scf_service_t *svc)
16763 16760  {
16764 16761          char    *pname;
16765 16762  
16766 16763          /* Add no support */
16767 16764          cur_svc = svc;
16768 16765          if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16769 16766                  return;
16770 16767  
16771 16768          pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16772 16769          if (pname == NULL)
16773 16770                  uu_die(gettext("Out of memory.\n"));
16774 16771  
16775 16772          (void) lscf_addpropvalue(pname, "boolean:", "0");
16776 16773  
16777 16774          uu_free(pname);
16778 16775          cur_svc = NULL;
16779 16776  }
16780 16777  
16781 16778  /*
16782 16779   * This function handles all upgrade scenarios for a service that doesn't have
16783 16780   * SCF_PG_MANIFESTFILES pg. The function creates and populates
16784 16781   * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16785 16782   * manifest(s) mapping. Manifests under supported directories are inventoried
16786 16783   * and a property is added for each file that delivers configuration to the
16787 16784   * service.  A service that has no corresponding manifest files (deleted) are
16788 16785   * removed from repository.
16789 16786   *
16790 16787   * Unsupported services:
16791 16788   *
16792 16789   * A service is considered unsupported if there is no corresponding manifest
16793 16790   * in the supported directories for that service and the service isn't in the
16794 16791   * history file list.  The history file, MFSTHISTFILE, contains a list of all
16795 16792   * services and instances that were delivered by Solaris before the introduction
16796 16793   * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16797 16794   * the path to the manifest file that defined the service or instance.
16798 16795   *
16799 16796   * Another type of unsupported services is 'handcrafted' services,
16800 16797   * programmatically created services or services created by dependent entries
16801 16798   * in other manifests. A handcrafted service is identified by its lack of any
16802 16799   * instance containing last-import snapshot which is created during svccfg
16803 16800   * import.
16804 16801   *
16805 16802   * This function sets a flag for unsupported services by setting services'
16806 16803   * SCF_PG_MANIFESTFILES/support property to false.
16807 16804   */
16808 16805  static void
16809 16806  upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16810 16807  {
16811 16808          service_manifest_t      *elem;
16812 16809          uu_list_walk_t          *mfwalk;
16813 16810          string_list_t           *mfile;
16814 16811          uu_list_t               *instances;
16815 16812          const char              *sname;
16816 16813          char                    *pname;
16817 16814          int                     r;
16818 16815  
16819 16816          /*
16820 16817           * Since there's no guarantee manifests under /var are available during
16821 16818           * early import, don't perform any upgrade during early import.
16822 16819           */
16823 16820          if (IGNORE_VAR)
16824 16821                  return;
16825 16822  
16826 16823          if (service_manifest_tree == NULL) {
16827 16824                  create_manifest_tree();
16828 16825          }
16829 16826  
16830 16827          /*
16831 16828           * Find service's supporting manifest(s) after
16832 16829           * stripping off the svc:/ prefix that is part
16833 16830           * of the fmri that is not used in the service
16834 16831           * manifest bundle list.
16835 16832           */
16836 16833          sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16837 16834              strlen(SCF_FMRI_SERVICE_PREFIX);
16838 16835          elem = find_add_svc_mfst(sname, NULL);
16839 16836          if (elem == NULL) {
16840 16837  
16841 16838                  /*
16842 16839                   * A handcrafted service, one that has no instance containing
16843 16840                   * last-import snapshot, should get unsupported flag.
16844 16841                   */
16845 16842                  instances = create_instance_list(svc, 1);
16846 16843                  if (instances == NULL) {
16847 16844                          uu_warn(gettext("Unable to create instance list %s\n"),
16848 16845                              svcname);
16849 16846                          return;
16850 16847                  }
16851 16848  
16852 16849                  if (uu_list_numnodes(instances) == 0) {
16853 16850                          svc_add_no_support(svc);
16854 16851                          return;
16855 16852                  }
16856 16853  
16857 16854                  /*
16858 16855                   * If the service is in the history file, and its supporting
16859 16856                   * manifests are not found, we can safely delete the service
16860 16857                   * because its manifests are removed from the system.
16861 16858                   *
16862 16859                   * Services not found in the history file are not delivered by
16863 16860                   * Solaris and/or delivered outside supported directories, set
16864 16861                   * unsupported flag for these services.
16865 16862                   */
16866 16863                  r = check_mfst_history(svcname);
16867 16864                  if (r == -1)
16868 16865                          return;
16869 16866  
16870 16867                  if (r) {
16871 16868                          /* Set unsupported flag for service  */
16872 16869                          svc_add_no_support(svc);
16873 16870                  } else {
16874 16871                          /* Delete the service */
16875 16872                          teardown_service(svc, svcname);
16876 16873                  }
16877 16874  
16878 16875                  return;
16879 16876          }
16880 16877  
16881 16878          /*
16882 16879           * Walk through the list of manifests and add them
16883 16880           * to the service.
16884 16881           *
16885 16882           * Create a manifestfiles pg and add the property.
16886 16883           */
16887 16884          mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16888 16885          if (mfwalk == NULL)
16889 16886                  return;
16890 16887  
16891 16888          cur_svc = svc;
16892 16889          r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16893 16890          if (r != 0) {
16894 16891                  cur_svc = NULL;
16895 16892                  return;
16896 16893          }
16897 16894  
16898 16895          while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16899 16896                  pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16900 16897                      mhash_filename_to_propname(mfile->str, 0));
16901 16898                  if (pname == NULL)
16902 16899                          uu_die(gettext("Out of memory.\n"));
16903 16900  
16904 16901                  (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16905 16902                  uu_free(pname);
16906 16903          }
16907 16904          uu_list_walk_end(mfwalk);
16908 16905  
16909 16906          cur_svc = NULL;
16910 16907  }
16911 16908  
16912 16909  /*
16913 16910   * Take a service and process the manifest file entires to see if
16914 16911   * there is continued support for the service and instances.  If
16915 16912   * not cleanup as appropriate.
16916 16913   *
16917 16914   * If a service does not have a manifest files entry flag it for
16918 16915   * upgrade and return.
16919 16916   *
16920 16917   * For each manifestfiles property check if the manifest file is
16921 16918   * under the supported /lib/svc/manifest or /var/svc/manifest path
16922 16919   * and if not then return immediately as this service is not supported
16923 16920   * by the cleanup mechanism and should be ignored.
16924 16921   *
16925 16922   * For each manifest file that is supported, check to see if the
16926 16923   * file exists.  If not then remove the manifest file property
16927 16924   * from the service and the smf/manifest hash table.  If the manifest
16928 16925   * file exists then verify that it supports the instances that are
16929 16926   * part of the service.
16930 16927   *
16931 16928   * Once all manifest files have been accounted for remove any instances
16932 16929   * that are no longer supported in the service.
16933 16930   *
16934 16931   * Return values :
16935 16932   * 0 - Successfully processed the service
16936 16933   * non-zero - failed to process the service
16937 16934   *
16938 16935   * On most errors, will just return to wait and get the next service,
16939 16936   * unless in case of unable to create the needed structures which is
16940 16937   * most likely a fatal error that is not going to be recoverable.
16941 16938   */
16942 16939  int
16943 16940  lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16944 16941  {
16945 16942          struct mpg_mfile        *mpntov;
16946 16943          struct mpg_mfile        **mpvarry = NULL;
16947 16944          scf_service_t           *svc;
16948 16945          scf_propertygroup_t     *mpg;
16949 16946          scf_property_t          *mp;
16950 16947          scf_value_t             *mv;
16951 16948          scf_iter_t              *mi;
16952 16949          scf_instance_t          *instance;
16953 16950          uu_list_walk_t          *insts;
16954 16951          uu_list_t               *instances = NULL;
16955 16952          boolean_t               activity = (boolean_t)act;
16956 16953          char                    *mpnbuf;
16957 16954          char                    *mpvbuf;
16958 16955          char                    *pgpropbuf;
16959 16956          int                     mfstcnt, rminstct, instct, mfstmax;
16960 16957          int                     index;
16961 16958          int                     r = 0;
16962 16959  
16963 16960          assert(g_hndl != NULL);
16964 16961          assert(wip->svc != NULL);
16965 16962          assert(wip->fmri != NULL);
16966 16963  
16967 16964          svc = wip->svc;
16968 16965  
16969 16966          mpg = scf_pg_create(g_hndl);
16970 16967          mp = scf_property_create(g_hndl);
16971 16968          mi = scf_iter_create(g_hndl);
16972 16969          mv = scf_value_create(g_hndl);
16973 16970          instance = scf_instance_create(g_hndl);
16974 16971  
16975 16972          if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16976 16973              instance == NULL) {
16977 16974                  uu_warn(gettext("Unable to create the supporting entities\n"));
16978 16975                  uu_warn(gettext("scf error is : %s\n"),
16979 16976                      scf_strerror(scf_error()));
16980 16977                  scfdie();
16981 16978          }
16982 16979  
16983 16980          /*
16984 16981           * Get the manifestfiles property group to be parsed for
16985 16982           * files existence.
16986 16983           */
16987 16984          if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16988 16985                  switch (scf_error()) {
16989 16986                  case SCF_ERROR_NOT_FOUND:
16990 16987                          upgrade_svc_mfst_connection(svc, wip->fmri);
16991 16988                          break;
16992 16989                  case SCF_ERROR_DELETED:
16993 16990                  case SCF_ERROR_CONNECTION_BROKEN:
16994 16991                          goto out;
16995 16992  
16996 16993                  case SCF_ERROR_HANDLE_MISMATCH:
16997 16994                  case SCF_ERROR_NOT_BOUND:
16998 16995                  case SCF_ERROR_NOT_SET:
16999 16996                  default:
17000 16997                          bad_error("scf_iter_pg_properties",
17001 16998                              scf_error());
17002 16999                  }
17003 17000  
17004 17001                  goto out;
17005 17002          }
17006 17003  
17007 17004          /*
17008 17005           * Iterate through each of the manifestfiles properties
17009 17006           * to determine what manifestfiles are available.
17010 17007           *
17011 17008           * If a manifest file is supported then increment the
17012 17009           * count and therefore the service is safe.
17013 17010           */
17014 17011          if (scf_iter_pg_properties(mi, mpg) != 0) {
17015 17012                  switch (scf_error()) {
17016 17013                  case SCF_ERROR_DELETED:
17017 17014                  case SCF_ERROR_CONNECTION_BROKEN:
17018 17015                          goto out;
17019 17016  
17020 17017                  case SCF_ERROR_HANDLE_MISMATCH:
17021 17018                  case SCF_ERROR_NOT_BOUND:
17022 17019                  case SCF_ERROR_NOT_SET:
17023 17020                  default:
17024 17021                          bad_error("scf_iter_pg_properties",
17025 17022                              scf_error());
17026 17023                  }
17027 17024          }
17028 17025  
17029 17026          mfstcnt = 0;
17030 17027          mfstmax = MFSTFILE_MAX;
17031 17028          mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17032 17029          while ((r = scf_iter_next_property(mi, mp)) != 0) {
17033 17030                  if (r == -1)
17034 17031                          bad_error(gettext("Unable to iterate through "
17035 17032                              "manifestfiles properties : %s"),
17036 17033                              scf_error());
17037 17034  
17038 17035                  mpntov = safe_malloc(sizeof (struct mpg_mfile));
17039 17036                  mpnbuf = safe_malloc(max_scf_name_len + 1);
17040 17037                  mpvbuf = safe_malloc(max_scf_value_len + 1);
17041 17038                  mpntov->mpg = mpnbuf;
17042 17039                  mpntov->mfile = mpvbuf;
17043 17040                  mpntov->access = 1;
17044 17041                  if (scf_property_get_name(mp, mpnbuf,
17045 17042                      max_scf_name_len + 1) < 0) {
17046 17043                          uu_warn(gettext("Unable to get manifest file "
17047 17044                              "property : %s\n"),
17048 17045                              scf_strerror(scf_error()));
17049 17046  
17050 17047                          switch (scf_error()) {
17051 17048                          case SCF_ERROR_DELETED:
17052 17049                          case SCF_ERROR_CONNECTION_BROKEN:
17053 17050                                  r = scferror2errno(scf_error());
17054 17051                                  goto out_free;
17055 17052  
17056 17053                          case SCF_ERROR_HANDLE_MISMATCH:
17057 17054                          case SCF_ERROR_NOT_BOUND:
17058 17055                          case SCF_ERROR_NOT_SET:
17059 17056                          default:
17060 17057                                  bad_error("scf_iter_pg_properties",
17061 17058                                      scf_error());
17062 17059                          }
17063 17060                  }
17064 17061  
17065 17062                  /*
17066 17063                   * The support property is a boolean value that indicates
17067 17064                   * if the service is supported for manifest file deletion.
17068 17065                   * Currently at this time there is no code that sets this
17069 17066                   * value to true.  So while we could just let this be caught
17070 17067                   * by the support check below, in the future this by be set
17071 17068                   * to true and require processing.  So for that, go ahead
17072 17069                   * and check here, and just return if false.  Otherwise,
17073 17070                   * fall through expecting that other support checks will
17074 17071                   * handle the entries.
17075 17072                   */
17076 17073                  if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17077 17074                          uint8_t support;
17078 17075  
17079 17076                          if (scf_property_get_value(mp, mv) != 0 ||
17080 17077                              scf_value_get_boolean(mv, &support) != 0) {
17081 17078                                  uu_warn(gettext("Unable to get the manifest "
17082 17079                                      "support value: %s\n"),
17083 17080                                      scf_strerror(scf_error()));
17084 17081  
17085 17082                                  switch (scf_error()) {
17086 17083                                  case SCF_ERROR_DELETED:
17087 17084                                  case SCF_ERROR_CONNECTION_BROKEN:
17088 17085                                          r = scferror2errno(scf_error());
17089 17086                                          goto out_free;
17090 17087  
17091 17088                                  case SCF_ERROR_HANDLE_MISMATCH:
17092 17089                                  case SCF_ERROR_NOT_BOUND:
17093 17090                                  case SCF_ERROR_NOT_SET:
17094 17091                                  default:
17095 17092                                          bad_error("scf_iter_pg_properties",
17096 17093                                              scf_error());
17097 17094                                  }
17098 17095                          }
17099 17096  
17100 17097                          if (support == B_FALSE)
17101 17098                                  goto out_free;
17102 17099                  }
17103 17100  
17104 17101                  /*
17105 17102                   * Anything with a manifest outside of the supported
17106 17103                   * directories, immediately bail out because that makes
17107 17104                   * this service non-supported.  We don't even want
17108 17105                   * to do instance processing in this case because the
17109 17106                   * instances could be part of the non-supported manifest.
17110 17107                   */
17111 17108                  if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17112 17109                          /*
17113 17110                           * Manifest is not in /lib/svc, so we need to
17114 17111                           * consider the /var/svc case.
17115 17112                           */
17116 17113                          if (strncmp(mpnbuf, VARSVC_PR,
17117 17114                              strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17118 17115                                  /*
17119 17116                                   * Either the manifest is not in /var/svc or
17120 17117                                   * /var is not yet mounted.  We ignore the
17121 17118                                   * manifest either because it is not in a
17122 17119                                   * standard location or because we cannot
17123 17120                                   * currently access the manifest.
17124 17121                                   */
17125 17122                                  goto out_free;
17126 17123                          }
17127 17124                  }
17128 17125  
17129 17126                  /*
17130 17127                   * Get the value to of the manifest file for this entry
17131 17128                   * for access verification and instance support
17132 17129                   * verification if it still exists.
17133 17130                   *
17134 17131                   * During Early Manifest Import if the manifest is in
17135 17132                   * /var/svc then it may not yet be available for checking
17136 17133                   * so we must determine if /var/svc is available.  If not
17137 17134                   * then defer until Late Manifest Import to cleanup.
17138 17135                   */
17139 17136                  if (scf_property_get_value(mp, mv) != 0) {
17140 17137                          uu_warn(gettext("Unable to get the manifest file "
17141 17138                              "value: %s\n"),
17142 17139                              scf_strerror(scf_error()));
17143 17140  
17144 17141                          switch (scf_error()) {
17145 17142                          case SCF_ERROR_DELETED:
17146 17143                          case SCF_ERROR_CONNECTION_BROKEN:
17147 17144                                  r = scferror2errno(scf_error());
17148 17145                                  goto out_free;
17149 17146  
17150 17147                          case SCF_ERROR_HANDLE_MISMATCH:
17151 17148                          case SCF_ERROR_NOT_BOUND:
17152 17149                          case SCF_ERROR_NOT_SET:
17153 17150                          default:
17154 17151                                  bad_error("scf_property_get_value",
17155 17152                                      scf_error());
17156 17153                          }
17157 17154                  }
17158 17155  
17159 17156                  if (scf_value_get_astring(mv, mpvbuf,
17160 17157                      max_scf_value_len + 1) < 0) {
17161 17158                          uu_warn(gettext("Unable to get the manifest "
17162 17159                              "file : %s\n"),
17163 17160                              scf_strerror(scf_error()));
17164 17161  
17165 17162                          switch (scf_error()) {
17166 17163                          case SCF_ERROR_DELETED:
17167 17164                          case SCF_ERROR_CONNECTION_BROKEN:
17168 17165                                  r = scferror2errno(scf_error());
17169 17166                                  goto out_free;
17170 17167  
17171 17168                          case SCF_ERROR_HANDLE_MISMATCH:
17172 17169                          case SCF_ERROR_NOT_BOUND:
17173 17170                          case SCF_ERROR_NOT_SET:
17174 17171                          default:
17175 17172                                  bad_error("scf_value_get_astring",
17176 17173                                      scf_error());
17177 17174                          }
17178 17175                  }
17179 17176  
17180 17177                  mpvarry[mfstcnt] = mpntov;
17181 17178                  mfstcnt++;
17182 17179  
17183 17180                  /*
17184 17181                   * Check for the need to reallocate array
17185 17182                   */
17186 17183                  if (mfstcnt >= (mfstmax - 1)) {
17187 17184                          struct mpg_mfile **newmpvarry;
17188 17185  
17189 17186                          mfstmax = mfstmax * 2;
17190 17187                          newmpvarry = realloc(mpvarry,
17191 17188                              sizeof (struct mpg_mfile *) * mfstmax);
17192 17189  
17193 17190                          if (newmpvarry == NULL)
17194 17191                                  goto out_free;
17195 17192  
17196 17193                          mpvarry = newmpvarry;
17197 17194                  }
17198 17195  
17199 17196                  mpvarry[mfstcnt] = NULL;
17200 17197          }
17201 17198  
17202 17199          for (index = 0; mpvarry[index]; index++) {
17203 17200                  mpntov = mpvarry[index];
17204 17201  
17205 17202                  /*
17206 17203                   * Check to see if the manifestfile is accessable, if so hand
17207 17204                   * this service and manifestfile off to be processed for
17208 17205                   * instance support.
17209 17206                   */
17210 17207                  mpnbuf = mpntov->mpg;
17211 17208                  mpvbuf = mpntov->mfile;
17212 17209                  if (access(mpvbuf, F_OK) != 0) {
17213 17210                          mpntov->access = 0;
17214 17211                          activity++;
17215 17212                          mfstcnt--;
17216 17213                          /* Remove the entry from the service */
17217 17214                          cur_svc = svc;
17218 17215                          pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17219 17216                              mpnbuf);
17220 17217                          if (pgpropbuf == NULL)
17221 17218                                  uu_die(gettext("Out of memory.\n"));
17222 17219  
17223 17220                          lscf_delprop(pgpropbuf);
17224 17221                          cur_svc = NULL;
17225 17222  
17226 17223                          uu_free(pgpropbuf);
17227 17224                  }
17228 17225          }
17229 17226  
17230 17227          /*
17231 17228           * If mfstcnt is 0, none of the manifests that supported the service
17232 17229           * existed so remove the service.
17233 17230           */
17234 17231          if (mfstcnt == 0) {
17235 17232                  teardown_service(svc, wip->fmri);
17236 17233  
17237 17234                  goto out_free;
17238 17235          }
17239 17236  
17240 17237          if (activity) {
17241 17238                  int     nosvcsupport = 0;
17242 17239  
17243 17240                  /*
17244 17241                   * If the list of service instances is NULL then
17245 17242                   * create the list.
17246 17243                   */
17247 17244                  instances = create_instance_list(svc, 1);
17248 17245                  if (instances == NULL) {
17249 17246                          uu_warn(gettext("Unable to create instance list %s\n"),
17250 17247                              wip->fmri);
17251 17248                          goto out_free;
17252 17249                  }
17253 17250  
17254 17251                  rminstct = uu_list_numnodes(instances);
17255 17252                  instct = rminstct;
17256 17253  
17257 17254                  for (index = 0; mpvarry[index]; index++) {
17258 17255                          mpntov = mpvarry[index];
17259 17256                          if (mpntov->access == 0)
17260 17257                                  continue;
17261 17258  
17262 17259                          mpnbuf = mpntov->mpg;
17263 17260                          mpvbuf = mpntov->mfile;
17264 17261                          r = check_instance_support(mpvbuf, wip->fmri,
17265 17262                              instances);
17266 17263                          if (r == -1) {
17267 17264                                  nosvcsupport++;
17268 17265                          } else {
17269 17266                                  rminstct -= r;
17270 17267                          }
17271 17268                  }
17272 17269  
17273 17270                  if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17274 17271                          teardown_service(svc, wip->fmri);
17275 17272  
17276 17273                          goto out_free;
17277 17274                  }
17278 17275          }
17279 17276  
17280 17277          /*
17281 17278           * If there are instances left on the instance list, then
17282 17279           * we must remove them.
17283 17280           */
17284 17281          if (instances != NULL && uu_list_numnodes(instances)) {
17285 17282                  string_list_t *sp;
17286 17283  
17287 17284                  insts = uu_list_walk_start(instances, 0);
17288 17285                  while ((sp = uu_list_walk_next(insts)) != NULL) {
17289 17286                          /*
17290 17287                           * Remove the instance from the instances list.
17291 17288                           */
17292 17289                          safe_printf(gettext("Delete instance %s from "
17293 17290                              "service %s\n"), sp->str, wip->fmri);
17294 17291                          if (scf_service_get_instance(svc, sp->str,
17295 17292                              instance) != SCF_SUCCESS) {
17296 17293                                  (void) uu_warn("scf_error - %s\n",
17297 17294                                      scf_strerror(scf_error()));
17298 17295  
17299 17296                                  continue;
17300 17297                          }
17301 17298  
17302 17299                          (void) disable_instance(instance);
17303 17300  
17304 17301                          (void) lscf_instance_delete(instance, 1);
17305 17302                  }
17306 17303                  scf_instance_destroy(instance);
17307 17304                  uu_list_walk_end(insts);
17308 17305          }
17309 17306  
17310 17307  out_free:
17311 17308          if (mpvarry) {
17312 17309                  struct mpg_mfile *fmpntov;
17313 17310  
17314 17311                  for (index = 0; mpvarry[index]; index++) {
17315 17312                          fmpntov  = mpvarry[index];
17316 17313                          if (fmpntov->mpg == mpnbuf)
17317 17314                                  mpnbuf = NULL;
17318 17315                          free(fmpntov->mpg);
17319 17316  
17320 17317                          if (fmpntov->mfile == mpvbuf)
17321 17318                                  mpvbuf = NULL;
17322 17319                          free(fmpntov->mfile);
17323 17320  
17324 17321                          if (fmpntov == mpntov)
17325 17322                                  mpntov = NULL;
17326 17323                          free(fmpntov);
17327 17324                  }
17328 17325                  if (mpnbuf)
17329 17326                          free(mpnbuf);
17330 17327                  if (mpvbuf)
17331 17328                          free(mpvbuf);
17332 17329                  if (mpntov)
17333 17330                          free(mpntov);
17334 17331  
17335 17332                  free(mpvarry);
17336 17333          }
17337 17334  out:
17338 17335          scf_pg_destroy(mpg);
17339 17336          scf_property_destroy(mp);
17340 17337          scf_iter_destroy(mi);
17341 17338          scf_value_destroy(mv);
17342 17339  
17343 17340          return (0);
17344 17341  }
17345 17342  
17346 17343  /*
17347 17344   * Take the service and search for the manifestfiles property
17348 17345   * in each of the property groups.  If the manifest file
17349 17346   * associated with the property does not exist then remove
17350 17347   * the property group.
17351 17348   */
17352 17349  int
17353 17350  lscf_hash_cleanup()
17354 17351  {
17355 17352          scf_service_t           *svc;
17356 17353          scf_scope_t             *scope;
17357 17354          scf_propertygroup_t     *pg;
17358 17355          scf_property_t          *prop;
17359 17356          scf_value_t             *val;
17360 17357          scf_iter_t              *iter;
17361 17358          char                    *pgname = NULL;
17362 17359          char                    *mfile = NULL;
17363 17360          int                     r;
17364 17361  
17365 17362          svc = scf_service_create(g_hndl);
17366 17363          scope = scf_scope_create(g_hndl);
17367 17364          pg = scf_pg_create(g_hndl);
17368 17365          prop = scf_property_create(g_hndl);
17369 17366          val = scf_value_create(g_hndl);
17370 17367          iter = scf_iter_create(g_hndl);
17371 17368          if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17372 17369              svc == NULL || scope == NULL) {
17373 17370                  uu_warn(gettext("Unable to create a property group, or "
17374 17371                      "property\n"));
17375 17372                  uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17376 17373                      "pg is not NULL");
17377 17374                  uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17378 17375                      "prop is not NULL");
17379 17376                  uu_warn("%s\n", val == NULL ? "val is NULL" :
17380 17377                      "val is not NULL");
17381 17378                  uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17382 17379                      "iter is not NULL");
17383 17380                  uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17384 17381                      "svc is not NULL");
17385 17382                  uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17386 17383                      "scope is not NULL");
17387 17384                  uu_warn(gettext("scf error is : %s\n"),
17388 17385                      scf_strerror(scf_error()));
17389 17386                  scfdie();
17390 17387          }
17391 17388  
17392 17389          if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17393 17390                  switch (scf_error()) {
17394 17391                  case SCF_ERROR_CONNECTION_BROKEN:
17395 17392                  case SCF_ERROR_NOT_FOUND:
17396 17393                          goto out;
17397 17394  
17398 17395                  case SCF_ERROR_HANDLE_MISMATCH:
17399 17396                  case SCF_ERROR_NOT_BOUND:
17400 17397                  case SCF_ERROR_INVALID_ARGUMENT:
17401 17398                  default:
17402 17399                          bad_error("scf_handle_get_scope", scf_error());
17403 17400                  }
17404 17401          }
17405 17402  
17406 17403          if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17407 17404                  uu_warn(gettext("Unable to process the hash service, %s\n"),
17408 17405                      HASH_SVC);
17409 17406                  goto out;
17410 17407          }
17411 17408  
17412 17409          pgname = safe_malloc(max_scf_name_len + 1);
17413 17410          mfile = safe_malloc(max_scf_value_len + 1);
17414 17411  
17415 17412          if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17416 17413                  uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17417 17414                      scf_strerror(scf_error()));
17418 17415                  goto out;
17419 17416          }
17420 17417  
17421 17418          while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17422 17419                  if (r == -1)
17423 17420                          goto out;
17424 17421  
17425 17422                  if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17426 17423                          switch (scf_error()) {
17427 17424                          case SCF_ERROR_DELETED:
17428 17425                                  return (ENODEV);
17429 17426  
17430 17427                          case SCF_ERROR_CONNECTION_BROKEN:
17431 17428                                  return (ECONNABORTED);
17432 17429  
17433 17430                          case SCF_ERROR_NOT_SET:
17434 17431                          case SCF_ERROR_NOT_BOUND:
17435 17432                          default:
17436 17433                                  bad_error("scf_pg_get_name", scf_error());
17437 17434                          }
17438 17435                  }
17439 17436                  if (IGNORE_VAR) {
17440 17437                          if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17441 17438                                  continue;
17442 17439                  }
17443 17440  
17444 17441                  /*
17445 17442                   * If unable to get the property continue as this is an
17446 17443                   * entry that has no location to check against.
17447 17444                   */
17448 17445                  if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17449 17446                          continue;
17450 17447                  }
17451 17448  
17452 17449                  if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17453 17450                          uu_warn(gettext("Unable to get value from %s\n"),
17454 17451                              pgname);
17455 17452  
17456 17453                          switch (scf_error()) {
17457 17454                          case SCF_ERROR_DELETED:
17458 17455                          case SCF_ERROR_CONSTRAINT_VIOLATED:
17459 17456                          case SCF_ERROR_NOT_FOUND:
17460 17457                          case SCF_ERROR_NOT_SET:
17461 17458                                  continue;
17462 17459  
17463 17460                          case SCF_ERROR_CONNECTION_BROKEN:
17464 17461                                  r = scferror2errno(scf_error());
17465 17462                                  goto out;
17466 17463  
17467 17464                          case SCF_ERROR_HANDLE_MISMATCH:
17468 17465                          case SCF_ERROR_NOT_BOUND:
17469 17466                          default:
17470 17467                                  bad_error("scf_property_get_value",
17471 17468                                      scf_error());
17472 17469                          }
17473 17470                  }
17474 17471  
17475 17472                  if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17476 17473                      == -1) {
17477 17474                          uu_warn(gettext("Unable to get astring from %s : %s\n"),
17478 17475                              pgname, scf_strerror(scf_error()));
17479 17476  
17480 17477                          switch (scf_error()) {
17481 17478                          case SCF_ERROR_NOT_SET:
17482 17479                          case SCF_ERROR_TYPE_MISMATCH:
17483 17480                                  continue;
17484 17481  
17485 17482                          default:
17486 17483                                  bad_error("scf_value_get_astring", scf_error());
17487 17484                          }
17488 17485                  }
17489 17486  
17490 17487                  if (access(mfile, F_OK) == 0)
17491 17488                          continue;
17492 17489  
17493 17490                  (void) scf_pg_delete(pg);
17494 17491          }
17495 17492  
17496 17493  out:
17497 17494          scf_scope_destroy(scope);
17498 17495          scf_service_destroy(svc);
17499 17496          scf_pg_destroy(pg);
17500 17497          scf_property_destroy(prop);
17501 17498          scf_value_destroy(val);
17502 17499          scf_iter_destroy(iter);
17503 17500          free(pgname);
17504 17501          free(mfile);
17505 17502  
17506 17503          return (0);
17507 17504  }
17508 17505  
17509 17506  #ifndef NATIVE_BUILD
17510 17507  /* ARGSUSED */
17511 17508  CPL_MATCH_FN(complete_select)
17512 17509  {
17513 17510          const char *arg0, *arg1, *arg1end;
17514 17511          int word_start, err = 0, r;
17515 17512          size_t len;
17516 17513          char *buf;
17517 17514  
17518 17515          lscf_prep_hndl();
17519 17516  
17520 17517          arg0 = line + strspn(line, " \t");
17521 17518          assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17522 17519  
17523 17520          arg1 = arg0 + sizeof ("select") - 1;
17524 17521          arg1 += strspn(arg1, " \t");
17525 17522          word_start = arg1 - line;
17526 17523  
17527 17524          arg1end = arg1 + strcspn(arg1, " \t");
17528 17525          if (arg1end < line + word_end)
17529 17526                  return (0);
17530 17527  
17531 17528          len = line + word_end - arg1;
17532 17529  
17533 17530          buf = safe_malloc(max_scf_name_len + 1);
17534 17531  
17535 17532          if (cur_snap != NULL) {
17536 17533                  return (0);
17537 17534          } else if (cur_inst != NULL) {
17538 17535                  return (0);
17539 17536          } else if (cur_svc != NULL) {
17540 17537                  scf_instance_t *inst;
17541 17538                  scf_iter_t *iter;
17542 17539  
17543 17540                  if ((inst = scf_instance_create(g_hndl)) == NULL ||
17544 17541                      (iter = scf_iter_create(g_hndl)) == NULL)
17545 17542                          scfdie();
17546 17543  
17547 17544                  if (scf_iter_service_instances(iter, cur_svc) != 0)
17548 17545                          scfdie();
17549 17546  
17550 17547                  for (;;) {
17551 17548                          r = scf_iter_next_instance(iter, inst);
17552 17549                          if (r == 0)
17553 17550                                  break;
17554 17551                          if (r != 1)
17555 17552                                  scfdie();
17556 17553  
17557 17554                          if (scf_instance_get_name(inst, buf,
17558 17555                              max_scf_name_len + 1) < 0)
17559 17556                                  scfdie();
17560 17557  
17561 17558                          if (strncmp(buf, arg1, len) == 0) {
17562 17559                                  err = cpl_add_completion(cpl, line, word_start,
17563 17560                                      word_end, buf + len, "", " ");
17564 17561                                  if (err != 0)
17565 17562                                          break;
17566 17563                          }
17567 17564                  }
17568 17565  
17569 17566                  scf_iter_destroy(iter);
17570 17567                  scf_instance_destroy(inst);
17571 17568  
17572 17569                  return (err);
17573 17570          } else {
17574 17571                  scf_service_t *svc;
17575 17572                  scf_iter_t *iter;
17576 17573  
17577 17574                  assert(cur_scope != NULL);
17578 17575  
17579 17576                  if ((svc = scf_service_create(g_hndl)) == NULL ||
17580 17577                      (iter = scf_iter_create(g_hndl)) == NULL)
17581 17578                          scfdie();
17582 17579  
17583 17580                  if (scf_iter_scope_services(iter, cur_scope) != 0)
17584 17581                          scfdie();
17585 17582  
17586 17583                  for (;;) {
17587 17584                          r = scf_iter_next_service(iter, svc);
17588 17585                          if (r == 0)
17589 17586                                  break;
17590 17587                          if (r != 1)
17591 17588                                  scfdie();
17592 17589  
17593 17590                          if (scf_service_get_name(svc, buf,
17594 17591                              max_scf_name_len + 1) < 0)
17595 17592                                  scfdie();
17596 17593  
17597 17594                          if (strncmp(buf, arg1, len) == 0) {
17598 17595                                  err = cpl_add_completion(cpl, line, word_start,
17599 17596                                      word_end, buf + len, "", " ");
17600 17597                                  if (err != 0)
17601 17598                                          break;
17602 17599                          }
17603 17600                  }
17604 17601  
17605 17602                  scf_iter_destroy(iter);
17606 17603                  scf_service_destroy(svc);
17607 17604  
17608 17605                  return (err);
17609 17606          }
17610 17607  }
17611 17608  
17612 17609  /* ARGSUSED */
17613 17610  CPL_MATCH_FN(complete_command)
17614 17611  {
17615 17612          uint32_t scope = 0;
17616 17613  
17617 17614          if (cur_snap != NULL)
17618 17615                  scope = CS_SNAP;
17619 17616          else if (cur_inst != NULL)
17620 17617                  scope = CS_INST;
17621 17618          else if (cur_svc != NULL)
17622 17619                  scope = CS_SVC;
17623 17620          else
17624 17621                  scope = CS_SCOPE;
17625 17622  
17626 17623          return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17627 17624  }
17628 17625  #endif  /* NATIVE_BUILD */
  
    | 
      ↓ open down ↓ | 
    13644 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX